mirror of
https://github.com/EQEmu/Server.git
synced 2026-02-21 13:42:24 +00:00
Merge branch 'master' of github.com:EQEmu/Server
This commit is contained in:
commit
467afc86af
@ -1,5 +1,11 @@
|
||||
EQEMu Changelog (Started on Sept 24, 2003 15:50)
|
||||
-------------------------------------------------------
|
||||
== 08/26/2014 ==
|
||||
Uleat: Implemented 'Smart' Player Trade transfers. Trades are processed by containers, stackables and then all remaining. QueryServ logs have been updated to match these transactions.
|
||||
Note: QueryServ logs previously listed 'Items' on the main entry table. This indicated the number of slots affected and not the actual number of items.
|
||||
This field now indicates the actual number of items transferred. For non-stackable, the value is '1' and stackable is the number of charges. A _detail_count
|
||||
property has been added to both 'Trade' and 'Handin' structs to indicate the number of details recorded..though, not tracked..it could be added.
|
||||
|
||||
== 08/24/2014 ==
|
||||
Uleat: Fix (attempted) for zone crashes related to zone shut-down. This change disables all Mob AI and disables/deletes all Mob timers once Zone::ShutDown() is called. More areas will be addressed as reports come in.
|
||||
Note: Perl and Lua quests tested to work..please post any aberrant behavior. (I finally set my spell-check to US English...)
|
||||
@ -49,6 +55,16 @@ Akkadius: Spawn related logging cleanup
|
||||
Akkadius: General code cleanup
|
||||
Akkadius: More to come for QueryServ
|
||||
|
||||
== 08/22/2014 ==
|
||||
Uleat: Rework of Trade::FinishedTrade() and Trade::ResetTrade() to parse items a little more intelligently.
|
||||
|
||||
Trade window items are now sent to client inventory in this order:
|
||||
- Bags
|
||||
- Partial stack movements
|
||||
- All remaining items
|
||||
|
||||
If any of these procedures cause any problems, please post them immediately.
|
||||
|
||||
== 08/20/2014 ==
|
||||
Uleat: Rework of Trade::AddEntity() - function used to move items into the trade window. Now accepts argument for 'stack_size' and updates client properly.
|
||||
Note: I tested trade with Titanium:{SoF,SoD,UF,RoF} in both directions and no client generated an OP_MoveItem event for attempting to place a stackable
|
||||
|
||||
@ -654,6 +654,99 @@ int16 Inventory::FindFreeSlot(bool for_bag, bool try_cursor, uint8 min_size, boo
|
||||
return INVALID_INDEX;
|
||||
}
|
||||
|
||||
// This is a mix of HasSpaceForItem and FindFreeSlot..due to existing coding behavior, it was better to add a new helper function...
|
||||
int16 Inventory::FindFreeSlotForTradeItem(const ItemInst* inst) {
|
||||
// Do not arbitrarily use this function..it is designed for use with Client::ResetTrade() and Client::FinishTrade().
|
||||
// If you have a need, use it..but, understand it is not a compatible replacement for Inventory::FindFreeSlot().
|
||||
//
|
||||
// I'll probably implement a bitmask in the new inventory system to avoid having to adjust stack bias -U
|
||||
|
||||
if (!inst || !inst->GetID())
|
||||
return INVALID_INDEX;
|
||||
|
||||
// step 1: find room for bags (caller should really ask for slots for bags first to avoid sending them to cursor..and bag item loss)
|
||||
if (inst->IsType(ItemClassContainer)) {
|
||||
for (int16 free_slot = EmuConstants::GENERAL_BEGIN; free_slot <= EmuConstants::GENERAL_END; ++free_slot)
|
||||
if (!m_inv[free_slot])
|
||||
return free_slot;
|
||||
|
||||
return MainCursor; // return cursor since bags do not stack and will not fit inside other bags..yet...)
|
||||
}
|
||||
|
||||
// step 2: find partial room for stackables
|
||||
if (inst->IsStackable()) {
|
||||
for (int16 free_slot = EmuConstants::GENERAL_BEGIN; free_slot <= EmuConstants::GENERAL_END; ++free_slot) {
|
||||
const ItemInst* main_inst = m_inv[free_slot];
|
||||
|
||||
if (!main_inst)
|
||||
continue;
|
||||
|
||||
if ((main_inst->GetID() == inst->GetID()) && (main_inst->GetCharges() < main_inst->GetItem()->StackSize))
|
||||
return free_slot;
|
||||
|
||||
if (main_inst->IsType(ItemClassContainer)) { // if item-specific containers already have bad items, we won't fix it here...
|
||||
for (uint8 free_bag_slot = SUB_BEGIN; (free_bag_slot < main_inst->GetItem()->BagSlots) && (free_bag_slot < EmuConstants::ITEM_CONTAINER_SIZE); ++free_bag_slot) {
|
||||
const ItemInst* sub_inst = main_inst->GetItem(free_bag_slot);
|
||||
|
||||
if (!sub_inst)
|
||||
continue;
|
||||
|
||||
if ((sub_inst->GetID() == inst->GetID()) && (sub_inst->GetCharges() < sub_inst->GetItem()->StackSize))
|
||||
return Inventory::CalcSlotId(free_slot, free_bag_slot);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// step 3a: find room for container-specific items (ItemClassArrow)
|
||||
if (inst->GetItem()->ItemType == ItemTypeArrow) {
|
||||
for (int16 free_slot = EmuConstants::GENERAL_BEGIN; free_slot <= EmuConstants::GENERAL_END; ++free_slot) {
|
||||
const ItemInst* main_inst = m_inv[free_slot];
|
||||
|
||||
if (!main_inst || (main_inst->GetItem()->BagType != BagTypeQuiver) || !main_inst->IsType(ItemClassContainer))
|
||||
continue;
|
||||
|
||||
for (uint8 free_bag_slot = SUB_BEGIN; (free_bag_slot < main_inst->GetItem()->BagSlots) && (free_bag_slot < EmuConstants::ITEM_CONTAINER_SIZE); ++free_bag_slot)
|
||||
if (!main_inst->GetItem(free_bag_slot))
|
||||
return Inventory::CalcSlotId(free_slot, free_bag_slot);
|
||||
}
|
||||
}
|
||||
|
||||
// step 3b: find room for container-specific items (ItemClassSmallThrowing)
|
||||
if (inst->GetItem()->ItemType == ItemTypeSmallThrowing) {
|
||||
for (int16 free_slot = EmuConstants::GENERAL_BEGIN; free_slot <= EmuConstants::GENERAL_END; ++free_slot) {
|
||||
const ItemInst* main_inst = m_inv[free_slot];
|
||||
|
||||
if (!main_inst || (main_inst->GetItem()->BagType != BagTypeBandolier) || !main_inst->IsType(ItemClassContainer))
|
||||
continue;
|
||||
|
||||
for (uint8 free_bag_slot = SUB_BEGIN; (free_bag_slot < main_inst->GetItem()->BagSlots) && (free_bag_slot < EmuConstants::ITEM_CONTAINER_SIZE); ++free_bag_slot)
|
||||
if (!main_inst->GetItem(free_bag_slot))
|
||||
return Inventory::CalcSlotId(free_slot, free_bag_slot);
|
||||
}
|
||||
}
|
||||
|
||||
// step 4: just find an empty slot
|
||||
for (int16 free_slot = EmuConstants::GENERAL_BEGIN; free_slot <= EmuConstants::GENERAL_END; ++free_slot) {
|
||||
const ItemInst* main_inst = m_inv[free_slot];
|
||||
|
||||
if (!main_inst)
|
||||
return free_slot;
|
||||
|
||||
if (main_inst->IsType(ItemClassContainer)) {
|
||||
if ((main_inst->GetItem()->BagSize < inst->GetItem()->Size) || (main_inst->GetItem()->BagType == BagTypeBandolier) || (main_inst->GetItem()->BagType == BagTypeQuiver))
|
||||
continue;
|
||||
|
||||
for (uint8 free_bag_slot = SUB_BEGIN; (free_bag_slot < main_inst->GetItem()->BagSlots) && (free_bag_slot < EmuConstants::ITEM_CONTAINER_SIZE); ++free_bag_slot)
|
||||
if (!main_inst->GetItem(free_bag_slot))
|
||||
return Inventory::CalcSlotId(free_slot, free_bag_slot);
|
||||
}
|
||||
}
|
||||
|
||||
//return INVALID_INDEX; // everything else pushes to the cursor
|
||||
return MainCursor;
|
||||
}
|
||||
|
||||
// Opposite of below: Get parent bag slot_id from a slot inside of bag
|
||||
int16 Inventory::CalcSlotId(int16 slot_id) {
|
||||
int16 parent_slot_id = INVALID_INDEX;
|
||||
|
||||
@ -172,6 +172,7 @@ public:
|
||||
|
||||
// Locate an available inventory slot
|
||||
int16 FindFreeSlot(bool for_bag, bool try_cursor, uint8 min_size = 0, bool is_arrow = false);
|
||||
int16 FindFreeSlotForTradeItem(const ItemInst* inst);
|
||||
|
||||
// Calculate slot_id for an item within a bag
|
||||
static int16 CalcSlotId(int16 slot_id); // Calc parent bag's slot_id
|
||||
|
||||
@ -40,7 +40,7 @@ public:
|
||||
MySQLRequestResult& operator=(MySQLRequestResult&& other);
|
||||
|
||||
bool Success() const { return m_Success;}
|
||||
std::string ErrorMessage() const {return std::string(m_ErrorBuffer);}
|
||||
std::string ErrorMessage() const {return m_ErrorBuffer ? std::string(m_ErrorBuffer) : std::string("");}
|
||||
uint32 ErrorNumber() const {return m_ErrorNumber;}
|
||||
uint32 RowsAffected() const {return m_RowsAffected;}
|
||||
uint32 RowCount() const {return m_RowCount;}
|
||||
|
||||
@ -1118,6 +1118,7 @@ struct QSPlayerLogTrade_Struct {
|
||||
uint32 char2_id;
|
||||
MoneyUpdate_Struct char2_money;
|
||||
uint16 char2_count;
|
||||
uint16 _detail_count;
|
||||
QSTradeItems_Struct items[0];
|
||||
};
|
||||
|
||||
@ -1141,6 +1142,7 @@ struct QSPlayerLogHandin_Struct {
|
||||
uint32 npc_id;
|
||||
MoneyUpdate_Struct npc_money;
|
||||
uint16 npc_count;
|
||||
uint16 _detail_count;
|
||||
QSHandinItems_Struct items[0];
|
||||
};
|
||||
|
||||
|
||||
@ -119,7 +119,7 @@ void Database::AddSpeech(const char* from, const char* to, const char* message,
|
||||
safe_delete_array(S3);
|
||||
}
|
||||
|
||||
void Database::LogPlayerTrade(QSPlayerLogTrade_Struct* QS, uint32 Items) {
|
||||
void Database::LogPlayerTrade(QSPlayerLogTrade_Struct* QS, uint32 DetailCount) {
|
||||
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
@ -134,8 +134,8 @@ void Database::LogPlayerTrade(QSPlayerLogTrade_Struct* QS, uint32 Items) {
|
||||
_log(QUERYSERV__ERROR, "%s", query);
|
||||
}
|
||||
|
||||
if(Items > 0) {
|
||||
for(int i = 0; i < Items; i++) {
|
||||
if(DetailCount > 0) {
|
||||
for(int i = 0; i < DetailCount; i++) {
|
||||
if(!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO `qs_player_trade_record_entries` SET `event_id`='%i', "
|
||||
"`from_id`='%i', `from_slot`='%i', `to_id`='%i', `to_slot`='%i', `item_id`='%i', "
|
||||
"`charges`='%i', `aug_1`='%i', `aug_2`='%i', `aug_3`='%i', `aug_4`='%i', `aug_5`='%i'",
|
||||
@ -149,7 +149,7 @@ void Database::LogPlayerTrade(QSPlayerLogTrade_Struct* QS, uint32 Items) {
|
||||
}
|
||||
}
|
||||
|
||||
void Database::LogPlayerHandin(QSPlayerLogHandin_Struct* QS, uint32 Items) {
|
||||
void Database::LogPlayerHandin(QSPlayerLogHandin_Struct* QS, uint32 DetailCount) {
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
uint32 lastid = 0;
|
||||
@ -163,8 +163,8 @@ void Database::LogPlayerHandin(QSPlayerLogHandin_Struct* QS, uint32 Items) {
|
||||
_log(QUERYSERV__ERROR, "%s", query);
|
||||
}
|
||||
|
||||
if(Items > 0) {
|
||||
for(int i = 0; i < Items; i++) {
|
||||
if(DetailCount > 0) {
|
||||
for(int i = 0; i < DetailCount; i++) {
|
||||
if(!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO `qs_player_handin_record_entries` SET `event_id`='%i', "
|
||||
"`action_type`='%s', `char_slot`='%i', `item_id`='%i', `charges`='%i', "
|
||||
"`aug_1`='%i', `aug_2`='%i', `aug_3`='%i', `aug_4`='%i', `aug_5`='%i'",
|
||||
|
||||
@ -43,8 +43,8 @@ public:
|
||||
~Database();
|
||||
|
||||
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 LogPlayerHandin(QSPlayerLogHandin_Struct* QS, uint32 Items);
|
||||
void LogPlayerTrade(QSPlayerLogTrade_Struct* QS, uint32 DetailCount);
|
||||
void LogPlayerHandin(QSPlayerLogHandin_Struct* QS, uint32 DetailCount);
|
||||
void LogPlayerNPCKill(QSPlayerLogNPCKill_Struct* QS, uint32 Members);
|
||||
void LogPlayerDelete(QSPlayerLogDelete_Struct* QS, uint32 Items);
|
||||
void LogPlayerMove(QSPlayerLogMove_Struct* QS, uint32 Items);
|
||||
|
||||
@ -80,14 +80,12 @@ void WorldServer::Process()
|
||||
}
|
||||
case ServerOP_QSPlayerLogTrades: {
|
||||
QSPlayerLogTrade_Struct *QS = (QSPlayerLogTrade_Struct*)pack->pBuffer;
|
||||
uint32 Items = QS->char1_count + QS->char2_count;
|
||||
database.LogPlayerTrade(QS, Items);
|
||||
database.LogPlayerTrade(QS, QS->_detail_count);
|
||||
break;
|
||||
}
|
||||
case ServerOP_QSPlayerLogHandins: {
|
||||
QSPlayerLogHandin_Struct *QS = (QSPlayerLogHandin_Struct*)pack->pBuffer;
|
||||
uint32 Items = QS->char_count + QS->npc_count;
|
||||
database.LogPlayerHandin(QS, Items);
|
||||
database.LogPlayerHandin(QS, QS->_detail_count);
|
||||
break;
|
||||
}
|
||||
case ServerOP_QSPlayerLogNPCKills: {
|
||||
|
||||
737
ucs/database.cpp
737
ucs/database.cpp
@ -102,208 +102,143 @@ Database::~Database()
|
||||
{
|
||||
}
|
||||
|
||||
void Database::GetAccountStatus(Client *c) {
|
||||
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
|
||||
if (!RunQuery(query,MakeAnyLenString(&query, "select `status`, `hideme`, `karma`, `revoked` from `account` where `id`='%i' limit 1",
|
||||
c->GetAccountID()),errbuf,&result)){
|
||||
|
||||
_log(UCS__ERROR, "Unable to get account status for character %s, error %s", c->GetName().c_str(), errbuf);
|
||||
|
||||
safe_delete_array(query);
|
||||
void Database::GetAccountStatus(Client *client) {
|
||||
|
||||
std::string query = StringFormat("SELECT `status`, `hideme`, `karma`, `revoked` "
|
||||
"FROM `account` WHERE `id` = '%i' LIMIT 1",
|
||||
client->GetAccountID());
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
_log(UCS__ERROR, "Unable to get account status for character %s, error %s", client->GetName().c_str(), results.ErrorMessage().c_str());
|
||||
return;
|
||||
}
|
||||
_log(UCS__TRACE, "GetAccountStatus Query: %s", query);
|
||||
safe_delete_array(query);
|
||||
|
||||
if(mysql_num_rows(result) != 1)
|
||||
_log(UCS__TRACE, "GetAccountStatus Query: %s", query.c_str());
|
||||
|
||||
if(results.RowCount() != 1)
|
||||
{
|
||||
_log(UCS__ERROR, "Error in GetAccountStatus");
|
||||
mysql_free_result(result);
|
||||
return;
|
||||
}
|
||||
|
||||
row = mysql_fetch_row(result);
|
||||
auto row = results.begin();
|
||||
|
||||
c->SetAccountStatus(atoi(row[0]));
|
||||
c->SetHideMe(atoi(row[1]) != 0);
|
||||
c->SetKarma(atoi(row[2]));
|
||||
c->SetRevoked((atoi(row[3])==1?true:false));
|
||||
client->SetAccountStatus(atoi(row[0]));
|
||||
client->SetHideMe(atoi(row[1]) != 0);
|
||||
client->SetKarma(atoi(row[2]));
|
||||
client->SetRevoked((atoi(row[3])==1?true:false));
|
||||
|
||||
_log(UCS__TRACE, "Set account status to %i, hideme to %i and karma to %i for %s", client->GetAccountStatus(), client->GetHideMe(), client->GetKarma(), client->GetName().c_str());
|
||||
|
||||
_log(UCS__TRACE, "Set account status to %i, hideme to %i and karma to %i for %s", c->GetAccountStatus(), c->GetHideMe(), c->GetKarma(), c->GetName().c_str());
|
||||
mysql_free_result(result);
|
||||
}
|
||||
|
||||
int Database::FindAccount(const char *CharacterName, Client *c) {
|
||||
int Database::FindAccount(const char *characterName, Client *client) {
|
||||
|
||||
_log(UCS__TRACE, "FindAccount for character %s", CharacterName);
|
||||
_log(UCS__TRACE, "FindAccount for character %s", characterName);
|
||||
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
|
||||
c->ClearCharacters();
|
||||
|
||||
if (!RunQuery(query,MakeAnyLenString(&query, "select `id`, `account_id`, `level` from `character_` where `name`='%s' limit 1",
|
||||
CharacterName),errbuf,&result))
|
||||
{
|
||||
_log(UCS__ERROR, "FindAccount query failed: %s", query);
|
||||
safe_delete_array(query);
|
||||
client->ClearCharacters();
|
||||
std::string query = StringFormat("SELECT `id`, `account_id`, `level` "
|
||||
"FROM `character_` WHERE `name` = '%s' LIMIT 1",
|
||||
characterName);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
_log(UCS__ERROR, "FindAccount query failed: %s", query.c_str());
|
||||
return -1;
|
||||
}
|
||||
safe_delete_array(query);
|
||||
|
||||
if (mysql_num_rows(result) != 1)
|
||||
{
|
||||
if (results.RowCount() != 1) {
|
||||
_log(UCS__ERROR, "Bad result from query");
|
||||
mysql_free_result(result);
|
||||
return -1;
|
||||
}
|
||||
|
||||
row = mysql_fetch_row(result);
|
||||
c->AddCharacter(atoi(row[0]), CharacterName, atoi(row[2]));
|
||||
int AccountID = atoi(row[1]);
|
||||
auto row = results.begin();
|
||||
client->AddCharacter(atoi(row[0]), characterName, atoi(row[2]));
|
||||
|
||||
mysql_free_result(result);
|
||||
_log(UCS__TRACE, "Account ID for %s is %i", CharacterName, AccountID);
|
||||
int accountID = atoi(row[1]);
|
||||
|
||||
if (!RunQuery(query,MakeAnyLenString(&query, "select `id`, `name`, `level` from `character_` where `account_id`=%i and `name` !='%s'",
|
||||
AccountID, CharacterName),errbuf,&result))
|
||||
{
|
||||
safe_delete_array(query);
|
||||
return AccountID;
|
||||
}
|
||||
safe_delete_array(query);
|
||||
_log(UCS__TRACE, "Account ID for %s is %i", characterName, accountID);
|
||||
|
||||
for(unsigned int i = 0; i < mysql_num_rows(result); i++)
|
||||
{
|
||||
row = mysql_fetch_row(result);
|
||||
c->AddCharacter(atoi(row[0]), row[1], atoi(row[2]));
|
||||
}
|
||||
mysql_free_result(result);
|
||||
return AccountID;
|
||||
query = StringFormat("SELECT `id`, `name`, `level` FROM `character_` "
|
||||
"WHERE `account_id` = %i AND `name` != '%s'",
|
||||
accountID, characterName);
|
||||
results = QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
return accountID;
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row)
|
||||
client->AddCharacter(atoi(row[0]), row[1], atoi(row[2]));
|
||||
|
||||
return accountID;
|
||||
}
|
||||
|
||||
bool Database::VerifyMailKey(std::string CharacterName, int IPAddress, std::string MailKey) {
|
||||
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
|
||||
if (!RunQuery(query,MakeAnyLenString(&query, "select `mailkey` from `character_` where `name`='%s' limit 1",
|
||||
CharacterName.c_str()),errbuf,&result)){
|
||||
|
||||
safe_delete_array(query);
|
||||
|
||||
_log(UCS__ERROR, "Error retrieving mailkey from database: %s", errbuf);
|
||||
bool Database::VerifyMailKey(std::string characterName, int IPAddress, std::string MailKey) {
|
||||
|
||||
std::string query = StringFormat("SELECT `mailkey` FROM `character_` WHERE `name`='%s' LIMIT 1",
|
||||
characterName.c_str());
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
_log(UCS__ERROR, "Error retrieving mailkey from database: %s", results.ErrorMessage().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
safe_delete_array(query);
|
||||
|
||||
row = mysql_fetch_row(result);
|
||||
auto row = results.begin();
|
||||
|
||||
// The key is the client's IP address (expressed as 8 hex digits) and an 8 hex digit random string generated
|
||||
// by world.
|
||||
//
|
||||
char CombinedKey[17];
|
||||
char combinedKey[17];
|
||||
|
||||
if(RuleB(Chat, EnableMailKeyIPVerification) == true)
|
||||
sprintf(CombinedKey, "%08X%s", IPAddress, MailKey.c_str());
|
||||
sprintf(combinedKey, "%08X%s", IPAddress, MailKey.c_str());
|
||||
else
|
||||
sprintf(CombinedKey, "%s", MailKey.c_str());
|
||||
sprintf(combinedKey, "%s", MailKey.c_str());
|
||||
|
||||
_log(UCS__TRACE, "DB key is [%s], Client key is [%s]", row[0], CombinedKey);
|
||||
|
||||
bool Valid = !strcmp(row[0], CombinedKey);
|
||||
|
||||
mysql_free_result(result);
|
||||
|
||||
return Valid;
|
||||
_log(UCS__TRACE, "DB key is [%s], Client key is [%s]", row[0], combinedKey);
|
||||
|
||||
return !strcmp(row[0], combinedKey);
|
||||
}
|
||||
|
||||
int Database::FindCharacter(const char *CharacterName) {
|
||||
int Database::FindCharacter(const char *characterName) {
|
||||
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
|
||||
char *SafeCharName = RemoveApostrophes(CharacterName);
|
||||
|
||||
if (!RunQuery(query,MakeAnyLenString(&query, "select `id` from `character_` where `name`='%s' limit 1",
|
||||
SafeCharName),errbuf,&result)){
|
||||
|
||||
_log(UCS__ERROR, "FindCharacter failed. %s %s", query, errbuf);
|
||||
|
||||
safe_delete_array(query);
|
||||
safe_delete_array(SafeCharName);
|
||||
char *safeCharName = RemoveApostrophes(characterName);
|
||||
std::string query = StringFormat("SELECT `id` FROM `character_` WHERE `name`='%s' LIMIT 1", safeCharName);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
_log(UCS__ERROR, "FindCharacter failed. %s %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
safe_delete(safeCharName);
|
||||
return -1;
|
||||
}
|
||||
safe_delete(safeCharName);
|
||||
|
||||
if (results.RowCount() != 1) {
|
||||
_log(UCS__ERROR, "Bad result from FindCharacter query for character %s", characterName);
|
||||
return -1;
|
||||
}
|
||||
|
||||
safe_delete_array(query);
|
||||
safe_delete_array(SafeCharName);
|
||||
auto row = results.begin();
|
||||
|
||||
if (mysql_num_rows(result) != 1) {
|
||||
|
||||
_log(UCS__ERROR, "Bad result from FindCharacter query for character %s", CharacterName);
|
||||
|
||||
mysql_free_result(result);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
row = mysql_fetch_row(result);
|
||||
|
||||
int CharacterID = atoi(row[0]);
|
||||
|
||||
mysql_free_result(result);
|
||||
|
||||
return CharacterID;
|
||||
int characterID = atoi(row[0]);
|
||||
|
||||
return characterID;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
std::string query = StringFormat("SELECT `value` FROM `variables` WHERE `varname` = '%s'", varname);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
_log(UCS__ERROR, "Unable to get message count from database. %s %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
safe_delete_array(query);
|
||||
|
||||
if (mysql_num_rows(result) != 1) {
|
||||
|
||||
mysql_free_result(result);
|
||||
|
||||
if (results.RowCount() != 1)
|
||||
return false;
|
||||
}
|
||||
|
||||
row = mysql_fetch_row(result);
|
||||
auto row = results.begin();
|
||||
|
||||
snprintf(varvalue, varvalue_len, "%s", row[0]);
|
||||
|
||||
mysql_free_result(result);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -311,302 +246,238 @@ bool Database::LoadChatChannels() {
|
||||
|
||||
_log(UCS__INIT, "Loading chat channels from the database.");
|
||||
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
|
||||
if (!RunQuery(query,MakeAnyLenString(&query, "select `name`,`owner`,`password`, `minstatus` from `chatchannels`"),errbuf,&result)){
|
||||
|
||||
_log(UCS__ERROR, "Failed to load channels. %s %s", query, errbuf);
|
||||
safe_delete_array(query);
|
||||
|
||||
const std::string query = "SELECT `name`, `owner`, `password`, `minstatus` FROM `chatchannels`";
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
_log(UCS__ERROR, "Failed to load channels. %s %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
safe_delete_array(query);
|
||||
for (auto row = results.begin();row != results.end(); ++row) {
|
||||
std::string channelName = row[0];
|
||||
std::string channelOwner = row[1];
|
||||
std::string channelPassword = row[2];
|
||||
|
||||
while((row = mysql_fetch_row(result))) {
|
||||
|
||||
std::string ChannelName = row[0];
|
||||
std::string ChannelOwner = row[1];
|
||||
std::string ChannelPassword = row[2];
|
||||
|
||||
ChannelList->CreateChannel(ChannelName, ChannelOwner, ChannelPassword, true, atoi(row[3]));
|
||||
ChannelList->CreateChannel(channelName, channelOwner, channelPassword, true, atoi(row[3]));
|
||||
}
|
||||
|
||||
mysql_free_result(result);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Database::SetChannelPassword(std::string ChannelName, std::string Password) {
|
||||
void Database::SetChannelPassword(std::string channelName, std::string password) {
|
||||
|
||||
_log(UCS__TRACE, "Database::SetChannelPassword(%s, %s)", ChannelName.c_str(), Password.c_str());
|
||||
_log(UCS__TRACE, "Database::SetChannelPassword(%s, %s)", channelName.c_str(), password.c_str());
|
||||
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
std::string query = StringFormat("UPDATE `chatchannels` SET `password` = '%s' WHERE `name` = '%s'",
|
||||
password.c_str(), channelName.c_str());
|
||||
auto results = QueryDatabase(query);
|
||||
if(!results.Success())
|
||||
_log(UCS__ERROR, "Error updating password in database: %s, %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
|
||||
if(!RunQuery(query, MakeAnyLenString(&query, "UPDATE `chatchannels` set `password`='%s' where `name`='%s'", Password.c_str(),
|
||||
ChannelName.c_str()), errbuf)) {
|
||||
|
||||
_log(UCS__ERROR, "Error updating password in database: %s, %s", query, errbuf);
|
||||
|
||||
}
|
||||
|
||||
safe_delete_array(query);
|
||||
}
|
||||
|
||||
void Database::SetChannelOwner(std::string ChannelName, std::string Owner) {
|
||||
void Database::SetChannelOwner(std::string channelName, std::string owner) {
|
||||
|
||||
_log(UCS__TRACE, "Database::SetChannelOwner(%s, %s)", ChannelName.c_str(), Owner.c_str());
|
||||
_log(UCS__TRACE, "Database::SetChannelOwner(%s, %s)", channelName.c_str(), owner.c_str());
|
||||
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
std::string query = StringFormat("UPDATE `chatchannels` SET `owner` = '%s' WHERE `name` = '%s'",
|
||||
owner.c_str(), channelName.c_str());
|
||||
auto results = QueryDatabase(query);
|
||||
if(!results.Success())
|
||||
_log(UCS__ERROR, "Error updating Owner in database: %s, %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
|
||||
if(!RunQuery(query, MakeAnyLenString(&query, "UPDATE `chatchannels` set `owner`='%s' where `name`='%s'", Owner.c_str(),
|
||||
ChannelName.c_str()), errbuf)) {
|
||||
|
||||
_log(UCS__ERROR, "Error updating Owner in database: %s, %s", query, errbuf);
|
||||
|
||||
}
|
||||
|
||||
safe_delete_array(query);
|
||||
}
|
||||
|
||||
void Database::SendHeaders(Client *c) {
|
||||
void Database::SendHeaders(Client *client) {
|
||||
|
||||
int UnknownField2 = 25015275;
|
||||
int UnknownField3 = 1;
|
||||
int unknownField2 = 25015275;
|
||||
int unknownField3 = 1;
|
||||
int characterID = FindCharacter(client->MailBoxName().c_str());
|
||||
|
||||
int CharacterID = FindCharacter(c->MailBoxName().c_str());
|
||||
_log(UCS__TRACE, "Sendheaders for %s, CharID is %i", c->MailBoxName().c_str(), CharacterID);
|
||||
if(CharacterID <= 0)
|
||||
_log(UCS__TRACE, "Sendheaders for %s, CharID is %i", client->MailBoxName().c_str(), characterID);
|
||||
|
||||
if(characterID <= 0)
|
||||
return;
|
||||
|
||||
std::string query = StringFormat("SELECT `msgid`,`timestamp`, `from`, `subject`, `status` "
|
||||
"FROM `mail` WHERE `charid`=%i", characterID);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
return;
|
||||
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
char buffer[100];
|
||||
|
||||
if (!RunQuery(query,MakeAnyLenString(&query, "select `msgid`,`timestamp`,`from`,`subject`, `status` from `mail` "
|
||||
"where `charid`=%i", CharacterID),errbuf,&result)){
|
||||
int headerCountPacketLength = 0;
|
||||
|
||||
safe_delete_array(query);
|
||||
sprintf(buffer, "%i", client->GetMailBoxNumber());
|
||||
headerCountPacketLength += (strlen(buffer) + 1);
|
||||
|
||||
return ;
|
||||
}
|
||||
sprintf(buffer, "%i", unknownField2);
|
||||
headerCountPacketLength += (strlen(buffer) + 1);
|
||||
|
||||
safe_delete_array(query);
|
||||
sprintf(buffer, "%i", unknownField3);
|
||||
headerCountPacketLength += (strlen(buffer) + 1);
|
||||
|
||||
char Buf[100];
|
||||
sprintf(buffer, "%i", results.RowCount());
|
||||
headerCountPacketLength += (strlen(buffer) + 1);
|
||||
|
||||
uint32 NumRows = mysql_num_rows(result);
|
||||
EQApplicationPacket *outapp = new EQApplicationPacket(OP_MailHeaderCount, headerCountPacketLength);
|
||||
|
||||
int HeaderCountPacketLength = 0;
|
||||
char *packetBuffer = (char *)outapp->pBuffer;
|
||||
|
||||
sprintf(Buf, "%i", c->GetMailBoxNumber());
|
||||
HeaderCountPacketLength += (strlen(Buf) + 1);
|
||||
|
||||
sprintf(Buf, "%i", UnknownField2);
|
||||
HeaderCountPacketLength += (strlen(Buf) + 1);
|
||||
|
||||
sprintf(Buf, "%i", UnknownField3);
|
||||
HeaderCountPacketLength += (strlen(Buf) + 1);
|
||||
|
||||
sprintf(Buf, "%i", NumRows);
|
||||
HeaderCountPacketLength += (strlen(Buf) + 1);
|
||||
|
||||
EQApplicationPacket *outapp = new EQApplicationPacket(OP_MailHeaderCount, HeaderCountPacketLength);
|
||||
|
||||
char *PacketBuffer = (char *)outapp->pBuffer;
|
||||
|
||||
VARSTRUCT_ENCODE_INTSTRING(PacketBuffer, c->GetMailBoxNumber());
|
||||
VARSTRUCT_ENCODE_INTSTRING(PacketBuffer, UnknownField2);
|
||||
VARSTRUCT_ENCODE_INTSTRING(PacketBuffer, UnknownField3);
|
||||
VARSTRUCT_ENCODE_INTSTRING(PacketBuffer, NumRows);
|
||||
VARSTRUCT_ENCODE_INTSTRING(packetBuffer, client->GetMailBoxNumber());
|
||||
VARSTRUCT_ENCODE_INTSTRING(packetBuffer, unknownField2);
|
||||
VARSTRUCT_ENCODE_INTSTRING(packetBuffer, unknownField3);
|
||||
VARSTRUCT_ENCODE_INTSTRING(packetBuffer, results.RowCount());
|
||||
|
||||
_pkt(UCS__PACKETS, outapp);
|
||||
|
||||
c->QueuePacket(outapp);
|
||||
client->QueuePacket(outapp);
|
||||
|
||||
safe_delete(outapp);
|
||||
|
||||
int RowNum = 0;
|
||||
int rowIndex = 0;
|
||||
for(auto row = results.begin(); row != results.end(); ++row, ++rowIndex) {
|
||||
int headerPacketLength = 0;
|
||||
|
||||
while((row = mysql_fetch_row(result))) {
|
||||
sprintf(buffer, "%i", client->GetMailBoxNumber());
|
||||
headerPacketLength += strlen(buffer) + 1;
|
||||
sprintf(buffer, "%i", unknownField2);
|
||||
headerPacketLength += strlen(buffer) + 1;
|
||||
sprintf(buffer, "%i", rowIndex);
|
||||
headerPacketLength += strlen(buffer) + 1;
|
||||
|
||||
headerPacketLength += strlen(row[0]) + 1;
|
||||
headerPacketLength += strlen(row[1]) + 1;
|
||||
headerPacketLength += strlen(row[4]) + 1;
|
||||
headerPacketLength += GetMailPrefix().length() + strlen(row[2]) + 1;
|
||||
headerPacketLength += strlen(row[3]) + 1;
|
||||
|
||||
int HeaderPacketLength = 0;
|
||||
outapp = new EQApplicationPacket(OP_MailHeader, headerPacketLength);
|
||||
|
||||
sprintf(Buf, "%i", c->GetMailBoxNumber());
|
||||
HeaderPacketLength = HeaderPacketLength + strlen(Buf) + 1;
|
||||
sprintf(Buf, "%i", UnknownField2);
|
||||
HeaderPacketLength = HeaderPacketLength + strlen(Buf) + 1;
|
||||
sprintf(Buf, "%i", RowNum);
|
||||
HeaderPacketLength = HeaderPacketLength + strlen(Buf) + 1;
|
||||
packetBuffer = (char *)outapp->pBuffer;
|
||||
|
||||
HeaderPacketLength = HeaderPacketLength + strlen(row[0]) + 1;
|
||||
HeaderPacketLength = HeaderPacketLength + strlen(row[1]) + 1;
|
||||
HeaderPacketLength = HeaderPacketLength + strlen(row[4]) + 1;
|
||||
HeaderPacketLength = HeaderPacketLength + GetMailPrefix().length() + strlen(row[2]) + 1;
|
||||
HeaderPacketLength = HeaderPacketLength + strlen(row[3]) + 1;
|
||||
|
||||
outapp = new EQApplicationPacket(OP_MailHeader, HeaderPacketLength);
|
||||
|
||||
PacketBuffer = (char *)outapp->pBuffer;
|
||||
|
||||
VARSTRUCT_ENCODE_INTSTRING(PacketBuffer, c->GetMailBoxNumber());
|
||||
VARSTRUCT_ENCODE_INTSTRING(PacketBuffer, UnknownField2);
|
||||
VARSTRUCT_ENCODE_INTSTRING(PacketBuffer, RowNum);
|
||||
VARSTRUCT_ENCODE_STRING(PacketBuffer, row[0]);
|
||||
VARSTRUCT_ENCODE_STRING(PacketBuffer, row[1]);
|
||||
VARSTRUCT_ENCODE_STRING(PacketBuffer, row[4]);
|
||||
VARSTRUCT_ENCODE_STRING(PacketBuffer, GetMailPrefix().c_str()); PacketBuffer--;
|
||||
VARSTRUCT_ENCODE_STRING(PacketBuffer, row[2]);
|
||||
VARSTRUCT_ENCODE_STRING(PacketBuffer, row[3]);
|
||||
VARSTRUCT_ENCODE_INTSTRING(packetBuffer, client->GetMailBoxNumber());
|
||||
VARSTRUCT_ENCODE_INTSTRING(packetBuffer, unknownField2);
|
||||
VARSTRUCT_ENCODE_INTSTRING(packetBuffer, rowIndex);
|
||||
VARSTRUCT_ENCODE_STRING(packetBuffer, row[0]);
|
||||
VARSTRUCT_ENCODE_STRING(packetBuffer, row[1]);
|
||||
VARSTRUCT_ENCODE_STRING(packetBuffer, row[4]);
|
||||
VARSTRUCT_ENCODE_STRING(packetBuffer, GetMailPrefix().c_str());
|
||||
packetBuffer--;
|
||||
VARSTRUCT_ENCODE_STRING(packetBuffer, row[2]);
|
||||
VARSTRUCT_ENCODE_STRING(packetBuffer, row[3]);
|
||||
|
||||
_pkt(UCS__PACKETS, outapp);
|
||||
|
||||
c->QueuePacket(outapp);
|
||||
client->QueuePacket(outapp);
|
||||
|
||||
safe_delete(outapp);
|
||||
|
||||
RowNum++;
|
||||
}
|
||||
|
||||
mysql_free_result(result);
|
||||
|
||||
}
|
||||
|
||||
void Database::SendBody(Client *c, int MessageNumber) {
|
||||
void Database::SendBody(Client *client, int messageNumber) {
|
||||
|
||||
int CharacterID = FindCharacter(c->MailBoxName().c_str());
|
||||
int characterID = FindCharacter(client->MailBoxName().c_str());
|
||||
|
||||
_log(UCS__TRACE, "SendBody: MsgID %i, to %s, CharID is %i", MessageNumber, c->MailBoxName().c_str(), CharacterID);
|
||||
_log(UCS__TRACE, "SendBody: MsgID %i, to %s, CharID is %i", messageNumber, client->MailBoxName().c_str(), characterID);
|
||||
|
||||
if(CharacterID <= 0)
|
||||
if(characterID <= 0)
|
||||
return;
|
||||
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
|
||||
if (!RunQuery(query,MakeAnyLenString(&query, "select `msgid`, `body`, `to` from `mail` "
|
||||
"where `charid`=%i and `msgid`=%i", CharacterID, MessageNumber), errbuf, &result)){
|
||||
safe_delete_array(query);
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
safe_delete_array(query);
|
||||
|
||||
if (mysql_num_rows(result) != 1) {
|
||||
|
||||
mysql_free_result(result);
|
||||
|
||||
std::string query = StringFormat("SELECT `msgid`, `body`, `to` FROM `mail` "
|
||||
"WHERE `charid`=%i AND `msgid`=%i", characterID, messageNumber);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
return;
|
||||
}
|
||||
|
||||
row = mysql_fetch_row(result);
|
||||
|
||||
_log(UCS__TRACE, "Message: %i body (%i bytes)", MessageNumber, strlen(row[1]));
|
||||
if (results.RowCount() != 1)
|
||||
return;
|
||||
|
||||
int PacketLength = 12 + strlen(row[0]) + strlen(row[1]) + strlen(row[2]);
|
||||
auto row = results.begin();
|
||||
|
||||
EQApplicationPacket *outapp = new EQApplicationPacket(OP_MailSendBody,PacketLength);
|
||||
_log(UCS__TRACE, "Message: %i body (%i bytes)", messageNumber, strlen(row[1]));
|
||||
|
||||
char *PacketBuffer = (char *)outapp->pBuffer;
|
||||
int packetLength = 12 + strlen(row[0]) + strlen(row[1]) + strlen(row[2]);
|
||||
|
||||
VARSTRUCT_ENCODE_INTSTRING(PacketBuffer, c->GetMailBoxNumber());
|
||||
VARSTRUCT_ENCODE_STRING(PacketBuffer,row[0]);
|
||||
VARSTRUCT_ENCODE_STRING(PacketBuffer,row[1]);
|
||||
VARSTRUCT_ENCODE_STRING(PacketBuffer,"1");
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, PacketBuffer, 0);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, PacketBuffer, 0x0a);
|
||||
VARSTRUCT_ENCODE_STRING(PacketBuffer, "TO:"); PacketBuffer--;
|
||||
VARSTRUCT_ENCODE_STRING(PacketBuffer, row[2]); PacketBuffer--; // Overwrite the null terminator
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, PacketBuffer, 0x0a);
|
||||
EQApplicationPacket *outapp = new EQApplicationPacket(OP_MailSendBody,packetLength);
|
||||
|
||||
mysql_free_result(result);
|
||||
char *packetBuffer = (char *)outapp->pBuffer;
|
||||
|
||||
VARSTRUCT_ENCODE_INTSTRING(packetBuffer, client->GetMailBoxNumber());
|
||||
VARSTRUCT_ENCODE_STRING(packetBuffer,row[0]);
|
||||
VARSTRUCT_ENCODE_STRING(packetBuffer,row[1]);
|
||||
VARSTRUCT_ENCODE_STRING(packetBuffer,"1");
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, packetBuffer, 0);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, packetBuffer, 0x0a);
|
||||
VARSTRUCT_ENCODE_STRING(packetBuffer, "TO:");
|
||||
packetBuffer--;
|
||||
VARSTRUCT_ENCODE_STRING(packetBuffer, row[2]);
|
||||
packetBuffer--; // Overwrite the null terminator
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, packetBuffer, 0x0a);
|
||||
|
||||
_pkt(UCS__PACKETS, outapp);
|
||||
|
||||
c->QueuePacket(outapp);
|
||||
client->QueuePacket(outapp);
|
||||
|
||||
safe_delete(outapp);
|
||||
|
||||
|
||||
}
|
||||
|
||||
bool Database::SendMail(std::string Recipient, std::string From, std::string Subject, std::string Body, std::string RecipientsString) {
|
||||
bool Database::SendMail(std::string recipient, std::string from, std::string subject, std::string body, std::string recipientsString) {
|
||||
|
||||
int CharacterID;
|
||||
int characterID;
|
||||
std::string characterName;
|
||||
|
||||
std::string CharacterName;
|
||||
auto lastPeriod = recipient.find_last_of(".");
|
||||
|
||||
//printf("Database::SendMail(%s, %s, %s)\n", Recipient.c_str(), From.c_str(), Subject.c_str());
|
||||
|
||||
std::string::size_type LastPeriod = Recipient.find_last_of(".");
|
||||
|
||||
if(LastPeriod == std::string::npos)
|
||||
CharacterName = Recipient;
|
||||
if(lastPeriod == std::string::npos)
|
||||
characterName = recipient;
|
||||
else
|
||||
CharacterName = Recipient.substr(LastPeriod+1);
|
||||
characterName = recipient.substr(lastPeriod+1);
|
||||
|
||||
CharacterName[0] = toupper(CharacterName[0]);
|
||||
characterName[0] = toupper(characterName[0]);
|
||||
|
||||
for(unsigned int i = 1; i < CharacterName.length(); i++)
|
||||
CharacterName[i] = tolower(CharacterName[i]);
|
||||
for(unsigned int i = 1; i < characterName.length(); i++)
|
||||
characterName[i] = tolower(characterName[i]);
|
||||
|
||||
CharacterID = FindCharacter(CharacterName.c_str());
|
||||
characterID = FindCharacter(characterName.c_str());
|
||||
|
||||
_log(UCS__TRACE, "SendMail: CharacterID for recipient %s is %i", CharacterName.c_str(), CharacterID);
|
||||
_log(UCS__TRACE, "SendMail: CharacterID for recipient %s is %i", characterName.c_str(), characterID);
|
||||
|
||||
if(CharacterID <= 0) return false;
|
||||
if(characterID <= 0)
|
||||
return false;
|
||||
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
char *escSubject = new char[subject.length() * 2 + 1];
|
||||
char *escBody = new char[body.length() * 2 + 1];
|
||||
|
||||
char *EscSubject = new char[Subject.length() * 2 + 1];
|
||||
char *EscBody = new char[Body.length() * 2 + 1];
|
||||
DoEscapeString(escSubject, subject.c_str(), subject.length());
|
||||
DoEscapeString(escBody, body.c_str(), body.length());
|
||||
|
||||
DoEscapeString(EscSubject, Subject.c_str(), Subject.length());
|
||||
DoEscapeString(EscBody, Body.c_str(), Body.length());
|
||||
|
||||
const char *MailQuery="INSERT INTO `mail` (`charid`, `timestamp`, `from`, `subject`, `body`, `to`, `status`) "
|
||||
"VALUES ('%i', %i, '%s', '%s', '%s', '%s', %i)";
|
||||
|
||||
uint32 LastMsgID;
|
||||
|
||||
int Now = time(nullptr); // time returns a 64 bit int on Windows at least, which vsnprintf doesn't like.
|
||||
|
||||
if(!RunQuery(query, MakeAnyLenString(&query, MailQuery, CharacterID, Now, From.c_str(), EscSubject, EscBody,
|
||||
RecipientsString.c_str(), 1), errbuf, 0, 0, &LastMsgID)) {
|
||||
|
||||
_log(UCS__ERROR, "SendMail: Query %s failed with error %s", query, errbuf);
|
||||
|
||||
safe_delete_array(EscSubject);
|
||||
safe_delete_array(EscBody);
|
||||
safe_delete_array(query);
|
||||
int now = time(nullptr); // time returns a 64 bit int on Windows at least, which vsnprintf doesn't like.
|
||||
|
||||
std::string query = StringFormat("INSERT INTO `mail` "
|
||||
"(`charid`, `timestamp`, `from`, `subject`, `body`, `to`, `status`) "
|
||||
"VALUES ('%i', %i, '%s', '%s', '%s', '%s', %i)",
|
||||
characterID, now, from.c_str(), escSubject, escBody,
|
||||
recipientsString.c_str(), 1);
|
||||
safe_delete_array(escSubject);
|
||||
safe_delete_array(escBody);
|
||||
auto results = QueryDatabase(query);
|
||||
if(!results.Success()) {
|
||||
_log(UCS__ERROR, "SendMail: Query %s failed with error %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
_log(UCS__TRACE, "MessageID %i generated, from %s, to %s", LastMsgID, From.c_str(), Recipient.c_str());
|
||||
_log(UCS__TRACE, "MessageID %i generated, from %s, to %s", results.LastInsertedID(), from.c_str(), recipient.c_str());
|
||||
|
||||
safe_delete_array(EscSubject);
|
||||
safe_delete_array(EscBody);
|
||||
safe_delete_array(query);
|
||||
|
||||
Client *c = CL->IsCharacterOnline(CharacterName);
|
||||
Client *client = CL->IsCharacterOnline(characterName);
|
||||
|
||||
if(c) {
|
||||
std::string FQN = GetMailPrefix() + From;
|
||||
|
||||
c->SendNotification(c->GetMailBoxNumber(CharacterName), Subject, FQN, LastMsgID);
|
||||
if(client) {
|
||||
std::string FQN = GetMailPrefix() + from;
|
||||
client->SendNotification(client->GetMailBoxNumber(characterName), subject, FQN, results.LastInsertedID());
|
||||
}
|
||||
|
||||
MailMessagesSent++;
|
||||
@ -614,156 +485,122 @@ bool Database::SendMail(std::string Recipient, std::string From, std::string Sub
|
||||
return true;
|
||||
}
|
||||
|
||||
void Database::SetMessageStatus(int MessageNumber, int Status) {
|
||||
void Database::SetMessageStatus(int messageNumber, int status) {
|
||||
|
||||
_log(UCS__TRACE, "SetMessageStatus %i %i", MessageNumber, Status);
|
||||
_log(UCS__TRACE, "SetMessageStatus %i %i", messageNumber, status);
|
||||
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
if(status == 0) {
|
||||
std::string query = StringFormat("DELETE FROM `mail` WHERE `msgid` = %i", messageNumber);
|
||||
auto results = QueryDatabase(query);
|
||||
return;
|
||||
}
|
||||
|
||||
if(Status == 0)
|
||||
RunQuery(query, MakeAnyLenString(&query, "delete from `mail` where `msgid`=%i", MessageNumber), errbuf);
|
||||
else if (!RunQuery(query, MakeAnyLenString(&query, "update `mail` set `status`=%i where `msgid`=%i", Status, MessageNumber), errbuf)) {
|
||||
std::string query = StringFormat("UPDATE `mail` SET `status` = %i WHERE `msgid`=%i", status, messageNumber);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
_log(UCS__ERROR, "Error updating status %s, %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
|
||||
_log(UCS__ERROR, "Error updating status %s, %s", query, errbuf);
|
||||
|
||||
}
|
||||
|
||||
safe_delete_array(query);
|
||||
}
|
||||
|
||||
void Database::ExpireMail() {
|
||||
|
||||
_log(UCS__INIT, "Expiring mail...");
|
||||
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
|
||||
uint32 AffectedRows;
|
||||
|
||||
if (!RunQuery(query,MakeAnyLenString(&query, "select COUNT(*) from `mail` "),errbuf,&result)){
|
||||
_log(UCS__ERROR, "Unable to get message count from database. %s %s", query, errbuf);
|
||||
safe_delete_array(query);
|
||||
return ;
|
||||
std::string query = "SELECT COUNT(*) FROM `mail`";
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
_log(UCS__ERROR, "Unable to get message count from database. %s %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return;
|
||||
}
|
||||
safe_delete_array(query);
|
||||
|
||||
row = mysql_fetch_row(result);
|
||||
auto row = results.begin();
|
||||
|
||||
_log(UCS__INIT, "There are %s messages in the database.", row[0]);
|
||||
|
||||
mysql_free_result(result);
|
||||
|
||||
// Expire Trash
|
||||
if(RuleI(Mail, ExpireTrash) >= 0) {
|
||||
if(RunQuery(query, MakeAnyLenString(&query, "delete from `mail` where `status`=4 and `timestamp` < %i",
|
||||
time(nullptr) - RuleI(Mail, ExpireTrash)), errbuf, 0, &AffectedRows)) {
|
||||
_log(UCS__INIT, "Expired %i trash messages.", AffectedRows);
|
||||
}
|
||||
else {
|
||||
_log(UCS__ERROR, "Error expiring trash messages, %s %s", query, errbuf);
|
||||
}
|
||||
safe_delete_array(query);
|
||||
query = StringFormat("DELETE FROM `mail` WHERE `status`=4 AND `timestamp` < %i",
|
||||
time(nullptr) - RuleI(Mail, ExpireTrash));
|
||||
results = QueryDatabase(query);
|
||||
if(!results.Success())
|
||||
_log(UCS__ERROR, "Error expiring trash messages, %s %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
else
|
||||
_log(UCS__INIT, "Expired %i trash messages.", results.RowsAffected());
|
||||
|
||||
}
|
||||
|
||||
// Expire Read
|
||||
if(RuleI(Mail, ExpireRead) >= 0) {
|
||||
if(RunQuery(query, MakeAnyLenString(&query, "delete from `mail` where `status`=3 and `timestamp` < %i",
|
||||
time(nullptr) - RuleI(Mail, ExpireRead)), errbuf, 0, &AffectedRows)) {
|
||||
_log(UCS__INIT, "Expired %i read messages.", AffectedRows);
|
||||
}
|
||||
else {
|
||||
_log(UCS__ERROR, "Error expiring read messages, %s %s", query, errbuf);
|
||||
}
|
||||
safe_delete_array(query);
|
||||
query = StringFormat("DELETE FROM `mail` WHERE `status` = 3 AND `timestamp` < %i",
|
||||
time(nullptr) - RuleI(Mail, ExpireRead));
|
||||
results = QueryDatabase(query);
|
||||
if(!results.Success())
|
||||
_log(UCS__INIT, "Expired %i read messages.", results.RowsAffected());
|
||||
else
|
||||
_log(UCS__ERROR, "Error expiring read messages, %s %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
}
|
||||
|
||||
// Expire Unread
|
||||
if(RuleI(Mail, ExpireUnread) >= 0) {
|
||||
if(RunQuery(query, MakeAnyLenString(&query, "delete from `mail` where `status`=1 and `timestamp` < %i",
|
||||
time(nullptr) - RuleI(Mail, ExpireUnread)), errbuf, 0, &AffectedRows)) {
|
||||
_log(UCS__INIT, "Expired %i unread messages.", AffectedRows);
|
||||
}
|
||||
else {
|
||||
_log(UCS__ERROR, "Error expiring unread messages, %s %s", query, errbuf);
|
||||
}
|
||||
safe_delete_array(query);
|
||||
query = StringFormat("DELETE FROM `mail` WHERE `status`=1 AND `timestamp` < %i",
|
||||
time(nullptr) - RuleI(Mail, ExpireUnread));
|
||||
results = QueryDatabase(query);
|
||||
if(!results.Success())
|
||||
_log(UCS__INIT, "Expired %i unread messages.", results.RowsAffected());
|
||||
else
|
||||
_log(UCS__ERROR, "Error expiring unread messages, %s %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void Database::AddFriendOrIgnore(int CharID, int Type, std::string Name) {
|
||||
void Database::AddFriendOrIgnore(int charID, int type, std::string name) {
|
||||
|
||||
const char *FriendsQuery="INSERT INTO `friends` (`charid`, `type`, `name`) VALUES ('%i', %i, '%s')";
|
||||
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
|
||||
|
||||
if(!RunQuery(query, MakeAnyLenString(&query, FriendsQuery, CharID, Type, CapitaliseName(Name).c_str()), errbuf, 0, 0))
|
||||
_log(UCS__ERROR, "Error adding friend/ignore, query was %s : %s", query, errbuf);
|
||||
std::string query = StringFormat("INSERT INTO `friends` (`charid`, `type`, `name`) "
|
||||
"VALUES('%i', %i, '%s')",
|
||||
charID, type, CapitaliseName(name).c_str());
|
||||
auto results = QueryDatabase(query);
|
||||
if(!results.Success())
|
||||
_log(UCS__ERROR, "Error adding friend/ignore, query was %s : %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
else
|
||||
_log(UCS__TRACE, "Wrote Friend/Ignore entry for charid %i, type %i, name %s to database.",
|
||||
CharID, Type, Name.c_str());
|
||||
_log(UCS__TRACE, "Wrote Friend/Ignore entry for charid %i, type %i, name %s to database.", charID, type, name.c_str());
|
||||
|
||||
|
||||
safe_delete_array(query);
|
||||
}
|
||||
|
||||
void Database::RemoveFriendOrIgnore(int CharID, int Type, std::string Name) {
|
||||
void Database::RemoveFriendOrIgnore(int charID, int type, std::string name) {
|
||||
|
||||
const char *FriendsQuery="DELETE FROM `friends` WHERE `charid`=%i AND `type`=%i and `name`='%s'";
|
||||
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
|
||||
if(!RunQuery(query, MakeAnyLenString(&query, FriendsQuery, CharID, Type, CapitaliseName(Name).c_str()), errbuf, 0, 0))
|
||||
_log(UCS__ERROR, "Error removing friend/ignore, query was %s", query);
|
||||
std::string query = StringFormat("DELETE FROM `friends` WHERE `charid` = %i "
|
||||
"AND `type` = %i AND `name` = '%s'",
|
||||
charID, type, CapitaliseName(name).c_str());
|
||||
auto results = QueryDatabase(query);
|
||||
if(!results.Success())
|
||||
_log(UCS__ERROR, "Error removing friend/ignore, query was %s", query.c_str());
|
||||
else
|
||||
_log(UCS__TRACE, "Removed Friend/Ignore entry for charid %i, type %i, name %s from database.",
|
||||
CharID, Type, Name.c_str());
|
||||
_log(UCS__TRACE, "Removed Friend/Ignore entry for charid %i, type %i, name %s from database.", charID, type, name.c_str());
|
||||
|
||||
|
||||
safe_delete_array(query);
|
||||
}
|
||||
|
||||
void Database::GetFriendsAndIgnore(int CharID, std::vector<std::string> &Friends, std::vector<std::string> &Ignorees) {
|
||||
void Database::GetFriendsAndIgnore(int charID, std::vector<std::string> &friends, std::vector<std::string> &ignorees) {
|
||||
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
|
||||
const char *FriendsQuery="select `type`, `name` from `friends` WHERE `charid`=%i";
|
||||
|
||||
if (!RunQuery(query,MakeAnyLenString(&query, FriendsQuery, CharID),errbuf,&result)){
|
||||
|
||||
_log(UCS__ERROR, "GetFriendsAndIgnore query error %s, %s", query, errbuf);
|
||||
|
||||
safe_delete_array(query);
|
||||
|
||||
return ;
|
||||
std::string query = StringFormat("select `type`, `name` FROM `friends` WHERE `charid`=%i", charID);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
_log(UCS__ERROR, "GetFriendsAndIgnore query error %s, %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
safe_delete_array(query);
|
||||
|
||||
while((row = mysql_fetch_row(result))) {
|
||||
|
||||
std::string Name = row[1];
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
std::string name = row[1];
|
||||
|
||||
if(atoi(row[0]) == 0)
|
||||
{
|
||||
Ignorees.push_back(Name);
|
||||
_log(UCS__TRACE, "Added Ignoree from DB %s", Name.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
Friends.push_back(Name);
|
||||
_log(UCS__TRACE, "Added Friend from DB %s", Name.c_str());
|
||||
ignorees.push_back(name);
|
||||
_log(UCS__TRACE, "Added Ignoree from DB %s", name.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
friends.push_back(name);
|
||||
_log(UCS__TRACE, "Added Friend from DB %s", name.c_str());
|
||||
}
|
||||
|
||||
mysql_free_result(result);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -877,8 +877,12 @@ bool Mob::CombatRange(Mob* other)
|
||||
|
||||
if (GetSpecialAbility(NPC_CHASE_DISTANCE)){
|
||||
|
||||
bool DoLoSCheck = true;
|
||||
float max_dist = static_cast<float>(GetSpecialAbilityParam(NPC_CHASE_DISTANCE, 0));
|
||||
float min_dist = static_cast<float>(GetSpecialAbilityParam(NPC_CHASE_DISTANCE, 1));
|
||||
|
||||
if (GetSpecialAbilityParam(NPC_CHASE_DISTANCE, 2));
|
||||
DoLoSCheck = false; //Ignore line of sight check
|
||||
|
||||
if (max_dist == 1)
|
||||
max_dist = 250.0f; //Default it to 250 if you forget to put a value
|
||||
@ -890,7 +894,7 @@ bool Mob::CombatRange(Mob* other)
|
||||
else
|
||||
min_dist = min_dist * min_dist;
|
||||
|
||||
if (CheckLastLosState() && (_DistNoRoot >= min_dist && _DistNoRoot <= max_dist))
|
||||
if ((DoLoSCheck && CheckLastLosState()) && (_DistNoRoot >= min_dist && _DistNoRoot <= max_dist))
|
||||
SetPseudoRoot(true);
|
||||
else
|
||||
SetPseudoRoot(false);
|
||||
|
||||
@ -268,7 +268,7 @@ public:
|
||||
void TradeRequestFailed(const EQApplicationPacket* app);
|
||||
void BuyTraderItem(TraderBuy_Struct* tbs,Client* trader,const EQApplicationPacket* app);
|
||||
void TraderUpdate(uint16 slot_id,uint32 trader_id);
|
||||
void FinishTrade(Mob* with, ServerPacket* qspack = nullptr, bool finalizer = false);
|
||||
void FinishTrade(Mob* with, bool finalizer = false, void* event_entry = nullptr, std::list<void*>* event_details = nullptr);
|
||||
void SendZonePoints();
|
||||
|
||||
void SendBuyerResults(char *SearchQuery, uint32 SearchID);
|
||||
|
||||
@ -3137,6 +3137,7 @@ void Client::Handle_OP_ItemLinkClick(const EQApplicationPacket *app)
|
||||
DumpPacket(app);
|
||||
return;
|
||||
}
|
||||
|
||||
DumpPacket(app);
|
||||
ItemViewRequest_Struct* ivrs = (ItemViewRequest_Struct*)app->pBuffer;
|
||||
|
||||
@ -3156,30 +3157,24 @@ void Client::Handle_OP_ItemLinkClick(const EQApplicationPacket *app)
|
||||
silentsaylink = true;
|
||||
}
|
||||
|
||||
if (sayid && sayid > 0)
|
||||
if (sayid > 0)
|
||||
{
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
|
||||
std::string query = StringFormat("SELECT `phrase` FROM saylink WHERE `id` = '%i'", sayid);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
Message(13, "Error: The saylink (%s) was not found in the database.", response.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if(database.RunQuery(query,MakeAnyLenString(&query,"SELECT `phrase` FROM saylink WHERE `id` = '%i'", sayid),errbuf,&result))
|
||||
{
|
||||
if (mysql_num_rows(result) == 1)
|
||||
{
|
||||
row = mysql_fetch_row(result);
|
||||
response = row[0];
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
Message(13, "Error: The saylink (%s) was not found in the database.",response.c_str());
|
||||
safe_delete_array(query);
|
||||
if (results.RowCount() != 1) {
|
||||
Message(13, "Error: The saylink (%s) was not found in the database.", response.c_str());
|
||||
return;
|
||||
}
|
||||
safe_delete_array(query);
|
||||
|
||||
auto row = results.begin();
|
||||
response = row[0];
|
||||
|
||||
}
|
||||
|
||||
if((response).size() > 0)
|
||||
@ -4628,7 +4623,7 @@ void Client::Handle_OP_CastSpell(const EQApplicationPacket *app)
|
||||
|
||||
p_timers.Start(pTimerHarmTouch, HarmTouchReuseTime);
|
||||
}
|
||||
|
||||
|
||||
if (spell_to_cast > 0) // if we've matched LoH or HT, cast now
|
||||
CastSpell(spell_to_cast, castspell->target_id, castspell->slot);
|
||||
}
|
||||
@ -4862,6 +4857,7 @@ void Client::Handle_OP_TradeAcceptClick(const EQApplicationPacket *app)
|
||||
{
|
||||
Mob* with = trade->With();
|
||||
trade->state = TradeAccepted;
|
||||
|
||||
if (with && with->IsClient()) {
|
||||
//finish trade...
|
||||
// Have both accepted?
|
||||
@ -4872,6 +4868,7 @@ void Client::Handle_OP_TradeAcceptClick(const EQApplicationPacket *app)
|
||||
other->trade->state = TradeCompleting;
|
||||
trade->state = TradeCompleting;
|
||||
|
||||
// should we do this for NoDrop items as well?
|
||||
if (CheckTradeLoreConflict(other) || other->CheckTradeLoreConflict(this)) {
|
||||
Message_StringID(13, TRADE_CANCEL_LORE);
|
||||
other->Message_StringID(13, TRADE_CANCEL_LORE);
|
||||
@ -4887,23 +4884,38 @@ void Client::Handle_OP_TradeAcceptClick(const EQApplicationPacket *app)
|
||||
|
||||
// start QS code
|
||||
if(RuleB(QueryServ, PlayerLogTrades)) {
|
||||
uint16 trade_count = 0;
|
||||
QSPlayerLogTrade_Struct event_entry;
|
||||
std::list<void*> event_details;
|
||||
|
||||
// Item trade count for packet sizing
|
||||
for(int16 slot_id = EmuConstants::TRADE_BEGIN; slot_id <= EmuConstants::TRADE_END; slot_id++) {
|
||||
if(other->GetInv().GetItem(slot_id)) { trade_count += other->GetInv().GetItem(slot_id)->GetTotalItemCount(); }
|
||||
if(m_inv[slot_id]) { trade_count += m_inv[slot_id]->GetTotalItemCount(); }
|
||||
}
|
||||
|
||||
ServerPacket* qspack = new ServerPacket(ServerOP_QSPlayerLogTrades, sizeof(QSPlayerLogTrade_Struct) + (sizeof(QSTradeItems_Struct) * trade_count));
|
||||
memset(&event_entry, 0, sizeof(QSPlayerLogTrade_Struct));
|
||||
|
||||
// Perform actual trade
|
||||
this->FinishTrade(other, qspack, true);
|
||||
other->FinishTrade(this, qspack, false);
|
||||
this->FinishTrade(other, true, &event_entry, &event_details);
|
||||
other->FinishTrade(this, false, &event_entry, &event_details);
|
||||
|
||||
qspack->Deflate();
|
||||
if(worldserver.Connected()) { worldserver.SendPacket(qspack); }
|
||||
safe_delete(qspack);
|
||||
event_entry._detail_count = event_details.size();
|
||||
|
||||
ServerPacket* qs_pack = new ServerPacket(ServerOP_QSPlayerLogTrades, sizeof(QSPlayerLogTrade_Struct)+(sizeof(QSTradeItems_Struct)* event_entry._detail_count));
|
||||
QSPlayerLogTrade_Struct* qs_buf = (QSPlayerLogTrade_Struct*)qs_pack->pBuffer;
|
||||
|
||||
memcpy(qs_buf, &event_entry, sizeof(QSPlayerLogTrade_Struct));
|
||||
|
||||
int offset = 0;
|
||||
|
||||
for (std::list<void*>::iterator iter = event_details.begin(); iter != event_details.end(); ++iter, ++offset) {
|
||||
QSTradeItems_Struct* detail = reinterpret_cast<QSTradeItems_Struct*>(*iter);
|
||||
qs_buf->items[offset] = *detail;
|
||||
safe_delete(detail);
|
||||
}
|
||||
|
||||
event_details.clear();
|
||||
|
||||
qs_pack->Deflate();
|
||||
|
||||
if(worldserver.Connected())
|
||||
worldserver.SendPacket(qs_pack);
|
||||
|
||||
safe_delete(qs_pack);
|
||||
// end QS code
|
||||
}
|
||||
else {
|
||||
@ -4928,25 +4940,43 @@ void Client::Handle_OP_TradeAcceptClick(const EQApplicationPacket *app)
|
||||
if(with->IsNPC()) {
|
||||
// Audit trade to database for player trade stream
|
||||
if(RuleB(QueryServ, PlayerLogHandins)) {
|
||||
uint16 handin_count = 0;
|
||||
QSPlayerLogHandin_Struct event_entry;
|
||||
std::list<void*> event_details;
|
||||
|
||||
for(int16 slot_id = EmuConstants::TRADE_BEGIN; slot_id <= EmuConstants::TRADE_NPC_END; slot_id++) {
|
||||
if(m_inv[slot_id]) { handin_count += m_inv[slot_id]->GetTotalItemCount(); }
|
||||
memset(&event_entry, 0, sizeof(QSPlayerLogHandin_Struct));
|
||||
|
||||
FinishTrade(with->CastToNPC(), false, &event_entry, &event_details);
|
||||
|
||||
event_entry._detail_count = event_details.size();
|
||||
|
||||
ServerPacket* qs_pack = new ServerPacket(ServerOP_QSPlayerLogHandins, sizeof(QSPlayerLogHandin_Struct)+(sizeof(QSHandinItems_Struct)* event_entry._detail_count));
|
||||
QSPlayerLogHandin_Struct* qs_buf = (QSPlayerLogHandin_Struct*)qs_pack->pBuffer;
|
||||
|
||||
memcpy(qs_buf, &event_entry, sizeof(QSPlayerLogHandin_Struct));
|
||||
|
||||
int offset = 0;
|
||||
|
||||
for (std::list<void*>::iterator iter = event_details.begin(); iter != event_details.end(); ++iter, ++offset) {
|
||||
QSHandinItems_Struct* detail = reinterpret_cast<QSHandinItems_Struct*>(*iter);
|
||||
qs_buf->items[offset] = *detail;
|
||||
safe_delete(detail);
|
||||
}
|
||||
|
||||
ServerPacket* qspack = new ServerPacket(ServerOP_QSPlayerLogHandins, sizeof(QSPlayerLogHandin_Struct) + (sizeof(QSHandinItems_Struct) * handin_count));
|
||||
event_details.clear();
|
||||
|
||||
FinishTrade(with->CastToNPC(), qspack);
|
||||
qs_pack->Deflate();
|
||||
|
||||
qspack->Deflate();
|
||||
if(worldserver.Connected()) { worldserver.SendPacket(qspack); }
|
||||
safe_delete(qspack);
|
||||
if(worldserver.Connected())
|
||||
worldserver.SendPacket(qs_pack);
|
||||
|
||||
safe_delete(qs_pack);
|
||||
}
|
||||
else {
|
||||
FinishTrade(with->CastToNPC());
|
||||
}
|
||||
}
|
||||
#ifdef BOTS
|
||||
// TODO: Log Bot trades
|
||||
else if(with->IsBot())
|
||||
with->CastToBot()->FinishTrade(this, Bot::BotTradeClientNormal);
|
||||
#endif
|
||||
@ -5864,9 +5894,9 @@ void Client::Handle_OP_ShopPlayerSell(const EQApplicationPacket *app)
|
||||
else
|
||||
this->DeleteItemInInventory(mp->itemslot,mp->quantity,false);
|
||||
|
||||
//This forces the price to show up correctly for charged items.
|
||||
//This forces the price to show up correctly for charged items.
|
||||
if(inst->IsCharged())
|
||||
mp->quantity = 1;
|
||||
mp->quantity = 1;
|
||||
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_ShopPlayerSell, sizeof(Merchant_Purchase_Struct));
|
||||
Merchant_Purchase_Struct* mco=(Merchant_Purchase_Struct*)outapp->pBuffer;
|
||||
@ -7635,7 +7665,7 @@ void Client::Handle_OP_Mend(const EQApplicationPacket *app)
|
||||
int mendhp = GetMaxHP() / 4;
|
||||
int currenthp = GetHP();
|
||||
if (MakeRandomInt(0, 199) < (int)GetSkill(SkillMend)) {
|
||||
|
||||
|
||||
int criticalchance = spellbonuses.CriticalMend + itembonuses.CriticalMend + aabonuses.CriticalMend;
|
||||
|
||||
if(MakeRandomInt(0,99) < criticalchance){
|
||||
@ -9532,7 +9562,7 @@ void Client::CompleteConnect() {
|
||||
|
||||
/* This sub event is for if a player logs in for the first time since entering world. */
|
||||
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());
|
||||
@ -11410,92 +11440,68 @@ void Client::Handle_OP_SetStartCity(const EQApplicationPacket *app)
|
||||
Message(15,"Your home city has already been set.", m_pp.binds[4].zoneId, database.GetZoneName(m_pp.binds[4].zoneId));
|
||||
return;
|
||||
}
|
||||
|
||||
if (app->size < 1) {
|
||||
LogFile->write(EQEMuLog::Error, "Wrong size: OP_SetStartCity, size=%i, expected %i", app->size, 1);
|
||||
DumpPacket(app);
|
||||
return;
|
||||
}
|
||||
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
MYSQL_RES *result = nullptr;
|
||||
MYSQL_ROW row = 0;
|
||||
float x(0),y(0),z(0);
|
||||
uint32 zoneid = 0;
|
||||
uint32 startCity = (uint32)strtol((const char*)app->pBuffer, nullptr, 10);
|
||||
|
||||
uint32 StartCity = (uint32)strtol((const char*)app->pBuffer, nullptr, 10);
|
||||
bool ValidCity = false;
|
||||
database.RunQuery
|
||||
(
|
||||
query,
|
||||
MakeAnyLenString
|
||||
(
|
||||
&query,
|
||||
"SELECT zone_id, bind_id, x, y, z FROM start_zones "
|
||||
"WHERE player_class=%i AND player_deity=%i AND player_race=%i",
|
||||
m_pp.class_,
|
||||
m_pp.deity,
|
||||
m_pp.race
|
||||
),
|
||||
errbuf,
|
||||
&result
|
||||
);
|
||||
safe_delete_array(query);
|
||||
|
||||
if(!result) {
|
||||
std::string query = StringFormat("SELECT zone_id, bind_id, x, y, z FROM start_zones "
|
||||
"WHERE player_class=%i AND player_deity=%i AND player_race=%i",
|
||||
m_pp.class_, m_pp.deity, m_pp.race);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if(!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "No valid start zones found for /setstartcity");
|
||||
return;
|
||||
}
|
||||
|
||||
while(row = mysql_fetch_row(result)) {
|
||||
bool validCity = false;
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
if(atoi(row[1]) != 0)
|
||||
zoneid = atoi(row[1]);
|
||||
else
|
||||
zoneid = atoi(row[0]);
|
||||
|
||||
if(zoneid == StartCity) {
|
||||
ValidCity = true;
|
||||
x = atof(row[2]);
|
||||
y = atof(row[3]);
|
||||
z = atof(row[4]);
|
||||
}
|
||||
if(zoneid != startCity)
|
||||
continue;
|
||||
|
||||
validCity = true;
|
||||
x = atof(row[2]);
|
||||
y = atof(row[3]);
|
||||
z = atof(row[4]);
|
||||
}
|
||||
|
||||
if(ValidCity) {
|
||||
if(validCity) {
|
||||
Message(15,"Your home city has been set");
|
||||
SetStartZone(StartCity, x, y, z);
|
||||
}
|
||||
else {
|
||||
database.RunQuery
|
||||
(
|
||||
query,
|
||||
MakeAnyLenString
|
||||
(
|
||||
&query,
|
||||
"SELECT zone_id, bind_id FROM start_zones "
|
||||
"WHERE player_class=%i AND player_deity=%i AND player_race=%i",
|
||||
m_pp.class_,
|
||||
m_pp.deity,
|
||||
m_pp.race
|
||||
),
|
||||
errbuf,
|
||||
&result
|
||||
);
|
||||
safe_delete_array(query);
|
||||
Message(15,"Use \"/startcity #\" to choose a home city from the following list:");
|
||||
char* name;
|
||||
while(row = mysql_fetch_row(result)) {
|
||||
if(atoi(row[1]) != 0)
|
||||
zoneid = atoi(row[1]);
|
||||
else
|
||||
zoneid = atoi(row[0]);
|
||||
database.GetZoneLongName(database.GetZoneName(zoneid),&name);
|
||||
Message(15,"%d - %s", zoneid, name);
|
||||
safe_delete_array(name);
|
||||
}
|
||||
SetStartZone(startCity, x, y, z);
|
||||
return;
|
||||
}
|
||||
|
||||
mysql_free_result(result);
|
||||
query = StringFormat("SELECT zone_id, bind_id FROM start_zones "
|
||||
"WHERE player_class=%i AND player_deity=%i AND player_race=%i",
|
||||
m_pp.class_, m_pp.deity, m_pp.race);
|
||||
results = database.QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
return;
|
||||
|
||||
Message(15,"Use \"/startcity #\" to choose a home city from the following list:");
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
if(atoi(row[1]) != 0)
|
||||
zoneid = atoi(row[1]);
|
||||
else
|
||||
zoneid = atoi(row[0]);
|
||||
|
||||
char* name;
|
||||
database.GetZoneLongName(database.GetZoneName(zoneid), &name);
|
||||
Message(15,"%d - %s", zoneid, name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Client::Handle_OP_Report(const EQApplicationPacket *app)
|
||||
@ -11602,7 +11608,7 @@ void Client::Handle_OP_GMSearchCorpse(const EQApplicationPacket *app)
|
||||
// Could make this into a rule, although there is a hard limit since we are using a popup, of 4096 bytes that can
|
||||
// be displayed in the window, including all the HTML formatting tags.
|
||||
//
|
||||
const int MaxResults = 10;
|
||||
const int maxResults = 10;
|
||||
|
||||
if(app->size < sizeof(GMSearchCorpse_Struct))
|
||||
{
|
||||
@ -11615,85 +11621,62 @@ void Client::Handle_OP_GMSearchCorpse(const EQApplicationPacket *app)
|
||||
GMSearchCorpse_Struct *gmscs = (GMSearchCorpse_Struct *)app->pBuffer;
|
||||
gmscs->Name[63] = '\0';
|
||||
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* Query = 0;
|
||||
MYSQL_RES *Result;
|
||||
MYSQL_ROW Row;
|
||||
char *escSearchString = new char[129];
|
||||
database.DoEscapeString(escSearchString, gmscs->Name, strlen(gmscs->Name));
|
||||
|
||||
char *EscSearchString = new char[129];
|
||||
std::string query = StringFormat("SELECT charname, zoneid, x, y, z, timeofdeath, rezzed, IsBurried "
|
||||
"FROM player_corpses WheRE charname LIKE '%%%s%%' ORDER BY charname LIMIT %i",
|
||||
escSearchString, maxResults);
|
||||
safe_delete_array(escSearchString);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
Message(0, "Query failed: %s.", results.ErrorMessage().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
database.DoEscapeString(EscSearchString, gmscs->Name, strlen(gmscs->Name));
|
||||
if (results.RowCount() == 0)
|
||||
return;
|
||||
|
||||
if (database.RunQuery(Query, MakeAnyLenString(&Query, "select charname, zoneid, x, y, z, timeofdeath, rezzed, IsBurried from "
|
||||
"player_corpses where charname like '%%%s%%' order by charname limit %i",
|
||||
EscSearchString, MaxResults), errbuf, &Result))
|
||||
{
|
||||
if(results.RowCount() == maxResults)
|
||||
Message(clientMessageError, "Your search found too many results; some are not displayed.");
|
||||
else
|
||||
Message(clientMessageYellow, "There are %i corpse(s) that match the search string '%s'.", results.RowCount(), gmscs->Name);
|
||||
|
||||
int NumberOfRows = mysql_num_rows(Result);
|
||||
char charName[64], timeOfDeath[20];
|
||||
|
||||
if(NumberOfRows == MaxResults)
|
||||
Message(clientMessageError, "Your search found too many results; some are not displayed.");
|
||||
else {
|
||||
Message(clientMessageYellow, "There are %i corpse(s) that match the search string '%s'.",
|
||||
NumberOfRows, gmscs->Name);
|
||||
}
|
||||
|
||||
if(NumberOfRows == 0)
|
||||
{
|
||||
mysql_free_result(Result);
|
||||
safe_delete_array(Query);
|
||||
return;
|
||||
}
|
||||
|
||||
char CharName[64], TimeOfDeath[20], Buffer[512];
|
||||
|
||||
std::string PopupText = "<table><tr><td>Name</td><td>Zone</td><td>X</td><td>Y</td><td>Z</td><td>Date</td><td>"
|
||||
std::string popupText = "<table><tr><td>Name</td><td>Zone</td><td>X</td><td>Y</td><td>Z</td><td>Date</td><td>"
|
||||
"Rezzed</td><td>Buried</td></tr><tr><td> </td><td></td><td></td><td></td><td></td><td>"
|
||||
"</td><td></td><td></td></tr>";
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
|
||||
while ((Row = mysql_fetch_row(Result)))
|
||||
{
|
||||
strn0cpy(charName, row[0], sizeof(charName));
|
||||
|
||||
strn0cpy(CharName, Row[0], sizeof(CharName));
|
||||
uint32 ZoneID = atoi(row[1]);
|
||||
float CorpseX = atof(row[2]);
|
||||
float CorpseY = atof(row[3]);
|
||||
float CorpseZ = atof(row[4]);
|
||||
|
||||
uint32 ZoneID = atoi(Row[1]);
|
||||
strn0cpy(timeOfDeath, row[5], sizeof(timeOfDeath));
|
||||
|
||||
float CorpseX = atof(Row[2]);
|
||||
float CorpseY = atof(Row[3]);
|
||||
float CorpseZ = atof(Row[4]);
|
||||
bool corpseRezzed = atoi(row[6]);
|
||||
bool corpseBuried = atoi(row[7]);
|
||||
|
||||
strn0cpy(TimeOfDeath, Row[5], sizeof(TimeOfDeath));
|
||||
popupText += StringFormat("<tr><td>%s</td><td>%s</td><td>%8.0f</td><td>%8.0f</td><td>%8.0f</td><td>%s</td><td>%s</td><td>%s</td></tr>",
|
||||
charName, StaticGetZoneName(ZoneID), CorpseX, CorpseY, CorpseZ, timeOfDeath,
|
||||
corpseRezzed ? "Yes" : "No", corpseBuried ? "Yes" : "No");
|
||||
|
||||
bool CorpseRezzed = atoi(Row[6]);
|
||||
bool CorpseBuried = atoi(Row[7]);
|
||||
if(popupText.size() > 4000) {
|
||||
Message(clientMessageError, "Unable to display all the results.");
|
||||
break;
|
||||
}
|
||||
|
||||
sprintf(Buffer, "<tr><td>%s</td><td>%s</td><td>%8.0f</td><td>%8.0f</td><td>%8.0f</td><td>%s</td><td>%s</td><td>%s</td></tr>",
|
||||
CharName, StaticGetZoneName(ZoneID), CorpseX, CorpseY, CorpseZ, TimeOfDeath,
|
||||
CorpseRezzed ? "Yes" : "No", CorpseBuried ? "Yes" : "No");
|
||||
}
|
||||
|
||||
PopupText += Buffer;
|
||||
popupText += "</table>";
|
||||
|
||||
if(PopupText.size() > 4000)
|
||||
{
|
||||
Message(clientMessageError, "Unable to display all the results.");
|
||||
break;
|
||||
}
|
||||
SendPopupToClient("Corpses", popupText.c_str());
|
||||
|
||||
}
|
||||
|
||||
PopupText += "</table>";
|
||||
|
||||
mysql_free_result(Result);
|
||||
|
||||
SendPopupToClient("Corpses", PopupText.c_str());
|
||||
}
|
||||
else{
|
||||
Message(0, "Query failed: %s.", errbuf);
|
||||
|
||||
}
|
||||
safe_delete_array(Query);
|
||||
safe_delete_array(EscSearchString);
|
||||
}
|
||||
|
||||
void Client::Handle_OP_GuildBank(const EQApplicationPacket *app)
|
||||
@ -12775,7 +12758,7 @@ void Client::Handle_OP_AltCurrencyReclaim(const EQApplicationPacket *app) {
|
||||
QServ->PlayerLogEvent(Player_Log_Alternate_Currency_Transactions, this->CharacterID(), event_desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Cursor to Item storage */
|
||||
else {
|
||||
uint32 max_currency = GetAlternateCurrencyValue(reclaim->currency_id);
|
||||
@ -12784,7 +12767,7 @@ void Client::Handle_OP_AltCurrencyReclaim(const EQApplicationPacket *app) {
|
||||
if(reclaim->count > max_currency) {
|
||||
SummonItem(item_id, max_currency);
|
||||
SetAlternateCurrencyValue(reclaim->currency_id, 0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
SummonItem(item_id, reclaim->count, 0, 0, 0, 0, 0, false, MainCursor);
|
||||
AddAlternateCurrencyValue(reclaim->currency_id, -((int32)reclaim->count));
|
||||
@ -12793,7 +12776,7 @@ void Client::Handle_OP_AltCurrencyReclaim(const EQApplicationPacket *app) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -12885,8 +12868,8 @@ void Client::Handle_OP_AltCurrencySell(const EQApplicationPacket *app) {
|
||||
/* 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);
|
||||
}
|
||||
QServ->PlayerLogEvent(Player_Log_Alternate_Currency_Transactions, this->CharacterID(), event_desc);
|
||||
}
|
||||
|
||||
FastQueuePacket(&outapp);
|
||||
AddAlternateCurrencyValue(alt_cur_id, cost);
|
||||
@ -12947,7 +12930,7 @@ void Client::Handle_OP_LFGuild(const EQApplicationPacket *app)
|
||||
switch(Command)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
{
|
||||
VERIFY_PACKET_LENGTH(OP_LFGuild, app, LFGuild_PlayerToggle_Struct);
|
||||
LFGuild_PlayerToggle_Struct *pts = (LFGuild_PlayerToggle_Struct *)app->pBuffer;
|
||||
|
||||
|
||||
@ -527,7 +527,7 @@ public:
|
||||
Mob* With();
|
||||
|
||||
// Add item from cursor slot to trade bucket (automatically does bag data too)
|
||||
void AddEntity(uint16 from_slot_id, uint16 trade_slot_id, uint32 stack_size);
|
||||
void AddEntity(uint16 trade_slot_id, uint32 stack_size);
|
||||
|
||||
// Audit trade
|
||||
void LogTrade();
|
||||
|
||||
232
zone/doors.cpp
232
zone/doors.cpp
@ -568,157 +568,137 @@ void Doors::DumpDoor(){
|
||||
}
|
||||
|
||||
int32 ZoneDatabase::GetDoorsCount(uint32* oMaxID, const char *zone_name, int16 version) {
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
query = new char[256];
|
||||
sprintf(query, "SELECT MAX(id), count(*) FROM doors WHERE zone='%s' AND (version=%u OR version=-1)", zone_name, version);
|
||||
if (RunQuery(query, strlen(query), errbuf, &result)) {
|
||||
safe_delete_array(query);
|
||||
row = mysql_fetch_row(result);
|
||||
if (row != nullptr && row[1] != 0) {
|
||||
int32 ret = atoi(row[1]);
|
||||
if (oMaxID) {
|
||||
if (row[0])
|
||||
*oMaxID = atoi(row[0]);
|
||||
else
|
||||
*oMaxID = 0;
|
||||
}
|
||||
mysql_free_result(result);
|
||||
return ret;
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else {
|
||||
std::cerr << "Error in GetDoorsCount query '" << query << "' " << errbuf << std::endl;
|
||||
safe_delete_array(query);
|
||||
std::string query = StringFormat("SELECT MAX(id), count(*) FROM doors "
|
||||
"WHERE zone = '%s' AND (version = %u OR version = -1)",
|
||||
zone_name, version);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
std::cerr << "Error in GetDoorsCount query '" << query << "' " << results.ErrorMessage() << std::endl;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (results.RowCount() != 1)
|
||||
return -1;
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
if (!oMaxID)
|
||||
return atoi(row[1]);
|
||||
|
||||
if (row[0])
|
||||
*oMaxID = atoi(row[0]);
|
||||
else
|
||||
*oMaxID = 0;
|
||||
|
||||
return atoi(row[1]);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32 ZoneDatabase::GetDoorsCountPlusOne(const char *zone_name, int16 version) {
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
uint32 oMaxID = 0;
|
||||
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
query = new char[256];
|
||||
sprintf(query, "SELECT MAX(id) FROM doors WHERE zone='%s' AND version=%u", zone_name, version);
|
||||
if (RunQuery(query, strlen(query), errbuf, &result)) {
|
||||
safe_delete_array(query);
|
||||
row = mysql_fetch_row(result);
|
||||
if (row != nullptr && row[1] != 0) {
|
||||
if (row[0])
|
||||
oMaxID = atoi(row[0]) + 1;
|
||||
else
|
||||
oMaxID = 0;
|
||||
mysql_free_result(result);
|
||||
return oMaxID;
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else {
|
||||
std::cerr << "Error in GetDoorsCountPlusOne query '" << query << "' " << errbuf << std::endl;
|
||||
safe_delete_array(query);
|
||||
std::string query = StringFormat("SELECT MAX(id) FROM doors "
|
||||
"WHERE zone = '%s' AND version = %u", zone_name, version);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
std::cerr << "Error in GetDoorsCountPlusOne query '" << query << "' " << results.ErrorMessage() << std::endl;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
if (results.RowCount() != 1)
|
||||
return -1;
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
if (!row[0])
|
||||
return 0;
|
||||
|
||||
return atoi(row[0]) + 1;
|
||||
}
|
||||
|
||||
int32 ZoneDatabase::GetDoorsDBCountPlusOne(const char *zone_name, int16 version) {
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
|
||||
uint32 oMaxID = 0;
|
||||
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
query = new char[256];
|
||||
sprintf(query, "SELECT MAX(doorid) FROM doors WHERE zone='%s' AND (version=%u OR version=-1)", zone_name, version);
|
||||
if (RunQuery(query, strlen(query), errbuf, &result)) {
|
||||
safe_delete_array(query);
|
||||
row = mysql_fetch_row(result);
|
||||
if (row != nullptr && row[1] != 0) {
|
||||
if (row[0])
|
||||
oMaxID = atoi(row[0]) + 1;
|
||||
else
|
||||
oMaxID = 0;
|
||||
mysql_free_result(result);
|
||||
return oMaxID;
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else {
|
||||
std::cerr << "Error in GetDoorsCountPlusOne query '" << query << "' " << errbuf << std::endl;
|
||||
safe_delete_array(query);
|
||||
std::string query = StringFormat("SELECT MAX(doorid) FROM doors "
|
||||
"WHERE zone = '%s' AND (version = %u OR version = -1)",
|
||||
zone_name, version);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
std::cerr << "Error in GetDoorsCountPlusOne query '" << query << "' " << results.ErrorMessage() << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
if (results.RowCount() != 1)
|
||||
return -1;
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
if (!row[0])
|
||||
return 0;
|
||||
|
||||
return atoi(row[0]) + 1;
|
||||
}
|
||||
|
||||
bool ZoneDatabase::LoadDoors(int32 iDoorCount, Door *into, const char *zone_name, int16 version) {
|
||||
LogFile->write(EQEMuLog::Status, "Loading Doors from database...");
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
|
||||
|
||||
// Door tmpDoor;
|
||||
MakeAnyLenString(&query, "SELECT id,doorid,zone,name,pos_x,pos_y,pos_z,heading,"
|
||||
"opentype,guild,lockpick,keyitem,nokeyring,triggerdoor,triggertype,dest_zone,dest_instance,dest_x,"
|
||||
"dest_y,dest_z,dest_heading,door_param,invert_state,incline,size,is_ldon_door,client_version_mask "
|
||||
"FROM doors WHERE zone='%s' AND (version=%u OR version=-1) ORDER BY doorid asc", zone_name, version);
|
||||
if (RunQuery(query, strlen(query), errbuf, &result)) {
|
||||
safe_delete_array(query);
|
||||
int32 r;
|
||||
for(r = 0; (row = mysql_fetch_row(result)); r++) {
|
||||
if(r >= iDoorCount) {
|
||||
std::cerr << "Error, Door Count of " << iDoorCount << " exceeded." << std::endl;
|
||||
break;
|
||||
}
|
||||
memset(&into[r], 0, sizeof(Door));
|
||||
into[r].db_id = atoi(row[0]);
|
||||
into[r].door_id = atoi(row[1]);
|
||||
strn0cpy(into[r].zone_name,row[2],32);
|
||||
strn0cpy(into[r].door_name,row[3],32);
|
||||
into[r].pos_x = (float)atof(row[4]);
|
||||
into[r].pos_y = (float)atof(row[5]);
|
||||
into[r].pos_z = (float)atof(row[6]);
|
||||
into[r].heading = (float)atof(row[7]);
|
||||
into[r].opentype = atoi(row[8]);
|
||||
into[r].guild_id = atoi(row[9]);
|
||||
into[r].lockpick = atoi(row[10]);
|
||||
into[r].keyitem = atoi(row[11]);
|
||||
into[r].nokeyring = atoi(row[12]);
|
||||
into[r].trigger_door = atoi(row[13]);
|
||||
into[r].trigger_type = atoi(row[14]);
|
||||
strn0cpy(into[r].dest_zone, row[15], 32);
|
||||
into[r].dest_instance_id = atoi(row[16]);
|
||||
into[r].dest_x = (float) atof(row[17]);
|
||||
into[r].dest_y = (float) atof(row[18]);
|
||||
into[r].dest_z = (float) atof(row[19]);
|
||||
into[r].dest_heading = (float) atof(row[20]);
|
||||
into[r].door_param=atoi(row[21]);
|
||||
into[r].invert_state=atoi(row[22]);
|
||||
into[r].incline=atoi(row[23]);
|
||||
into[r].size=atoi(row[24]);
|
||||
into[r].is_ldon_door=atoi(row[25]);
|
||||
into[r].client_version_mask = (uint32)strtoul(row[26], nullptr, 10);
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Error in DBLoadDoors query '" << query << "' " << errbuf << std::endl;
|
||||
safe_delete_array(query);
|
||||
std::string query = StringFormat("SELECT id, doorid, zone, name, pos_x, pos_y, pos_z, heading, "
|
||||
"opentype, guild, lockpick, keyitem, nokeyring, triggerdoor, triggertype, "
|
||||
"dest_zone, dest_instance, dest_x, dest_y, dest_z, dest_heading, "
|
||||
"door_param, invert_state, incline, size, is_ldon_door, client_version_mask "
|
||||
"FROM doors WHERE zone = '%s' AND (version = %u OR version = -1) "
|
||||
"ORDER BY doorid asc", zone_name, version);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()){
|
||||
std::cerr << "Error in DBLoadDoors query '" << query << "' " << results.ErrorMessage() << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
int32 rowIndex = 0;
|
||||
for(auto row = results.begin(); row != results.end(); ++row, ++rowIndex) {
|
||||
if(rowIndex >= iDoorCount) {
|
||||
std::cerr << "Error, Door Count of " << iDoorCount << " exceeded." << std::endl;
|
||||
break;
|
||||
}
|
||||
|
||||
memset(&into[rowIndex], 0, sizeof(Door));
|
||||
|
||||
into[rowIndex].db_id = atoi(row[0]);
|
||||
into[rowIndex].door_id = atoi(row[1]);
|
||||
|
||||
strn0cpy(into[rowIndex].zone_name,row[2],32);
|
||||
strn0cpy(into[rowIndex].door_name,row[3],32);
|
||||
|
||||
into[rowIndex].pos_x = (float)atof(row[4]);
|
||||
into[rowIndex].pos_y = (float)atof(row[5]);
|
||||
into[rowIndex].pos_z = (float)atof(row[6]);
|
||||
into[rowIndex].heading = (float)atof(row[7]);
|
||||
into[rowIndex].opentype = atoi(row[8]);
|
||||
into[rowIndex].guild_id = atoi(row[9]);
|
||||
into[rowIndex].lockpick = atoi(row[10]);
|
||||
into[rowIndex].keyitem = atoi(row[11]);
|
||||
into[rowIndex].nokeyring = atoi(row[12]);
|
||||
into[rowIndex].trigger_door = atoi(row[13]);
|
||||
into[rowIndex].trigger_type = atoi(row[14]);
|
||||
|
||||
strn0cpy(into[rowIndex].dest_zone, row[15], 32);
|
||||
|
||||
into[rowIndex].dest_instance_id = atoi(row[16]);
|
||||
into[rowIndex].dest_x = (float) atof(row[17]);
|
||||
into[rowIndex].dest_y = (float) atof(row[18]);
|
||||
into[rowIndex].dest_z = (float) atof(row[19]);
|
||||
into[rowIndex].dest_heading = (float) atof(row[20]);
|
||||
into[rowIndex].door_param=atoi(row[21]);
|
||||
into[rowIndex].invert_state=atoi(row[22]);
|
||||
into[rowIndex].incline=atoi(row[23]);
|
||||
into[rowIndex].size=atoi(row[24]);
|
||||
into[rowIndex].is_ldon_door=atoi(row[25]);
|
||||
into[rowIndex].client_version_mask = (uint32)strtoul(row[26], nullptr, 10);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -644,104 +644,66 @@ GuildBankManager::~GuildBankManager()
|
||||
}
|
||||
}
|
||||
|
||||
bool GuildBankManager::Load(uint32 GuildID)
|
||||
bool GuildBankManager::Load(uint32 guildID)
|
||||
{
|
||||
const char *LoadQuery = "SELECT `area`, `slot`, `itemid`, `qty`, `donator`, `permissions`, `whofor` from `guild_bank` "
|
||||
"WHERE `guildid` = %i";
|
||||
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
|
||||
char* query = 0;
|
||||
|
||||
MYSQL_RES *result;
|
||||
|
||||
MYSQL_ROW row;
|
||||
|
||||
if(database.RunQuery(query, MakeAnyLenString(&query, LoadQuery, GuildID), errbuf, &result))
|
||||
{
|
||||
GuildBank *Bank = new GuildBank;
|
||||
|
||||
Bank->GuildID = GuildID;
|
||||
|
||||
for(int i = 0; i < GUILD_BANK_MAIN_AREA_SIZE; ++i)
|
||||
Bank->Items.MainArea[i].ItemID = 0;
|
||||
|
||||
for(int i = 0; i < GUILD_BANK_DEPOSIT_AREA_SIZE; ++i)
|
||||
Bank->Items.DepositArea[i].ItemID = 0;
|
||||
|
||||
char Donator[64], WhoFor[64];
|
||||
|
||||
while((row = mysql_fetch_row(result)))
|
||||
{
|
||||
int Area = atoi(row[0]);
|
||||
|
||||
int Slot = atoi(row[1]);
|
||||
|
||||
int ItemID = atoi(row[2]);
|
||||
|
||||
int Qty = atoi(row[3]);
|
||||
|
||||
if(row[4])
|
||||
strn0cpy(Donator, row[4], sizeof(Donator));
|
||||
else
|
||||
Donator[0] = '\0';
|
||||
|
||||
int Permissions = atoi(row[5]);
|
||||
|
||||
if(row[6])
|
||||
strn0cpy(WhoFor, row[6], sizeof(WhoFor));
|
||||
else
|
||||
WhoFor[0] = '\0';
|
||||
|
||||
if(Area == GuildBankMainArea)
|
||||
{
|
||||
if((Slot >= 0) && (Slot < GUILD_BANK_MAIN_AREA_SIZE))
|
||||
{
|
||||
Bank->Items.MainArea[Slot].ItemID = ItemID;
|
||||
|
||||
Bank->Items.MainArea[Slot].Quantity = Qty;
|
||||
|
||||
strn0cpy(Bank->Items.MainArea[Slot].Donator, Donator, sizeof(Donator));
|
||||
|
||||
Bank->Items.MainArea[Slot].Permissions = Permissions;
|
||||
|
||||
strn0cpy(Bank->Items.MainArea[Slot].WhoFor, WhoFor, sizeof(WhoFor));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if((Slot >= 0 ) && (Slot < GUILD_BANK_DEPOSIT_AREA_SIZE))
|
||||
{
|
||||
Bank->Items.DepositArea[Slot].ItemID = ItemID;
|
||||
|
||||
Bank->Items.DepositArea[Slot].Quantity = Qty;
|
||||
|
||||
strn0cpy(Bank->Items.DepositArea[Slot].Donator, Donator, sizeof(Donator));
|
||||
|
||||
Bank->Items.DepositArea[Slot].Permissions = Permissions;
|
||||
|
||||
strn0cpy(Bank->Items.DepositArea[Slot].WhoFor, WhoFor, sizeof(WhoFor));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
mysql_free_result(result);
|
||||
|
||||
safe_delete_array(query);
|
||||
|
||||
Banks.push_back(Bank);
|
||||
}
|
||||
else
|
||||
{
|
||||
_log(GUILDS__BANK_ERROR, "Error Loading guild bank: %s, %s", query, errbuf);
|
||||
|
||||
safe_delete_array(query);
|
||||
|
||||
std::string query = StringFormat("SELECT `area`, `slot`, `itemid`, `qty`, `donator`, `permissions`, `whofor` "
|
||||
"FROM `guild_bank` WHERE `guildid` = %i", guildID);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if(!results.Success()) {
|
||||
_log(GUILDS__BANK_ERROR, "Error Loading guild bank: %s, %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
GuildBank *bank = new GuildBank;
|
||||
|
||||
bank->GuildID = guildID;
|
||||
|
||||
for(int i = 0; i < GUILD_BANK_MAIN_AREA_SIZE; ++i)
|
||||
bank->Items.MainArea[i].ItemID = 0;
|
||||
|
||||
for(int i = 0; i < GUILD_BANK_DEPOSIT_AREA_SIZE; ++i)
|
||||
bank->Items.DepositArea[i].ItemID = 0;
|
||||
|
||||
char donator[64], whoFor[64];
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row)
|
||||
{
|
||||
int area = atoi(row[0]);
|
||||
int slot = atoi(row[1]);
|
||||
int itemID = atoi(row[2]);
|
||||
int qty = atoi(row[3]);
|
||||
|
||||
if(row[4])
|
||||
strn0cpy(donator, row[4], sizeof(donator));
|
||||
else
|
||||
donator[0] = '\0';
|
||||
|
||||
int permissions = atoi(row[5]);
|
||||
|
||||
if(row[6])
|
||||
strn0cpy(whoFor, row[6], sizeof(whoFor));
|
||||
else
|
||||
whoFor[0] = '\0';
|
||||
|
||||
if(slot < 0 ||
|
||||
((area != GuildBankMainArea || slot >= GUILD_BANK_MAIN_AREA_SIZE) ||
|
||||
(area == GuildBankMainArea || slot >= GUILD_BANK_DEPOSIT_AREA_SIZE)))
|
||||
continue;
|
||||
|
||||
bank->Items.MainArea[slot].ItemID = itemID;
|
||||
bank->Items.MainArea[slot].Quantity = qty;
|
||||
|
||||
strn0cpy(bank->Items.MainArea[slot].Donator, donator, sizeof(donator));
|
||||
|
||||
bank->Items.MainArea[slot].Permissions = permissions;
|
||||
|
||||
strn0cpy(bank->Items.MainArea[slot].WhoFor, whoFor, sizeof(whoFor));
|
||||
}
|
||||
|
||||
Banks.push_back(bank);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GuildBankManager::IsLoaded(uint32 GuildID)
|
||||
@ -973,156 +935,127 @@ bool GuildBankManager::AddItem(uint32 GuildID, uint8 Area, uint32 ItemID, int32
|
||||
return true;
|
||||
}
|
||||
|
||||
int GuildBankManager::Promote(uint32 GuildID, int SlotID)
|
||||
int GuildBankManager::Promote(uint32 guildID, int slotID)
|
||||
{
|
||||
if((SlotID < 0) || (SlotID > (GUILD_BANK_DEPOSIT_AREA_SIZE - 1)))
|
||||
if((slotID < 0) || (slotID > (GUILD_BANK_DEPOSIT_AREA_SIZE - 1)))
|
||||
return -1;
|
||||
|
||||
std::list<GuildBank*>::iterator Iterator = GetGuildBank(GuildID);
|
||||
auto iter = GetGuildBank(guildID);
|
||||
|
||||
if(Iterator == Banks.end())
|
||||
{
|
||||
if(iter == Banks.end())
|
||||
return -1;
|
||||
}
|
||||
|
||||
if((*Iterator)->Items.DepositArea[SlotID].ItemID == 0)
|
||||
{
|
||||
if((*iter)->Items.DepositArea[slotID].ItemID == 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
int MainSlot = -1;
|
||||
int mainSlot = -1;
|
||||
|
||||
for(int i = 0; i < GUILD_BANK_MAIN_AREA_SIZE; ++i)
|
||||
if((*Iterator)->Items.MainArea[i].ItemID == 0)
|
||||
{
|
||||
MainSlot = i;
|
||||
|
||||
if((*iter)->Items.MainArea[i].ItemID == 0) {
|
||||
mainSlot = i;
|
||||
break;
|
||||
}
|
||||
|
||||
if(MainSlot == -1)
|
||||
if(mainSlot == -1)
|
||||
return -1;
|
||||
|
||||
(*iter)->Items.MainArea[mainSlot].ItemID = (*iter)->Items.DepositArea[slotID].ItemID;
|
||||
(*iter)->Items.MainArea[mainSlot].Quantity = (*iter)->Items.DepositArea[slotID].Quantity;
|
||||
(*iter)->Items.MainArea[mainSlot].Permissions = (*iter)->Items.DepositArea[slotID].Permissions;
|
||||
|
||||
(*Iterator)->Items.MainArea[MainSlot].ItemID = (*Iterator)->Items.DepositArea[SlotID].ItemID;
|
||||
|
||||
(*Iterator)->Items.MainArea[MainSlot].Quantity = (*Iterator)->Items.DepositArea[SlotID].Quantity;
|
||||
|
||||
strn0cpy((*Iterator)->Items.MainArea[MainSlot].Donator, (*Iterator)->Items.DepositArea[SlotID].Donator, sizeof((*Iterator)->Items.MainArea[MainSlot].Donator));
|
||||
(*Iterator)->Items.MainArea[MainSlot].Permissions = (*Iterator)->Items.DepositArea[SlotID].Permissions;
|
||||
|
||||
strn0cpy((*Iterator)->Items.MainArea[MainSlot].WhoFor, (*Iterator)->Items.DepositArea[SlotID].WhoFor, sizeof((*Iterator)->Items.MainArea[MainSlot].WhoFor));
|
||||
|
||||
const char *Query="UPDATE `guild_bank` SET `area` = 1, `slot` = %i WHERE `guildid` = %i AND `area` = 0 AND `slot` = %i LIMIT 1";
|
||||
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
|
||||
char* query = 0;
|
||||
|
||||
if(!database.RunQuery(query, MakeAnyLenString(&query, Query, MainSlot, GuildID, SlotID), errbuf))
|
||||
{
|
||||
_log(GUILDS__BANK_ERROR, "error promoting item: %s : %s", query, errbuf);
|
||||
|
||||
safe_delete_array(query);
|
||||
strn0cpy((*iter)->Items.MainArea[mainSlot].Donator, (*iter)->Items.DepositArea[slotID].Donator, sizeof((*iter)->Items.MainArea[mainSlot].Donator));
|
||||
strn0cpy((*iter)->Items.MainArea[mainSlot].WhoFor, (*iter)->Items.DepositArea[slotID].WhoFor, sizeof((*iter)->Items.MainArea[mainSlot].WhoFor));
|
||||
|
||||
std::string query = StringFormat("UPDATE `guild_bank` SET `area` = 1, `slot` = %i "
|
||||
"WHERE `guildid` = %i AND `area` = 0 AND `slot` = %i "
|
||||
"LIMIT 1", mainSlot, guildID, slotID);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
_log(GUILDS__BANK_ERROR, "error promoting item: %s : %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return -1;
|
||||
}
|
||||
|
||||
safe_delete_array(query);
|
||||
(*iter)->Items.DepositArea[slotID].ItemID = 0;
|
||||
|
||||
(*Iterator)->Items.DepositArea[SlotID].ItemID = 0;
|
||||
|
||||
const Item_Struct *Item = database.GetItem((*Iterator)->Items.MainArea[MainSlot].ItemID);
|
||||
const Item_Struct *Item = database.GetItem((*iter)->Items.MainArea[mainSlot].ItemID);
|
||||
|
||||
GuildBankItemUpdate_Struct gbius;
|
||||
|
||||
if(!Item->Stackable)
|
||||
gbius.Init(GuildBankItemUpdate, 1, MainSlot, GuildBankMainArea, 1, Item->ID, Item->Icon, 1, 0, 0, 0);
|
||||
gbius.Init(GuildBankItemUpdate, 1, mainSlot, GuildBankMainArea, 1, Item->ID, Item->Icon, 1, 0, 0, 0);
|
||||
else
|
||||
{
|
||||
if((*Iterator)->Items.MainArea[MainSlot].Quantity == Item->StackSize)
|
||||
gbius.Init(GuildBankItemUpdate, 1, MainSlot, GuildBankMainArea, 1, Item->ID, Item->Icon,
|
||||
(*Iterator)->Items.MainArea[MainSlot].Quantity, 0, 0, 0);
|
||||
if((*iter)->Items.MainArea[mainSlot].Quantity == Item->StackSize)
|
||||
gbius.Init(GuildBankItemUpdate, 1, mainSlot, GuildBankMainArea, 1, Item->ID, Item->Icon,
|
||||
(*iter)->Items.MainArea[mainSlot].Quantity, 0, 0, 0);
|
||||
else
|
||||
gbius.Init(GuildBankItemUpdate, 1, MainSlot, GuildBankMainArea, 1, Item->ID, Item->Icon,
|
||||
(*Iterator)->Items.MainArea[MainSlot].Quantity, 0, 1, 0);
|
||||
gbius.Init(GuildBankItemUpdate, 1, mainSlot, GuildBankMainArea, 1, Item->ID, Item->Icon,
|
||||
(*iter)->Items.MainArea[mainSlot].Quantity, 0, 1, 0);
|
||||
}
|
||||
|
||||
strn0cpy(gbius.ItemName, Item->Name, sizeof(gbius.ItemName));
|
||||
|
||||
entity_list.QueueClientsGuildBankItemUpdate(&gbius, GuildID);
|
||||
entity_list.QueueClientsGuildBankItemUpdate(&gbius, guildID);
|
||||
|
||||
gbius.Init(GuildBankItemUpdate, 1, SlotID, GuildBankDepositArea, 0, 0, 0, 0, 0, 0, 0);
|
||||
gbius.Init(GuildBankItemUpdate, 1, slotID, GuildBankDepositArea, 0, 0, 0, 0, 0, 0, 0);
|
||||
|
||||
entity_list.QueueClientsGuildBankItemUpdate(&gbius, GuildID);
|
||||
entity_list.QueueClientsGuildBankItemUpdate(&gbius, guildID);
|
||||
|
||||
return MainSlot;
|
||||
return mainSlot;
|
||||
}
|
||||
|
||||
void GuildBankManager::SetPermissions(uint32 GuildID, uint16 SlotID, uint32 Permissions, const char *MemberName)
|
||||
void GuildBankManager::SetPermissions(uint32 guildID, uint16 slotID, uint32 permissions, const char *memberName)
|
||||
{
|
||||
if((SlotID > (GUILD_BANK_MAIN_AREA_SIZE - 1)))
|
||||
if((slotID > (GUILD_BANK_MAIN_AREA_SIZE - 1)))
|
||||
return;
|
||||
|
||||
std::list<GuildBank*>::iterator Iterator = GetGuildBank(GuildID);
|
||||
auto iter = GetGuildBank(guildID);
|
||||
|
||||
if(Iterator == Banks.end())
|
||||
if(iter == Banks.end())
|
||||
return;
|
||||
|
||||
if((*iter)->Items.MainArea[slotID].ItemID == 0)
|
||||
return;
|
||||
|
||||
std::string query = StringFormat("UPDATE `guild_bank` SET `permissions` = %i, `whofor` = '%s' "
|
||||
"WHERE `guildid` = %i AND `area` = 1 AND `slot` = %i LIMIT 1",
|
||||
permissions, memberName, guildID, slotID);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if(!results.Success())
|
||||
{
|
||||
_log(GUILDS__BANK_ERROR, "error changing permissions: %s : %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if((*Iterator)->Items.MainArea[SlotID].ItemID == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
(*iter)->Items.MainArea[slotID].Permissions = permissions;
|
||||
|
||||
const char *Query="UPDATE `guild_bank` SET `permissions` = %i, `whofor` = '%s' WHERE `guildid` = %i AND `area` = 1 AND `slot` = %i LIMIT 1";
|
||||
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
|
||||
char* query = 0;
|
||||
|
||||
if(!database.RunQuery(query, MakeAnyLenString(&query, Query, Permissions, MemberName, GuildID, SlotID), errbuf))
|
||||
{
|
||||
_log(GUILDS__BANK_ERROR, "error changing permissions: %s : %s", query, errbuf);
|
||||
|
||||
safe_delete_array(query);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
safe_delete_array(query);
|
||||
|
||||
(*Iterator)->Items.MainArea[SlotID].Permissions = Permissions;
|
||||
|
||||
if(Permissions == GuildBankSingleMember)
|
||||
strn0cpy((*Iterator)->Items.MainArea[SlotID].WhoFor, MemberName, sizeof((*Iterator)->Items.MainArea[SlotID].WhoFor));
|
||||
if(permissions == GuildBankSingleMember)
|
||||
strn0cpy((*iter)->Items.MainArea[slotID].WhoFor, memberName, sizeof((*iter)->Items.MainArea[slotID].WhoFor));
|
||||
else
|
||||
(*Iterator)->Items.MainArea[SlotID].WhoFor[0] = '\0';
|
||||
(*iter)->Items.MainArea[slotID].WhoFor[0] = '\0';
|
||||
|
||||
|
||||
const Item_Struct *Item = database.GetItem((*Iterator)->Items.MainArea[SlotID].ItemID);
|
||||
const Item_Struct *Item = database.GetItem((*iter)->Items.MainArea[slotID].ItemID);
|
||||
|
||||
GuildBankItemUpdate_Struct gbius;
|
||||
|
||||
if(!Item->Stackable)
|
||||
gbius.Init(GuildBankItemUpdate, 1, SlotID, GuildBankMainArea, 1, Item->ID, Item->Icon, 1, (*Iterator)->Items.MainArea[SlotID].Permissions, 0, 0);
|
||||
gbius.Init(GuildBankItemUpdate, 1, slotID, GuildBankMainArea, 1, Item->ID, Item->Icon, 1, (*iter)->Items.MainArea[slotID].Permissions, 0, 0);
|
||||
else
|
||||
{
|
||||
if((*Iterator)->Items.MainArea[SlotID].Quantity == Item->StackSize)
|
||||
gbius.Init(GuildBankItemUpdate, 1, SlotID, GuildBankMainArea, 1, Item->ID, Item->Icon,
|
||||
(*Iterator)->Items.MainArea[SlotID].Quantity, (*Iterator)->Items.MainArea[SlotID].Permissions, 0, 0);
|
||||
if((*iter)->Items.MainArea[slotID].Quantity == Item->StackSize)
|
||||
gbius.Init(GuildBankItemUpdate, 1, slotID, GuildBankMainArea, 1, Item->ID, Item->Icon,
|
||||
(*iter)->Items.MainArea[slotID].Quantity, (*iter)->Items.MainArea[slotID].Permissions, 0, 0);
|
||||
else
|
||||
gbius.Init(GuildBankItemUpdate, 1, SlotID, GuildBankMainArea, 1, Item->ID, Item->Icon,
|
||||
(*Iterator)->Items.MainArea[SlotID].Quantity, (*Iterator)->Items.MainArea[SlotID].Permissions, 1, 0);
|
||||
gbius.Init(GuildBankItemUpdate, 1, slotID, GuildBankMainArea, 1, Item->ID, Item->Icon,
|
||||
(*iter)->Items.MainArea[slotID].Quantity, (*iter)->Items.MainArea[slotID].Permissions, 1, 0);
|
||||
}
|
||||
|
||||
|
||||
strn0cpy(gbius.ItemName, Item->Name, sizeof(gbius.ItemName));
|
||||
|
||||
strn0cpy(gbius.WhoFor, (*Iterator)->Items.MainArea[SlotID].WhoFor, sizeof(gbius.WhoFor));
|
||||
strn0cpy(gbius.WhoFor, (*iter)->Items.MainArea[slotID].WhoFor, sizeof(gbius.WhoFor));
|
||||
|
||||
entity_list.QueueClientsGuildBankItemUpdate(&gbius, GuildID);
|
||||
entity_list.QueueClientsGuildBankItemUpdate(&gbius, guildID);
|
||||
}
|
||||
|
||||
ItemInst* GuildBankManager::GetItem(uint32 GuildID, uint16 Area, uint16 SlotID, uint32 Quantity)
|
||||
@ -1208,90 +1141,73 @@ std::list<GuildBank*>::iterator GuildBankManager::GetGuildBank(uint32 GuildID)
|
||||
return Iterator;
|
||||
}
|
||||
|
||||
bool GuildBankManager::DeleteItem(uint32 GuildID, uint16 Area, uint16 SlotID, uint32 Quantity)
|
||||
bool GuildBankManager::DeleteItem(uint32 guildID, uint16 area, uint16 slotID, uint32 quantity)
|
||||
{
|
||||
std::list<GuildBank*>::iterator Iterator = GetGuildBank(GuildID);
|
||||
auto iter = GetGuildBank(guildID);
|
||||
|
||||
if(Iterator == Banks.end())
|
||||
if(iter == Banks.end())
|
||||
return false;
|
||||
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
|
||||
char* query = 0;
|
||||
|
||||
GuildBankItem* BankArea = nullptr;
|
||||
|
||||
if(Area == GuildBankMainArea)
|
||||
if(area == GuildBankMainArea)
|
||||
{
|
||||
if(SlotID > (GUILD_BANK_MAIN_AREA_SIZE - 1))
|
||||
if(slotID > (GUILD_BANK_MAIN_AREA_SIZE - 1))
|
||||
return false;
|
||||
|
||||
BankArea = &(*Iterator)->Items.MainArea[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
if(SlotID > (GUILD_BANK_DEPOSIT_AREA_SIZE - 1))
|
||||
BankArea = &(*iter)->Items.MainArea[0];
|
||||
} else {
|
||||
if(slotID > (GUILD_BANK_DEPOSIT_AREA_SIZE - 1))
|
||||
return false;
|
||||
|
||||
BankArea = &(*Iterator)->Items.DepositArea[0];
|
||||
BankArea = &(*iter)->Items.DepositArea[0];
|
||||
}
|
||||
|
||||
bool deleted = true;
|
||||
|
||||
bool Deleted = true;
|
||||
|
||||
const Item_Struct *Item = database.GetItem(BankArea[SlotID].ItemID);
|
||||
|
||||
if(!Item->Stackable || (Quantity >= BankArea[SlotID].Quantity))
|
||||
{
|
||||
const char *Query = "DELETE from `guild_bank` where `guildid` = %i AND `area` = %i AND `slot` = %i LIMIT 1";
|
||||
|
||||
if(!database.RunQuery(query, MakeAnyLenString(&query, Query, GuildID, Area, SlotID), errbuf))
|
||||
{
|
||||
_log(GUILDS__BANK_ERROR, "Delete item failed. %s : %s", query, errbuf);
|
||||
|
||||
safe_delete_array(query);
|
||||
const Item_Struct *Item = database.GetItem(BankArea[slotID].ItemID);
|
||||
|
||||
if(!Item->Stackable || (quantity >= BankArea[slotID].Quantity)) {
|
||||
std::string query = StringFormat("DELETE FROM `guild_bank` WHERE `guildid` = %i "
|
||||
"AND `area` = %i AND `slot` = %i LIMIT 1",
|
||||
guildID, area, slotID);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if(!results.Success()) {
|
||||
_log(GUILDS__BANK_ERROR, "Delete item failed. %s : %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
safe_delete_array(query);
|
||||
|
||||
BankArea[SlotID].ItemID = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
const char *Query = "UPDATE `guild_bank` SET `qty` = %i where `guildid` = %i AND `area` = %i AND `slot` = %i LIMIT 1";
|
||||
|
||||
if(!database.RunQuery(query, MakeAnyLenString(&query, Query, BankArea[SlotID].Quantity - Quantity,
|
||||
GuildID, Area, SlotID), errbuf))
|
||||
{
|
||||
_log(GUILDS__BANK_ERROR, "Update item failed. %s : %s", query, errbuf);
|
||||
|
||||
safe_delete_array(query);
|
||||
BankArea[slotID].ItemID = 0;
|
||||
|
||||
} else {
|
||||
std::string query = StringFormat("UPDATE `guild_bank` SET `qty` = %i WHERE `guildid` = %i "
|
||||
"AND `area` = %i AND `slot` = %i LIMIT 1",
|
||||
BankArea[slotID].Quantity - quantity, guildID, area, slotID);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if(!results.Success()) {
|
||||
_log(GUILDS__BANK_ERROR, "Update item failed. %s : %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
safe_delete_array(query);
|
||||
BankArea[slotID].Quantity -= quantity;
|
||||
|
||||
BankArea[SlotID].Quantity -= Quantity;
|
||||
|
||||
Deleted = false;
|
||||
deleted = false;
|
||||
}
|
||||
|
||||
GuildBankItemUpdate_Struct gbius;
|
||||
|
||||
if(!Deleted)
|
||||
if(!deleted)
|
||||
{
|
||||
gbius.Init(GuildBankItemUpdate, 1, SlotID, Area, 1, Item->ID, Item->Icon, BankArea[SlotID].Quantity, BankArea[SlotID].Permissions, 1, 0);
|
||||
gbius.Init(GuildBankItemUpdate, 1, slotID, area, 1, Item->ID, Item->Icon, BankArea[slotID].Quantity, BankArea[slotID].Permissions, 1, 0);
|
||||
|
||||
strn0cpy(gbius.ItemName, Item->Name, sizeof(gbius.ItemName));
|
||||
|
||||
strn0cpy(gbius.WhoFor, BankArea[SlotID].WhoFor, sizeof(gbius.WhoFor));
|
||||
strn0cpy(gbius.WhoFor, BankArea[slotID].WhoFor, sizeof(gbius.WhoFor));
|
||||
}
|
||||
else
|
||||
gbius.Init(GuildBankItemUpdate, 1, SlotID, Area, 0, 0, 0, 0, 0, 0, 0);
|
||||
gbius.Init(GuildBankItemUpdate, 1, slotID, area, 0, 0, 0, 0, 0, 0, 0);
|
||||
|
||||
entity_list.QueueClientsGuildBankItemUpdate(&gbius, GuildID);
|
||||
entity_list.QueueClientsGuildBankItemUpdate(&gbius, guildID);
|
||||
|
||||
return true;
|
||||
|
||||
@ -1422,26 +1338,20 @@ bool GuildBankManager::SplitStack(uint32 GuildID, uint16 SlotID, uint32 Quantity
|
||||
return true;
|
||||
}
|
||||
|
||||
void GuildBankManager::UpdateItemQuantity(uint32 GuildID, uint16 Area, uint16 SlotID, uint32 Quantity)
|
||||
void GuildBankManager::UpdateItemQuantity(uint32 guildID, uint16 area, uint16 slotID, uint32 quantity)
|
||||
{
|
||||
// Helper method for MergeStacks. Assuming all passed parameters are valid.
|
||||
//
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
|
||||
char* query = 0;
|
||||
|
||||
const char *Query = "UPDATE `guild_bank` SET `qty` = %i where `guildid` = %i AND `area` = %i AND `slot` = %i LIMIT 1";
|
||||
|
||||
if(!database.RunQuery(query, MakeAnyLenString(&query, Query, Quantity, GuildID, Area, SlotID), errbuf))
|
||||
{
|
||||
_log(GUILDS__BANK_ERROR, "Update item quantity failed. %s : %s", query, errbuf);
|
||||
|
||||
safe_delete_array(query);
|
||||
|
||||
std::string query = StringFormat("UPDATE `guild_bank` SET `qty` = %i "
|
||||
"WHERE `guildid` = %i AND `area` = %i "
|
||||
"AND `slot` = %i LIMIT 1",
|
||||
quantity, guildID, area, slotID);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if(!results.Success()) {
|
||||
_log(GUILDS__BANK_ERROR, "Update item quantity failed. %s : %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
safe_delete_array(query);
|
||||
}
|
||||
|
||||
bool GuildBankManager::AllowedToWithdraw(uint32 GuildID, uint16 Area, uint16 SlotID, const char *Name)
|
||||
|
||||
@ -822,25 +822,24 @@ bool Client::PushItemOnCursor(const ItemInst& inst, bool client_update)
|
||||
return database.SaveCursor(CharacterID(), s, e);
|
||||
}
|
||||
|
||||
bool Client::PutItemInInventory(int16 slot_id, const ItemInst& inst, bool client_update)
|
||||
{
|
||||
bool Client::PutItemInInventory(int16 slot_id, const ItemInst& inst, bool client_update) {
|
||||
mlog(INVENTORY__SLOTS, "Putting item %s (%d) into slot %d", inst.GetItem()->Name, inst.GetItem()->ID, slot_id);
|
||||
|
||||
if (slot_id == MainCursor)
|
||||
{
|
||||
return PushItemOnCursor(inst,client_update);
|
||||
}
|
||||
return PushItemOnCursor(inst, client_update);
|
||||
else
|
||||
m_inv.PutItem(slot_id, inst);
|
||||
|
||||
if (client_update) {
|
||||
SendItemPacket(slot_id, &inst, (slot_id == MainCursor) ? ItemPacketSummonItem : ItemPacketTrade);
|
||||
}
|
||||
if (client_update)
|
||||
SendItemPacket(slot_id, &inst, ((slot_id == MainCursor) ? ItemPacketSummonItem : ItemPacketTrade));
|
||||
|
||||
if (slot_id == MainCursor) {
|
||||
std::list<ItemInst*>::const_iterator s=m_inv.cursor_begin(),e=m_inv.cursor_end();
|
||||
std::list<ItemInst*>::const_iterator s = m_inv.cursor_begin(), e = m_inv.cursor_end();
|
||||
return database.SaveCursor(this->CharacterID(), s, e);
|
||||
} else
|
||||
}
|
||||
else {
|
||||
return database.SaveInventory(this->CharacterID(), &inst, slot_id);
|
||||
}
|
||||
|
||||
CalcBonuses();
|
||||
}
|
||||
@ -1539,7 +1538,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
|
||||
// Also sends trade information to other client of trade session
|
||||
if(RuleB(QueryServ, PlayerLogMoves)) { QSSwapItemAuditor(move_in); } // QS Audit
|
||||
|
||||
trade->AddEntity(src_slot_id, dst_slot_id, move_in->number_in_stack);
|
||||
trade->AddEntity(dst_slot_id, move_in->number_in_stack);
|
||||
|
||||
return true;
|
||||
} else {
|
||||
|
||||
283
zone/npc.cpp
283
zone/npc.cpp
@ -1787,252 +1787,49 @@ void NPC::ModifyNPCStat(const char *identifier, const char *newValue)
|
||||
{
|
||||
std::string id = identifier;
|
||||
std::string val = newValue;
|
||||
for(int i = 0; i < id.length(); ++i)
|
||||
{
|
||||
for(int i = 0; i < id.length(); ++i) {
|
||||
id[i] = std::tolower(id[i]);
|
||||
}
|
||||
|
||||
if(id == "ac")
|
||||
{
|
||||
AC = atoi(val.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if(id == "str")
|
||||
{
|
||||
STR = atoi(val.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if(id == "sta")
|
||||
{
|
||||
STA = atoi(val.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if(id == "agi")
|
||||
{
|
||||
AGI = atoi(val.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if(id == "dex")
|
||||
{
|
||||
DEX = atoi(val.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if(id == "wis")
|
||||
{
|
||||
WIS = atoi(val.c_str());
|
||||
CalcMaxMana();
|
||||
return;
|
||||
}
|
||||
|
||||
if(id == "int" || id == "_int")
|
||||
{
|
||||
INT = atoi(val.c_str());
|
||||
CalcMaxMana();
|
||||
return;
|
||||
}
|
||||
|
||||
if(id == "cha")
|
||||
{
|
||||
CHA = atoi(val.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if(id == "max_hp")
|
||||
{
|
||||
base_hp = atoi(val.c_str());
|
||||
CalcMaxHP();
|
||||
if(cur_hp > max_hp)
|
||||
cur_hp = max_hp;
|
||||
return;
|
||||
}
|
||||
|
||||
if(id == "max_mana")
|
||||
{
|
||||
npc_mana = atoi(val.c_str());
|
||||
CalcMaxMana();
|
||||
if(cur_mana > max_mana)
|
||||
cur_mana = max_mana;
|
||||
return;
|
||||
}
|
||||
|
||||
if(id == "mr")
|
||||
{
|
||||
MR = atoi(val.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if(id == "fr")
|
||||
{
|
||||
FR = atoi(val.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if(id == "cr")
|
||||
{
|
||||
CR = atoi(val.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if(id == "pr")
|
||||
{
|
||||
PR = atoi(val.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if(id == "dr")
|
||||
{
|
||||
DR = atoi(val.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if(id == "PhR")
|
||||
{
|
||||
PhR = atoi(val.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if(id == "runspeed")
|
||||
{
|
||||
runspeed = (float)atof(val.c_str());
|
||||
CalcBonuses();
|
||||
return;
|
||||
}
|
||||
|
||||
if(id == "special_attacks")
|
||||
{
|
||||
//Added reset flag.
|
||||
NPCSpecialAttacks(val.c_str(), 0, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
if(id == "attack_speed")
|
||||
{
|
||||
attack_speed = (float)atof(val.c_str());
|
||||
CalcBonuses();
|
||||
return;
|
||||
}
|
||||
|
||||
if(id == "atk")
|
||||
{
|
||||
ATK = atoi(val.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if(id == "accuracy")
|
||||
{
|
||||
accuracy_rating = atoi(val.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if(id == "avoidance")
|
||||
{
|
||||
avoidance_rating = atoi(val.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if(id == "trackable")
|
||||
{
|
||||
trackable = atoi(val.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if(id == "min_hit")
|
||||
{
|
||||
min_dmg = atoi(val.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if(id == "max_hit")
|
||||
{
|
||||
max_dmg = atoi(val.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if(id == "attack_count")
|
||||
{
|
||||
attack_count = atoi(val.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if(id == "see_invis")
|
||||
{
|
||||
see_invis = atoi(val.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if(id == "see_invis_undead")
|
||||
{
|
||||
see_invis_undead = atoi(val.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if(id == "see_hide")
|
||||
{
|
||||
see_hide = atoi(val.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if(id == "see_improved_hide")
|
||||
{
|
||||
see_improved_hide = atoi(val.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if(id == "hp_regen")
|
||||
{
|
||||
hp_regen = atoi(val.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if(id == "mana_regen")
|
||||
{
|
||||
mana_regen = atoi(val.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if(id == "level")
|
||||
{
|
||||
SetLevel(atoi(val.c_str()));
|
||||
return;
|
||||
}
|
||||
|
||||
if(id == "aggro")
|
||||
{
|
||||
pAggroRange = atof(val.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if(id == "assist")
|
||||
{
|
||||
pAssistRange = atof(val.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if(id == "slow_mitigation")
|
||||
{
|
||||
slow_mitigation = atoi(val.c_str());
|
||||
return;
|
||||
}
|
||||
if(id == "loottable_id")
|
||||
{
|
||||
loottable_id = atof(val.c_str());
|
||||
return;
|
||||
}
|
||||
if(id == "healscale")
|
||||
{
|
||||
healscale = atof(val.c_str());
|
||||
return;
|
||||
}
|
||||
if(id == "spellscale")
|
||||
{
|
||||
spellscale = atof(val.c_str());
|
||||
return;
|
||||
}
|
||||
if(id == "ac") { AC = atoi(val.c_str()); return; }
|
||||
else if(id == "str") { STR = atoi(val.c_str()); return; }
|
||||
else if(id == "sta") { STA = atoi(val.c_str()); return; }
|
||||
else if(id == "agi") { AGI = atoi(val.c_str()); return; }
|
||||
else if(id == "dex") { DEX = atoi(val.c_str()); return; }
|
||||
else if(id == "wis") { WIS = atoi(val.c_str()); CalcMaxMana(); return; }
|
||||
else if(id == "int" || id == "_int") { INT = atoi(val.c_str()); CalcMaxMana(); return; }
|
||||
else if(id == "cha") { CHA = atoi(val.c_str()); return; }
|
||||
else if(id == "max_hp") { base_hp = atoi(val.c_str()); CalcMaxHP(); if (cur_hp > max_hp) { cur_hp = max_hp; } return; }
|
||||
else if(id == "max_mana") { npc_mana = atoi(val.c_str()); CalcMaxMana(); if (cur_mana > max_mana){ cur_mana = max_mana; } return; }
|
||||
else if(id == "mr") { MR = atoi(val.c_str()); return; }
|
||||
else if(id == "fr") { FR = atoi(val.c_str()); return; }
|
||||
else if(id == "cr") { CR = atoi(val.c_str()); return; }
|
||||
else if(id == "pr") { PR = atoi(val.c_str()); return; }
|
||||
else if(id == "dr") { DR = atoi(val.c_str()); return; }
|
||||
else if(id == "PhR") { PhR = atoi(val.c_str()); return; }
|
||||
else if(id == "runspeed") { runspeed = (float)atof(val.c_str()); CalcBonuses(); return; }
|
||||
else if(id == "special_attacks") { NPCSpecialAttacks(val.c_str(), 0, 1); return; }
|
||||
else if(id == "attack_speed") { attack_speed = (float)atof(val.c_str()); CalcBonuses(); return; }
|
||||
else if(id == "atk") { ATK = atoi(val.c_str()); return; }
|
||||
else if(id == "accuracy") { accuracy_rating = atoi(val.c_str()); return; }
|
||||
else if(id == "avoidance") { avoidance_rating = atoi(val.c_str()); return; }
|
||||
else if(id == "trackable") { trackable = atoi(val.c_str()); return; }
|
||||
else if(id == "min_hit") { min_dmg = atoi(val.c_str()); return; }
|
||||
else if(id == "max_hit") { max_dmg = atoi(val.c_str()); return; }
|
||||
else if(id == "attack_count") { attack_count = atoi(val.c_str()); return; }
|
||||
else if(id == "see_invis") { see_invis = atoi(val.c_str()); return; }
|
||||
else if(id == "see_invis_undead") { see_invis_undead = atoi(val.c_str()); return; }
|
||||
else if(id == "see_hide") { see_hide = atoi(val.c_str()); return; }
|
||||
else if(id == "see_improved_hide") { see_improved_hide = atoi(val.c_str()); return; }
|
||||
else if(id == "hp_regen") { hp_regen = atoi(val.c_str()); return; }
|
||||
else if(id == "mana_regen") { mana_regen = atoi(val.c_str()); return; }
|
||||
else if(id == "level") { SetLevel(atoi(val.c_str())); return; }
|
||||
else if(id == "aggro") { pAggroRange = atof(val.c_str()); return; }
|
||||
else if(id == "assist") { pAssistRange = atof(val.c_str()); return; }
|
||||
else if(id == "slow_mitigation") { slow_mitigation = atoi(val.c_str()); return; }
|
||||
else if(id == "loottable_id") { loottable_id = atof(val.c_str()); return; }
|
||||
else if(id == "healscale") { healscale = atof(val.c_str()); return; }
|
||||
else if(id == "spellscale") { spellscale = atof(val.c_str()); return; }
|
||||
}
|
||||
|
||||
void NPC::LevelScale() {
|
||||
|
||||
536
zone/spawn2.cpp
536
zone/spawn2.cpp
@ -354,96 +354,86 @@ void Spawn2::DeathReset(bool realdeath)
|
||||
}
|
||||
|
||||
bool ZoneDatabase::PopulateZoneSpawnList(uint32 zoneid, LinkedList<Spawn2*> &spawn2_list, int16 version, uint32 repopdelay) {
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
|
||||
const char *zone_name = database.GetZoneName(zoneid);
|
||||
|
||||
MakeAnyLenString(&query, "SELECT id, spawngroupID, x, y, z, heading, respawntime, variance, pathgrid, _condition, cond_value, enabled, animation FROM spawn2 WHERE zone='%s' AND version=%u", zone_name, version);
|
||||
if (RunQuery(query, strlen(query), errbuf, &result))
|
||||
{
|
||||
safe_delete_array(query);
|
||||
while((row = mysql_fetch_row(result)))
|
||||
{
|
||||
Spawn2* newSpawn = 0;
|
||||
|
||||
bool perl_enabled = atoi(row[11]) == 1 ? true : false;
|
||||
uint32 spawnLeft = (GetSpawnTimeLeft(atoi(row[0]), zone->GetInstanceID()) * 1000);
|
||||
newSpawn = new Spawn2(atoi(row[0]), atoi(row[1]), atof(row[2]), atof(row[3]), atof(row[4]), atof(row[5]), atoi(row[6]), atoi(row[7]), spawnLeft, atoi(row[8]), atoi(row[9]), atoi(row[10]), perl_enabled, (EmuAppearance)atoi(row[12]));
|
||||
spawn2_list.Insert( newSpawn );
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogFile->write(EQEMuLog::Error, "Error in PopulateZoneLists query '%s': %s", query, errbuf);
|
||||
safe_delete_array(query);
|
||||
std::string query = StringFormat("SELECT id, spawngroupID, x, y, z, heading, "
|
||||
"respawntime, variance, pathgrid, _condition, "
|
||||
"cond_value, enabled, animation FROM spawn2 "
|
||||
"WHERE zone = '%s' AND version = %u",
|
||||
zone_name, version);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in PopulateZoneLists query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
Spawn2* newSpawn = 0;
|
||||
|
||||
bool perl_enabled = atoi(row[11]) == 1? true: false;
|
||||
uint32 spawnLeft = (GetSpawnTimeLeft(atoi(row[0]), zone->GetInstanceID()) * 1000);
|
||||
newSpawn = new Spawn2(atoi(row[0]), atoi(row[1]), atof(row[2]), atof(row[3]), atof(row[4]),
|
||||
atof(row[5]), atoi(row[6]), atoi(row[7]), spawnLeft, atoi(row[8]),
|
||||
atoi(row[9]), atoi(row[10]), perl_enabled, (EmuAppearance)atoi(row[12]));
|
||||
|
||||
spawn2_list.Insert(newSpawn);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Spawn2* ZoneDatabase::LoadSpawn2(LinkedList<Spawn2*> &spawn2_list, uint32 spawn2id, uint32 timeleft) {
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
|
||||
if (RunQuery(query, MakeAnyLenString(&query, "SELECT id, spawngroupID, x, y, z, heading, respawntime, variance, pathgrid, _condition, cond_value, enabled, animation FROM spawn2 WHERE id=%i", spawn2id), errbuf, &result)) {
|
||||
if (mysql_num_rows(result) == 1)
|
||||
{
|
||||
row = mysql_fetch_row(result);
|
||||
bool perl_enabled = atoi(row[11]) == 1 ? true : false;
|
||||
Spawn2* newSpawn = new Spawn2(atoi(row[0]), atoi(row[1]), atof(row[2]), atof(row[3]), atof(row[4]), atof(row[5]), atoi(row[6]), atoi(row[7]), timeleft, atoi(row[8]), atoi(row[9]), atoi(row[10]), perl_enabled, (EmuAppearance)atoi(row[12]));
|
||||
spawn2_list.Insert( newSpawn );
|
||||
mysql_free_result(result);
|
||||
safe_delete_array(query);
|
||||
return newSpawn;
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
std::string query = StringFormat("SELECT id, spawngroupID, x, y, z, heading, "
|
||||
"respawntime, variance, pathgrid, _condition, "
|
||||
"cond_value, enabled, animation FROM spawn2 "
|
||||
"WHERE id = %i", spawn2id);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in LoadSpawn2 query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
LogFile->write(EQEMuLog::Error, "Error in LoadSpawn2 query '%s': %s", query, errbuf);
|
||||
safe_delete_array(query);
|
||||
return 0;
|
||||
if (results.RowCount() != 1) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in LoadSpawn2 query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
bool perl_enabled = atoi(row[11]) == 1 ? true : false;
|
||||
|
||||
Spawn2* newSpawn = new Spawn2(atoi(row[0]), atoi(row[1]), atof(row[2]), atof(row[3]), atof(row[4]),
|
||||
atof(row[5]), atoi(row[6]), atoi(row[7]), timeleft, atoi(row[8]),
|
||||
atoi(row[9]), atoi(row[10]), perl_enabled, (EmuAppearance)atoi(row[12]));
|
||||
|
||||
spawn2_list.Insert(newSpawn);
|
||||
|
||||
return newSpawn;
|
||||
}
|
||||
|
||||
bool ZoneDatabase::CreateSpawn2(Client *c, uint32 spawngroup, const char* zone, float heading, float x, float y, float z, uint32 respawn, uint32 variance, uint16 condition, int16 cond_value)
|
||||
bool ZoneDatabase::CreateSpawn2(Client *client, uint32 spawngroup, const char* zone, float heading, float x, float y, float z, uint32 respawn, uint32 variance, uint16 condition, int16 cond_value)
|
||||
{
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
|
||||
char *query = 0;
|
||||
uint32 affected_rows = 0;
|
||||
|
||||
// if(GetInverseXY()==1) {
|
||||
// float temp=x;
|
||||
// x=y;
|
||||
// y=temp;
|
||||
// }
|
||||
if (RunQuery(query, MakeAnyLenString(&query,
|
||||
"INSERT INTO spawn2 (spawngroupID,zone,x,y,z,heading,respawntime,variance,_condition,cond_value) Values (%i, '%s', %f, %f, %f, %f, %i, %i, %u, %i)",
|
||||
spawngroup, zone, x, y, z, heading, respawn, variance, condition, cond_value
|
||||
), errbuf, 0, &affected_rows)) {
|
||||
safe_delete_array(query);
|
||||
if (affected_rows == 1) {
|
||||
if(c) c->LogSQL(query);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
LogFile->write(EQEMuLog::Error, "Error in CreateSpawn2 query '%s': %s", query, errbuf);
|
||||
safe_delete_array(query);
|
||||
std::string query = StringFormat("INSERT INTO spawn2 (spawngroupID, zone, x, y, z, heading, "
|
||||
"respawntime, variance, _condition, cond_value) "
|
||||
"VALUES (%i, '%s', %f, %f, %f, %f, %i, %i, %u, %i)",
|
||||
spawngroup, zone, x, y, z, heading,
|
||||
respawn, variance, condition, cond_value);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in CreateSpawn2 query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
if (results.RowsAffected() != 1)
|
||||
return false;
|
||||
|
||||
if(client)
|
||||
client->LogSQL(query.c_str());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32 Zone::CountSpawn2() {
|
||||
@ -671,177 +661,159 @@ void SpawnConditionManager::ExecEvent(SpawnEvent &event, bool send_update) {
|
||||
}
|
||||
|
||||
void SpawnConditionManager::UpdateDBEvent(SpawnEvent &event) {
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
int len;
|
||||
|
||||
SpawnCondition cond;
|
||||
len = MakeAnyLenString(&query,
|
||||
"UPDATE spawn_events SET "
|
||||
"next_minute=%d, next_hour=%d, next_day=%d, next_month=%d, "
|
||||
"next_year=%d, enabled=%d, strict=%d "
|
||||
"WHERE id=%d",
|
||||
event.next.minute, event.next.hour, event.next.day, event.next.month,
|
||||
event.next.year, event.enabled?1:0, event.strict?1:0,event.id
|
||||
);
|
||||
if(!database.RunQuery(query, len, errbuf)) {
|
||||
LogFile->write(EQEMuLog::Error, "Unable to update spawn event '%s': %s\n", query, errbuf);
|
||||
}
|
||||
safe_delete_array(query);
|
||||
std::string query = StringFormat("UPDATE spawn_events SET "
|
||||
"next_minute = %d, next_hour = %d, "
|
||||
"next_day = %d, next_month = %d, "
|
||||
"next_year = %d, enabled = %d, "
|
||||
"strict = %d WHERE id = %d",
|
||||
event.next.minute, event.next.hour,
|
||||
event.next.day, event.next.month,
|
||||
event.next.year, event.enabled? 1: 0,
|
||||
event.strict? 1: 0, event.id);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if(!results.Success())
|
||||
LogFile->write(EQEMuLog::Error, "Unable to update spawn event '%s': %s\n", query.c_str(), results.ErrorMessage().c_str());
|
||||
|
||||
}
|
||||
|
||||
void SpawnConditionManager::UpdateDBCondition(const char* zone_name, uint32 instance_id, uint16 cond_id, int16 value) {
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
int len;
|
||||
|
||||
SpawnCondition cond;
|
||||
len = MakeAnyLenString(&query,
|
||||
"REPLACE INTO spawn_condition_values (id, value, zone, instance_id) VALUES(%u, %u, '%s', %u)",
|
||||
cond_id, value, zone_name, instance_id
|
||||
);
|
||||
if(!database.RunQuery(query, len, errbuf)) {
|
||||
LogFile->write(EQEMuLog::Error, "Unable to update spawn condition '%s': %s\n", query, errbuf);
|
||||
}
|
||||
safe_delete_array(query);
|
||||
std::string query = StringFormat("REPLACE INTO spawn_condition_values "
|
||||
"(id, value, zone, instance_id) "
|
||||
"VALUES( %u, %u, '%s', %u)",
|
||||
cond_id, value, zone_name, instance_id);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if(!results.Success())
|
||||
LogFile->write(EQEMuLog::Error, "Unable to update spawn condition '%s': %s\n", query.c_str(), results.ErrorMessage().c_str());
|
||||
|
||||
}
|
||||
|
||||
bool SpawnConditionManager::LoadDBEvent(uint32 event_id, SpawnEvent &event, std::string &zone_name) {
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
int len;
|
||||
|
||||
bool ret = false;
|
||||
|
||||
len = MakeAnyLenString(&query,
|
||||
"SELECT id,cond_id,period,next_minute,next_hour,next_day,next_month,next_year,enabled,action,argument,strict,zone "
|
||||
"FROM spawn_events WHERE id=%d", event_id);
|
||||
if (database.RunQuery(query, len, errbuf, &result)) {
|
||||
safe_delete_array(query);
|
||||
if((row = mysql_fetch_row(result))) {
|
||||
event.id = atoi(row[0]);
|
||||
event.condition_id = atoi(row[1]);
|
||||
event.period = atoi(row[2]);
|
||||
|
||||
event.next.minute = atoi(row[3]);
|
||||
event.next.hour = atoi(row[4]);
|
||||
event.next.day = atoi(row[5]);
|
||||
event.next.month = atoi(row[6]);
|
||||
event.next.year = atoi(row[7]);
|
||||
|
||||
event.enabled = atoi(row[8])==0?false:true;
|
||||
event.action = (SpawnEvent::Action) atoi(row[9]);
|
||||
event.argument = atoi(row[10]);
|
||||
event.strict = atoi(row[11])==0?false:true;
|
||||
zone_name = row[12];
|
||||
|
||||
std::string t;
|
||||
EQTime::ToString(&event.next, t);
|
||||
_log(SPAWNS__CONDITIONS, "(LoadDBEvent) Loaded %s spawn event %d on condition %d with period %d, action %d, argument %d, strict %d. Will trigger at %s",
|
||||
event.enabled?"enabled":"disabled", event.id, event.condition_id, event.period, event.action, event.argument, event.strict, t.c_str());
|
||||
|
||||
ret = true;
|
||||
}
|
||||
mysql_free_result(result);
|
||||
} else {
|
||||
LogFile->write(EQEMuLog::Error, "Error in LoadDBEvent query '%s': %s", query, errbuf);
|
||||
safe_delete_array(query);
|
||||
std::string query = StringFormat("SELECT id, cond_id, period, "
|
||||
"next_minute, next_hour, next_day, "
|
||||
"next_month, next_year, enabled, "
|
||||
"action, argument, strict, zone "
|
||||
"FROM spawn_events WHERE id = %d", event_id);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in LoadDBEvent query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return false;
|
||||
}
|
||||
return(ret);
|
||||
|
||||
if (results.RowCount() == 0)
|
||||
return false;
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
event.id = atoi(row[0]);
|
||||
event.condition_id = atoi(row[1]);
|
||||
event.period = atoi(row[2]);
|
||||
|
||||
event.next.minute = atoi(row[3]);
|
||||
event.next.hour = atoi(row[4]);
|
||||
event.next.day = atoi(row[5]);
|
||||
event.next.month = atoi(row[6]);
|
||||
event.next.year = atoi(row[7]);
|
||||
|
||||
event.enabled = atoi(row[8]) != 0;
|
||||
event.action = (SpawnEvent::Action) atoi(row[9]);
|
||||
event.argument = atoi(row[10]);
|
||||
event.strict = atoi(row[11]) != 0;
|
||||
zone_name = row[12];
|
||||
|
||||
std::string timeAsString;
|
||||
EQTime::ToString(&event.next, timeAsString);
|
||||
|
||||
_log(SPAWNS__CONDITIONS, "(LoadDBEvent) Loaded %s spawn event %d on condition %d with period %d, action %d, argument %d, strict %d. Will trigger at %s", event.enabled? "enabled": "disabled", event.id, event.condition_id, event.period, event.action, event.argument, event.strict, timeAsString.c_str());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SpawnConditionManager::LoadSpawnConditions(const char* zone_name, uint32 instance_id)
|
||||
{
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
int len;
|
||||
|
||||
//clear out old stuff..
|
||||
spawn_conditions.clear();
|
||||
|
||||
//load spawn conditions
|
||||
SpawnCondition cond;
|
||||
len = MakeAnyLenString(&query, "SELECT id, onchange, value FROM spawn_conditions WHERE zone='%s'", zone_name);
|
||||
if (database.RunQuery(query, len, errbuf, &result)) {
|
||||
safe_delete_array(query);
|
||||
while((row = mysql_fetch_row(result))) {
|
||||
cond.condition_id = atoi(row[0]);
|
||||
cond.value = atoi(row[2]);
|
||||
cond.on_change = (SpawnCondition::OnChange) atoi(row[1]);
|
||||
spawn_conditions[cond.condition_id] = cond;
|
||||
|
||||
_log(SPAWNS__CONDITIONS, "Loaded spawn condition %d with value %d and on_change %d", cond.condition_id, cond.value, cond.on_change);
|
||||
}
|
||||
mysql_free_result(result);
|
||||
} else {
|
||||
LogFile->write(EQEMuLog::Error, "Error in LoadSpawnConditions query '%s': %s", query, errbuf);
|
||||
safe_delete_array(query);
|
||||
|
||||
std::string query = StringFormat("SELECT id, onchange, value "
|
||||
"FROM spawn_conditions "
|
||||
"WHERE zone = '%s'", zone_name);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in LoadSpawnConditions query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
//load spawn conditions
|
||||
SpawnCondition cond;
|
||||
|
||||
cond.condition_id = atoi(row[0]);
|
||||
cond.value = atoi(row[2]);
|
||||
cond.on_change = (SpawnCondition::OnChange) atoi(row[1]);
|
||||
spawn_conditions[cond.condition_id] = cond;
|
||||
|
||||
_log(SPAWNS__CONDITIONS, "Loaded spawn condition %d with value %d and on_change %d", cond.condition_id, cond.value, cond.on_change);
|
||||
}
|
||||
|
||||
//load values
|
||||
len = MakeAnyLenString(&query, "SELECT id, value FROM spawn_condition_values WHERE zone='%s' and instance_id=%u", zone_name, instance_id);
|
||||
if (database.RunQuery(query, len, errbuf, &result)) {
|
||||
safe_delete_array(query);
|
||||
while((row = mysql_fetch_row(result)))
|
||||
{
|
||||
std::map<uint16, SpawnCondition>::iterator iter = spawn_conditions.find(atoi(row[0]));
|
||||
if(iter != spawn_conditions.end())
|
||||
{
|
||||
iter->second.value = atoi(row[1]);
|
||||
}
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogFile->write(EQEMuLog::Error, "Error in LoadSpawnConditions query '%s': %s", query, errbuf);
|
||||
safe_delete_array(query);
|
||||
query = StringFormat("SELECT id, value FROM spawn_condition_values "
|
||||
"WHERE zone = '%s' AND instance_id = %u",
|
||||
zone_name, instance_id);
|
||||
results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in LoadSpawnConditions query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
spawn_conditions.clear();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
auto iter = spawn_conditions.find(atoi(row[0]));
|
||||
|
||||
if(iter != spawn_conditions.end())
|
||||
iter->second.value = atoi(row[1]);
|
||||
}
|
||||
|
||||
//load spawn events
|
||||
SpawnEvent event;
|
||||
len = MakeAnyLenString(&query,
|
||||
"SELECT id,cond_id,period,next_minute,next_hour,next_day,next_month,next_year,enabled,action,argument,strict "
|
||||
"FROM spawn_events WHERE zone='%s'", zone_name);
|
||||
if (database.RunQuery(query, len, errbuf, &result)) {
|
||||
safe_delete_array(query);
|
||||
while((row = mysql_fetch_row(result))) {
|
||||
event.id = atoi(row[0]);
|
||||
event.condition_id = atoi(row[1]);
|
||||
event.period = atoi(row[2]);
|
||||
if(event.period == 0) {
|
||||
LogFile->write(EQEMuLog::Error, "Refusing to load spawn event #%d because it has a period of 0\n", event.id);
|
||||
continue;
|
||||
}
|
||||
|
||||
event.next.minute = atoi(row[3]);
|
||||
event.next.hour = atoi(row[4]);
|
||||
event.next.day = atoi(row[5]);
|
||||
event.next.month = atoi(row[6]);
|
||||
event.next.year = atoi(row[7]);
|
||||
|
||||
event.enabled = atoi(row[8])==0?false:true;
|
||||
event.action = (SpawnEvent::Action) atoi(row[9]);
|
||||
event.argument = atoi(row[10]);
|
||||
event.strict = atoi(row[11])==0?false:true;
|
||||
spawn_events.push_back(event);
|
||||
|
||||
_log(SPAWNS__CONDITIONS, "(LoadSpawnConditions) Loaded %s spawn event %d on condition %d with period %d, action %d, argument %d, strict %d",
|
||||
event.enabled?"enabled":"disabled", event.id, event.condition_id, event.period, event.action, event.argument, event.strict);
|
||||
}
|
||||
mysql_free_result(result);
|
||||
} else {
|
||||
LogFile->write(EQEMuLog::Error, "Error in LoadSpawnConditions events query '%s': %s", query, errbuf);
|
||||
safe_delete_array(query);
|
||||
query = StringFormat("SELECT id, cond_id, period, next_minute, next_hour, "
|
||||
"next_day, next_month, next_year, enabled, action, argument, strict "
|
||||
"FROM spawn_events WHERE zone = '%s'", zone_name);
|
||||
results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in LoadSpawnConditions events query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
SpawnEvent event;
|
||||
|
||||
event.id = atoi(row[0]);
|
||||
event.condition_id = atoi(row[1]);
|
||||
event.period = atoi(row[2]);
|
||||
|
||||
if(event.period == 0) {
|
||||
LogFile->write(EQEMuLog::Error, "Refusing to load spawn event #%d because it has a period of 0\n", event.id);
|
||||
continue;
|
||||
}
|
||||
|
||||
event.next.minute = atoi(row[3]);
|
||||
event.next.hour = atoi(row[4]);
|
||||
event.next.day = atoi(row[5]);
|
||||
event.next.month = atoi(row[6]);
|
||||
event.next.year = atoi(row[7]);
|
||||
|
||||
event.enabled = atoi(row[8])==0?false:true;
|
||||
event.action = (SpawnEvent::Action) atoi(row[9]);
|
||||
event.argument = atoi(row[10]);
|
||||
event.strict = atoi(row[11])==0?false:true;
|
||||
|
||||
spawn_events.push_back(event);
|
||||
|
||||
_log(SPAWNS__CONDITIONS, "(LoadSpawnConditions) Loaded %s spawn event %d on condition %d with period %d, action %d, argument %d, strict %d", event.enabled? "enabled": "disabled", event.id, event.condition_id, event.period, event.action, event.argument, event.strict);
|
||||
}
|
||||
|
||||
//now we need to catch up on events that happened while we were away
|
||||
//and use them to alter just the condition variables.
|
||||
@ -855,18 +827,14 @@ bool SpawnConditionManager::LoadSpawnConditions(const char* zone_name, uint32 in
|
||||
TimeOfDay_Struct tod;
|
||||
zone->zone_time.getEQTimeOfDay(&tod);
|
||||
|
||||
std::vector<SpawnEvent>::iterator cur,end;
|
||||
cur = spawn_events.begin();
|
||||
end = spawn_events.end();
|
||||
bool ran;
|
||||
for(; cur != end; ++cur) {
|
||||
for(auto cur = spawn_events.begin(); cur != spawn_events.end(); ++cur) {
|
||||
SpawnEvent &cevent = *cur;
|
||||
|
||||
bool StrictCheck = false;
|
||||
if(cevent.strict &&
|
||||
cevent.next.hour == tod.hour &&
|
||||
cevent.next.day == tod.day &&
|
||||
cevent.next.month == tod.month &&
|
||||
if(cevent.strict &&
|
||||
cevent.next.hour == tod.hour &&
|
||||
cevent.next.day == tod.day &&
|
||||
cevent.next.month == tod.month &&
|
||||
cevent.next.year == tod.year)
|
||||
StrictCheck = true;
|
||||
|
||||
@ -874,43 +842,42 @@ bool SpawnConditionManager::LoadSpawnConditions(const char* zone_name, uint32 in
|
||||
if(!cevent.enabled || !StrictCheck)
|
||||
SetCondition(zone->GetShortName(), zone->GetInstanceID(),cevent.condition_id,0);
|
||||
|
||||
if(cevent.enabled)
|
||||
{
|
||||
//watch for special case of all 0s, which means to reset next to now
|
||||
if(cevent.next.year == 0 && cevent.next.month == 0 && cevent.next.day == 0 && cevent.next.hour == 0 && cevent.next.minute == 0) {
|
||||
_log(SPAWNS__CONDITIONS, "Initial next trigger time set for spawn event %d", cevent.id);
|
||||
memcpy(&cevent.next, &tod, sizeof(cevent.next));
|
||||
//add one period
|
||||
EQTime::AddMinutes(cevent.period, &cevent.next);
|
||||
//save it in the db.
|
||||
UpdateDBEvent(cevent);
|
||||
continue; //were done with this event.
|
||||
}
|
||||
if(!cevent.enabled)
|
||||
continue;
|
||||
|
||||
ran = false;
|
||||
while(EQTime::IsTimeBefore(&tod, &cevent.next)) {
|
||||
_log(SPAWNS__CONDITIONS, "Catch up triggering on event %d", cevent.id);
|
||||
//this event has been triggered.
|
||||
//execute the event
|
||||
if(!cevent.strict || StrictCheck)
|
||||
ExecEvent(cevent, false);
|
||||
|
||||
//add the period of the event to the trigger time
|
||||
EQTime::AddMinutes(cevent.period, &cevent.next);
|
||||
ran = true;
|
||||
}
|
||||
//only write it out if the event actually ran
|
||||
if(ran) {
|
||||
//save the event in the DB
|
||||
UpdateDBEvent(cevent);
|
||||
}
|
||||
}
|
||||
//watch for special case of all 0s, which means to reset next to now
|
||||
if(cevent.next.year == 0 && cevent.next.month == 0 && cevent.next.day == 0 && cevent.next.hour == 0 && cevent.next.minute == 0) {
|
||||
_log(SPAWNS__CONDITIONS, "Initial next trigger time set for spawn event %d", cevent.id);
|
||||
memcpy(&cevent.next, &tod, sizeof(cevent.next));
|
||||
//add one period
|
||||
EQTime::AddMinutes(cevent.period, &cevent.next);
|
||||
//save it in the db.
|
||||
UpdateDBEvent(cevent);
|
||||
continue; //were done with this event.
|
||||
}
|
||||
|
||||
bool ran = false;
|
||||
while(EQTime::IsTimeBefore(&tod, &cevent.next)) {
|
||||
_log(SPAWNS__CONDITIONS, "Catch up triggering on event %d", cevent.id);
|
||||
//this event has been triggered.
|
||||
//execute the event
|
||||
if(!cevent.strict || StrictCheck)
|
||||
ExecEvent(cevent, false);
|
||||
|
||||
//add the period of the event to the trigger time
|
||||
EQTime::AddMinutes(cevent.period, &cevent.next);
|
||||
ran = true;
|
||||
}
|
||||
|
||||
//only write it out if the event actually ran
|
||||
if(ran)
|
||||
UpdateDBEvent(cevent); //save the event in the DB
|
||||
}
|
||||
|
||||
//now our event timers are all up to date, find our closest event.
|
||||
FindNearestEvent();
|
||||
|
||||
return(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
void SpawnConditionManager::FindNearestEvent() {
|
||||
@ -926,7 +893,7 @@ void SpawnConditionManager::FindNearestEvent() {
|
||||
if(cevent.enabled)
|
||||
{
|
||||
//see if this event is before our last nearest
|
||||
if(EQTime::IsTimeBefore(&next_event, &cevent.next))
|
||||
if(EQTime::IsTimeBefore(&next_event, &cevent.next))
|
||||
{
|
||||
memcpy(&next_event, &cevent.next, sizeof(next_event));
|
||||
next_id = cevent.id;
|
||||
@ -1162,37 +1129,28 @@ int16 SpawnConditionManager::GetCondition(const char *zone_short, uint32 instanc
|
||||
}
|
||||
|
||||
SpawnCondition &cond = condi->second;
|
||||
return(cond.value);
|
||||
} else {
|
||||
//this is a remote spawn condition, grab it from the DB
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
int len;
|
||||
|
||||
int16 value;
|
||||
|
||||
//load spawn conditions
|
||||
SpawnCondition cond;
|
||||
len = MakeAnyLenString(&query, "SELECT value FROM spawn_condition_values WHERE zone='%s' AND instance_id=%u AND id=%d",
|
||||
zone_short, instance_id, condition_id);
|
||||
if (database.RunQuery(query, len, errbuf, &result)) {
|
||||
safe_delete_array(query);
|
||||
if((row = mysql_fetch_row(result))) {
|
||||
value = atoi(row[0]);
|
||||
} else {
|
||||
_log(SPAWNS__CONDITIONS, "Unable to load remote condition %d from zone %s in Get request.", condition_id, zone_short);
|
||||
value = 0; //dunno a better thing to do...
|
||||
}
|
||||
mysql_free_result(result);
|
||||
} else {
|
||||
_log(SPAWNS__CONDITIONS, "Unable to query remote condition %d from zone %s in Get request.", condition_id, zone_short);
|
||||
safe_delete_array(query);
|
||||
value = 0; //dunno a better thing to do...
|
||||
}
|
||||
return(value);
|
||||
return cond.value;
|
||||
}
|
||||
|
||||
//this is a remote spawn condition, grab it from the DB
|
||||
//load spawn conditions
|
||||
std::string query = StringFormat("SELECT value FROM spawn_condition_values "
|
||||
"WHERE zone = '%s' AND instance_id = %u AND id = %d",
|
||||
zone_short, instance_id, condition_id);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
_log(SPAWNS__CONDITIONS, "Unable to query remote condition %d from zone %s in Get request.", condition_id, zone_short);
|
||||
return 0; //dunno a better thing to do...
|
||||
}
|
||||
|
||||
if (results.RowCount() == 0) {
|
||||
_log(SPAWNS__CONDITIONS, "Unable to load remote condition %d from zone %s in Get request.", condition_id, zone_short);
|
||||
return 0; //dunno a better thing to do...
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
return atoi(row[0]);
|
||||
}
|
||||
|
||||
bool SpawnConditionManager::Check(uint16 condition, int16 min_value) {
|
||||
|
||||
@ -140,101 +140,92 @@ bool SpawnGroupList::RemoveSpawnGroup(uint32 in_id) {
|
||||
}
|
||||
|
||||
bool ZoneDatabase::LoadSpawnGroups(const char* zone_name, uint16 version, SpawnGroupList* spawn_group_list) {
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
|
||||
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))
|
||||
{
|
||||
safe_delete_array(query);
|
||||
while((row = mysql_fetch_row(result))) {
|
||||
SpawnGroup* newSpawnGroup = new SpawnGroup( atoi(row[0]), row[1], atoi(row[2]), atof(row[3]), atof(row[4]), atof(row[5]), atof(row[6]), atof(row[7]), atoi(row[8]), atoi(row[9]), atoi(row[10]), atoi(row[11]));
|
||||
spawn_group_list->AddSpawnGroup(newSpawnGroup);
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
_log(ZONE__SPAWNS, "Error2 in PopulateZoneLists query '%s' ", query);
|
||||
safe_delete_array(query);
|
||||
std::string query = StringFormat("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);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
_log(ZONE__SPAWNS, "Error2 in PopulateZoneLists query '%s' ", query.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
query = 0;
|
||||
if (RunQuery(query, MakeAnyLenString(&query,
|
||||
"SELECT DISTINCT spawnentry.spawngroupID, npcid, chance, "
|
||||
"npc_types.spawn_limit AS sl "
|
||||
"FROM spawnentry, spawn2, npc_types "
|
||||
"WHERE spawnentry.npcID=npc_types.id AND spawnentry.spawngroupID=spawn2.spawngroupID "
|
||||
"AND zone='%s'", zone_name), errbuf, &result)) {
|
||||
safe_delete_array(query);
|
||||
while((row = mysql_fetch_row(result)))
|
||||
{
|
||||
SpawnEntry* newSpawnEntry = new SpawnEntry( atoi(row[1]), atoi(row[2]), row[3]?atoi(row[3]):0);
|
||||
SpawnGroup *sg = spawn_group_list->GetSpawnGroup(atoi(row[0]));
|
||||
if (sg)
|
||||
sg->AddSpawnEntry(newSpawnEntry);
|
||||
else
|
||||
_log(ZONE__SPAWNS, "Error in LoadSpawnGroups %s ", query);
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
_log(ZONE__SPAWNS, "Error2 in PopulateZoneLists query '%'", query);
|
||||
safe_delete_array(query);
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
SpawnGroup* newSpawnGroup = new SpawnGroup(atoi(row[0]), row[1], atoi(row[2]), atof(row[3]),
|
||||
atof(row[4]), atof(row[5]), atof(row[6]), atof(row[7]),
|
||||
atoi(row[8]), atoi(row[9]), atoi(row[10]), atoi(row[11]));
|
||||
spawn_group_list->AddSpawnGroup(newSpawnGroup);
|
||||
}
|
||||
|
||||
query = StringFormat("SELECT DISTINCT spawnentry.spawngroupID, npcid, chance, "
|
||||
"npc_types.spawn_limit AS sl "
|
||||
"FROM spawnentry, spawn2, npc_types "
|
||||
"WHERE spawnentry.npcID=npc_types.id "
|
||||
"AND spawnentry.spawngroupID = spawn2.spawngroupID "
|
||||
"AND zone = '%s'", zone_name);
|
||||
results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
_log(ZONE__SPAWNS, "Error2 in PopulateZoneLists query '%'", query.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
SpawnEntry* newSpawnEntry = new SpawnEntry( atoi(row[1]), atoi(row[2]), row[3]?atoi(row[3]):0);
|
||||
SpawnGroup *sg = spawn_group_list->GetSpawnGroup(atoi(row[0]));
|
||||
|
||||
if (!sg) {
|
||||
_log(ZONE__SPAWNS, "Error in LoadSpawnGroups %s ", query.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
sg->AddSpawnEntry(newSpawnEntry);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ZoneDatabase::LoadSpawnGroupsByID(int spawngroupid, SpawnGroupList* spawn_group_list) {
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
|
||||
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))
|
||||
{
|
||||
safe_delete_array(query);
|
||||
while((row = mysql_fetch_row(result))) {
|
||||
SpawnGroup* newSpawnGroup = new SpawnGroup( atoi(row[0]), row[1], atoi(row[2]), atof(row[3]), atof(row[4]), atof(row[5]), atof(row[6]), atof(row[7]), atoi(row[8]), atoi(row[9]), atoi(row[10]), atoi(row[11]));
|
||||
spawn_group_list->AddSpawnGroup(newSpawnGroup);
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
_log(ZONE__SPAWNS, "Error2 in PopulateZoneLists query %s", query);
|
||||
safe_delete_array(query);
|
||||
|
||||
std::string query = StringFormat("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);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
_log(ZONE__SPAWNS, "Error2 in PopulateZoneLists query %s", query.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
SpawnGroup* newSpawnGroup = new SpawnGroup(atoi(row[0]), row[1], atoi(row[2]), atof(row[3]), atof(row[4]), atof(row[5]), atof(row[6]), atof(row[7]), atoi(row[8]), atoi(row[9]), atoi(row[10]), atoi(row[11]));
|
||||
spawn_group_list->AddSpawnGroup(newSpawnGroup);
|
||||
}
|
||||
|
||||
query = StringFormat("SELECT DISTINCT(spawnentry.spawngroupID), spawnentry.npcid, "
|
||||
"spawnentry.chance, spawngroup.spawn_limit FROM spawnentry, spawngroup "
|
||||
"WHERE spawnentry.spawngroupID = '%i' AND spawngroup.spawn_limit = '0' "
|
||||
"ORDER BY chance", spawngroupid);
|
||||
results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
_log(ZONE__SPAWNS, "Error3 in PopulateZoneLists query '%s'", query.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
query = 0;
|
||||
if (RunQuery(query, MakeAnyLenString(&query,
|
||||
"SELECT DISTINCT spawnentry.spawngroupID, spawnentry.npcid, spawnentry.chance, spawngroup.spawn_limit FROM spawnentry,spawngroup WHERE spawnentry.spawngroupID='%i' AND spawngroup.spawn_limit='0' ORDER by chance", spawngroupid), errbuf, &result)) {
|
||||
safe_delete_array(query);
|
||||
while((row = mysql_fetch_row(result)))
|
||||
{
|
||||
SpawnEntry* newSpawnEntry = new SpawnEntry( atoi(row[1]), atoi(row[2]), row[3]?atoi(row[3]):0);
|
||||
SpawnGroup *sg = spawn_group_list->GetSpawnGroup(atoi(row[0]));
|
||||
if (sg)
|
||||
sg->AddSpawnEntry(newSpawnEntry);
|
||||
else
|
||||
_log(ZONE__SPAWNS, "Error in SpawngroupID: %s ", row[0]);
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
_log(ZONE__SPAWNS, "Error3 in PopulateZoneLists query '%s'", row[0]);
|
||||
safe_delete_array(query);
|
||||
return false;
|
||||
}
|
||||
for(auto row = results.begin(); row != results.end(); ++row) {
|
||||
SpawnEntry* newSpawnEntry = new SpawnEntry( atoi(row[1]), atoi(row[2]), row[3]?atoi(row[3]):0);
|
||||
SpawnGroup *sg = spawn_group_list->GetSpawnGroup(atoi(row[0]));
|
||||
if (!sg) {
|
||||
_log(ZONE__SPAWNS, "Error in SpawngroupID: %s ", row[0]);
|
||||
continue;
|
||||
}
|
||||
|
||||
sg->AddSpawnEntry(newSpawnEntry);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
160
zone/spells.cpp
160
zone/spells.cpp
@ -1252,7 +1252,7 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot,
|
||||
}
|
||||
}
|
||||
|
||||
if(IsClient()) {
|
||||
if(IsClient()) {
|
||||
CheckNumHitsRemaining(NUMHIT_MatchingSpells);
|
||||
TrySympatheticProc(target, spell_id);
|
||||
}
|
||||
@ -1378,7 +1378,7 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce
|
||||
mlog(AA__MESSAGE, "Project Illusion overwrote target caster: %s spell id: %d was ON", GetName(), spell_id);
|
||||
targetType = ST_GroupClientAndPet;
|
||||
}
|
||||
|
||||
|
||||
if (spell_target && !spell_target->PassCastRestriction(true, spells[spell_id].CastRestriction)){
|
||||
Message_StringID(13,SPELL_NEED_TAR);
|
||||
return false;
|
||||
@ -1386,16 +1386,16 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce
|
||||
|
||||
//Must be out of combat. (If Beneficial checks casters combat state, Deterimental checks targets)
|
||||
if (!spells[spell_id].InCombat && spells[spell_id].OutofCombat){
|
||||
if (IsDetrimentalSpell(spell_id)) {
|
||||
if ( (spell_target->IsNPC() && spell_target->IsEngaged()) ||
|
||||
if (IsDetrimentalSpell(spell_id)) {
|
||||
if ( (spell_target->IsNPC() && spell_target->IsEngaged()) ||
|
||||
(spell_target->IsClient() && spell_target->CastToClient()->GetAggroCount())){
|
||||
Message_StringID(13,SPELL_NO_EFFECT); //Unsure correct string
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
else if (IsBeneficialSpell(spell_id)) {
|
||||
if ( (IsNPC() && IsEngaged()) ||
|
||||
else if (IsBeneficialSpell(spell_id)) {
|
||||
if ( (IsNPC() && IsEngaged()) ||
|
||||
(IsClient() && CastToClient()->GetAggroCount())){
|
||||
if (IsDiscipline(spell_id))
|
||||
Message_StringID(13,NO_ABILITY_IN_COMBAT);
|
||||
@ -1409,16 +1409,16 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce
|
||||
|
||||
//Must be in combat. (If Beneficial checks casters combat state, Deterimental checks targets)
|
||||
else if (spells[spell_id].InCombat && !spells[spell_id].OutofCombat){
|
||||
if (IsDetrimentalSpell(spell_id)) {
|
||||
if ( (spell_target->IsNPC() && !spell_target->IsEngaged()) ||
|
||||
if (IsDetrimentalSpell(spell_id)) {
|
||||
if ( (spell_target->IsNPC() && !spell_target->IsEngaged()) ||
|
||||
(spell_target->IsClient() && !spell_target->CastToClient()->GetAggroCount())){
|
||||
Message_StringID(13,SPELL_NO_EFFECT); //Unsure correct string
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
else if (IsBeneficialSpell(spell_id)) {
|
||||
if ( (IsNPC() && !IsEngaged()) ||
|
||||
else if (IsBeneficialSpell(spell_id)) {
|
||||
if ( (IsNPC() && !IsEngaged()) ||
|
||||
(IsClient() && !CastToClient()->GetAggroCount())){
|
||||
if (IsDiscipline(spell_id))
|
||||
Message_StringID(13,NO_ABILITY_OUT_OF_COMBAT);
|
||||
@ -1782,10 +1782,10 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce
|
||||
|
||||
case ST_PetMaster:
|
||||
{
|
||||
|
||||
|
||||
Mob *owner = nullptr;
|
||||
|
||||
if (IsPet())
|
||||
|
||||
if (IsPet())
|
||||
owner = GetOwner();
|
||||
else if ((IsNPC() && CastToNPC()->GetSwarmOwner()))
|
||||
owner = entity_list.GetMobID(CastToNPC()->GetSwarmOwner());
|
||||
@ -1975,7 +1975,7 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16
|
||||
if (!TrySpellProjectile(spell_target, spell_id))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
else if(!SpellOnTarget(spell_id, spell_target, false, true, resist_adjust, false)) {
|
||||
if(IsBuffSpell(spell_id) && IsBeneficialSpell(spell_id)) {
|
||||
// Prevent mana usage/timers being set for beneficial buffs
|
||||
@ -2723,7 +2723,7 @@ int Mob::CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2,
|
||||
if ((effect2 == SE_BStacker) && (!IsCastonFadeDurationSpell(spellid1) && buffs[buffslot].ticsremaining != 1 && IsEffectInSpell(spellid1, SE_CStacker)))
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
if (spellbonuses.DStacker[0]) {
|
||||
if ((effect2 == SE_DStacker) && (sp2.effectid[i] <= spellbonuses.DStacker[1]))
|
||||
return -1;
|
||||
@ -2775,7 +2775,7 @@ int Mob::CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2,
|
||||
mlog(SPELLS__STACKING, "%s (%d) blocks effect %d on slot %d below %d, but we do not have that effect on that slot. Ignored.",
|
||||
sp1.name, spellid1, blocked_effect, blocked_slot, blocked_below_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mlog(SPELLS__STACKING, "%s (%d) and %s (%d) appear to be in the same line, skipping Stacking Overwrite/Blocking checks",
|
||||
@ -3564,7 +3564,7 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r
|
||||
if(spell_effectiveness == 0 || !IsPartialCapableSpell(spell_id) )
|
||||
{
|
||||
mlog(SPELLS__RESISTS, "Spell %d was completely resisted by %s", spell_id, spelltar->GetName());
|
||||
|
||||
|
||||
if (spells[spell_id].resisttype == RESIST_PHYSICAL){
|
||||
Message_StringID(MT_SpellFailure, PHYSICAL_RESIST_FAIL,spells[spell_id].name);
|
||||
spelltar->Message_StringID(MT_SpellFailure, YOU_RESIST, spells[spell_id].name);
|
||||
@ -3707,7 +3707,7 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r
|
||||
|
||||
TrySpellTrigger(spelltar, spell_id);
|
||||
TryApplyEffect(spelltar, spell_id);
|
||||
|
||||
|
||||
if (spelltar->IsAIControlled() && IsDetrimentalSpell(spell_id) && !IsHarmonySpell(spell_id)) {
|
||||
int32 aggro_amount = CheckAggroAmount(spell_id, isproc);
|
||||
mlog(SPELLS__CASTING, "Spell %d cast on %s generated %d hate", spell_id, spelltar->GetName(), aggro_amount);
|
||||
@ -3733,7 +3733,7 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r
|
||||
safe_delete(action_packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// cause the effects to the target
|
||||
if(!spelltar->SpellEffect(this, spell_id, spell_effectiveness))
|
||||
{
|
||||
@ -3746,11 +3746,11 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (IsDetrimentalSpell(spell_id)) {
|
||||
|
||||
|
||||
CheckNumHitsRemaining(NUMHIT_OutgoingSpells);
|
||||
|
||||
|
||||
if (spelltar)
|
||||
spelltar->CheckNumHitsRemaining(NUMHIT_IncomingSpells);
|
||||
}
|
||||
@ -4408,7 +4408,7 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use
|
||||
|
||||
if (CharismaCheck)
|
||||
{
|
||||
/*
|
||||
/*
|
||||
Charisma ONLY effects the initial resist check when charm is cast with 10 CHA = -1 Resist mod up to 255 CHA (min ~ 75 cha)
|
||||
Charisma less than ~ 75 gives a postive modifier to resist checks at approximate ratio of -10 CHA = +6 Resist.
|
||||
Mez spells do same initial resist check as a above.
|
||||
@ -4470,7 +4470,7 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use
|
||||
if (CharmTick) {
|
||||
|
||||
int min_charmbreakchance = ((100/RuleI(Spells, CharmBreakCheckChance))/66 * 100)*2;
|
||||
|
||||
|
||||
if (resist_chance < min_charmbreakchance)
|
||||
resist_chance = min_charmbreakchance;
|
||||
}
|
||||
@ -4965,68 +4965,56 @@ int Client::FindSpellBookSlotBySpellID(uint16 spellid) {
|
||||
return -1; //default
|
||||
}
|
||||
|
||||
bool Client::SpellGlobalCheck(uint16 Spell_ID, uint16 Char_ID) {
|
||||
bool Client::SpellGlobalCheck(uint16 spell_ID, uint16 char_ID) {
|
||||
|
||||
std::string Spell_Global_Name;
|
||||
int Spell_Global_Value;
|
||||
int Global_Value;
|
||||
std::string spell_Global_Name;
|
||||
int spell_Global_Value;
|
||||
int global_Value;
|
||||
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
|
||||
if (database.RunQuery(query,MakeAnyLenString(&query, "SELECT qglobal, value FROM spell_globals WHERE spellid=%i", Spell_ID), errbuf, &result)) {
|
||||
safe_delete_array(query);
|
||||
|
||||
if (mysql_num_rows(result) == 1) {
|
||||
row = mysql_fetch_row(result);
|
||||
Spell_Global_Name = row[0];
|
||||
Spell_Global_Value = atoi(row[1]);
|
||||
|
||||
mysql_free_result(result);
|
||||
|
||||
if (Spell_Global_Name.empty()) { // If the entry in the spell_globals table has nothing set for the qglobal name
|
||||
return true;
|
||||
}
|
||||
else if (database.RunQuery(query,MakeAnyLenString(&query, "SELECT value FROM quest_globals WHERE charid=%i AND name='%s'", Char_ID, Spell_Global_Name.c_str()), errbuf, &result)) {
|
||||
safe_delete_array(query);
|
||||
|
||||
if (mysql_num_rows(result) == 1) {
|
||||
row = mysql_fetch_row(result);
|
||||
|
||||
Global_Value = atoi(row[0]);
|
||||
mysql_free_result(result);
|
||||
if (Global_Value == Spell_Global_Value) { // If the values match from both tables, allow the spell to be scribed
|
||||
return true;
|
||||
}
|
||||
else if (Global_Value > Spell_Global_Value) { // Check if the qglobal value is greater than the require spellglobal value
|
||||
return true;
|
||||
}
|
||||
else // If no matching result found in qglobals, don't scribe this spell
|
||||
{
|
||||
LogFile->write(EQEMuLog::Error, "Char ID: %i Spell_globals Name: '%s' Value: '%i' did not match QGlobal Value: '%i' for Spell ID %i", Char_ID, Spell_Global_Name.c_str(), Spell_Global_Value, Global_Value, Spell_ID);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
LogFile->write(EQEMuLog::Error, "Char ID: %i does not have the Qglobal Name: '%s' for Spell ID %i", Char_ID, Spell_Global_Name.c_str(), Spell_ID);
|
||||
safe_delete_array(query);
|
||||
}
|
||||
else
|
||||
LogFile->write(EQEMuLog::Error, "Spell ID %i query of spell_globals with Name: '%s' Value: '%i' failed", Spell_ID, Spell_Global_Name.c_str(), Spell_Global_Value);
|
||||
}
|
||||
else {
|
||||
return true; // Spell ID isn't listed in the spells_global table, so it is not restricted from scribing
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else {
|
||||
LogFile->write(EQEMuLog::Error, "Error while querying Spell ID %i spell_globals table query '%s': %s", Spell_ID, query, errbuf);
|
||||
safe_delete_array(query);
|
||||
std::string query = StringFormat("SELECT qglobal, value FROM spell_globals "
|
||||
"WHERE spellid = %i", spell_ID);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error while querying Spell ID %i spell_globals table query '%s': %s", spell_ID, query.c_str(), results.ErrorMessage().c_str());
|
||||
return false; // Query failed, so prevent spell from scribing just in case
|
||||
}
|
||||
return false; // Default is false
|
||||
}
|
||||
|
||||
if (results.RowCount() != 1)
|
||||
return true; // Spell ID isn't listed in the spells_global table, so it is not restricted from scribing
|
||||
|
||||
auto row = results.begin();
|
||||
spell_Global_Name = row[0];
|
||||
spell_Global_Value = atoi(row[1]);
|
||||
|
||||
if (spell_Global_Name.empty())
|
||||
return true; // If the entry in the spell_globals table has nothing set for the qglobal name
|
||||
|
||||
query = StringFormat("SELECT value FROM quest_globals "
|
||||
"WHERE charid = %i AND name = '%s'",
|
||||
char_ID, spell_Global_Name.c_str());
|
||||
results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Spell ID %i query of spell_globals with Name: '%s' Value: '%i' failed", spell_ID, spell_Global_Name.c_str(), spell_Global_Value);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (results.RowCount() != 1) {
|
||||
LogFile->write(EQEMuLog::Error, "Char ID: %i does not have the Qglobal Name: '%s' for Spell ID %i", char_ID, spell_Global_Name.c_str(), spell_ID);
|
||||
return false;
|
||||
}
|
||||
|
||||
row = results.begin();
|
||||
|
||||
global_Value = atoi(row[0]);
|
||||
|
||||
if (global_Value == spell_Global_Value)
|
||||
return true; // If the values match from both tables, allow the spell to be scribed
|
||||
else if (global_Value > spell_Global_Value)
|
||||
return true; // Check if the qglobal value is greater than the require spellglobal value
|
||||
|
||||
// If no matching result found in qglobals, don't scribe this spell
|
||||
LogFile->write(EQEMuLog::Error, "Char ID: %i Spell_globals Name: '%s' Value: '%i' did not match QGlobal Value: '%i' for Spell ID %i", char_ID, spell_Global_Name.c_str(), spell_Global_Value, global_Value, spell_ID);
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO get rid of this
|
||||
@ -5081,7 +5069,7 @@ bool Mob::FindType(uint16 type, bool bOffensive, uint16 threshold) {
|
||||
}
|
||||
|
||||
bool Mob::IsCombatProc(uint16 spell_id) {
|
||||
|
||||
|
||||
if (RuleB(Spells, FocusCombatProcs))
|
||||
return false;
|
||||
|
||||
@ -5092,7 +5080,7 @@ bool Mob::IsCombatProc(uint16 spell_id) {
|
||||
{
|
||||
|
||||
for (int i = 0; i < MAX_PROCS; i++){
|
||||
if (PermaProcs[i].spellID == spell_id || SpellProcs[i].spellID == spell_id
|
||||
if (PermaProcs[i].spellID == spell_id || SpellProcs[i].spellID == spell_id
|
||||
|| RangedProcs[i].spellID == spell_id){
|
||||
return true;
|
||||
}
|
||||
@ -5150,7 +5138,7 @@ bool Mob::AddDefensiveProc(uint16 spell_id, uint16 iChance, uint16 base_spell_id
|
||||
{
|
||||
if(spell_id == SPELL_UNKNOWN)
|
||||
return(false);
|
||||
|
||||
|
||||
int i;
|
||||
for (i = 0; i < MAX_PROCS; i++) {
|
||||
if (DefensiveProcs[i].spellID == SPELL_UNKNOWN) {
|
||||
|
||||
659
zone/trading.cpp
659
zone/trading.cpp
@ -22,7 +22,10 @@
|
||||
#include "../common/rulesys.h"
|
||||
#include "quest_parser_collection.h"
|
||||
#include "worldserver.h"
|
||||
#include "queryserv.h"
|
||||
|
||||
extern WorldServer worldserver;
|
||||
extern QueryServ* QServ;
|
||||
|
||||
// The maximum amount of a single bazaar/barter transaction expressed in copper.
|
||||
// Equivalent to 2 Million plat
|
||||
@ -71,8 +74,8 @@ void Trade::Start(uint32 mob_id, bool initiate_with)
|
||||
}
|
||||
|
||||
// Add item from a given slot to trade bucket (automatically does bag data too)
|
||||
void Trade::AddEntity(uint16 from_slot_id, uint16 trade_slot_id, uint32 stack_size) {
|
||||
// TODO: review for inventory saves
|
||||
void Trade::AddEntity(uint16 trade_slot_id, uint32 stack_size) {
|
||||
// TODO: review for inventory saves / consider changing return type to bool so failure can be passed to desync handler
|
||||
|
||||
if (!owner || !owner->IsClient()) {
|
||||
// This should never happen
|
||||
@ -121,7 +124,7 @@ void Trade::AddEntity(uint16 from_slot_id, uint16 trade_slot_id, uint32 stack_si
|
||||
if (_stack_size > 0)
|
||||
inst->SetCharges(_stack_size);
|
||||
else
|
||||
client->DeleteItemInInventory(from_slot_id);
|
||||
client->DeleteItemInInventory(MainCursor);
|
||||
|
||||
SendItemData(inst2, trade_slot_id);
|
||||
}
|
||||
@ -136,7 +139,7 @@ void Trade::AddEntity(uint16 from_slot_id, uint16 trade_slot_id, uint32 stack_si
|
||||
_log(TRADING__HOLDER, "%s added item '%s' to trade slot %i", owner->GetName(), inst->GetItem()->Name, trade_slot_id);
|
||||
|
||||
client->PutItemInInventory(trade_slot_id, *inst);
|
||||
client->DeleteItemInInventory(from_slot_id);
|
||||
client->DeleteItemInInventory(MainCursor);
|
||||
}
|
||||
}
|
||||
|
||||
@ -316,200 +319,464 @@ void Trade::DumpTrade()
|
||||
#endif
|
||||
|
||||
void Client::ResetTrade() {
|
||||
const Item_Struct* TempItem = 0;
|
||||
ItemInst* ins;
|
||||
int x;
|
||||
AddMoneyToPP(trade->cp, trade->sp, trade->gp, trade->pp, true);
|
||||
for(x = EmuConstants::TRADE_BEGIN; x <= EmuConstants::TRADE_END; x++)
|
||||
{
|
||||
TempItem = 0;
|
||||
ins = GetInv().GetItem(x);
|
||||
if (ins)
|
||||
TempItem = ins->GetItem();
|
||||
if (TempItem)
|
||||
{
|
||||
bool is_arrow = (TempItem->ItemType == ItemTypeArrow) ? true : false;
|
||||
int freeslotid = GetInv().FindFreeSlot(ins->IsType(ItemClassContainer), true, TempItem->Size, is_arrow);
|
||||
if (freeslotid == INVALID_INDEX)
|
||||
{
|
||||
DropInst(ins);
|
||||
|
||||
// step 1: process bags
|
||||
for (int16 trade_slot = EmuConstants::TRADE_BEGIN; trade_slot <= EmuConstants::TRADE_END; ++trade_slot) {
|
||||
const ItemInst* inst = m_inv[trade_slot];
|
||||
|
||||
if (inst && inst->IsType(ItemClassContainer)) {
|
||||
int16 free_slot = m_inv.FindFreeSlotForTradeItem(inst);
|
||||
|
||||
if (free_slot != INVALID_INDEX) {
|
||||
PutItemInInventory(free_slot, *inst);
|
||||
SendItemPacket(free_slot, inst, ItemPacketTrade);
|
||||
}
|
||||
else
|
||||
{
|
||||
PutItemInInventory(freeslotid, *ins);
|
||||
SendItemPacket(freeslotid, ins, ItemPacketTrade);
|
||||
else {
|
||||
DropInst(inst);
|
||||
}
|
||||
DeleteItemInInventory(x);
|
||||
|
||||
DeleteItemInInventory(trade_slot);
|
||||
}
|
||||
}
|
||||
|
||||
// step 2a: process stackables
|
||||
for (int16 trade_slot = EmuConstants::TRADE_BEGIN; trade_slot <= EmuConstants::TRADE_END; ++trade_slot) {
|
||||
ItemInst* inst = GetInv().GetItem(trade_slot);
|
||||
|
||||
if (inst && inst->IsStackable()) {
|
||||
while (true) {
|
||||
// there's no built-in safety check against an infinite loop..but, it should break on one of the conditional checks
|
||||
int16 free_slot = m_inv.FindFreeSlotForTradeItem(inst);
|
||||
|
||||
if ((free_slot == MainCursor) || (free_slot == INVALID_INDEX))
|
||||
break;
|
||||
|
||||
ItemInst* partial_inst = GetInv().GetItem(free_slot);
|
||||
|
||||
if (!partial_inst)
|
||||
break;
|
||||
|
||||
if (partial_inst->GetID() != inst->GetID()) {
|
||||
_log(TRADING__ERROR, "Client::ResetTrade() - an incompatible location reference was returned by Inventory::FindFreeSlotForTradeItem()");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if ((partial_inst->GetCharges() + inst->GetCharges()) > partial_inst->GetItem()->StackSize) {
|
||||
int16 new_charges = (partial_inst->GetCharges() + inst->GetCharges()) - partial_inst->GetItem()->StackSize;
|
||||
|
||||
partial_inst->SetCharges(partial_inst->GetItem()->StackSize);
|
||||
inst->SetCharges(new_charges);
|
||||
}
|
||||
else {
|
||||
partial_inst->SetCharges(partial_inst->GetCharges() + inst->GetCharges());
|
||||
inst->SetCharges(0);
|
||||
}
|
||||
|
||||
PutItemInInventory(free_slot, *partial_inst);
|
||||
SendItemPacket(free_slot, partial_inst, ItemPacketTrade);
|
||||
|
||||
if (inst->GetCharges() == 0) {
|
||||
DeleteItemInInventory(trade_slot);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// step 2b: adjust trade stack bias
|
||||
// (if any partial stacks exist before the final stack, FindFreeSlotForTradeItem() will return that slot in step 3 and an overwrite will occur)
|
||||
for (int16 trade_slot = EmuConstants::TRADE_END; trade_slot >= EmuConstants::TRADE_BEGIN; --trade_slot) {
|
||||
ItemInst* inst = GetInv().GetItem(trade_slot);
|
||||
|
||||
if (inst && inst->IsStackable()) {
|
||||
for (int16 bias_slot = EmuConstants::TRADE_BEGIN; bias_slot <= EmuConstants::TRADE_END; ++bias_slot) {
|
||||
if (bias_slot >= trade_slot)
|
||||
break;
|
||||
|
||||
ItemInst* bias_inst = GetInv().GetItem(bias_slot);
|
||||
|
||||
if (!bias_inst || (bias_inst->GetID() != inst->GetID()) || (bias_inst->GetCharges() >= bias_inst->GetItem()->StackSize))
|
||||
continue;
|
||||
|
||||
if ((bias_inst->GetCharges() + inst->GetCharges()) > bias_inst->GetItem()->StackSize) {
|
||||
int16 new_charges = (bias_inst->GetCharges() + inst->GetCharges()) - bias_inst->GetItem()->StackSize;
|
||||
|
||||
bias_inst->SetCharges(bias_inst->GetItem()->StackSize);
|
||||
inst->SetCharges(new_charges);
|
||||
}
|
||||
else {
|
||||
bias_inst->SetCharges(bias_inst->GetCharges() + inst->GetCharges());
|
||||
inst->SetCharges(0);
|
||||
}
|
||||
|
||||
if (inst->GetCharges() == 0) {
|
||||
DeleteItemInInventory(trade_slot);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// step 3: process everything else
|
||||
for (int16 trade_slot = EmuConstants::TRADE_BEGIN; trade_slot <= EmuConstants::TRADE_END; ++trade_slot) {
|
||||
const ItemInst* inst = m_inv[trade_slot];
|
||||
|
||||
if (inst) {
|
||||
int16 free_slot = m_inv.FindFreeSlotForTradeItem(inst);
|
||||
|
||||
if (free_slot != INVALID_INDEX) {
|
||||
PutItemInInventory(free_slot, *inst);
|
||||
SendItemPacket(free_slot, inst, ItemPacketTrade);
|
||||
}
|
||||
else {
|
||||
DropInst(inst);
|
||||
}
|
||||
|
||||
DeleteItemInInventory(trade_slot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Client::FinishTrade(Mob* tradingWith, ServerPacket* qspack, bool finalizer) {
|
||||
|
||||
void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, std::list<void*>* event_details) {
|
||||
if(tradingWith && tradingWith->IsClient()) {
|
||||
Client* other = tradingWith->CastToClient();
|
||||
QSPlayerLogTrade_Struct* qs_audit = nullptr;
|
||||
bool qs_log = false;
|
||||
|
||||
if(other) {
|
||||
mlog(TRADING__CLIENT, "Finishing trade with client %s", other->GetName());
|
||||
|
||||
int16 slot_id;
|
||||
const Item_Struct* item = nullptr;
|
||||
QSPlayerLogTrade_Struct* qsaudit = nullptr;
|
||||
bool QSPLT = false;
|
||||
|
||||
this->AddMoneyToPP(other->trade->cp, other->trade->sp, other->trade->gp, other->trade->pp, true);
|
||||
|
||||
// step 0: pre-processing
|
||||
// QS code
|
||||
if(qspack && RuleB(QueryServ, PlayerLogTrades)) {
|
||||
qsaudit = (QSPlayerLogTrade_Struct*) qspack->pBuffer;
|
||||
QSPLT = true;
|
||||
if (RuleB(QueryServ, PlayerLogTrades) && event_entry && event_details) {
|
||||
qs_audit = (QSPlayerLogTrade_Struct*)event_entry;
|
||||
qs_log = true;
|
||||
|
||||
if (finalizer) {
|
||||
qs_audit->char2_id = this->character_id;
|
||||
|
||||
if(finalizer) { qsaudit->char2_id = this->character_id; }
|
||||
else { qsaudit->char1_id = this->character_id; }
|
||||
qs_audit->char2_money.platinum = this->trade->pp;
|
||||
qs_audit->char2_money.gold = this->trade->gp;
|
||||
qs_audit->char2_money.silver = this->trade->sp;
|
||||
qs_audit->char2_money.copper = this->trade->cp;
|
||||
}
|
||||
else {
|
||||
qs_audit->char1_id = this->character_id;
|
||||
|
||||
qs_audit->char1_money.platinum = this->trade->pp;
|
||||
qs_audit->char1_money.gold = this->trade->gp;
|
||||
qs_audit->char1_money.silver = this->trade->sp;
|
||||
qs_audit->char1_money.copper = this->trade->cp;
|
||||
}
|
||||
}
|
||||
|
||||
// Move each trade slot into free inventory slot
|
||||
for(int16 i = EmuConstants::TRADE_BEGIN; i <= EmuConstants::TRADE_END; i++){
|
||||
const ItemInst* inst = m_inv[i];
|
||||
uint16 parent_offset = 0;
|
||||
// step 1: process bags
|
||||
for (int16 trade_slot = EmuConstants::TRADE_BEGIN; trade_slot <= EmuConstants::TRADE_END; ++trade_slot) {
|
||||
const ItemInst* inst = m_inv[trade_slot];
|
||||
|
||||
if(inst == nullptr) { continue; }
|
||||
if (inst && inst->IsType(ItemClassContainer)) {
|
||||
mlog(TRADING__CLIENT, "Giving container %s (%d) in slot %d to %s", inst->GetItem()->Name, inst->GetItem()->ID, trade_slot, other->GetName());
|
||||
|
||||
mlog(TRADING__CLIENT, "Giving %s (%d) in slot %d to %s", inst->GetItem()->Name, inst->GetItem()->ID, i, other->GetName());
|
||||
// TODO: need to check bag items/augments for no drop..everything for attuned...
|
||||
if (inst->GetItem()->NoDrop != 0 || Admin() >= RuleI(Character, MinStatusForNoDropExemptions) || RuleI(World, FVNoDropFlag) == 1 || other == this) {
|
||||
int16 free_slot = other->GetInv().FindFreeSlotForTradeItem(inst);
|
||||
|
||||
/// Log Player Trades through QueryServ if Rule Enabled
|
||||
if(QSPLT) {
|
||||
uint16 item_count = qsaudit->char1_count + qsaudit->char2_count;
|
||||
parent_offset = item_count;
|
||||
if (free_slot != INVALID_INDEX) {
|
||||
if (other->PutItemInInventory(free_slot, *inst, true)) {
|
||||
mlog(TRADING__CLIENT, "Container %s (%d) successfully transferred, deleting from trade slot.", inst->GetItem()->Name, inst->GetItem()->ID);
|
||||
if (qs_log) {
|
||||
QSTradeItems_Struct* detail = new QSTradeItems_Struct;
|
||||
|
||||
qsaudit->items[item_count].from_id = this->character_id;
|
||||
qsaudit->items[item_count].from_slot = i;
|
||||
qsaudit->items[item_count].to_id = other->CharacterID();
|
||||
qsaudit->items[item_count].to_slot = 0;
|
||||
qsaudit->items[item_count].item_id = inst->GetID();
|
||||
qsaudit->items[item_count].charges = inst->GetCharges();
|
||||
qsaudit->items[item_count].aug_1 = inst->GetAugmentItemID(1);
|
||||
qsaudit->items[item_count].aug_2 = inst->GetAugmentItemID(2);
|
||||
qsaudit->items[item_count].aug_3 = inst->GetAugmentItemID(3);
|
||||
qsaudit->items[item_count].aug_4 = inst->GetAugmentItemID(4);
|
||||
qsaudit->items[item_count].aug_5 = inst->GetAugmentItemID(5);
|
||||
detail->from_id = this->character_id;
|
||||
detail->from_slot = trade_slot;
|
||||
detail->to_id = other->CharacterID();
|
||||
detail->to_slot = free_slot;
|
||||
detail->item_id = inst->GetID();
|
||||
detail->charges = 1;
|
||||
detail->aug_1 = inst->GetAugmentItemID(1);
|
||||
detail->aug_2 = inst->GetAugmentItemID(2);
|
||||
detail->aug_3 = inst->GetAugmentItemID(3);
|
||||
detail->aug_4 = inst->GetAugmentItemID(4);
|
||||
detail->aug_5 = inst->GetAugmentItemID(5);
|
||||
|
||||
if(finalizer) { qsaudit->char2_count++; }
|
||||
else { qsaudit->char1_count++; }
|
||||
event_details->push_back(detail);
|
||||
|
||||
if (finalizer)
|
||||
qs_audit->char2_count += detail->charges;
|
||||
else
|
||||
qs_audit->char1_count += detail->charges;
|
||||
|
||||
if(inst->IsType(ItemClassContainer)) {
|
||||
// Pseudo-Slot ID's are generated based on how the db saves bag items...
|
||||
for(uint8 j = SUB_BEGIN; j < inst->GetItem()->BagSlots; j++) {
|
||||
const ItemInst* baginst = inst->GetItem(j);
|
||||
//for (uint8 sub_slot = SUB_BEGIN; ((sub_slot < inst->GetItem()->BagSlots) && (sub_slot < EmuConstants::ITEM_CONTAINER_SIZE)); ++sub_slot) {
|
||||
for (uint8 sub_slot = SUB_BEGIN; (sub_slot < EmuConstants::ITEM_CONTAINER_SIZE); ++sub_slot) { // this is to catch ALL items
|
||||
const ItemInst* bag_inst = inst->GetItem(sub_slot);
|
||||
|
||||
if(baginst == nullptr) { continue; }
|
||||
if (bag_inst) {
|
||||
detail = new QSTradeItems_Struct;
|
||||
|
||||
int16 k=Inventory::CalcSlotId(i, j);
|
||||
item_count = qsaudit->char1_count + qsaudit->char2_count;
|
||||
detail->from_id = this->character_id;
|
||||
detail->from_slot = Inventory::CalcSlotId(trade_slot, sub_slot);
|
||||
detail->to_id = other->CharacterID();
|
||||
detail->to_slot = Inventory::CalcSlotId(free_slot, sub_slot);
|
||||
detail->item_id = bag_inst->GetID();
|
||||
detail->charges = (!bag_inst->IsStackable() ? 1 : bag_inst->GetCharges());
|
||||
detail->aug_1 = bag_inst->GetAugmentItemID(1);
|
||||
detail->aug_2 = bag_inst->GetAugmentItemID(2);
|
||||
detail->aug_3 = bag_inst->GetAugmentItemID(3);
|
||||
detail->aug_4 = bag_inst->GetAugmentItemID(4);
|
||||
detail->aug_5 = bag_inst->GetAugmentItemID(5);
|
||||
|
||||
qsaudit->items[item_count].from_id = this->character_id;
|
||||
qsaudit->items[item_count].from_slot = k;
|
||||
qsaudit->items[item_count].to_id = other->CharacterID();
|
||||
qsaudit->items[item_count].to_slot = 0;
|
||||
qsaudit->items[item_count].item_id = baginst->GetID();
|
||||
qsaudit->items[item_count].charges = baginst->GetCharges();
|
||||
qsaudit->items[item_count].aug_1 = baginst->GetAugmentItemID(1);
|
||||
qsaudit->items[item_count].aug_2 = baginst->GetAugmentItemID(2);
|
||||
qsaudit->items[item_count].aug_3 = baginst->GetAugmentItemID(3);
|
||||
qsaudit->items[item_count].aug_4 = baginst->GetAugmentItemID(4);
|
||||
qsaudit->items[item_count].aug_5 = baginst->GetAugmentItemID(5);
|
||||
event_details->push_back(detail);
|
||||
|
||||
if(finalizer) { qsaudit->char2_count++; }
|
||||
else { qsaudit->char1_count++; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (inst->GetItem()->NoDrop != 0 || Admin() >= RuleI(Character, MinStatusForNoDropExemptions) || RuleI(World, FVNoDropFlag) == 1 || other == this) {
|
||||
bool is_arrow = (inst->GetItem()->ItemType == ItemTypeArrow) ? true : false;
|
||||
slot_id = other->GetInv().FindFreeSlot(inst->IsType(ItemClassContainer), true, inst->GetItem()->Size, is_arrow);
|
||||
|
||||
mlog(TRADING__CLIENT, "Trying to put %s (%d) into slot %d", inst->GetItem()->Name, inst->GetItem()->ID, slot_id);
|
||||
|
||||
if(other->PutItemInInventory(slot_id, *inst, true)) {
|
||||
mlog(TRADING__CLIENT, "Item %s (%d) successfully transfered, deleting from trade slot.", inst->GetItem()->Name, inst->GetItem()->ID);
|
||||
|
||||
if(QSPLT) {
|
||||
qsaudit->items[parent_offset].to_slot = slot_id;
|
||||
|
||||
if(inst->IsType(ItemClassContainer)) {
|
||||
for(uint8 bagslot_idx = SUB_BEGIN; bagslot_idx < inst->GetItem()->BagSlots; bagslot_idx++) {
|
||||
const ItemInst* bag_inst = inst->GetItem(bagslot_idx);
|
||||
|
||||
if(bag_inst == nullptr) { continue; }
|
||||
int16 to_bagslot_id = Inventory::CalcSlotId(slot_id, bagslot_idx);
|
||||
|
||||
qsaudit->items[++parent_offset].to_slot = to_bagslot_id;
|
||||
if (finalizer)
|
||||
qs_audit->char2_count += detail->charges;
|
||||
else
|
||||
qs_audit->char1_count += detail->charges;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
mlog(TRADING__ERROR, "Transfer of container %s (%d) to %s failed, returning to giver.", inst->GetItem()->Name, inst->GetItem()->ID, other->GetName());
|
||||
PushItemOnCursor(*inst, true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
mlog(TRADING__ERROR, "%s's inventory is full, returning container %s (%d) to giver.", other->GetName(), inst->GetItem()->Name, inst->GetItem()->ID);
|
||||
PushItemOnCursor(*inst, true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
mlog(TRADING__ERROR, "Container %s (%d) is NoDrop, returning to giver.", inst->GetItem()->Name, inst->GetItem()->ID);
|
||||
PushItemOnCursor(*inst, true);
|
||||
mlog(TRADING__ERROR, "Unable to give item %d (%d) to %s, returning to giver.", inst->GetItem()->Name, inst->GetItem()->ID, other->GetName());
|
||||
|
||||
if(QSPLT) {
|
||||
qsaudit->items[parent_offset].to_id = this->character_id;
|
||||
qsaudit->items[parent_offset].to_slot = MainCursor;
|
||||
|
||||
if(inst->IsType(ItemClassContainer)) {
|
||||
for(uint8 bagslot_idx = SUB_BEGIN; bagslot_idx < inst->GetItem()->BagSlots; bagslot_idx++) {
|
||||
const ItemInst* bag_inst = inst->GetItem(bagslot_idx);
|
||||
|
||||
if(bag_inst == nullptr) { continue; }
|
||||
int16 to_bagslot_id = Inventory::CalcSlotId(MainCursor, bagslot_idx);
|
||||
|
||||
qsaudit->items[++parent_offset].to_id = this->character_id;
|
||||
qsaudit->items[parent_offset].to_slot = to_bagslot_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DeleteItemInInventory(i);
|
||||
DeleteItemInInventory(trade_slot);
|
||||
}
|
||||
else {
|
||||
PushItemOnCursor(*inst, true);
|
||||
DeleteItemInInventory(i);
|
||||
}
|
||||
|
||||
if(QSPLT) {
|
||||
qsaudit->items[parent_offset].to_id = this->character_id;
|
||||
qsaudit->items[parent_offset].to_slot = MainCursor;
|
||||
// step 2a: process stackables
|
||||
for (int16 trade_slot = EmuConstants::TRADE_BEGIN; trade_slot <= EmuConstants::TRADE_END; ++trade_slot) {
|
||||
ItemInst* inst = GetInv().GetItem(trade_slot);
|
||||
|
||||
if(inst->IsType(ItemClassContainer)) {
|
||||
for(uint8 bagslot_idx = SUB_BEGIN; bagslot_idx < inst->GetItem()->BagSlots; bagslot_idx++) {
|
||||
const ItemInst* bag_inst = inst->GetItem(bagslot_idx);
|
||||
if (inst && inst->IsStackable()) {
|
||||
while (true) {
|
||||
// there's no built-in safety check against an infinite loop..but, it should break on one of the conditional checks
|
||||
int16 partial_slot = other->GetInv().FindFreeSlotForTradeItem(inst);
|
||||
|
||||
if(bag_inst == nullptr) { continue; }
|
||||
int16 to_bagslot_id = Inventory::CalcSlotId(MainCursor, bagslot_idx);
|
||||
if ((partial_slot == MainCursor) || (partial_slot == INVALID_INDEX))
|
||||
break;
|
||||
|
||||
qsaudit->items[++parent_offset].to_id = this->character_id;
|
||||
qsaudit->items[parent_offset].to_slot = to_bagslot_id;
|
||||
ItemInst* partial_inst = other->GetInv().GetItem(partial_slot);
|
||||
|
||||
if (!partial_inst)
|
||||
break;
|
||||
|
||||
if (partial_inst->GetID() != inst->GetID()) {
|
||||
_log(TRADING__ERROR, "Client::ResetTrade() - an incompatible location reference was returned by Inventory::FindFreeSlotForTradeItem()");
|
||||
break;
|
||||
}
|
||||
|
||||
int16 old_charges = inst->GetCharges();
|
||||
int16 partial_charges = partial_inst->GetCharges();
|
||||
|
||||
if ((partial_inst->GetCharges() + inst->GetCharges()) > partial_inst->GetItem()->StackSize) {
|
||||
int16 new_charges = (partial_inst->GetCharges() + inst->GetCharges()) - partial_inst->GetItem()->StackSize;
|
||||
|
||||
partial_inst->SetCharges(partial_inst->GetItem()->StackSize);
|
||||
inst->SetCharges(new_charges);
|
||||
}
|
||||
else {
|
||||
partial_inst->SetCharges(partial_inst->GetCharges() + inst->GetCharges());
|
||||
inst->SetCharges(0);
|
||||
}
|
||||
|
||||
mlog(TRADING__CLIENT, "Transferring partial stack %s (%d) in slot %d to %s", inst->GetItem()->Name, inst->GetItem()->ID, trade_slot, other->GetName());
|
||||
|
||||
if (other->PutItemInInventory(partial_slot, *partial_inst, true)) {
|
||||
mlog(TRADING__CLIENT, "Partial stack %s (%d) successfully transferred, deleting %i charges from trade slot.",
|
||||
inst->GetItem()->Name, inst->GetItem()->ID, (old_charges - inst->GetCharges()));
|
||||
if (qs_log) {
|
||||
QSTradeItems_Struct* detail = new QSTradeItems_Struct;
|
||||
|
||||
detail->from_id = this->character_id;
|
||||
detail->from_slot = trade_slot;
|
||||
detail->to_id = other->CharacterID();
|
||||
detail->to_slot = partial_slot;
|
||||
detail->item_id = inst->GetID();
|
||||
detail->charges = (old_charges - inst->GetCharges());
|
||||
detail->aug_1 = 0;
|
||||
detail->aug_2 = 0;
|
||||
detail->aug_3 = 0;
|
||||
detail->aug_4 = 0;
|
||||
detail->aug_5 = 0;
|
||||
|
||||
event_details->push_back(detail);
|
||||
|
||||
if (finalizer)
|
||||
qs_audit->char2_count += detail->charges;
|
||||
else
|
||||
qs_audit->char1_count += detail->charges;
|
||||
}
|
||||
}
|
||||
else {
|
||||
mlog(TRADING__ERROR, "Transfer of partial stack %s (%d) to %s failed, returning %i charges to trade slot.",
|
||||
inst->GetItem()->Name, inst->GetItem()->ID, other->GetName(), (old_charges - inst->GetCharges()));
|
||||
|
||||
inst->SetCharges(old_charges);
|
||||
partial_inst->SetCharges(partial_charges);
|
||||
break;
|
||||
}
|
||||
|
||||
if (inst->GetCharges() == 0) {
|
||||
DeleteItemInInventory(trade_slot);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Money - look into how NPC's receive cash
|
||||
this->AddMoneyToPP(other->trade->cp, other->trade->sp, other->trade->gp, other->trade->pp, true);
|
||||
// step 2b: adjust trade stack bias
|
||||
// (if any partial stacks exist before the final stack, FindFreeSlotForTradeItem() will return that slot in step 3 and an overwrite will occur)
|
||||
for (int16 trade_slot = EmuConstants::TRADE_END; trade_slot >= EmuConstants::TRADE_BEGIN; --trade_slot) {
|
||||
ItemInst* inst = GetInv().GetItem(trade_slot);
|
||||
|
||||
// This is currently setup to show character offers, not receipts
|
||||
if(QSPLT) {
|
||||
if(finalizer) {
|
||||
qsaudit->char2_money.platinum = this->trade->pp;
|
||||
qsaudit->char2_money.gold = this->trade->gp;
|
||||
qsaudit->char2_money.silver = this->trade->sp;
|
||||
qsaudit->char2_money.copper = this->trade->cp;
|
||||
if (inst && inst->IsStackable()) {
|
||||
for (int16 bias_slot = EmuConstants::TRADE_BEGIN; bias_slot <= EmuConstants::TRADE_END; ++bias_slot) {
|
||||
if (bias_slot >= trade_slot)
|
||||
break;
|
||||
|
||||
ItemInst* bias_inst = GetInv().GetItem(bias_slot);
|
||||
|
||||
if (!bias_inst || (bias_inst->GetID() != inst->GetID()) || (bias_inst->GetCharges() >= bias_inst->GetItem()->StackSize))
|
||||
continue;
|
||||
|
||||
int16 old_charges = inst->GetCharges();
|
||||
|
||||
if ((bias_inst->GetCharges() + inst->GetCharges()) > bias_inst->GetItem()->StackSize) {
|
||||
int16 new_charges = (bias_inst->GetCharges() + inst->GetCharges()) - bias_inst->GetItem()->StackSize;
|
||||
|
||||
bias_inst->SetCharges(bias_inst->GetItem()->StackSize);
|
||||
inst->SetCharges(new_charges);
|
||||
}
|
||||
else {
|
||||
bias_inst->SetCharges(bias_inst->GetCharges() + inst->GetCharges());
|
||||
inst->SetCharges(0);
|
||||
}
|
||||
|
||||
if (qs_log) {
|
||||
QSTradeItems_Struct* detail = new QSTradeItems_Struct;
|
||||
|
||||
detail->from_id = this->character_id;
|
||||
detail->from_slot = trade_slot;
|
||||
detail->to_id = this->character_id;
|
||||
detail->to_slot = bias_slot;
|
||||
detail->item_id = inst->GetID();
|
||||
detail->charges = (old_charges - inst->GetCharges());
|
||||
detail->aug_1 = 0;
|
||||
detail->aug_2 = 0;
|
||||
detail->aug_3 = 0;
|
||||
detail->aug_4 = 0;
|
||||
detail->aug_5 = 0;
|
||||
|
||||
event_details->push_back(detail);
|
||||
}
|
||||
|
||||
if (inst->GetCharges() == 0) {
|
||||
DeleteItemInInventory(trade_slot);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
qsaudit->char1_money.platinum = this->trade->pp;
|
||||
qsaudit->char1_money.gold = this->trade->gp;
|
||||
qsaudit->char1_money.silver = this->trade->sp;
|
||||
qsaudit->char1_money.copper = this->trade->cp;
|
||||
}
|
||||
|
||||
// step 3: process everything else
|
||||
for (int16 trade_slot = EmuConstants::TRADE_BEGIN; trade_slot <= EmuConstants::TRADE_END; ++trade_slot) {
|
||||
const ItemInst* inst = m_inv[trade_slot];
|
||||
|
||||
if (inst) {
|
||||
mlog(TRADING__CLIENT, "Giving item %s (%d) in slot %d to %s", inst->GetItem()->Name, inst->GetItem()->ID, trade_slot, other->GetName());
|
||||
|
||||
// TODO: need to check bag items/augments for no drop..everything for attuned...
|
||||
if (inst->GetItem()->NoDrop != 0 || Admin() >= RuleI(Character, MinStatusForNoDropExemptions) || RuleI(World, FVNoDropFlag) == 1 || other == this) {
|
||||
int16 free_slot = other->GetInv().FindFreeSlotForTradeItem(inst);
|
||||
|
||||
if (free_slot != INVALID_INDEX) {
|
||||
if (other->PutItemInInventory(free_slot, *inst, true)) {
|
||||
mlog(TRADING__CLIENT, "Item %s (%d) successfully transferred, deleting from trade slot.", inst->GetItem()->Name, inst->GetItem()->ID);
|
||||
if (qs_log) {
|
||||
QSTradeItems_Struct* detail = new QSTradeItems_Struct;
|
||||
|
||||
detail->from_id = this->character_id;
|
||||
detail->from_slot = trade_slot;
|
||||
detail->to_id = other->CharacterID();
|
||||
detail->to_slot = free_slot;
|
||||
detail->item_id = inst->GetID();
|
||||
detail->charges = (!inst->IsStackable() ? 1 : inst->GetCharges());
|
||||
detail->aug_1 = inst->GetAugmentItemID(1);
|
||||
detail->aug_2 = inst->GetAugmentItemID(2);
|
||||
detail->aug_3 = inst->GetAugmentItemID(3);
|
||||
detail->aug_4 = inst->GetAugmentItemID(4);
|
||||
detail->aug_5 = inst->GetAugmentItemID(5);
|
||||
|
||||
event_details->push_back(detail);
|
||||
|
||||
if (finalizer)
|
||||
qs_audit->char2_count += detail->charges;
|
||||
else
|
||||
qs_audit->char1_count += detail->charges;
|
||||
|
||||
// 'step 3' should never really see containers..but, just in case...
|
||||
//for (uint8 sub_slot = SUB_BEGIN; ((sub_slot < inst->GetItem()->BagSlots) && (sub_slot < EmuConstants::ITEM_CONTAINER_SIZE)); ++sub_slot) {
|
||||
for (uint8 sub_slot = SUB_BEGIN; (sub_slot < EmuConstants::ITEM_CONTAINER_SIZE); ++sub_slot) { // this is to catch ALL items
|
||||
const ItemInst* bag_inst = inst->GetItem(sub_slot);
|
||||
|
||||
if (bag_inst) {
|
||||
detail = new QSTradeItems_Struct;
|
||||
|
||||
detail->from_id = this->character_id;
|
||||
detail->from_slot = trade_slot;
|
||||
detail->to_id = other->CharacterID();
|
||||
detail->to_slot = free_slot;
|
||||
detail->item_id = bag_inst->GetID();
|
||||
detail->charges = (!bag_inst->IsStackable() ? 1 : bag_inst->GetCharges());
|
||||
detail->aug_1 = bag_inst->GetAugmentItemID(1);
|
||||
detail->aug_2 = bag_inst->GetAugmentItemID(2);
|
||||
detail->aug_3 = bag_inst->GetAugmentItemID(3);
|
||||
detail->aug_4 = bag_inst->GetAugmentItemID(4);
|
||||
detail->aug_5 = bag_inst->GetAugmentItemID(5);
|
||||
|
||||
event_details->push_back(detail);
|
||||
|
||||
if (finalizer)
|
||||
qs_audit->char2_count += detail->charges;
|
||||
else
|
||||
qs_audit->char1_count += detail->charges;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
mlog(TRADING__ERROR, "Transfer of Item %s (%d) to %s failed, returning to giver.", inst->GetItem()->Name, inst->GetItem()->ID, other->GetName());
|
||||
PushItemOnCursor(*inst, true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
mlog(TRADING__ERROR, "%s's inventory is full, returning item %s (%d) to giver.", other->GetName(), inst->GetItem()->Name, inst->GetItem()->ID);
|
||||
PushItemOnCursor(*inst, true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
mlog(TRADING__ERROR, "Item %s (%d) is NoDrop, returning to giver.", inst->GetItem()->Name, inst->GetItem()->ID);
|
||||
PushItemOnCursor(*inst, true);
|
||||
}
|
||||
|
||||
DeleteItemInInventory(trade_slot);
|
||||
}
|
||||
}
|
||||
|
||||
@ -517,62 +784,72 @@ void Client::FinishTrade(Mob* tradingWith, ServerPacket* qspack, bool finalizer)
|
||||
}
|
||||
}
|
||||
else if(tradingWith && tradingWith->IsNPC()) {
|
||||
QSPlayerLogHandin_Struct* qsaudit = nullptr;
|
||||
bool QSPLH = false;
|
||||
QSPlayerLogHandin_Struct* qs_audit = nullptr;
|
||||
bool qs_log = false;
|
||||
|
||||
// QS code
|
||||
if(qspack && RuleB(QueryServ, PlayerLogTrades)) {
|
||||
if(RuleB(QueryServ, PlayerLogTrades) && event_entry && event_details) {
|
||||
// Currently provides only basic functionality. Calling method will also
|
||||
// need to be modified before item returns and rewards can be logged. -U
|
||||
qsaudit = (QSPlayerLogHandin_Struct*) qspack->pBuffer;
|
||||
QSPLH = true;
|
||||
qs_audit = (QSPlayerLogHandin_Struct*)event_entry;
|
||||
qs_log = true;
|
||||
|
||||
qsaudit->quest_id = 0;
|
||||
qsaudit->char_id = character_id;
|
||||
qsaudit->char_money.platinum = trade->pp;
|
||||
qsaudit->char_money.gold = trade->gp;
|
||||
qsaudit->char_money.silver = trade->sp;
|
||||
qsaudit->char_money.copper = trade->cp;
|
||||
qsaudit->char_count = 0;
|
||||
qsaudit->npc_id = tradingWith->GetNPCTypeID();
|
||||
qsaudit->npc_money.platinum = 0;
|
||||
qsaudit->npc_money.gold = 0;
|
||||
qsaudit->npc_money.silver = 0;
|
||||
qsaudit->npc_money.copper = 0;
|
||||
qsaudit->npc_count = 0;
|
||||
qs_audit->quest_id = 0;
|
||||
qs_audit->char_id = character_id;
|
||||
qs_audit->char_money.platinum = trade->pp;
|
||||
qs_audit->char_money.gold = trade->gp;
|
||||
qs_audit->char_money.silver = trade->sp;
|
||||
qs_audit->char_money.copper = trade->cp;
|
||||
qs_audit->char_count = 0;
|
||||
qs_audit->npc_id = tradingWith->GetNPCTypeID();
|
||||
qs_audit->npc_money.platinum = 0;
|
||||
qs_audit->npc_money.gold = 0;
|
||||
qs_audit->npc_money.silver = 0;
|
||||
qs_audit->npc_money.copper = 0;
|
||||
qs_audit->npc_count = 0;
|
||||
}
|
||||
|
||||
if(QSPLH) { // This can be incoporated below when revisions are made -U
|
||||
for(int16 slot_id = EmuConstants::TRADE_BEGIN; slot_id <= EmuConstants::TRADE_NPC_END; slot_id++) {
|
||||
const ItemInst* trade_inst = m_inv[slot_id];
|
||||
if(qs_log) { // This can be incorporated below when revisions are made -U
|
||||
for (int16 trade_slot = EmuConstants::TRADE_BEGIN; trade_slot <= EmuConstants::TRADE_NPC_END; ++trade_slot) {
|
||||
const ItemInst* trade_inst = m_inv[trade_slot];
|
||||
|
||||
if(trade_inst) {
|
||||
strcpy(qsaudit->items[qsaudit->char_count].action_type, "HANDIN");
|
||||
QSHandinItems_Struct* detail = new QSHandinItems_Struct;
|
||||
|
||||
qsaudit->items[qsaudit->char_count].char_slot = slot_id;
|
||||
qsaudit->items[qsaudit->char_count].item_id = trade_inst->GetID();
|
||||
qsaudit->items[qsaudit->char_count].charges = trade_inst->GetCharges();
|
||||
qsaudit->items[qsaudit->char_count].aug_1 = trade_inst->GetAugmentItemID(1);
|
||||
qsaudit->items[qsaudit->char_count].aug_2 = trade_inst->GetAugmentItemID(2);
|
||||
qsaudit->items[qsaudit->char_count].aug_3 = trade_inst->GetAugmentItemID(3);
|
||||
qsaudit->items[qsaudit->char_count].aug_4 = trade_inst->GetAugmentItemID(4);
|
||||
qsaudit->items[qsaudit->char_count++].aug_5 = trade_inst->GetAugmentItemID(5);
|
||||
strcpy(detail->action_type, "HANDIN");
|
||||
|
||||
detail->char_slot = trade_slot;
|
||||
detail->item_id = trade_inst->GetID();
|
||||
detail->charges = (!trade_inst->IsStackable() ? 1 : trade_inst->GetCharges());
|
||||
detail->aug_1 = trade_inst->GetAugmentItemID(1);
|
||||
detail->aug_2 = trade_inst->GetAugmentItemID(2);
|
||||
detail->aug_3 = trade_inst->GetAugmentItemID(3);
|
||||
detail->aug_4 = trade_inst->GetAugmentItemID(4);
|
||||
detail->aug_5 = trade_inst->GetAugmentItemID(5);
|
||||
|
||||
event_details->push_back(detail);
|
||||
qs_audit->char_count += detail->charges;
|
||||
|
||||
if(trade_inst->IsType(ItemClassContainer)) {
|
||||
for(uint8 bag_idx = SUB_BEGIN; bag_idx < trade_inst->GetItem()->BagSlots; bag_idx++) {
|
||||
const ItemInst* trade_baginst = trade_inst->GetItem(bag_idx);
|
||||
for (uint8 sub_slot = SUB_BEGIN; sub_slot < trade_inst->GetItem()->BagSlots; ++sub_slot) {
|
||||
const ItemInst* trade_baginst = trade_inst->GetItem(sub_slot);
|
||||
|
||||
if(trade_baginst) {
|
||||
strcpy(qsaudit->items[qsaudit->char_count].action_type, "HANDIN");
|
||||
detail = new QSHandinItems_Struct;
|
||||
|
||||
qsaudit->items[qsaudit->char_count].char_slot = Inventory::CalcSlotId(slot_id, bag_idx);
|
||||
qsaudit->items[qsaudit->char_count].item_id = trade_baginst->GetID();
|
||||
qsaudit->items[qsaudit->char_count].charges = trade_baginst->GetCharges();
|
||||
qsaudit->items[qsaudit->char_count].aug_1 = trade_baginst->GetAugmentItemID(1);
|
||||
qsaudit->items[qsaudit->char_count].aug_2 = trade_baginst->GetAugmentItemID(2);
|
||||
qsaudit->items[qsaudit->char_count].aug_3 = trade_baginst->GetAugmentItemID(3);
|
||||
qsaudit->items[qsaudit->char_count].aug_4 = trade_baginst->GetAugmentItemID(4);
|
||||
qsaudit->items[qsaudit->char_count++].aug_5 = trade_baginst->GetAugmentItemID(5);
|
||||
strcpy(detail->action_type, "HANDIN");
|
||||
|
||||
detail->char_slot = Inventory::CalcSlotId(trade_slot, sub_slot);
|
||||
detail->item_id = trade_baginst->GetID();
|
||||
detail->charges = (!trade_inst->IsStackable() ? 1 : trade_inst->GetCharges());
|
||||
detail->aug_1 = trade_baginst->GetAugmentItemID(1);
|
||||
detail->aug_2 = trade_baginst->GetAugmentItemID(2);
|
||||
detail->aug_3 = trade_baginst->GetAugmentItemID(3);
|
||||
detail->aug_4 = trade_baginst->GetAugmentItemID(4);
|
||||
detail->aug_5 = trade_baginst->GetAugmentItemID(5);
|
||||
|
||||
event_details->push_back(detail);
|
||||
qs_audit->char_count += detail->charges;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -869,97 +869,78 @@ void NPC::AssignWaypoints(int32 grid) {
|
||||
return;
|
||||
}
|
||||
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
|
||||
bool GridErr = false, WPErr = false;
|
||||
Waypoints.clear();
|
||||
roamer = false;
|
||||
|
||||
// Retrieve the wander and pause types for this grid
|
||||
if(database.RunQuery(query,MakeAnyLenString(&query,"SELECT `type`,`type2` FROM `grid` WHERE `id`=%i AND `zoneid`=%i",grid,zone->GetZoneID()),errbuf, &result))
|
||||
{
|
||||
if((row = mysql_fetch_row(result)))
|
||||
{
|
||||
if(row[0] != 0)
|
||||
wandertype = atoi(row[0]);
|
||||
else
|
||||
wandertype = 0;
|
||||
if(row[1] != 0)
|
||||
pausetype = atoi(row[1]);
|
||||
else
|
||||
pausetype = 0;
|
||||
}
|
||||
else // No grid record found in this zone for the given ID
|
||||
GridErr = true;
|
||||
mysql_free_result(result);
|
||||
std::string query = StringFormat("SELECT `type`, `type2` FROM `grid` WHERE `id` = %i AND `zoneid` = %i", grid, zone->GetZoneID());
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "MySQL Error while trying to assign grid %u to mob %s: %s", grid, name, results.ErrorMessage().c_str());
|
||||
return;
|
||||
}
|
||||
else // DB query error!
|
||||
{
|
||||
GridErr = true;
|
||||
LogFile->write(EQEMuLog::Error, "MySQL Error while trying to assign grid %u to mob %s: %s", grid, name, errbuf);
|
||||
}
|
||||
safe_delete_array(query);
|
||||
|
||||
if(!GridErr)
|
||||
{
|
||||
this->CastToNPC()->SetGrid(grid); // Assign grid number
|
||||
if (results.RowCount() == 0)
|
||||
return;
|
||||
|
||||
// Retrieve all waypoints for this grid
|
||||
if(database.RunQuery(query,MakeAnyLenString(&query,"SELECT `x`,`y`,`z`,`pause`,`heading` FROM grid_entries WHERE `gridid`=%i AND `zoneid`=%i ORDER BY `number`",grid,zone->GetZoneID()),errbuf,&result))
|
||||
{
|
||||
roamer = true;
|
||||
max_wp = -1; // Initialize it; will increment it for each waypoint successfully added to the list
|
||||
auto row = results.begin();
|
||||
|
||||
while((row = mysql_fetch_row(result)))
|
||||
{
|
||||
if(row[0] != 0 && row[1] != 0 && row[2] != 0 && row[3] != 0)
|
||||
{
|
||||
wplist newwp;
|
||||
newwp.index = ++max_wp;
|
||||
newwp.x = atof(row[0]);
|
||||
newwp.y = atof(row[1]);
|
||||
newwp.z = atof(row[2]);
|
||||
wandertype = atoi(row[0]);
|
||||
pausetype = atoi(row[1]);
|
||||
|
||||
if(zone->HasMap() && RuleB(Map, FixPathingZWhenLoading) )
|
||||
{
|
||||
if(!RuleB(Watermap, CheckWaypointsInWaterWhenLoading) || !zone->HasWaterMap() ||
|
||||
(zone->HasWaterMap() && !zone->watermap->InWater(newwp.x, newwp.y, newwp.z)))
|
||||
{
|
||||
Map::Vertex dest(newwp.x, newwp.y, newwp.z);
|
||||
|
||||
float newz = zone->zonemap->FindBestZ(dest, nullptr);
|
||||
this->CastToNPC()->SetGrid(grid); // Assign grid number
|
||||
|
||||
if( (newz > -2000) && ABS(newz-dest.z) < RuleR(Map, FixPathingZMaxDeltaLoading))
|
||||
newwp.z = newz + 1;
|
||||
}
|
||||
}
|
||||
// Retrieve all waypoints for this grid
|
||||
query = StringFormat("SELECT `x`,`y`,`z`,`pause`,`heading` "
|
||||
"FROM grid_entries WHERE `gridid` = %i AND `zoneid` = %i "
|
||||
"ORDER BY `number`", grid, zone->GetZoneID());
|
||||
results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "MySQL Error while trying to assign waypoints from grid %u to mob %s: %s", grid, name, results.ErrorMessage().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
roamer = true;
|
||||
max_wp = 0; // Initialize it; will increment it for each waypoint successfully added to the list
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row, ++max_wp)
|
||||
{
|
||||
wplist newwp;
|
||||
newwp.index = max_wp;
|
||||
newwp.x = atof(row[0]);
|
||||
newwp.y = atof(row[1]);
|
||||
newwp.z = atof(row[2]);
|
||||
|
||||
if(zone->HasMap() && RuleB(Map, FixPathingZWhenLoading) )
|
||||
{
|
||||
if(!RuleB(Watermap, CheckWaypointsInWaterWhenLoading) || !zone->HasWaterMap() ||
|
||||
(zone->HasWaterMap() && !zone->watermap->InWater(newwp.x, newwp.y, newwp.z)))
|
||||
{
|
||||
Map::Vertex dest(newwp.x, newwp.y, newwp.z);
|
||||
|
||||
float newz = zone->zonemap->FindBestZ(dest, nullptr);
|
||||
|
||||
if( (newz > -2000) && ABS(newz-dest.z) < RuleR(Map, FixPathingZMaxDeltaLoading))
|
||||
newwp.z = newz + 1;
|
||||
}
|
||||
}
|
||||
|
||||
newwp.pause = atoi(row[3]);
|
||||
newwp.heading = atof(row[4]);
|
||||
Waypoints.push_back(newwp);
|
||||
}
|
||||
|
||||
newwp.pause = atoi(row[3]);
|
||||
newwp.heading = atof(row[4]);
|
||||
Waypoints.push_back(newwp);
|
||||
}
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else // DB query error!
|
||||
{
|
||||
WPErr = true;
|
||||
LogFile->write(EQEMuLog::Error, "MySQL Error while trying to assign waypoints from grid %u to mob %s: %s", grid, name, errbuf);
|
||||
}
|
||||
safe_delete_array(query);
|
||||
} // end if (!GridErr)
|
||||
if(Waypoints.size() < 2) {
|
||||
roamer = false;
|
||||
} else if(!GridErr && !WPErr) {
|
||||
UpdateWaypoint(0);
|
||||
SetWaypointPause();
|
||||
if (wandertype == 1 || wandertype == 2 || wandertype == 5)
|
||||
CalculateNewWaypoint();
|
||||
} else {
|
||||
roamer = false;
|
||||
}
|
||||
|
||||
UpdateWaypoint(0);
|
||||
SetWaypointPause();
|
||||
|
||||
if (wandertype == 1 || wandertype == 2 || wandertype == 5)
|
||||
CalculateNewWaypoint();
|
||||
|
||||
}
|
||||
|
||||
void Mob::SendTo(float new_x, float new_y, float new_z) {
|
||||
@ -1049,159 +1030,123 @@ int ZoneDatabase::GetHighestGrid(uint32 zoneid) {
|
||||
}
|
||||
|
||||
uint8 ZoneDatabase::GetGridType2(uint32 grid, uint16 zoneid) {
|
||||
char *query = 0;
|
||||
char errbuff[MYSQL_ERRMSG_SIZE];
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
int type2 = 0;
|
||||
if (RunQuery(query, MakeAnyLenString(&query,"SELECT type2 from grid where id = %i and zoneid = %i",grid,zoneid),errbuff,&result)) {
|
||||
safe_delete_array(query);
|
||||
if (mysql_num_rows(result) == 1) {
|
||||
row = mysql_fetch_row(result);
|
||||
type2 = atoi( row[0] );
|
||||
}
|
||||
mysql_free_result(result);
|
||||
} else {
|
||||
LogFile->write(EQEMuLog::Error, "Error in GetGridType2 query '%s': %s", query, errbuff);
|
||||
safe_delete_array(query);
|
||||
}
|
||||
|
||||
return(type2);
|
||||
int type2 = 0;
|
||||
std::string query = StringFormat("SELECT type2 FROM grid WHERE id = %i AND zoneid = %i", grid, zoneid);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in GetGridType2 query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (results.RowCount() != 1)
|
||||
return 0;
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
return atoi(row[0]);
|
||||
}
|
||||
|
||||
bool ZoneDatabase::GetWaypoints(uint32 grid, uint16 zoneid, uint32 num, wplist* wp) {
|
||||
char *query = 0;
|
||||
char errbuff[MYSQL_ERRMSG_SIZE];
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
if (RunQuery(query, MakeAnyLenString(&query,"SELECT x, y, z, pause, heading from grid_entries where gridid = %i and number = %i and zoneid = %i",grid,num,zoneid),errbuff,&result)) {
|
||||
safe_delete_array(query);
|
||||
if (mysql_num_rows(result) == 1) {
|
||||
row = mysql_fetch_row(result);
|
||||
if ( wp ) {
|
||||
wp->x = atof( row[0] );
|
||||
wp->y = atof( row[1] );
|
||||
wp->z = atof( row[2] );
|
||||
wp->pause = atoi( row[3] );
|
||||
wp->heading = atof( row[4] );
|
||||
}
|
||||
mysql_free_result(result);
|
||||
return true;
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else {
|
||||
LogFile->write(EQEMuLog::Error, "Error in GetWaypoints query '%s': %s", query, errbuff);
|
||||
safe_delete_array(query);
|
||||
}
|
||||
return false;
|
||||
|
||||
if (wp == nullptr)
|
||||
return false;
|
||||
|
||||
std::string query = StringFormat("SELECT x, y, z, pause, heading FROM grid_entries "
|
||||
"WHERE gridid = %i AND number = %i AND zoneid = %i", grid, num, zoneid);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in GetWaypoints query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (results.RowCount() != 1)
|
||||
return false;
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
wp->x = atof(row[0]);
|
||||
wp->y = atof(row[1]);
|
||||
wp->z = atof(row[2]);
|
||||
wp->pause = atoi(row[3]);
|
||||
wp->heading = atof(row[4]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ZoneDatabase::AssignGrid(Client *client, float x, float y, uint32 grid)
|
||||
{
|
||||
char *query = 0;
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
int matches = 0, fuzzy = 0, spawn2id = 0;
|
||||
uint32 affected_rows;
|
||||
float dbx = 0, dby = 0;
|
||||
|
||||
// looks like most of the stuff in spawn2 is straight integers
|
||||
// so let's try that first
|
||||
if(!RunQuery(
|
||||
query,
|
||||
MakeAnyLenString(
|
||||
&query,
|
||||
"SELECT id,x,y FROM spawn2 WHERE zone='%s' AND x=%i AND y=%i",
|
||||
zone->GetShortName(), (int)x, (int)y
|
||||
),
|
||||
errbuf,
|
||||
&result
|
||||
)) {
|
||||
LogFile->write(EQEMuLog::Error, "Error querying spawn2 '%s': '%s'", query, errbuf);
|
||||
return;
|
||||
std::string query = StringFormat("SELECT id, x, y FROM spawn2 WHERE zone = '%s' AND x = %i AND y = %i",
|
||||
zone->GetShortName(), (int)x, (int)y);
|
||||
auto results = QueryDatabase(query);
|
||||
if(!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error querying spawn2 '%s': '%s'", query.c_str(), results.ErrorMessage().c_str());
|
||||
return;
|
||||
}
|
||||
safe_delete_array(query);
|
||||
|
||||
// how much it's allowed to be off by
|
||||
#define _GASSIGN_TOLERANCE 1.0
|
||||
if(!(matches = mysql_num_rows(result))) // try a fuzzy match if that didn't find it
|
||||
if(results.RowCount() == 0) // try a fuzzy match if that didn't find it
|
||||
{
|
||||
mysql_free_result(result);
|
||||
if(!RunQuery(
|
||||
query,
|
||||
MakeAnyLenString(
|
||||
&query,
|
||||
"SELECT id,x,y FROM spawn2 WHERE zone='%s' AND "
|
||||
"ABS( ABS(x) - ABS(%f) ) < %f AND "
|
||||
"ABS( ABS(y) - ABS(%f) ) < %f",
|
||||
zone->GetShortName(), x, _GASSIGN_TOLERANCE, y, _GASSIGN_TOLERANCE
|
||||
),
|
||||
errbuf,
|
||||
&result
|
||||
)) {
|
||||
LogFile->write(EQEMuLog::Error, "Error querying fuzzy spawn2 '%s': '%s'", query, errbuf);
|
||||
query = StringFormat("SELECT id,x,y FROM spawn2 WHERE zone='%s' AND "
|
||||
"ABS( ABS(x) - ABS(%f) ) < %f AND "
|
||||
"ABS( ABS(y) - ABS(%f) ) < %f",
|
||||
zone->GetShortName(), x, _GASSIGN_TOLERANCE, y, _GASSIGN_TOLERANCE);
|
||||
results = QueryDatabase(query);
|
||||
if(!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error querying fuzzy spawn2 '%s': '%s'", query.c_str(), results.ErrorMessage().c_str());
|
||||
return;
|
||||
}
|
||||
safe_delete_array(query);
|
||||
|
||||
fuzzy = 1;
|
||||
if(!(matches = mysql_num_rows(result)))
|
||||
mysql_free_result(result);
|
||||
matches = results.RowCount();
|
||||
}
|
||||
if(matches)
|
||||
|
||||
if (matches == 0) {
|
||||
client->Message(0, "ERROR: Unable to assign grid - can't find it in spawn2");
|
||||
return;
|
||||
}
|
||||
|
||||
if(matches == 1)
|
||||
{
|
||||
if(matches > 1)
|
||||
{
|
||||
client->Message(0, "ERROR: Unable to assign grid - multiple spawn2 rows match");
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
row = mysql_fetch_row(result);
|
||||
spawn2id = atoi(row[0]);
|
||||
dbx = atof(row[1]);
|
||||
dby = atof(row[2]);
|
||||
if(!RunQuery(
|
||||
query,
|
||||
MakeAnyLenString(
|
||||
&query,
|
||||
"UPDATE spawn2 SET pathgrid = %d WHERE id = %d", grid, spawn2id
|
||||
),
|
||||
errbuf,
|
||||
&result,
|
||||
&affected_rows
|
||||
)) {
|
||||
LogFile->write(EQEMuLog::Error, "Error updating spawn2 '%s': '%s'", query, errbuf);
|
||||
return;
|
||||
}
|
||||
if(affected_rows == 1)
|
||||
{
|
||||
if(client) client->LogSQL(query);
|
||||
if(fuzzy)
|
||||
{
|
||||
float difference;
|
||||
difference = sqrtf(pow(fabs(x-dbx),2) + pow(fabs(y-dby),2));
|
||||
client->Message(0,
|
||||
"Grid assign: spawn2 id = %d updated - fuzzy match: deviation %f",
|
||||
spawn2id, difference
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
client->Message(0, "Grid assign: spawn2 id = %d updated - exact match", spawn2id);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
client->Message(0, "ERROR: found spawn2 id %d but the update query failed", spawn2id);
|
||||
}
|
||||
}
|
||||
client->Message(0, "ERROR: Unable to assign grid - multiple spawn2 rows match");
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
spawn2id = atoi(row[0]);
|
||||
dbx = atof(row[1]);
|
||||
dby = atof(row[2]);
|
||||
|
||||
query = StringFormat("UPDATE spawn2 SET pathgrid = %d WHERE id = %d", grid, spawn2id);
|
||||
results = QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
{
|
||||
client->Message(0, "ERROR: Unable to assign grid - can't find it in spawn2");
|
||||
}
|
||||
LogFile->write(EQEMuLog::Error, "Error updating spawn2 '%s': '%s'", query.c_str(), results.ErrorMessage().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (results.RowsAffected() != 1) {
|
||||
client->Message(0, "ERROR: found spawn2 id %d but the update query failed", spawn2id);
|
||||
return;
|
||||
}
|
||||
|
||||
if(client)
|
||||
client->LogSQL(query.c_str());
|
||||
|
||||
if(!fuzzy) {
|
||||
client->Message(0, "Grid assign: spawn2 id = %d updated - exact match", spawn2id);
|
||||
return;
|
||||
}
|
||||
|
||||
float difference = sqrtf(pow(fabs(x - dbx) , 2) + pow(fabs(y - dby), 2));
|
||||
client->Message(0, "Grid assign: spawn2 id = %d updated - fuzzy match: deviation %f", spawn2id, difference);
|
||||
}
|
||||
|
||||
/******************
|
||||
@ -1211,53 +1156,57 @@ void ZoneDatabase::AssignGrid(Client *client, float x, float y, uint32 grid)
|
||||
* type,type2: The type and type2 values for the grid being created (ignored if grid is being deleted)
|
||||
* zoneid: The ID number of the zone the grid is being created/deleted in
|
||||
*/
|
||||
void ZoneDatabase::ModifyGrid(Client *client, bool remove, uint32 id, uint8 type, uint8 type2, uint16 zoneid) {
|
||||
|
||||
void ZoneDatabase::ModifyGrid(Client *c, bool remove, uint32 id, uint8 type, uint8 type2, uint16 zoneid) {
|
||||
char *query = 0;
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
if (!remove)
|
||||
{
|
||||
if(!RunQuery(query, MakeAnyLenString(&query,"INSERT INTO grid(id,zoneid,type,type2) VALUES(%i,%i,%i,%i)",id,zoneid,type,type2), errbuf)) {
|
||||
LogFile->write(EQEMuLog::Error, "Error creating grid entry '%s': '%s'", query, errbuf);
|
||||
} else {
|
||||
if(c) c->LogSQL(query);
|
||||
}
|
||||
safe_delete_array(query);
|
||||
std::string query = StringFormat("INSERT INTO grid(id, zoneid, type, type2) "
|
||||
"VALUES (%i, %i, %i, %i)", id, zoneid, type, type2);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error creating grid entry '%s': '%s'", query.c_str(), results.ErrorMessage().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if(client)
|
||||
client->LogSQL(query.c_str());
|
||||
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!RunQuery(query, MakeAnyLenString(&query,"DELETE FROM grid where id=%i",id), errbuf)) {
|
||||
LogFile->write(EQEMuLog::Error, "Error deleting grid '%s': '%s'", query, errbuf);
|
||||
} else {
|
||||
if(c) c->LogSQL(query);
|
||||
}
|
||||
safe_delete_array(query);
|
||||
query = 0;
|
||||
if(!RunQuery(query, MakeAnyLenString(&query,"DELETE FROM grid_entries WHERE zoneid=%i AND gridid=%i",zoneid,id), errbuf)) {
|
||||
LogFile->write(EQEMuLog::Error, "Error deleting grid entries '%s': '%s'", query, errbuf);
|
||||
} else {
|
||||
if(c) c->LogSQL(query);
|
||||
}
|
||||
safe_delete_array(query);
|
||||
}
|
||||
} /*** END ZoneDatabase::ModifyGrid() ***/
|
||||
|
||||
std::string query = StringFormat("DELETE FROM grid where id=%i", id);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
LogFile->write(EQEMuLog::Error, "Error deleting grid '%s': '%s'", query.c_str(), results.ErrorMessage().c_str());
|
||||
else if(client)
|
||||
client->LogSQL(query.c_str());
|
||||
|
||||
query = StringFormat("DELETE FROM grid_entries WHERE zoneid = %i AND gridid = %i", zoneid, id);
|
||||
results = QueryDatabase(query);
|
||||
if(!results.Success())
|
||||
LogFile->write(EQEMuLog::Error, "Error deleting grid entries '%s': '%s'", query.c_str(), results.ErrorMessage().c_str());
|
||||
else if(client)
|
||||
client->LogSQL(query.c_str());
|
||||
|
||||
}
|
||||
|
||||
/**************************************
|
||||
* AddWP - Adds a new waypoint to a specific grid for a specific zone.
|
||||
*/
|
||||
|
||||
void ZoneDatabase::AddWP(Client *c, uint32 gridid, uint32 wpnum, float xpos, float ypos, float zpos, uint32 pause, uint16 zoneid, float heading)
|
||||
void ZoneDatabase::AddWP(Client *client, uint32 gridid, uint32 wpnum, float xpos, float ypos, float zpos, uint32 pause, uint16 zoneid, float heading)
|
||||
{
|
||||
char *query = 0;
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
|
||||
if(!RunQuery(query,MakeAnyLenString(&query,"INSERT INTO grid_entries (gridid,zoneid,`number`,x,y,z,pause,heading) values (%i,%i,%i,%f,%f,%f,%i,%f)",gridid,zoneid,wpnum,xpos,ypos,zpos,pause,heading), errbuf)) {
|
||||
LogFile->write(EQEMuLog::Error, "Error adding waypoint '%s': '%s'", query, errbuf);
|
||||
} else {
|
||||
if(c) c->LogSQL(query);
|
||||
std::string query = StringFormat("INSERT INTO grid_entries (gridid, zoneid, `number`, x, y, z, pause, heading) "
|
||||
"VALUES (%i, %i, %i, %f, %f, %f, %i, %f)",
|
||||
gridid, zoneid, wpnum, xpos, ypos, zpos, pause, heading);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error adding waypoint '%s': '%s'", query.c_str(), results.ErrorMessage().c_str());
|
||||
return;
|
||||
}
|
||||
safe_delete_array(query);
|
||||
} /*** END ZoneDatabase::AddWP() ***/
|
||||
|
||||
if(client)
|
||||
client->LogSQL(query.c_str());
|
||||
}
|
||||
|
||||
|
||||
/**********
|
||||
@ -1270,19 +1219,20 @@ void ZoneDatabase::AddWP(Client *c, uint32 gridid, uint32 wpnum, float xpos, flo
|
||||
* wp_num: The number of the waypoint being deleted
|
||||
* zoneid: The ID number of the zone that contains the waypoint being deleted
|
||||
*/
|
||||
|
||||
void ZoneDatabase::DeleteWaypoint(Client *c, uint32 grid_num, uint32 wp_num, uint16 zoneid)
|
||||
void ZoneDatabase::DeleteWaypoint(Client *client, uint32 grid_num, uint32 wp_num, uint16 zoneid)
|
||||
{
|
||||
char *query=0;
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
|
||||
if(!RunQuery(query, MakeAnyLenString(&query,"DELETE FROM grid_entries where gridid=%i and zoneid=%i and `number`=%i",grid_num,zoneid,wp_num), errbuf)) {
|
||||
LogFile->write(EQEMuLog::Error, "Error deleting waypoint '%s': '%s'", query, errbuf);
|
||||
} else {
|
||||
if(c) c->LogSQL(query);
|
||||
std::string query = StringFormat("DELETE FROM grid_entries WHERE "
|
||||
"gridid = %i AND zoneid = %i AND `number` = %i",
|
||||
grid_num, zoneid, wp_num);
|
||||
auto results = QueryDatabase(query);
|
||||
if(!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error deleting waypoint '%s': '%s'", query.c_str(), results.ErrorMessage().c_str());
|
||||
return;
|
||||
}
|
||||
safe_delete_array(query);
|
||||
} /*** END ZoneDatabase::DeleteWaypoint() ***/
|
||||
|
||||
if(client)
|
||||
client->LogSQL(query.c_str());
|
||||
}
|
||||
|
||||
|
||||
/******************
|
||||
@ -1292,139 +1242,112 @@ void ZoneDatabase::DeleteWaypoint(Client *c, uint32 grid_num, uint32 wp_num, uin
|
||||
* Returns 0 if the function didn't have to create a new grid. If the function had to create a new grid for the spawn, then the ID of
|
||||
* the created grid is returned.
|
||||
*/
|
||||
uint32 ZoneDatabase::AddWPForSpawn(Client *client, uint32 spawn2id, float xpos, float ypos, float zpos, uint32 pause, int type1, int type2, uint16 zoneid, float heading) {
|
||||
|
||||
uint32 ZoneDatabase::AddWPForSpawn(Client *c, uint32 spawn2id, float xpos, float ypos, float zpos, uint32 pause, int type1, int type2, uint16 zoneid, float heading) {
|
||||
char *query = 0;
|
||||
uint32 grid_num, // The grid number the spawn is assigned to (if spawn has no grid, will be the grid number we end up creating)
|
||||
next_wp_num; // The waypoint number we should be assigning to the new waypoint
|
||||
bool CreatedNewGrid; // Did we create a new grid in this function?
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
uint32 grid_num; // The grid number the spawn is assigned to (if spawn has no grid, will be the grid number we end up creating)
|
||||
uint32 next_wp_num; // The waypoint number we should be assigning to the new waypoint
|
||||
bool createdNewGrid; // Did we create a new grid in this function?
|
||||
|
||||
// See what grid number our spawn is assigned
|
||||
if(RunQuery(query, MakeAnyLenString(&query,"SELECT pathgrid FROM spawn2 WHERE id=%i",spawn2id),errbuf,&result))
|
||||
{
|
||||
safe_delete_array(query);
|
||||
if(mysql_num_rows(result) > 0)
|
||||
{
|
||||
row = mysql_fetch_row(result);
|
||||
grid_num = atoi(row[0]);
|
||||
}
|
||||
else // This spawn ID was not found in the `spawn2` table
|
||||
return 0;
|
||||
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else { // Query error
|
||||
LogFile->write(EQEMuLog::Error, "Error setting pathgrid '%s': '%s'", query, errbuf);
|
||||
std::string query = StringFormat("SELECT pathgrid FROM spawn2 WHERE id = %i", spawn2id);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
// Query error
|
||||
LogFile->write(EQEMuLog::Error, "Error setting pathgrid '%s': '%s'", query.c_str(), results.ErrorMessage().c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (grid_num == 0) // Our spawn doesn't have a grid assigned to it -- we need to create a new grid and assign it to the spawn
|
||||
{
|
||||
CreatedNewGrid = true;
|
||||
if((grid_num = GetFreeGrid(zoneid)) == 0) // There are no grids for the current zone -- create Grid #1
|
||||
grid_num = 1;
|
||||
if (results.RowCount() == 0)
|
||||
return 0;
|
||||
|
||||
if(!RunQuery(query, MakeAnyLenString(&query,"insert into grid set id='%i',zoneid= %i, type='%i', type2='%i'",grid_num,zoneid,type1,type2), errbuf)) {
|
||||
LogFile->write(EQEMuLog::Error, "Error adding grid '%s': '%s'", query, errbuf);
|
||||
} else {
|
||||
if(c) c->LogSQL(query);
|
||||
}
|
||||
safe_delete_array(query);
|
||||
auto row = results.begin();
|
||||
grid_num = atoi(row[0]);
|
||||
|
||||
query = 0;
|
||||
if(!RunQuery(query, MakeAnyLenString(&query,"update spawn2 set pathgrid='%i' where id='%i'",grid_num,spawn2id), errbuf)) {
|
||||
LogFile->write(EQEMuLog::Error, "Error updating spawn2 pathing '%s': '%s'", query, errbuf);
|
||||
} else {
|
||||
if(c) c->LogSQL(query);
|
||||
}
|
||||
safe_delete_array(query);
|
||||
if (grid_num == 0)
|
||||
{ // Our spawn doesn't have a grid assigned to it -- we need to create a new grid and assign it to the spawn
|
||||
createdNewGrid = true;
|
||||
grid_num = GetFreeGrid(zoneid);
|
||||
if(grid_num == 0) // There are no grids for the current zone -- create Grid #1
|
||||
grid_num = 1;
|
||||
|
||||
query = StringFormat("INSERT INTO grid SET id = '%i', zoneid = %i, type ='%i', type2 = '%i'",
|
||||
grid_num, zoneid, type1, type2);
|
||||
results = QueryDatabase(query);
|
||||
if(!results.Success())
|
||||
LogFile->write(EQEMuLog::Error, "Error adding grid '%s': '%s'", query.c_str(), results.ErrorMessage().c_str());
|
||||
else if(client)
|
||||
client->LogSQL(query.c_str());
|
||||
|
||||
query = StringFormat("UPDATE spawn2 SET pathgrid = '%i' WHERE id = '%i'", grid_num, spawn2id);
|
||||
results = QueryDatabase(query);
|
||||
if(!results.Success())
|
||||
LogFile->write(EQEMuLog::Error, "Error updating spawn2 pathing '%s': '%s'", query.c_str(), results.ErrorMessage().c_str());
|
||||
else if(client)
|
||||
client->LogSQL(query.c_str());
|
||||
}
|
||||
else // NPC had a grid assigned to it
|
||||
CreatedNewGrid = false;
|
||||
|
||||
createdNewGrid = false;
|
||||
|
||||
// Find out what the next waypoint is for this grid
|
||||
query = 0;
|
||||
if(RunQuery(query, MakeAnyLenString(&query,"SELECT max(`number`) FROM grid_entries WHERE zoneid='%i' AND gridid='%i'",zoneid,grid_num),errbuf,&result))
|
||||
{
|
||||
safe_delete_array(query);
|
||||
row = mysql_fetch_row(result);
|
||||
if(row[0] != 0)
|
||||
next_wp_num = atoi(row[0]) + 1;
|
||||
else // No waypoints in this grid yet
|
||||
next_wp_num = 1;
|
||||
query = StringFormat("SELECT max(`number`) FROM grid_entries WHERE zoneid = '%i' AND gridid = '%i'", zoneid, grid_num);
|
||||
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else { // Query error
|
||||
LogFile->write(EQEMuLog::Error, "Error getting next waypoint id '%s': '%s'", query, errbuf);
|
||||
if(!results.Success()) { // Query error
|
||||
LogFile->write(EQEMuLog::Error, "Error getting next waypoint id '%s': '%s'", query.c_str(), results.ErrorMessage().c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
query = 0;
|
||||
if(!RunQuery(query, MakeAnyLenString(&query,"INSERT INTO grid_entries(gridid,zoneid,`number`,x,y,z,pause,heading) VALUES (%i,%i,%i,%f,%f,%f,%i,%f)",grid_num,zoneid,next_wp_num,xpos,ypos,zpos,pause,heading), errbuf)) {
|
||||
LogFile->write(EQEMuLog::Error, "Error adding grid entry '%s': '%s'", query, errbuf);
|
||||
} else {
|
||||
if(c) c->LogSQL(query);
|
||||
}
|
||||
safe_delete_array(query);
|
||||
row = results.begin();
|
||||
if(row[0] != 0)
|
||||
next_wp_num = atoi(row[0]) + 1;
|
||||
else // No waypoints in this grid yet
|
||||
next_wp_num = 1;
|
||||
|
||||
if(CreatedNewGrid)
|
||||
return grid_num;
|
||||
|
||||
return 0;
|
||||
} /*** END ZoneDatabase::AddWPForSpawn() ***/
|
||||
query = StringFormat("INSERT INTO grid_entries(gridid, zoneid, `number`, x, y, z, pause, heading) "
|
||||
"VALUES (%i, %i, %i, %f, %f, %f, %i, %f)",
|
||||
grid_num, zoneid, next_wp_num, xpos, ypos, zpos, pause, heading);
|
||||
results = QueryDatabase(query);
|
||||
if(!results.Success())
|
||||
LogFile->write(EQEMuLog::Error, "Error adding grid entry '%s': '%s'", query.c_str(), results.ErrorMessage().c_str());
|
||||
else if(client)
|
||||
client->LogSQL(query.c_str());
|
||||
|
||||
return createdNewGrid? grid_num: 0;
|
||||
}
|
||||
|
||||
uint32 ZoneDatabase::GetFreeGrid(uint16 zoneid) {
|
||||
char *query = 0;
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
if (RunQuery(query, MakeAnyLenString(&query,"SELECT max(id) from grid where zoneid = %i",zoneid),errbuf,&result)) {
|
||||
safe_delete_array(query);
|
||||
if (mysql_num_rows(result) == 1) {
|
||||
row = mysql_fetch_row(result);
|
||||
uint32 tmp=0;
|
||||
if (row[0])
|
||||
tmp = atoi(row[0]);
|
||||
mysql_free_result(result);
|
||||
tmp++;
|
||||
return tmp;
|
||||
}
|
||||
mysql_free_result(result);
|
||||
|
||||
std::string query = StringFormat("SELECT max(id) FROM grid WHERE zoneid = %i", zoneid);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in GetFreeGrid query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
LogFile->write(EQEMuLog::Error, "Error in GetFreeGrid query '%s': %s", query, errbuf);
|
||||
safe_delete_array(query);
|
||||
}
|
||||
return 0;
|
||||
|
||||
if (results.RowCount() != 1)
|
||||
return 0;
|
||||
|
||||
auto row = results.begin();
|
||||
uint32 freeGridID = 1;
|
||||
freeGridID = atoi(row[0]) + 1;
|
||||
|
||||
return freeGridID;
|
||||
}
|
||||
|
||||
int ZoneDatabase::GetHighestWaypoint(uint32 zoneid, uint32 gridid) {
|
||||
char *query = 0;
|
||||
char errbuff[MYSQL_ERRMSG_SIZE];
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
int res = 0;
|
||||
if (RunQuery(query, MakeAnyLenString(&query,
|
||||
"SELECT COALESCE(MAX(number), 0) FROM grid_entries WHERE zoneid = %i AND gridid = %i",
|
||||
zoneid, gridid),errbuff,&result)) {
|
||||
safe_delete_array(query);
|
||||
if (mysql_num_rows(result) == 1) {
|
||||
row = mysql_fetch_row(result);
|
||||
res = atoi( row[0] );
|
||||
}
|
||||
mysql_free_result(result);
|
||||
} else {
|
||||
LogFile->write(EQEMuLog::Error, "Error in GetHighestWaypoint query '%s': %s", query, errbuff);
|
||||
safe_delete_array(query);
|
||||
|
||||
std::string query = StringFormat("SELECT COALESCE(MAX(number), 0) FROM grid_entries "
|
||||
"WHERE zoneid = %i AND gridid = %i", zoneid, gridid);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in GetHighestWaypoint query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
return(res);
|
||||
if (results.RowCount() != 1)
|
||||
return 0;
|
||||
|
||||
auto row = results.begin();
|
||||
return atoi(row[0]);
|
||||
}
|
||||
|
||||
void NPC::SaveGuardSpotCharm()
|
||||
|
||||
@ -1691,45 +1691,41 @@ ZonePoint* Zone::GetClosestZonePointWithoutZone(float x, float y, float z, Clien
|
||||
|
||||
bool ZoneDatabase::LoadStaticZonePoints(LinkedList<ZonePoint*>* zone_point_list, const char* zonename, uint32 version)
|
||||
{
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
|
||||
zone_point_list->Clear();
|
||||
zone->numzonepoints = 0;
|
||||
MakeAnyLenString(&query, "SELECT x, y, z, target_x, target_y, "
|
||||
"target_z, target_zone_id, heading, target_heading, number, "
|
||||
"target_instance, client_version_mask FROM zone_points "
|
||||
"WHERE zone='%s' AND (version=%i OR version=-1) order by number", zonename, version);
|
||||
if (RunQuery(query, strlen(query), errbuf, &result))
|
||||
{
|
||||
safe_delete_array(query);
|
||||
while((row = mysql_fetch_row(result)))
|
||||
{
|
||||
ZonePoint* zp = new ZonePoint;
|
||||
zp->x = atof(row[0]);
|
||||
zp->y = atof(row[1]);
|
||||
zp->z = atof(row[2]);
|
||||
zp->target_x = atof(row[3]);
|
||||
zp->target_y = atof(row[4]);
|
||||
zp->target_z = atof(row[5]);
|
||||
zp->target_zone_id = atoi(row[6]);
|
||||
zp->heading = atof(row[7]);
|
||||
zp->target_heading = atof(row[8]);
|
||||
zp->number = atoi(row[9]);
|
||||
zp->target_zone_instance = atoi(row[10]);
|
||||
zp->client_version_mask = (uint32)strtoul(row[11], nullptr, 0);
|
||||
zone_point_list->Insert(zp);
|
||||
zone->numzonepoints++;
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Error1 in LoadStaticZonePoints query '" << query << "' " << errbuf << std::endl;
|
||||
safe_delete_array(query);
|
||||
std::string query = StringFormat("SELECT x, y, z, target_x, target_y, "
|
||||
"target_z, target_zone_id, heading, target_heading, "
|
||||
"number, target_instance, client_version_mask "
|
||||
"FROM zone_points WHERE zone='%s' AND (version=%i OR version=-1) "
|
||||
"ORDER BY number", zonename, version);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
std::cerr << "Error1 in LoadStaticZonePoints query '" << query << "' " << results.ErrorMessage() << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
ZonePoint* zp = new ZonePoint;
|
||||
|
||||
zp->x = atof(row[0]);
|
||||
zp->y = atof(row[1]);
|
||||
zp->z = atof(row[2]);
|
||||
zp->target_x = atof(row[3]);
|
||||
zp->target_y = atof(row[4]);
|
||||
zp->target_z = atof(row[5]);
|
||||
zp->target_zone_id = atoi(row[6]);
|
||||
zp->heading = atof(row[7]);
|
||||
zp->target_heading = atof(row[8]);
|
||||
zp->number = atoi(row[9]);
|
||||
zp->target_zone_instance = atoi(row[10]);
|
||||
zp->client_version_mask = (uint32)strtoul(row[11], nullptr, 0);
|
||||
|
||||
zone_point_list->Insert(zp);
|
||||
|
||||
zone->numzonepoints++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user