From ca430e24942aa3d82837be7b604ecabf85976f01 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sun, 31 Aug 2014 17:52:43 -0500 Subject: [PATCH] Fix void Database::GetCharName(uint32 char_id, char* name) Increased MAX_PP_SPELLBOOK to 720 for UF/RoF Increased MAX_PP_MEMSPELL to 12 Implemented up to 12 spell slots Fix for public_note default value in bool BaseGuildManager::DBSetGuild(uint32 charid, uint32 guild_id, uint8 rank) Updated all CastSpell entries to use the appropriate slot type defines located now in zone/common.h Fixed Guild Loading from character_data Fixed #guild list Refactored Merchantlist loading Refactored Temp Merchantlist loading Gutted most of dbasync Added: LoadCharacterSpellBook(uint32 character_id, PlayerProfile_Struct* pp); LoadCharacterMemmedSpells(uint32 character_id, PlayerProfile_Struct* pp); LoadCharacterLanguages(uint32 character_id, PlayerProfile_Struct* pp); LoadCharacterBindPoint(uint32 character_id, PlayerProfile_Struct* pp); SaveCharacterSpellSwap(uint32 character_id, uint32 spell_id, uint32 from_slot, uint32 to_slot); SaveCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id); SaveCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id); DeleteCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id); DeleteCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id); Removed Zone::LoadTempMerchantData_result(MYSQL_RES* result) Removed Zone::LoadMerchantData_result(MYSQL_RES* result) Removed SharedDatabase::GetPlayerProfile Removed SharedDatabase::SetPlayerProfile Removed SharedDatabase::SetPlayerProfile_MQ Removed Zone::DBAWComplete(uint8 workpt_b1, DBAsyncWork* dbaw) from zone.cpp --- common/database.cpp | 23 +-- common/eq_packet_structs.h | 4 +- common/guild_base.cpp | 2 +- common/patches/underfoot.cpp | 3 +- common/patches/underfoot_structs.h | 3 +- common/shareddb.cpp | 100 ------------ common/shareddb.h | 3 - world/worlddb.cpp | 5 +- zone/aa.cpp | 7 +- zone/bot.h | 4 +- zone/client.cpp | 52 +++--- zone/client.h | 7 +- zone/client_packet.cpp | 254 ++++++++++++++--------------- zone/command.cpp | 6 +- zone/common.h | 4 + zone/mob.h | 2 +- zone/spells.cpp | 8 +- zone/zone.cpp | 164 ++++++------------- zone/zone.h | 3 - zone/zonedb.cpp | 250 ++++++++++++++++++---------- zone/zonedb.h | 16 +- zone/zonedbasync.cpp | 24 --- 22 files changed, 423 insertions(+), 521 deletions(-) diff --git a/common/database.cpp b/common/database.cpp index 429da0e42..fcfab3c52 100644 --- a/common/database.cpp +++ b/common/database.cpp @@ -758,17 +758,18 @@ void Database::GetAccountName(uint32 accountid, char* name, uint32* oLSAccountID void Database::GetCharName(uint32 char_id, char* name) { - std::string query = StringFormat("SELECT name FROM character_ WHERE id='%i'", char_id); + std::string query = StringFormat("SELECT `name` FROM `character_data` WHERE id='%i'", char_id); auto results = QueryDatabase(query); - if (!results.Success()) - { + if (!results.Success()) { std::cerr << "Error in GetCharName query '" << query << "' " << results.ErrorMessage() << std::endl; - return; + return; } auto row = results.begin(); - strcpy(name, row[0]); + for (auto row = results.begin(); row != results.end(); ++row) { + strcpy(name, row[0]); + } } static inline void loadbar(unsigned int x, unsigned int n, unsigned int w = 50) { @@ -849,7 +850,7 @@ bool Database::CheckDatabaseConversions() { " `level2` tinyint(11) UNSIGNED NOT NULL DEFAULT 0, " " `anon` tinyint(11) UNSIGNED NOT NULL DEFAULT 0, " " `gm` tinyint(11) UNSIGNED NOT NULL DEFAULT 0, " - " `intoxication` int(11) UNSIGNED NOT NULL, " + " `intoxication` int(11) UNSIGNED NOT NULL DEFAULT 0, " " `hair_color` tinyint(11) UNSIGNED NOT NULL DEFAULT 0, " " `beard_color` tinyint(11) UNSIGNED NOT NULL DEFAULT 0, " " `eye_color_1` tinyint(11) UNSIGNED NOT NULL DEFAULT 0, " @@ -885,9 +886,9 @@ bool Database::CheckDatabaseConversions() { " `drakkin_heritage` int(11) UNSIGNED NOT NULL DEFAULT 0, " " `drakkin_tattoo` int(11) UNSIGNED NOT NULL DEFAULT 0, " " `drakkin_details` int(11) UNSIGNED NOT NULL DEFAULT 0, " - " `toxicity` int(11) UNSIGNED NOT NULL DEFAULT 0, " - " `hunger_level` int(11) UNSIGNED NOT NULL DEFAULT 0, " - " `thirst_level` int(11) UNSIGNED NOT NULL DEFAULT 0, " + " `toxicity` int(11) NOT NULL DEFAULT 0, " + " `hunger_level` int(11) NOT NULL DEFAULT 0, " + " `thirst_level` int(11) NOT NULL DEFAULT 0, " " `ability_up` int(11) UNSIGNED NOT NULL DEFAULT 0, " " `zone_id` int(11) UNSIGNED NOT NULL DEFAULT 0, " " `zone_instance` int(11) UNSIGNED NOT NULL DEFAULT 0, " @@ -1092,7 +1093,7 @@ bool Database::CheckDatabaseConversions() { // querylen = MakeAnyLenString(&query, "SELECT `id` FROM `character_` WHERE `id` = 61238"); int char_iter_count = 0; - querylen = MakeAnyLenString(&query, "SELECT `id` FROM `character_` WHERE `id` >= 61238 LIMIT 1"); + querylen = MakeAnyLenString(&query, "SELECT `id` FROM `character_` WHERE `id` >= 61238 LIMIT 100"); if (RunQuery(query, querylen, errbuf, &result)) { safe_delete_array(query); while (row = mysql_fetch_row(result)) { @@ -1147,6 +1148,8 @@ bool Database::CheckDatabaseConversions() { ); auto results = QueryDatabase(rquery); + if (pp->tribute_time_remaining < 0 || pp->tribute_time_remaining == 4294967295){ pp->tribute_time_remaining = 0; } + /* Run Character Data Convert */ rquery = StringFormat( "REPLACE INTO `character_data` (" diff --git a/common/eq_packet_structs.h b/common/eq_packet_structs.h index d2fbcbb76..d6ffd119b 100644 --- a/common/eq_packet_structs.h +++ b/common/eq_packet_structs.h @@ -801,8 +801,8 @@ struct SuspendedMinion_Struct ** OpCode: 0x006a */ static const uint32 MAX_PP_LANGUAGE = 28; -static const uint32 MAX_PP_SPELLBOOK = 480; // Increased to 480 to support SoF -static const uint32 MAX_PP_MEMSPELL = 9; +static const uint32 MAX_PP_SPELLBOOK = 720; // Increased to 480 to support SoF +static const uint32 MAX_PP_MEMSPELL = 12; static const uint32 MAX_PP_SKILL = _SkillPacketArraySize; // 100 - actual skills buffer size static const uint32 MAX_PP_AA_ARRAY = 240; static const uint32 MAX_GROUP_MEMBERS = 6; diff --git a/common/guild_base.cpp b/common/guild_base.cpp index 8f6144270..99e54934e 100644 --- a/common/guild_base.cpp +++ b/common/guild_base.cpp @@ -751,7 +751,7 @@ bool BaseGuildManager::DBSetGuild(uint32 charid, uint32 guild_id, uint8 rank) { std::string query; if(guild_id != GUILD_NONE) { - query = StringFormat("REPLACE INTO guild_members (char_id,guild_id,rank) VALUES(%d,%d,%d)", charid, guild_id, rank); + query = StringFormat("REPLACE INTO guild_members (char_id,guild_id,rank,public_note) VALUES(%d,%d,%d,'')", charid, guild_id, rank); auto results = m_db->QueryDatabase(query); if (!results.Success()) { diff --git a/common/patches/underfoot.cpp b/common/patches/underfoot.cpp index bdac3c72b..1eab127d5 100644 --- a/common/patches/underfoot.cpp +++ b/common/patches/underfoot.cpp @@ -479,7 +479,6 @@ ENCODE(OP_PlayerProfile) { uint32 r; eq->available_slots=0xffffffff; - memset(eq->unknown06284, 0xff, sizeof(eq->unknown06284)); memset(eq->unknown07284, 0xff, sizeof(eq->unknown07284)); // OUT(checksum); @@ -546,7 +545,7 @@ ENCODE(OP_PlayerProfile) { OUT(gold); OUT(silver); OUT(copper); - OUT(platinum_cursor); + OUT(platinum_cursor); OUT(gold_cursor); OUT(silver_cursor); OUT(copper_cursor); diff --git a/common/patches/underfoot_structs.h b/common/patches/underfoot_structs.h index ee7286dab..860fdd34a 100644 --- a/common/patches/underfoot_structs.h +++ b/common/patches/underfoot_structs.h @@ -766,7 +766,7 @@ struct BindStruct { ** OpCode: 0x006a */ static const uint32 MAX_PP_LANGUAGE = 25; // -static const uint32 MAX_PP_SPELLBOOK = 480; // Confirmed 60 pages on Underfoot now +static const uint32 MAX_PP_SPELLBOOK = 720; // Confirmed 60 pages on Underfoot now static const uint32 MAX_PP_MEMSPELL = 10; //was 9 now 10 on Underfoot static const uint32 MAX_PP_SKILL = _SkillPacketArraySize; // 100 - actual skills buffer size static const uint32 MAX_PP_AA_ARRAY = 300; //was 299 @@ -879,7 +879,6 @@ struct PlayerProfile_Struct /*04216*/ uint8 face; // Player face - Actually uint32? /*04217*/ uint8 unknown04217[147]; // was [175] /*04364*/ uint32 spell_book[MAX_PP_SPELLBOOK]; // List of the Spells in spellbook 720 = 90 pages [2880] was [1920] -/*06284*/ uint8 unknown06284[960]; // Spacer for the end of the book for now (pages 60 to 90) /*07244*/ uint32 mem_spells[MAX_PP_MEMSPELL]; // List of spells memorized /*07284*/ uint8 unknown07284[28]; //#### uint8 unknown04396[32]; in Titanium ####[28] /*07312*/ uint32 platinum; // Platinum Pieces on player diff --git a/common/shareddb.cpp b/common/shareddb.cpp index c10e87856..e4336b02f 100644 --- a/common/shareddb.cpp +++ b/common/shareddb.cpp @@ -1209,106 +1209,6 @@ bool SharedDatabase::LoadNPCFactionLists() { return true; } -// Get the player profile and inventory for the given account "account_id" and -// character name "name". Return true if the character was found, otherwise false. -// False will also be returned if there is a database error. -bool SharedDatabase::GetPlayerProfile(uint32 account_id, char* name, PlayerProfile_Struct* pp, Inventory* inv, ExtendedProfile_Struct *ext, char* current_zone, uint32 *current_instance) { - char errbuf[MYSQL_ERRMSG_SIZE]; - char* query = 0; - MYSQL_RES* result; - MYSQL_ROW row; - bool ret = false; - - unsigned long* lengths; - - if (RunQuery(query, MakeAnyLenString(&query, "SELECT profile,zonename,x,y,z,extprofile,instanceid FROM character_ WHERE account_id=%i AND name='%s'", account_id, name), errbuf, &result)) { - if (mysql_num_rows(result) == 1) { - row = mysql_fetch_row(result); - lengths = mysql_fetch_lengths(result); - if (lengths[0] == sizeof(PlayerProfile_Struct)) { - memcpy(pp, row[0], sizeof(PlayerProfile_Struct)); - - if (current_zone) - strcpy(current_zone, row[1]); - pp->zone_id = GetZoneID(row[1]); - pp->x = atof(row[2]); - pp->y = atof(row[3]); - pp->z = atof(row[4]); - pp->zoneInstance = atoi(row[6]); - if (pp->x == -1 && pp->y == -1 && pp->z == -1) - GetSafePoints(pp->zone_id, GetInstanceVersion(pp->zoneInstance), &pp->x, &pp->y, &pp->z); - - if(current_instance) - *current_instance = pp->zoneInstance; - - if(ext) { - //SetExtendedProfile handles any conversion - SetExtendedProfile(ext, row[5], lengths[5]); - } - - // Retrieve character inventory - ret = GetInventory(account_id, name, inv); - } - else { - LogFile->write(EQEMuLog::Error, "Player profile length mismatch in GetPlayerProfile. Found: %i, Expected: %i", - lengths[0], sizeof(PlayerProfile_Struct)); - } - } - - mysql_free_result(result); - } - else { - LogFile->write(EQEMuLog::Error, "GetPlayerProfile query '%s' %s", query, errbuf); - } - - safe_delete_array(query); - return ret; -} - -bool SharedDatabase::SetPlayerProfile(uint32 account_id, uint32 charid, PlayerProfile_Struct* pp, Inventory* inv, ExtendedProfile_Struct *ext, uint32 current_zone, uint32 current_instance, uint8 MaxXTargets) { - char errbuf[MYSQL_ERRMSG_SIZE]; - char* query = 0; - uint32 affected_rows = 0; - bool ret = false; - - clock_t t = std::clock(); /* Function timer start */ - if (RunQuery(query, SetPlayerProfile_MQ(&query, account_id, charid, pp, inv, ext, current_zone, current_instance, MaxXTargets), errbuf, 0, &affected_rows)) { - ret = (affected_rows != 0); - } - LogFile->write(EQEMuLog::Status, "SharedDatabase::SetPlayerProfile SetPlayerProfile_MQ done... Took %f seconds", ((float)(std::clock() - t)) / CLOCKS_PER_SEC); - - if (!ret) { - LogFile->write(EQEMuLog::Error, "SetPlayerProfile query '%s' %s", query, errbuf); - } - - safe_delete_array(query); - return ret; -} - -// Generate SQL for updating player profile -uint32 SharedDatabase::SetPlayerProfile_MQ(char** query, uint32 account_id, uint32 charid, PlayerProfile_Struct* pp, Inventory* inv, ExtendedProfile_Struct *ext, uint32 current_zone, uint32 current_instance, uint8 MaxXTargets) { - *query = new char[396 + sizeof(PlayerProfile_Struct)*2 + sizeof(ExtendedProfile_Struct)*2 + 4]; - char* end = *query; - if (!current_zone) - current_zone = pp->zone_id; - - if (!current_instance) - current_instance = pp->zoneInstance; - - if(strlen(pp->name) == 0) /* Sanity check in case pp never loaded */ - return false; - - end += sprintf(end, "UPDATE character_ SET timelaston=unix_timestamp(now()),name=\'%s\', zonename=\'%s\', zoneid=%u, instanceid=%u, x = %f, y = %f, z = %f, profile=\'", pp->name, GetZoneName(current_zone), current_zone, current_instance, pp->x, pp->y, pp->z); - end += DoEscapeString(end, (char*)pp, sizeof(PlayerProfile_Struct)); - end += sprintf(end,"\', extprofile=\'"); - end += DoEscapeString(end, (char*)ext, sizeof(ExtendedProfile_Struct)); - end += sprintf(end,"\',class=%d,level=%d,xtargets=%u WHERE id=%u", pp->class_, pp->level, MaxXTargets, charid); - - return (uint32) (end - (*query)); -} - - - // Create appropriate ItemInst class ItemInst* SharedDatabase::CreateItem(uint32 item_id, int16 charges, uint32 aug1, uint32 aug2, uint32 aug3, uint32 aug4, uint32 aug5) { diff --git a/common/shareddb.h b/common/shareddb.h index 0fd72426c..5401bfa0a 100644 --- a/common/shareddb.h +++ b/common/shareddb.h @@ -40,9 +40,6 @@ public: bool SetGMSpeed(uint32 account_id, uint8 gmspeed); uint8 GetGMSpeed(uint32 account_id); bool SetHideMe(uint32 account_id, uint8 hideme); - bool GetPlayerProfile(uint32 account_id, char* name, PlayerProfile_Struct* pp, Inventory* inv, ExtendedProfile_Struct *ext, char* current_zone = 0, uint32 *current_instance = 0); - bool SetPlayerProfile(uint32 account_id, uint32 charid, PlayerProfile_Struct* pp, Inventory* inv, ExtendedProfile_Struct *ext, uint32 current_zone, uint32 current_instance, uint8 MaxXTargets); - uint32 SetPlayerProfile_MQ(char** query, uint32 account_id, uint32 charid, PlayerProfile_Struct* pp, Inventory* inv, ExtendedProfile_Struct *ext, uint32 current_zone, uint32 current_instance, uint8 MaxXTargets); int32 DeleteStalePlayerCorpses(); int32 DeleteStalePlayerBackups(); void GetPlayerInspectMessage(char* playername, InspectMessage_Struct* message); diff --git a/world/worlddb.cpp b/world/worlddb.cpp index 7a07c6f6f..02dfa4290 100644 --- a/world/worlddb.cpp +++ b/world/worlddb.cpp @@ -41,11 +41,12 @@ void WorldDatabase::GetCharSelectInfo(uint32 account_id, CharacterSelect_Struct* MYSQL_ROW row; Inventory *inv; + /* Initialize Variables */ for (int i=0; i<10; i++) { strcpy(cs->name[i], ""); cs->zone[i] = 0; cs->level[i] = 0; - cs->tutorial[i] = 0; + cs->tutorial[i] = 0; cs->gohome[i] = 0; } @@ -165,7 +166,7 @@ void WorldDatabase::GetCharSelectInfo(uint32 account_id, CharacterSelect_Struct* if(result2) { row2 = mysql_fetch_row(result2); ExtendedProfile_Struct* ext = (ExtendedProfile_Struct*)row2[0]; - SetPlayerProfile(account_id,char_id,pp,inv,ext, 0, 0, 5); + // SetPlayerProfile(account_id,char_id,pp,inv,ext, 0, 0, 5); } mysql_free_result(result2); } diff --git a/zone/aa.cpp b/zone/aa.cpp index 390174cf5..2af81a619 100644 --- a/zone/aa.cpp +++ b/zone/aa.cpp @@ -300,7 +300,7 @@ void Client::ActivateAA(aaID activate){ return; } } else { - if(!CastSpell(caa->spell_id, target_id, 10, -1, -1, 0, -1, AATimerID + pTimerAAStart, timer_base, 1)) { + if (!CastSpell(caa->spell_id, target_id, USE_ITEM_SPELL_SLOT, -1, -1, 0, -1, AATimerID + pTimerAAStart, timer_base, 1)) { //Reset on failed cast SendAATimer(AATimerID, 0, 0xFFFFFF); Message_StringID(15,ABILITY_FAILED); @@ -525,7 +525,7 @@ void Client::HandleAAAction(aaID activate) { //cast the spell, if we have one if(IsValidSpell(spell_id)) { int aatid = GetAATimerID(activate); - if(!CastSpell(spell_id, target_id , 10, -1, -1, 0, -1, pTimerAAStart + aatid , CalcAAReuseTimer(caa), 1)) { + if (!CastSpell(spell_id, target_id, USE_ITEM_SPELL_SLOT, -1, -1, 0, -1, pTimerAAStart + aatid, CalcAAReuseTimer(caa), 1)) { SendAATimer(aatid, 0, 0xFFFFFF); Message_StringID(15,ABILITY_FAILED); p_timers.Clear(&database, pTimerAAStart + aatid); @@ -1822,8 +1822,7 @@ void ZoneDatabase::LoadAAs(SendAA_Struct **load){ } AALevelCost_Struct aalcs; - for (auto row = results.begin(); row != results.end(); ++row) - { + for (auto row = results.begin(); row != results.end(); ++row) { aalcs.Level = atoi(row[1]); aalcs.Cost = atoi(row[2]); AARequiredLevelAndCost[atoi(row[0])] = aalcs; diff --git a/zone/bot.h b/zone/bot.h index 9c1ec9cb2..7601dd00c 100644 --- a/zone/bot.h +++ b/zone/bot.h @@ -311,11 +311,11 @@ public: virtual float GetAOERange(uint16 spell_id); virtual bool SpellEffect(Mob* caster, uint16 spell_id, float partial = 100); virtual void DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caster_level, Mob* caster = 0); - virtual bool CastSpell(uint16 spell_id, uint16 target_id, uint16 slot = 10, int32 casttime = -1, int32 mana_cost = -1, uint32* oSpellWillFinish = 0, uint32 item_slot = 0xFFFFFFFF, int16 *resist_adjust = nullptr); + virtual bool CastSpell(uint16 spell_id, uint16 target_id, uint16 slot = USE_ITEM_SPELL_SLOT, int32 casttime = -1, int32 mana_cost = -1, uint32* oSpellWillFinish = 0, uint32 item_slot = 0xFFFFFFFF, int16 *resist_adjust = nullptr); virtual bool SpellOnTarget(uint16 spell_id, Mob* spelltar); virtual bool IsImmuneToSpell(uint16 spell_id, Mob *caster); virtual bool DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_center, CastAction_type &CastAction); - virtual bool DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot = 10, int32 casttime = -1, int32 mana_cost = -1, uint32* oSpellWillFinish = 0, uint32 item_slot = 0xFFFFFFFF); + virtual bool DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot = USE_ITEM_SPELL_SLOT, int32 casttime = -1, int32 mana_cost = -1, uint32* oSpellWillFinish = 0, uint32 item_slot = 0xFFFFFFFF); // Bot Action Command Methods bool MesmerizeTarget(Mob* target); diff --git a/zone/client.cpp b/zone/client.cpp index 0065d31c5..975e61dc1 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -545,7 +545,7 @@ bool Client::Save(uint8 iCommitNow) { database.SaveCharacterCurrency(this->CharacterID(), &m_pp); /* Save Character AA */ - SaveAA(); + // SaveAA(); /* Save Character Buffs */ database.SaveBuffs(this); @@ -591,31 +591,31 @@ bool Client::Save(uint8 iCommitNow) { /* Save Character Data */ database.SaveCharacterData(this->CharacterID(), this->AccountID(), &m_pp); - if (iCommitNow <= 1) { - char* query = 0; - uint32_breakdown workpt; - workpt.b4() = DBA_b4_Entity; - workpt.w2_3() = GetID(); - workpt.b1() = DBA_b1_Entity_Client_Save; - DBAsyncWork* dbaw = new DBAsyncWork(&database, &MTdbafq, workpt, DBAsync::Write, 0xFFFFFFFF); - dbaw->AddQuery(iCommitNow == 0 ? true : false, &query, database.SetPlayerProfile_MQ(&query, account_id, character_id, &m_pp, &m_inv, &m_epp, 0, 0, MaxXTargets), false); - if (iCommitNow == 0){ - pQueuedSaveWorkID = dbasync->AddWork(&dbaw, 2500); - } - else { - dbasync->AddWork(&dbaw, 0); - SaveBackup(); - } - safe_delete_array(query); - return true; - } - else if (database.SetPlayerProfile(account_id, character_id, &m_pp, &m_inv, &m_epp, 0, 0, MaxXTargets)) { - SaveBackup(); - } - else { - std::cerr << "Failed to update player profile" << std::endl; - return false; - } + // if (iCommitNow <= 1) { + // char* query = 0; + // uint32_breakdown workpt; + // workpt.b4() = DBA_b4_Entity; + // workpt.w2_3() = GetID(); + // workpt.b1() = DBA_b1_Entity_Client_Save; + // DBAsyncWork* dbaw = new DBAsyncWork(&database, &MTdbafq, workpt, DBAsync::Write, 0xFFFFFFFF); + // dbaw->AddQuery(iCommitNow == 0 ? true : false, &query, database.SetPlayerProfile_MQ(&query, account_id, character_id, &m_pp, &m_inv, &m_epp, 0, 0, MaxXTargets), false); + // if (iCommitNow == 0){ + // pQueuedSaveWorkID = dbasync->AddWork(&dbaw, 2500); + // } + // else { + // dbasync->AddWork(&dbaw, 0); + // SaveBackup(); + // } + // safe_delete_array(query); + // return true; + // } + // else if (database.SetPlayerProfile(account_id, character_id, &m_pp, &m_inv, &m_epp, 0, 0, MaxXTargets)) { + // SaveBackup(); + // } + // else { + // std::cerr << "Failed to update player profile" << std::endl; + // return false; + // } /* Mirror Character Data */ database.StoreCharacterLookup(this->CharacterID()); diff --git a/zone/client.h b/zone/client.h index a490d73c4..bab48e8ea 100644 --- a/zone/client.h +++ b/zone/client.h @@ -37,6 +37,7 @@ class Client; #include "../common/item_struct.h" #include "../common/clientversions.h" +#include "common.h" #include "zonedb.h" #include "errno.h" #include "mob.h" @@ -102,11 +103,6 @@ enum { //scribing argument to MemorizeSpell memSpellSpellbar = 3 }; -#define USE_ITEM_SPELL_SLOT 10 -#define POTION_BELT_SPELL_SLOT 11 -#define DISCIPLINE_SPELL_SLOT 10 -#define ABILITY_SPELL_SLOT 9 - //Modes for the zoning state of the client. typedef enum { ZoneToSafeCoords, // Always send ZonePlayerToBind_Struct to client: Succor/Evac @@ -239,7 +235,6 @@ public: void KeyRingList(); virtual bool IsClient() const { return true; } virtual void DBAWComplete(uint8 workpt_b1, DBAsyncWork* dbaw); - bool FinishConnState2(DBAsyncWork* dbaw); void CompleteConnect(); bool TryStacking(ItemInst* item, uint8 type = ItemPacketTrade, bool try_worn = true, bool try_cursor = true); void SendTraderPacket(Client* trader, uint32 Unknown72 = 51); diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 9b2af6c45..9921298fe 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -506,19 +506,18 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) if(strlen(cze->char_name) > 63) return; - conn_state = ReceivedZoneEntry; - + conn_state = ReceivedZoneEntry; ClientVersion = Connection()->ClientVersion(); ClientVersionBit = 1 << (ClientVersion - 1); - // Antighost code - // tmp var is so the search doesnt find this object + /* Antighost code + tmp var is so the search doesnt find this object + */ Client* client = entity_list.GetClientByName(cze->char_name); if (!zone->GetAuth(ip, cze->char_name, &WID, &account_id, &character_id, &admin, lskey, &tellsoff)) { LogFile->write(EQEMuLog::Error, "GetAuth() returned false kicking client"); - if (client != 0) - { + if (client != 0) { client->Save(); client->Kick(); } @@ -527,7 +526,9 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) return; } + strcpy(name, cze->char_name); + /* Check for Client Spoofing */ if (client != 0) { struct in_addr ghost_addr; ghost_addr.s_addr = eqs->GetRemoteIP(); @@ -554,8 +555,10 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) uint32 cid = CharacterID(); character_id = cid; + /* Flush and reload factions */ database.RemoveTempFactions(this); database.LoadCharacterFactionValues(cid, factionvalues); + /* Load Character Account Data: Temp until I move */ query = StringFormat("SELECT `status`, `name`, `lsaccount_id`, `gmspeed`, `revoked`, `hideme` FROM `account` WHERE `id` = %i", this->AccountID()); auto results = database.QueryDatabase(query); @@ -565,74 +568,75 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) if (lsaccountid && atoi(row[2]) > 0){ lsaccountid = atoi(row[2]); } else{ lsaccountid = 0; } if (gmspeed){ gmspeed = atoi(row[3]); } - if (revoked){ revoked = atoi(row[4]); } + if (revoked){ revoked = atoi(row[4]); } if (gmhideme){ gmhideme = atoi(row[5]); } if (account_creation){ account_creation = atoul(row[6]); } } + /* Load Character Legacy Data: Temp until I move */ - query = StringFormat("id,profile,zonename,x,y,z,guild_id,rank,extprofile,class,level,lfp,lfg,instanceid,xtargets,firstlogon FROM character_ LEFT JOIN guild_members ON id=char_id WHERE id=%i", cid); + query = StringFormat("SELECT id,profile,zonename,x,y,z,guild_id,rank,extprofile,class,level,lfp,lfg,instanceid,xtargets,firstlogon FROM character_ LEFT JOIN guild_members ON id=char_id WHERE id=%i", cid); results = database.QueryDatabase(query); for (auto row = results.begin(); row != results.end(); ++row) { m_pp.lastlogin = time(nullptr); - + if (row[6]){ + guild_id = atoi(row[6]); + if (guildrank) { + if (row[7] != nullptr){ guildrank = atoi(row[7]); } + else{ guildrank = GUILD_RANK_NONE; } + } + } if (RuleB(Character, SharedBankPlat)) m_pp.platinum_shared = database.GetSharedPlatinum(database.GetAccountIDByChar(cid)); - if (guildrank) { - if (row[7] != nullptr) - guildrank = atoi(row[7]); - else - guildrank = GUILD_RANK_NONE; - } // if (ext) { SetExtendedProfile(ext, row[8], lengths[8]); } if (level){ level = atoi(row[10]); } if (LFP){ LFP = atoi(row[11]); } if (LFG){ LFG = atoi(row[12]); } if (firstlogon){ firstlogon = atoi(row[15]); } } - /* Load Character Inventory */ - loaditems = database.GetInventory(cid, &m_inv); - /* Load Character Currency into PP */ - database.LoadCharacterCurrency(cid, &m_pp); - /* Load Character Data from DB into PP */ - database.LoadCharacterData(cid, &m_pp); - /* Move to another method when can, this is pointless... */ - database.GetPlayerInspectMessage(m_pp.name, &m_inspect_message); - /* Load Character Currency */ - database.LoadCharacterCurrency(cid, &m_pp); - /* Load Character Skills */ - database.LoadCharacterSkills(cid, &m_pp); - /* Load Character Disciplines */ - database.LoadCharacterDisciplines(cid, &m_pp); + + loaditems = database.GetInventory(cid, &m_inv); /* Load Character Inventory */ + database.LoadCharacterBindPoint(cid, &m_pp); /* Load Character Bind */ + database.LoadCharacterCurrency(cid, &m_pp); /* Load Character Currency into PP */ + database.LoadCharacterData(cid, &m_pp); /* Load Character Data from DB into PP */ + database.GetPlayerInspectMessage(m_pp.name, &m_inspect_message); /* Move to another method when can, this is pointless... */ + database.LoadCharacterCurrency(cid, &m_pp); /* Load Character Currency */ + database.LoadCharacterSkills(cid, &m_pp); /* Load Character Skills */ + database.LoadCharacterLanguages(cid, &m_pp); /* Load Character Languages */ + database.LoadCharacterSpellBook(cid, &m_pp); /* Load Character Spell Book */ + database.LoadCharacterMemmedSpells(cid, &m_pp); /* Load Character Memorized Spells */ + database.LoadCharacterDisciplines(cid, &m_pp); /* Load Character Disciplines */ + /* If GM, not trackable */ if (gmhideme) { trackable = false; } - + /* Set Con State for Reporting */ conn_state = PlayerProfileLoaded; - - /* Set Current zone */ + // m_pp.zone_id = zone->GetZoneID(); // m_pp.zoneInstance = zone->GetInstanceID(); + /* Set Total Seconds Played */ TotalSecondsPlayed = m_pp.timePlayedMin * 60; - + /* Set Max AA XP */ max_AAXP = RuleI(AA, ExpPerPoint); - + /* If we can maintain intoxication across zones, check for it */ if (!RuleB(Character, MaintainIntoxicationAcrossZones)) - m_pp.intoxication = 0; - + m_pp.intoxication = 0; + strcpy(name, m_pp.name); + strcpy(lastname, m_pp.last_name); + /* If PP is set to wierd coordinates */ if ((m_pp.x == -1 && m_pp.y == -1 && m_pp.z == -1) || (m_pp.x == -2 && m_pp.y == -2 && m_pp.z == -2)) { m_pp.x = zone->safe_x(); m_pp.y = zone->safe_y(); m_pp.z = zone->safe_z(); - } - + } /* If too far below ground, then fix */ float ground_z = GetGroundZ(m_pp.x, m_pp.y, m_pp.z); if (m_pp.z < (ground_z - 500)) m_pp.z = ground_z; - class_ = m_pp.class_; - + /* Set Mob variables for spawn */ + class_ = m_pp.class_; level = m_pp.level; x_pos = m_pp.x; y_pos = m_pp.y; @@ -642,7 +646,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) base_race = m_pp.race; gender = m_pp.gender; base_gender = m_pp.gender; - deity = m_pp.deity; //FYI: DEITY_AGNOSTIC = 396; still valid? + deity = m_pp.deity; haircolor = m_pp.haircolor; beardcolor = m_pp.beardcolor; eyecolor1 = m_pp.eyecolor1; @@ -654,42 +658,41 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) drakkin_tattoo = m_pp.drakkin_tattoo; drakkin_details = m_pp.drakkin_details; + /* If GM not set in DB, and does not meet min status to be GM, reset */ if (m_pp.gm && admin < minStatusToBeGM) m_pp.gm = 0; /* Load Guild */ if (!IsInAGuild()) { m_pp.guild_id = GUILD_NONE; } else { - m_pp.guild_id = GuildID(); - + m_pp.guild_id = GuildID(); if (zone->GetZoneID() == RuleI(World, GuildBankZoneID)) GuildBanker = (guild_mgr.IsGuildLeader(GuildID(), CharacterID()) || guild_mgr.GetBankerFlag(CharacterID())); } - m_pp.guildbanker = GuildBanker; switch (race) { - case OGRE: - size = 9; break; - case TROLL: - size = 8; break; - case VAHSHIR: case BARBARIAN: - size = 7; break; - case HUMAN: case HIGH_ELF: case ERUDITE: case IKSAR: case DRAKKIN: - size = 6; break; - case HALF_ELF: - size = 5.5; break; - case WOOD_ELF: case DARK_ELF: case FROGLOK: - size = 5; break; - case DWARF: - size = 4; break; - case HALFLING: - size = 3.5; break; - case GNOME: - size = 3; break; - default: - size = 0; + case OGRE: + size = 9; break; + case TROLL: + size = 8; break; + case VAHSHIR: case BARBARIAN: + size = 7; break; + case HUMAN: case HIGH_ELF: case ERUDITE: case IKSAR: case DRAKKIN: + size = 6; break; + case HALF_ELF: + size = 5.5; break; + case WOOD_ELF: case DARK_ELF: case FROGLOK: + size = 5; break; + case DWARF: + size = 4; break; + case HALFLING: + size = 3.5; break; + case GNOME: + size = 3; break; + default: + size = 0; } /* Check for Invalid points */ @@ -700,6 +703,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) if (m_pp.ldon_points_tak < 0 || m_pp.ldon_points_tak > 2000000000){ m_pp.ldon_points_tak = 0; } if (m_pp.ldon_points_available < 0 || m_pp.ldon_points_available > 2000000000){ m_pp.ldon_points_available = 0; } + /* Set Swimming Skill 100 by default if under 100 */ if (GetSkill(SkillSwimming) < 100) SetSkill(SkillSwimming, 100); @@ -859,29 +863,20 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) Mob::SetMana(m_pp.mana); SetEndurance(m_pp.endurance); - if (IsLFP()) { - // Update LFP in case any (or all) of our group disbanded while we were zoning. - UpdateLFP(); - } - - if (m_pp.z <= zone->newzone_data.underworld) { - m_pp.x = zone->newzone_data.safe_x; - m_pp.y = zone->newzone_data.safe_y; - m_pp.z = zone->newzone_data.safe_z; - } + /* Update LFP in case any (or all) of our group disbanded while we were zoning. */ + if (IsLFP()) { UpdateLFP(); } /* Get Expansions from variables table and ship via PP */ char val[20] = { 0 }; - if (database.GetVariable("Expansions", val, 20)) - m_pp.expansions = atoi(val); - else - m_pp.expansions = 0x3FF; + if (database.GetVariable("Expansions", val, 20)){ m_pp.expansions = atoi(val); } + else{ m_pp.expansions = 0x3FF; } p_timers.SetCharID(CharacterID()); if (!p_timers.Load(&database)) { LogFile->write(EQEMuLog::Error, "Unable to load ability timers from the database for %s (%i)!", GetCleanName(), CharacterID()); } + /* Load Spell Slot Refresh from Currently Memoried Spells */ for (unsigned int i = 0; i < MAX_PP_MEMSPELL; ++i) if (IsValidSpell(m_pp.mem_spells[i])) m_pp.spellSlotRefresh[i] = p_timers.GetRemainingTime(pTimerSpellStart + m_pp.mem_spells[i]) * 1000; @@ -904,14 +899,12 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) m_inv.dumpEntireInventory(); #endif - //lost in current PP - // strcpy(m_pp.servername,"eqemulator"); - - m_pp.air_remaining = 60; //Reset to max so they dont drown on zone in if its underwater - + /* Reset to max so they dont drown on zone in if its underwater */ + m_pp.air_remaining = 60; + /* Check for PVP Zone status*/ if (zone->IsPVPZone()) m_pp.pvp = 1; - + /* Time entitled on Account: Move to account */ m_pp.timeentitledonaccount = database.GetTotalTimeEntitledOnAccount(AccountID()) / 1440; /* Reset rest timer if the durations have been lowered in the database */ @@ -934,9 +927,9 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) database.LoadPetInfo(this); /* - This was moved before the spawn packets are sent - in hopes that it adds more consistency... - Remake pet + This was moved before the spawn packets are sent + in hopes that it adds more consistency... + Remake pet */ if (m_petinfo.SpellID > 1 && !GetPet() && m_petinfo.SpellID <= SPDAT_RECORDS) { @@ -985,16 +978,15 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) } /* - Character Inventory Packet - this is not quite where live sends inventory, they do it after tribute + Character Inventory Packet + this is not quite where live sends inventory, they do it after tribute */ - if (loaditems) { //dont load if a length error occurs + if (loaditems) { /* Dont load if a length error occurs */ BulkSendInventoryItems(); - - // Send stuff on the cursor which isnt sent in bulk + /* Send stuff on the cursor which isnt sent in bulk */ iter_queue it; for (it = m_inv.cursor_begin(); it != m_inv.cursor_end(); ++it) { - // First item cursor is sent in bulk inventory packet + /* First item cursor is sent in bulk inventory packet */ if (it == m_inv.cursor_begin()) continue; const ItemInst *inst = *it; @@ -1005,15 +997,13 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) /* Task Packets */ LoadClientTaskState(); - if (GetClientVersion() >= EQClientRoF) - { + if (GetClientVersion() >= EQClientRoF) { outapp = new EQApplicationPacket(OP_ReqNewZone, 0); Handle_Connect_OP_ReqNewZone(outapp); safe_delete(outapp); } - if (ClientVersionBit & BIT_UnderfootAndLater) - { + if (ClientVersionBit & BIT_UnderfootAndLater) { outapp = new EQApplicationPacket(OP_XTargetResponse, 8); outapp->WriteUInt32(GetMaxXTargets()); outapp->WriteUInt32(0); @@ -1021,17 +1011,16 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) } /* - Weather Packet - This shouldent be moved, this seems to be what the client - uses to advance to the next state (sending ReqNewZone) + Weather Packet + This shouldent be moved, this seems to be what the client + uses to advance to the next state (sending ReqNewZone) */ outapp = new EQApplicationPacket(OP_Weather, 12); Weather_Struct *ws = (Weather_Struct *)outapp->pBuffer; ws->val1 = 0x000000FF; if (zone->zone_weather == 1) ws->type = 0x31; // Rain - if (zone->zone_weather == 2) - { + if (zone->zone_weather == 2) { outapp->pBuffer[8] = 0x01; ws->type = 0x02; } @@ -2585,7 +2574,7 @@ void Client::Handle_OP_ItemVerifyRequest(const EQApplicationPacket *app) } if(i == 0) { - CastSpell(item->Click.Effect, target_id, 10, item->CastTime, 0, 0, slot_id); + CastSpell(item->Click.Effect, target_id, USE_ITEM_SPELL_SLOT, item->CastTime, 0, 0, slot_id); } } else @@ -2612,7 +2601,7 @@ void Client::Handle_OP_ItemVerifyRequest(const EQApplicationPacket *app) } if(i == 0) { - CastSpell(augitem->Click.Effect, target_id, 10, augitem->CastTime, 0, 0, slot_id); + CastSpell(augitem->Click.Effect, target_id, USE_ITEM_SPELL_SLOT, augitem->CastTime, 0, 0, slot_id); } } else @@ -4947,6 +4936,7 @@ void Client::Handle_OP_MemorizeSpell(const EQApplicationPacket *app) void Client::Handle_OP_SwapSpell(const EQApplicationPacket *app) { + if (app->size != sizeof(SwapSpell_Struct)) { std::cout << "Wrong size on OP_SwapSpell. Got: " << app->size << ", Expected: " << sizeof(SwapSpell_Struct) << std::endl; return; @@ -4958,8 +4948,13 @@ void Client::Handle_OP_SwapSpell(const EQApplicationPacket *app) return; swapspelltemp = m_pp.spell_book[swapspell->from_slot]; + if (swapspelltemp < 0){ + return; + } m_pp.spell_book[swapspell->from_slot] = m_pp.spell_book[swapspell->to_slot]; m_pp.spell_book[swapspell->to_slot] = swapspelltemp; + + database.SaveCharacterSpellSwap(this->CharacterID(), swapspelltemp, swapspell->from_slot, swapspell->to_slot); QueuePacket(app); return; @@ -4991,7 +4986,27 @@ void Client::Handle_OP_CastSpell(const EQApplicationPacket *app) #endif LogFile->write(EQEMuLog::Debug, "OP CastSpell: slot=%d, spell=%d, target=%d, inv=%lx", castspell->slot, castspell->spell_id, castspell->target_id, (unsigned long)castspell->inventoryslot); - if ((castspell->slot == USE_ITEM_SPELL_SLOT) || (castspell->slot == POTION_BELT_SPELL_SLOT)) // ITEM or POTION cast + std::cout << "OP_CastSpell " << castspell->slot << " spell " << castspell->spell_id << " inventory slot " << castspell->inventoryslot << "\n" << std::endl; + + /* Memorized Spell */ + if (m_pp.mem_spells[castspell->slot] && m_pp.mem_spells[castspell->slot] == castspell->spell_id){ + uint16 spell_to_cast = 0; + if (castspell->slot < MAX_PP_MEMSPELL) { + spell_to_cast = m_pp.mem_spells[castspell->slot]; + if (spell_to_cast != castspell->spell_id) { + InterruptSpell(castspell->spell_id); //CHEATER!!! + return; + } + } + else if (castspell->slot >= MAX_PP_MEMSPELL) { + InterruptSpell(); + return; + } + + CastSpell(spell_to_cast, castspell->target_id, castspell->slot); + } + /* Spell Slot or Potion Belt Slot */ + else if ((castspell->slot == USE_ITEM_SPELL_SLOT) || (castspell->slot == POTION_BELT_SPELL_SLOT)) // ITEM or POTION cast { //discipline, using the item spell slot if (castspell->inventoryslot == 0xFFFFFFFF) { @@ -5070,14 +5085,16 @@ void Client::Handle_OP_CastSpell(const EQApplicationPacket *app) InterruptSpell(castspell->spell_id); } } - else if (castspell->slot == DISCIPLINE_SPELL_SLOT) { // DISCIPLINE cast + /* Discipline */ + else if (castspell->slot == DISCIPLINE_SPELL_SLOT) { if (!UseDiscipline(castspell->spell_id, castspell->target_id)) { printf("Unknown ability being used by %s, spell being cast is: %i\n", GetName(), castspell->spell_id); InterruptSpell(castspell->spell_id); return; } } - else if (castspell->slot == ABILITY_SPELL_SLOT) { // ABILITY cast (LoH and Harm Touch) + /* ABILITY cast (LoH and Harm Touch) */ + else if (castspell->slot == ABILITY_SPELL_SLOT) { uint16 spell_to_cast = 0; if (castspell->spell_id == SPELL_LAY_ON_HANDS && GetClass() == PALADIN) { @@ -5109,26 +5126,6 @@ void Client::Handle_OP_CastSpell(const EQApplicationPacket *app) if (spell_to_cast > 0) // if we've matched LoH or HT, cast now CastSpell(spell_to_cast, castspell->target_id, castspell->slot); } - else // MEMORIZED SPELL (first confirm that it's a valid memmed spell slot, then validate that the spell is currently memorized) - { - uint16 spell_to_cast = 0; - - if(castspell->slot < MAX_PP_MEMSPELL) - { - spell_to_cast = m_pp.mem_spells[castspell->slot]; - if(spell_to_cast != castspell->spell_id) - { - InterruptSpell(castspell->spell_id); //CHEATER!!! - return; - } - } - else if (castspell->slot >= MAX_PP_MEMSPELL) { - InterruptSpell(); - return; - } - - CastSpell(spell_to_cast, castspell->target_id, castspell->slot); - } return; } @@ -9224,8 +9221,7 @@ void Client::CompleteConnect() { SendAppearancePacket(AT_GuildID, GuildID(), false); SendAppearancePacket(AT_GuildRank, GuildRank(), false); } - for (uint32 spellInt = 0; spellInt < MAX_PP_SPELLBOOK; spellInt++) - { + for (uint32 spellInt = 0; spellInt < MAX_PP_SPELLBOOK; spellInt++) { if (m_pp.spell_book[spellInt] < 3 || m_pp.spell_book[spellInt] > 50000) m_pp.spell_book[spellInt] = 0xFFFFFFFF; } diff --git a/zone/command.cpp b/zone/command.cpp index 011cb0f09..b1d195bf4 100644 --- a/zone/command.cpp +++ b/zone/command.cpp @@ -2491,14 +2491,14 @@ void command_castspell(Client *c, const Seperator *sep) else if (c->GetTarget() == 0) if(c->Admin() >= commandInstacast) - c->SpellFinished(spellid, 0, 10, 0, -1, spells[spellid].ResistDiff); + c->SpellFinished(spellid, 0, USE_ITEM_SPELL_SLOT, 0, -1, spells[spellid].ResistDiff); else - c->CastSpell(spellid, 0, 10, 0); + c->CastSpell(spellid, 0, USE_ITEM_SPELL_SLOT, 0); else if(c->Admin() >= commandInstacast) c->SpellFinished(spellid, c->GetTarget(), 10, 0, -1, spells[spellid].ResistDiff); else - c->CastSpell(spellid, c->GetTarget()->GetID(), 10, 0); + c->CastSpell(spellid, c->GetTarget()->GetID(), USE_ITEM_SPELL_SLOT, 0); } } diff --git a/zone/common.h b/zone/common.h index 1401af860..0dbb68e0b 100644 --- a/zone/common.h +++ b/zone/common.h @@ -17,6 +17,10 @@ #define _NPCPET(x) (x && x->IsNPC() && x->CastToMob()->GetOwner() && x->CastToMob()->GetOwner()->IsNPC()) #define _BECOMENPCPET(x) (x && x->CastToMob()->GetOwner() && x->CastToMob()->GetOwner()->IsClient() && x->CastToMob()->GetOwner()->CastToClient()->IsBecomeNPC()) +#define USE_ITEM_SPELL_SLOT 10 +#define POTION_BELT_SPELL_SLOT 11 +#define DISCIPLINE_SPELL_SLOT 10 +#define ABILITY_SPELL_SLOT 9 //LOS Parameters: #define HEAD_POSITION 0.9f //ratio of GetSize() where NPCs see from diff --git a/zone/mob.h b/zone/mob.h index 55a57892b..51439cfee 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -205,7 +205,7 @@ public: void SendSpellBarEnable(uint16 spellid); void ZeroCastingVars(); virtual void SpellProcess(); - virtual bool CastSpell(uint16 spell_id, uint16 target_id, uint16 slot = 10, int32 casttime = -1, + virtual bool CastSpell(uint16 spell_id, uint16 target_id, uint16 slot = USE_ITEM_SPELL_SLOT, int32 casttime = -1, int32 mana_cost = -1, uint32* oSpellWillFinish = 0, uint32 item_slot = 0xFFFFFFFF, uint32 timer = 0xFFFFFFFF, uint32 timer_duration = 0, uint32 type = 0, int16 *resist_adjust = nullptr); virtual bool DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot = 10, int32 casttime = -1, diff --git a/zone/spells.cpp b/zone/spells.cpp index 357fafbd4..94921c685 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -4843,6 +4843,8 @@ void Client::MemSpell(uint16 spell_id, int slot, bool update_client) m_pp.mem_spells[slot] = spell_id; mlog(CLIENT__SPELLS, "Spell %d memorized into slot %d", spell_id, slot); + database.SaveCharacterMemorizedSpell(this->CharacterID(), m_pp.mem_spells[slot], slot); + if(update_client) { MemorizeSpell(slot, spell_id, memSpellMemorize); @@ -4857,6 +4859,8 @@ void Client::UnmemSpell(int slot, bool update_client) mlog(CLIENT__SPELLS, "Spell %d forgotten from slot %d", m_pp.mem_spells[slot], slot); m_pp.mem_spells[slot] = 0xFFFFFFFF; + database.DeleteCharacterMemorizedSpell(this->CharacterID(), m_pp.mem_spells[slot], slot); + if(update_client) { MemorizeSpell(slot, m_pp.mem_spells[slot], memSpellForget); @@ -4884,6 +4888,7 @@ void Client::ScribeSpell(uint16 spell_id, int slot, bool update_client) } m_pp.spell_book[slot] = spell_id; + database.SaveCharacterSpell(this->CharacterID(), spell_id, slot); mlog(CLIENT__SPELLS, "Spell %d scribed into spell book slot %d", spell_id, slot); if(update_client) @@ -4899,7 +4904,8 @@ void Client::UnscribeSpell(int slot, bool update_client) mlog(CLIENT__SPELLS, "Spell %d erased from spell book slot %d", m_pp.spell_book[slot], slot); m_pp.spell_book[slot] = 0xFFFFFFFF; - + + database.DeleteCharacterSpell(this->CharacterID(), m_pp.spell_book[slot], slot); if(update_client) { EQApplicationPacket* outapp = new EQApplicationPacket(OP_DeleteSpell, sizeof(DeleteSpell_Struct)); diff --git a/zone/zone.cpp b/zone/zone.cpp index 8f4b211d8..a9c63b22f 100644 --- a/zone/zone.cpp +++ b/zone/zone.cpp @@ -401,40 +401,33 @@ uint32 Zone::GetTempMerchantQuantity(uint32 NPCID, uint32 Slot) { void Zone::LoadTempMerchantData(){ LogFile->write(EQEMuLog::Status, "Loading Temporary Merchant Lists..."); - - char* query = 0; - uint32_breakdown workpt; - workpt.b4() = DBA_b4_Zone; - workpt.w2_3() = 0; - workpt.b1() = DBA_b1_Zone_MerchantListsTemp; - DBAsyncWork* dbaw = new DBAsyncWork(&database, &MTdbafq, workpt, DBAsync::Read); - dbaw->AddQuery(1, &query, MakeAnyLenString(&query, - "select ml.npcid,ml.slot,ml.itemid,ml.charges " - "from " - " merchantlist_temp ml, " - " spawnentry se, " - " spawn2 s2 " - "where " - " ml.npcid=se.npcid " - " and se.spawngroupid=s2.spawngroupid " - " and s2.zone='%s' and s2.version=%u", GetShortName(), GetInstanceVersion())); - if (!(pQueuedMerchantsWorkID = dbasync->AddWork(&dbaw))) { - safe_delete(dbaw); - LogFile->write(EQEMuLog::Error, "dbasync->AddWork() failed adding merchant list query"); + std::string query = StringFormat( + "SELECT " + "ml.npcid, " + "ml.slot, " + "ml.charges, " + "ml.itemid " + "FROM " + "merchantlist_temp ml, " + "spawnentry se, " + "spawn2 s2 " + "WHERE " + "ml.npcid = se.npcid " + "AND se.spawngroupid = s2.spawngroupid " + "AND s2.zone = '%s' AND s2.version = %i", GetShortName(), GetInstanceVersion()); + auto results = database.QueryDatabase(query); + if (!results.Success()) { + LogFile->write(EQEMuLog::Error, "Error in LoadTempMerchantData query '%s' %s", query.c_str(), results.ErrorMessage().c_str()); return; } -} - -void Zone::LoadTempMerchantData_result(MYSQL_RES* result) { - MYSQL_ROW row; - std::map >::iterator cur; + std::map >::iterator cur; uint32 npcid = 0; - while((row = mysql_fetch_row(result))) { + for (auto row = results.begin(); row != results.end(); ++row) { TempMerchantList ml; ml.npcid = atoul(row[0]); - if(npcid != ml.npcid){ + if (npcid != ml.npcid){ cur = tmpmerchanttable.find(ml.npcid); - if(cur == tmpmerchanttable.end()) { + if (cur == tmpmerchanttable.end()) { std::list empty; tmpmerchanttable[ml.npcid] = empty; cur = tmpmerchanttable.find(ml.npcid); @@ -447,9 +440,9 @@ void Zone::LoadTempMerchantData_result(MYSQL_RES* result) { ml.origslot = ml.slot; cur->second.push_back(ml); } + pQueuedMerchantsWorkID = 0; } -//there should prolly be a temp counterpart of this... void Zone::LoadNewMerchantData(uint32 merchantid){ std::list merlist; @@ -476,16 +469,35 @@ void Zone::LoadNewMerchantData(uint32 merchantid){ merchanttable[merchantid] = merlist; } -void Zone::LoadMerchantData_result(MYSQL_RES* result) { - MYSQL_ROW row; - std::map >::iterator cur; +void Zone::GetMerchantDataForZoneLoad(){ + LogFile->write(EQEMuLog::Status, "Loading Merchant Lists..."); + std::string query = StringFormat( + "SELECT " + "ml.merchantid, " + "ml.slot, " + "ml.item, " + "ml.faction_required, " + "ml.level_required, " + "ml.alt_currency_cost, " + "ml.classes_required, " + "ml.probability " + "FROM " + "merchantlist AS ml, " + "npc_types AS nt, " + "spawnentry AS se, " + "spawn2 AS s2 " + "WHERE nt.merchant_id = ml.merchantid AND nt.id = se.npcid " + "AND se.spawngroupid = s2.spawngroupid AND s2.zone = '%s' AND s2.version = %i ", GetShortName(), GetInstanceVersion()); + auto results = database.QueryDatabase(query); + std::map >::iterator cur; uint32 npcid = 0; - while((row = mysql_fetch_row(result))) { + if (results.RowCount() == 0){ LogFile->write(EQEMuLog::Error, "Error in loading Merchant Data for zone"); return; } + for (auto row = results.begin(); row != results.end(); ++row) { MerchantList ml; ml.id = atoul(row[0]); - if(npcid != ml.id){ + if (npcid != ml.id){ cur = merchanttable.find(ml.id); - if(cur == merchanttable.end()) { + if (cur == merchanttable.end()) { std::list empty; merchanttable[ml.id] = empty; cur = merchanttable.find(ml.id); @@ -495,15 +507,15 @@ void Zone::LoadMerchantData_result(MYSQL_RES* result) { std::list::iterator iter = cur->second.begin(); bool found = false; - while(iter != cur->second.end()) { - if((*iter).item == ml.id) { + while (iter != cur->second.end()) { + if ((*iter).item == ml.id) { found = true; break; } ++iter; } - if(found) { + if (found) { continue; } @@ -516,28 +528,7 @@ void Zone::LoadMerchantData_result(MYSQL_RES* result) { ml.probability = atoul(row[7]); cur->second.push_back(ml); } -} -void Zone::GetMerchantDataForZoneLoad(){ - LogFile->write(EQEMuLog::Status, "Loading Merchant Lists..."); - char* query = 0; - uint32_breakdown workpt; - workpt.b4() = DBA_b4_Zone; - workpt.w2_3() = 0; - workpt.b1() = DBA_b1_Zone_MerchantLists; - DBAsyncWork* dbaw = new DBAsyncWork(&database, &MTdbafq, workpt, DBAsync::Read); - dbaw->AddQuery(1, &query, MakeAnyLenString(&query, - "select ml.merchantid,ml.slot,ml.item,ml.faction_required,ml.level_required,ml.alt_currency_cost,ml.classes_required,ml.probability " - "from merchantlist ml, npc_types nt, spawnentry se, spawn2 s2 " - "where nt.merchant_id=ml.merchantid and nt.id=se.npcid " - "and se.spawngroupid=s2.spawngroupid and s2.zone='%s' and s2.version=%u " - //"group by ml.merchantid,slot order by merchantid,slot asc" //this made the query use a temp table/filesort (very slow)... so we handle unsorted data on our end. - , GetShortName(), GetInstanceVersion())); - if (!(pQueuedMerchantsWorkID = dbasync->AddWork(&dbaw))) { - safe_delete(dbaw); - LogFile->write(EQEMuLog::Error,"dbasync->AddWork() failed adding merchant list query"); - return; - } } void Zone::LoadMercTemplates(){ @@ -663,61 +654,6 @@ void Zone::LoadMercSpells(){ } -void Zone::DBAWComplete(uint8 workpt_b1, DBAsyncWork* dbaw) { -// LogFile->write(EQEMuLog::Debug, "Zone work complete..."); - switch (workpt_b1) { - case DBA_b1_Zone_MerchantLists: { - char errbuf[MYSQL_ERRMSG_SIZE]; - MYSQL_RES* result = 0; - DBAsyncQuery* dbaq = dbaw->PopAnswer(); - if(dbaq == nullptr) { - LogFile->write(EQEMuLog::Error, "nullptr answer provided for async merchant list load."); - break; - } - if(!dbaq->GetAnswer(errbuf, &result)) { - LogFile->write(EQEMuLog::Error, "Zone::DBAWComplete(): Unable to get results for merchant lists"); - break; - } - if(dbaq->QPT() != 1) { - LogFile->write(EQEMuLog::Error, "Zone::DBAWComplete(): Invalid query part for merchant lists"); - break; - } - - LoadMerchantData_result(result); - - pQueuedMerchantsWorkID = 0; - break; - } - case DBA_b1_Zone_MerchantListsTemp: { - char errbuf[MYSQL_ERRMSG_SIZE]; - MYSQL_RES* result = 0; - DBAsyncQuery* dbaq = dbaw->PopAnswer(); - if(dbaq == nullptr) { - LogFile->write(EQEMuLog::Error, "nullptr answer provided for async temp merchant list load."); - break; - } - if(!dbaq->GetAnswer(errbuf, &result)) { - LogFile->write(EQEMuLog::Error, "Zone::DBAWComplete(): Unable to get results for temp merchant lists"); - break; - } - if(dbaq->QPT() != 1) { - LogFile->write(EQEMuLog::Error, "Zone::DBAWComplete(): Invalid query part for temp merchant lists"); - break; - } - - LoadTempMerchantData_result(result); - - pQueuedMerchantsWorkID = 0; - break; - } - - default: { - LogFile->write(EQEMuLog::Error, "Zone::DBAWComplete(): Unknown workpt_b1"); - break; - } - } -} - bool Zone::IsLoaded() { return ZoneLoaded; } diff --git a/zone/zone.h b/zone/zone.h index 77132124e..9ad692fa0 100644 --- a/zone/zone.h +++ b/zone/zone.h @@ -166,7 +166,6 @@ public: void SetStaticZone(bool sz) { staticzone = sz; } inline bool IsStaticZone() { return staticzone; } inline void GotCurTime(bool time) { gottime = time; } - void DBAWComplete(uint8 workpt_b1, DBAsyncWork* dbaw); void SpawnConditionChanged(const SpawnCondition &c, int16 old_value); @@ -174,8 +173,6 @@ public: void LoadNewMerchantData(uint32 merchantid); void LoadTempMerchantData(); uint32 GetTempMerchantQuantity(uint32 NPCID, uint32 Slot); - void LoadTempMerchantData_result(MYSQL_RES* result); - void LoadMerchantData_result(MYSQL_RES* result); int SaveTempItem(uint32 merchantid, uint32 npcid, uint32 item, int32 charges, bool sold=false); void LoadMercTemplates(); void LoadMercSpells(); diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index 4eb0e64ab..09aa26bc8 100644 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -1022,6 +1022,45 @@ bool ZoneDatabase::LoadCharacterFactionValues(uint32 character_id, faction_map & return true; } +bool ZoneDatabase::LoadCharacterMemmedSpells(uint32 character_id, PlayerProfile_Struct* pp){ + std::string query = StringFormat( + "SELECT " + "slot_id, " + "`spell_id` " + "FROM " + "`character_memmed_spells` " + "WHERE `id` = %u ORDER BY `slot_id`", character_id); + auto results = database.QueryDatabase(query); int i = 0; + for (auto row = results.begin(); row != results.end(); ++row) { i = atoi(row[0]); pp->mem_spells[i] = atoi(row[1]); } + return true; +} + +bool ZoneDatabase::LoadCharacterSpellBook(uint32 character_id, PlayerProfile_Struct* pp){ + std::string query = StringFormat( + "SELECT " + "slot_id, " + "`spell_id` " + "FROM " + "`character_spells` " + "WHERE `id` = %u ORDER BY `slot_id`", character_id); + auto results = database.QueryDatabase(query); int i = 0; + for (auto row = results.begin(); row != results.end(); ++row) { i = atoi(row[0]); pp->spell_book[i] = atoi(row[1]); } + return true; +} + +bool ZoneDatabase::LoadCharacterLanguages(uint32 character_id, PlayerProfile_Struct* pp){ + std::string query = StringFormat( + "SELECT " + "lang_id, " + "`value` " + "FROM " + "`character_languages` " + "WHERE `id` = %u ORDER BY `language_id`", character_id); + auto results = database.QueryDatabase(query); int i = 0; + for (auto row = results.begin(); row != results.end(); ++row) { i = atoi(row[0]); pp->languages[i] = atoi(row[1]); } + return true; +} + bool ZoneDatabase::LoadCharacterDisciplines(uint32 character_id, PlayerProfile_Struct* pp){ std::string query = StringFormat( "SELECT " @@ -1092,8 +1131,23 @@ bool ZoneDatabase::LoadCharacterCurrency(uint32 character_id, PlayerProfile_Stru return true; } +bool ZoneDatabase::LoadCharacterBindPoint(uint32 character_id, PlayerProfile_Struct* pp){ + std::string query = StringFormat("SELECT id, zone_id, instance_id, x, y, z, heading FROM character_bind_home WHERE `id` = %u", character_id); + auto results = database.QueryDatabase(query); int i = 0; + for (auto row = results.begin(); row != results.end(); ++row) { + pp->binds[4].zoneId = atoi(row[i]); i++; + i++; /* Instance ID can go here eventually */ + pp->binds[4].x = atoi(row[i]); i++; + pp->binds[4].y = atoi(row[i]); i++; + pp->binds[4].z = atoi(row[i]); i++; + pp->binds[4].heading = atoi(row[i]); i++; + } + return true; +} + bool ZoneDatabase::SaveCharacterData(uint32 character_id, uint32 account_id, PlayerProfile_Struct* pp){ clock_t t = std::clock(); /* Function timer start */ + if (pp->tribute_time_remaining < 0 || pp->tribute_time_remaining == 4294967295){ pp->tribute_time_remaining = 0; } std::string query = StringFormat( "REPLACE INTO `character_data` (" " id, " @@ -1187,96 +1241,96 @@ bool ZoneDatabase::SaveCharacterData(uint32 character_id, uint32 account_id, Pla " guild_auto_consent, " " RestTimer) " "VALUES (" - "%i," // id " id, " - "%i," // account_id " account_id, " + "%u," // id " id, " + "%u," // account_id " account_id, " "'%s'," // `name` pp->name, " `name`, " "'%s'," // last_name pp->last_name, " last_name, " - "%i," // gender pp->gender, " gender, " - "%i," // race pp->race, " race, " - "%i," // class pp->class_, " class, " - "%i," // `level` pp->level, " `level`, " - "%i," // deity pp->deity, " deity, " - "%i," // birthday pp->birthday, " birthday, " - "%i," // last_login pp->lastlogin, " last_login, " - "%i," // time_played pp->timePlayedMin, " time_played, " - "%i," // pvp_status pp->pvp, " pvp_status, " - "%i," // level2 pp->level2, " level2, " - "%i," // anon pp->anon, " anon, " - "%i," // gm pp->gm, " gm, " - "%i," // intoxication pp->intoxication, " intoxication, " - "%i," // hair_color pp->haircolor, " hair_color, " - "%i," // beard_color pp->beardcolor, " beard_color, " - "%i," // eye_color_1 pp->eyecolor1, " eye_color_1, " - "%i," // eye_color_2 pp->eyecolor2, " eye_color_2, " - "%i," // hair_style pp->hairstyle, " hair_style, " - "%i," // beard pp->beard, " beard, " - "%i," // ability_time_seconds pp->ability_time_seconds, " ability_time_seconds, " - "%i," // ability_number pp->ability_number, " ability_number, " - "%i," // ability_time_minutes pp->ability_time_minutes, " ability_time_minutes, " - "%i," // ability_time_hours pp->ability_time_hours, " ability_time_hours, " + "%u," // gender pp->gender, " gender, " + "%u," // race pp->race, " race, " + "%u," // class pp->class_, " class, " + "%u," // `level` pp->level, " `level`, " + "%u," // deity pp->deity, " deity, " + "%u," // birthday pp->birthday, " birthday, " + "%u," // last_login pp->lastlogin, " last_login, " + "%u," // time_played pp->timePlayedMin, " time_played, " + "%u," // pvp_status pp->pvp, " pvp_status, " + "%u," // level2 pp->level2, " level2, " + "%u," // anon pp->anon, " anon, " + "%u," // gm pp->gm, " gm, " + "%u," // intoxication pp->intoxication, " intoxication, " + "%u," // hair_color pp->haircolor, " hair_color, " + "%u," // beard_color pp->beardcolor, " beard_color, " + "%u," // eye_color_1 pp->eyecolor1, " eye_color_1, " + "%u," // eye_color_2 pp->eyecolor2, " eye_color_2, " + "%u," // hair_style pp->hairstyle, " hair_style, " + "%u," // beard pp->beard, " beard, " + "%u," // ability_time_seconds pp->ability_time_seconds, " ability_time_seconds, " + "%u," // ability_number pp->ability_number, " ability_number, " + "%u," // ability_time_minutes pp->ability_time_minutes, " ability_time_minutes, " + "%u," // ability_time_hours pp->ability_time_hours, " ability_time_hours, " "'%s'," // title pp->title, " title, " " "'%s'," // suffix pp->suffix, " suffix, " - "%i," // exp pp->exp, " exp, " - "%i," // points pp->points, " points, " - "%i," // mana pp->mana, " mana, " - "%i," // cur_hp pp->cur_hp, " cur_hp, " - "%i," // str pp->STR, " str, " - "%i," // sta pp->STA, " sta, " - "%i," // cha pp->CHA, " cha, " - "%i," // dex pp->DEX, " dex, " - "%i," // `int` pp->INT, " `int`, " - "%i," // agi pp->AGI, " agi, " - "%i," // wis pp->WIS, " wis, " - "%i," // face pp->face, " face, " + "%u," // exp pp->exp, " exp, " + "%u," // points pp->points, " points, " + "%u," // mana pp->mana, " mana, " + "%u," // cur_hp pp->cur_hp, " cur_hp, " + "%u," // str pp->STR, " str, " + "%u," // sta pp->STA, " sta, " + "%u," // cha pp->CHA, " cha, " + "%u," // dex pp->DEX, " dex, " + "%u," // `int` pp->INT, " `int`, " + "%u," // agi pp->AGI, " agi, " + "%u," // wis pp->WIS, " wis, " + "%u," // face pp->face, " face, " "%f," // y pp->y, " y, " "%f," // x pp->x, " x, " "%f," // z pp->z, " z, " "%f," // heading pp->heading, " heading, " - "%i," // pvp2 pp->pvp2, " pvp2, " - "%i," // pvp_type pp->pvptype, " pvp_type, " - "%i," // autosplit_enabled pp->autosplit, " autosplit_enabled, " - "%i," // zone_change_count pp->zone_change_count, " zone_change_count, " - "%i," // drakkin_heritage pp->drakkin_heritage, " drakkin_heritage, " - "%i," // drakkin_tattoo pp->drakkin_tattoo, " drakkin_tattoo, " - "%i," // drakkin_details pp->drakkin_details, " drakkin_details, " + "%u," // pvp2 pp->pvp2, " pvp2, " + "%u," // pvp_type pp->pvptype, " pvp_type, " + "%u," // autosplit_enabled pp->autosplit, " autosplit_enabled, " + "%u," // zone_change_count pp->zone_change_count, " zone_change_count, " + "%u," // drakkin_heritage pp->drakkin_heritage, " drakkin_heritage, " + "%u," // drakkin_tattoo pp->drakkin_tattoo, " drakkin_tattoo, " + "%u," // drakkin_details pp->drakkin_details, " drakkin_details, " "%i," // toxicity pp->toxicity, " toxicity, " "%i," // hunger_level pp->hunger_level, " hunger_level, " "%i," // thirst_level pp->thirst_level, " thirst_level, " - "%i," // ability_up pp->ability_up, " ability_up, " - "%i," // zone_id pp->zone_id, " zone_id, " - "%i," // zone_instance pp->zoneInstance, " zone_instance, " - "%i," // leadership_exp_on pp->leadAAActive, " leadership_exp_on, " - "%i," // ldon_points_guk pp->ldon_points_guk, " ldon_points_guk, " - "%i," // ldon_points_mir pp->ldon_points_mir, " ldon_points_mir, " - "%i," // ldon_points_mmc pp->ldon_points_mmc, " ldon_points_mmc, " - "%i," // ldon_points_ruj pp->ldon_points_ruj, " ldon_points_ruj, " - "%i," // ldon_points_tak pp->ldon_points_tak, " ldon_points_tak, " - "%i," // ldon_points_available pp->ldon_points_available, " ldon_points_available, " - "%i," // tribute_time_remaining pp->tribute_time_remaining, " tribute_time_remaining, " - "%i," // show_helm pp->showhelm, " show_helm, " - "%i," // career_tribute_points pp->career_tribute_points, " career_tribute_points, " - "%i," // tribute_points pp->tribute_points, " tribute_points, " - "%i," // tribute_active pp->tribute_active, " tribute_active, " - "%i," // endurance pp->endurance, " endurance, " - "%i," // group_leadership_exp pp->group_leadership_exp, " group_leadership_exp, " - "%i," // raid_leadership_exp pp->raid_leadership_exp, " raid_leadership_exp, " - "%i," // group_leadership_points pp->group_leadership_points, " group_leadership_points, " - "%i," // raid_leadership_points pp->raid_leadership_points, " raid_leadership_points, " - "%i," // air_remaining pp->air_remaining, " air_remaining, " - "%i," // pvp_kills pp->PVPKills, " pvp_kills, " - "%i," // pvp_deaths pp->PVPDeaths, " pvp_deaths, " - "%i," // pvp_current_points pp->PVPCurrentPoints, " pvp_current_points, " - "%i," // pvp_career_points pp->PVPCareerPoints, " pvp_career_points, " - "%i," // pvp_best_kill_streak pp->PVPBestKillStreak, " pvp_best_kill_streak, " - "%i," // pvp_worst_death_streak pp->PVPWorstDeathStreak, " pvp_worst_death_streak, " - "%i," // pvp_current_kill_streak pp->PVPCurrentKillStreak, " pvp_current_kill_streak, " - "%i," // aa_points_spent pp->aapoints_spent, " aa_points_spent, " - "%i," // aa_exp pp->expAA, " aa_exp, " - "%i," // aa_points pp->aapoints, " aa_points, " - "%i," // group_auto_consent pp->groupAutoconsent, " group_auto_consent, " - "%i," // raid_auto_consent pp->raidAutoconsent, " raid_auto_consent, " - "%i," // guild_auto_consent pp->guildAutoconsent, " guild_auto_consent, " - "%i" // RestTimer pp->RestTimer, " RestTimer) " + "%u," // ability_up pp->ability_up, " ability_up, " + "%u," // zone_id pp->zone_id, " zone_id, " + "%u," // zone_instance pp->zoneInstance, " zone_instance, " + "%u," // leadership_exp_on pp->leadAAActive, " leadership_exp_on, " + "%u," // ldon_points_guk pp->ldon_points_guk, " ldon_points_guk, " + "%u," // ldon_points_mir pp->ldon_points_mir, " ldon_points_mir, " + "%u," // ldon_points_mmc pp->ldon_points_mmc, " ldon_points_mmc, " + "%u," // ldon_points_ruj pp->ldon_points_ruj, " ldon_points_ruj, " + "%u," // ldon_points_tak pp->ldon_points_tak, " ldon_points_tak, " + "%u," // ldon_points_available pp->ldon_points_available, " ldon_points_available, " + "%u," // tribute_time_remaining pp->tribute_time_remaining, " tribute_time_remaining, " + "%u," // show_helm pp->showhelm, " show_helm, " + "%u," // career_tribute_points pp->career_tribute_points, " career_tribute_points, " + "%u," // tribute_points pp->tribute_points, " tribute_points, " + "%u," // tribute_active pp->tribute_active, " tribute_active, " + "%u," // endurance pp->endurance, " endurance, " + "%u," // group_leadership_exp pp->group_leadership_exp, " group_leadership_exp, " + "%u," // raid_leadership_exp pp->raid_leadership_exp, " raid_leadership_exp, " + "%u," // group_leadership_points pp->group_leadership_points, " group_leadership_points, " + "%u," // raid_leadership_points pp->raid_leadership_points, " raid_leadership_points, " + "%u," // air_remaining pp->air_remaining, " air_remaining, " + "%u," // pvp_kills pp->PVPKills, " pvp_kills, " + "%u," // pvp_deaths pp->PVPDeaths, " pvp_deaths, " + "%u," // pvp_current_points pp->PVPCurrentPoints, " pvp_current_points, " + "%u," // pvp_career_points pp->PVPCareerPoints, " pvp_career_points, " + "%u," // pvp_best_kill_streak pp->PVPBestKillStreak, " pvp_best_kill_streak, " + "%u," // pvp_worst_death_streak pp->PVPWorstDeathStreak, " pvp_worst_death_streak, " + "%u," // pvp_current_kill_streak pp->PVPCurrentKillStreak, " pvp_current_kill_streak, " + "%u," // aa_points_spent pp->aapoints_spent, " aa_points_spent, " + "%u," // aa_exp pp->expAA, " aa_exp, " + "%u," // aa_points pp->aapoints, " aa_points, " + "%u," // group_auto_consent pp->groupAutoconsent, " group_auto_consent, " + "%u," // raid_auto_consent pp->raidAutoconsent, " raid_auto_consent, " + "%u," // guild_auto_consent pp->guildAutoconsent, " guild_auto_consent, " + "%u" // RestTimer pp->RestTimer, " RestTimer) " ")", character_id, account_id, @@ -1370,7 +1424,12 @@ bool ZoneDatabase::SaveCharacterData(uint32 character_id, uint32 account_id, Pla pp->RestTimer ); auto results = database.QueryDatabase(query); - LogFile->write(EQEMuLog::Status, "ZoneDatabase::SaveCharacterData %i, done... Took %f seconds", character_id, ((float)(std::clock() - t)) / CLOCKS_PER_SEC); + //if (results.RowsAffected() != 2) { + // LogFile->write(EQEMuLog::Error, "Error in ZoneDatabase::SaveCharacterData Error! Query: %s \n", query); return false; + //} + //else{ + LogFile->write(EQEMuLog::Status, "ZoneDatabase::SaveCharacterData %i, done... Took %f seconds", character_id, ((float)(std::clock() - t)) / CLOCKS_PER_SEC); + //} return true; } @@ -1407,7 +1466,7 @@ bool ZoneDatabase::SaveCharacterCurrency(uint32 character_id, PlayerProfile_Stru pp->currentEbonCrystals, pp->careerEbonCrystals); auto results = database.QueryDatabase(query); - LogFile->write(EQEMuLog::Status, "Saving Currency for character ID: %i, done", character_id); + LogFile->write(EQEMuLog::Status, "Saving Currency for character ID: %i, done", character_id); return true; } @@ -1416,10 +1475,35 @@ bool ZoneDatabase::SaveCharacterAA(uint32 character_id, uint32 aa_id, uint32 cur " VALUES (%u, %u, %u)", character_id, aa_id, current_level); auto results = QueryDatabase(rquery); - LogFile->write(EQEMuLog::Status, "Saving AA for character ID: %i, aa_id: %u current_level: %i", character_id, aa_id, current_level); + LogFile->write(EQEMuLog::Status, "Saving AA for character ID: %u, aa_id: %u current_level: %u", character_id, aa_id, current_level); return true; } +bool ZoneDatabase::SaveCharacterSpellSwap(uint32 character_id, uint32 spell_id, uint32 from_slot, uint32 to_slot){ + std::string rquery = StringFormat("UPDATE `character_spells` SET `slot_id` = %u WHERE `slot_id` = %u AND `id` = %u", + to_slot, from_slot, character_id); + clock_t t = std::clock(); /* Function timer start */ + auto results = QueryDatabase(rquery); + LogFile->write(EQEMuLog::Status, "ZoneDatabase::SaveCharacterSpellSwap for character ID: %u, from_slot: %u to_slot: %u spell: %u time: %f seconds", character_id, from_slot, to_slot, spell_id, ((float)(std::clock() - t)) / CLOCKS_PER_SEC); + return true; +} + +bool ZoneDatabase::SaveCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id){ + std::string query = StringFormat("REPLACE INTO `character_spells` (id, slot_id, spell_id) VALUES (%u, %u, %u)", character_id, slot_id, spell_id); QueryDatabase(query); return true; +} + +bool ZoneDatabase::DeleteCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id){ + std::string query = StringFormat("DELETE FROM `character_spells` WHERE `slot_id` = %u AND `id` = %u", slot_id, character_id); QueryDatabase(query); return true; +} + +bool ZoneDatabase::SaveCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id){ + std::string query = StringFormat("REPLACE INTO `character_memmed_spells` (id, slot_id, spell_id) VALUES (%u, %u, %u)", character_id, slot_id, spell_id); QueryDatabase(query); return true; +} + +bool ZoneDatabase::DeleteCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id){ + std::string query = StringFormat("DELETE FROM `character_memmed_spells` WHERE `slot_id` = %u AND `id` = %u", slot_id, character_id); QueryDatabase(query); return true; +} + bool ZoneDatabase::NoRentExpired(const char* name){ char errbuf[MYSQL_ERRMSG_SIZE]; char *query = 0; @@ -1429,7 +1513,7 @@ bool ZoneDatabase::NoRentExpired(const char* name){ safe_delete_array(query); if (mysql_num_rows(result) == 1) { row = mysql_fetch_row(result); - uint32 seconds = atoi(row[0]); + uint32 seconds = atoi(row[0]); mysql_free_result(result); return (seconds>1800); } diff --git a/zone/zonedb.h b/zone/zonedb.h index ce32e919f..87aefd4cf 100644 --- a/zone/zonedb.h +++ b/zone/zonedb.h @@ -256,18 +256,28 @@ public: void SavePetInfo(Client *c); void RemoveTempFactions(Client *c); - /* Player Profile Loaders */ + /* Character Data Loaders */ bool LoadCharacterFactionValues(uint32 character_id, faction_map & val_list); + bool LoadCharacterSpellBook(uint32 character_id, PlayerProfile_Struct* pp); + bool LoadCharacterMemmedSpells(uint32 character_id, PlayerProfile_Struct* pp); + bool LoadCharacterLanguages(uint32 character_id, PlayerProfile_Struct* pp); bool LoadCharacterDisciplines(uint32 character_id, PlayerProfile_Struct* pp); bool LoadCharacterSkills(uint32 character_id, PlayerProfile_Struct* pp); bool LoadCharacterData(uint32 character_id, PlayerProfile_Struct* pp); bool LoadCharacterCurrency(uint32 character_id, PlayerProfile_Struct* pp); + bool LoadCharacterBindPoint(uint32 character_id, PlayerProfile_Struct* pp); - /* Player Profile Saves */ - + /* Character Data Saves */ bool SaveCharacterCurrency(uint32 character_id, PlayerProfile_Struct* pp); bool SaveCharacterData(uint32 character_id, uint32 account_id, PlayerProfile_Struct* pp); bool SaveCharacterAA(uint32 character_id, uint32 aa_id, uint32 current_level); + bool SaveCharacterSpellSwap(uint32 character_id, uint32 spell_id, uint32 from_slot, uint32 to_slot); + bool SaveCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id); + bool SaveCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id); + + /* Character Data Deletes */ + bool DeleteCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id); + bool DeleteCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id); /* * Character Inventory diff --git a/zone/zonedbasync.cpp b/zone/zonedbasync.cpp index 579517d55..454252ab6 100644 --- a/zone/zonedbasync.cpp +++ b/zone/zonedbasync.cpp @@ -12,30 +12,6 @@ void DispatchFinishedDBAsync(DBAsyncWork* dbaw) { uint32_breakdown workpt; workpt = dbaw->WPT(); switch (workpt.b4()) { -/* case DBA_b4_Main: { - switch (workpt.i24_1()) { - case DBA_i24_1_Main_LoadVariables: { - char errbuf[MYSQL_ERRMSG_SIZE]; - MYSQL_RES* result; - DBAsyncQuery* dbaq = dbaw->PopAnswer(); - if (dbaq->GetAnswer(errbuf, result)) - database.LoadVariables_result(result); - else - std::cout << "Async DB.LoadVariables() failed: '" << errbuf << "'" << std::endl; - break; - } - default: { - std::cout << "Error: DispatchFinishedDBAsync(): Unknown workpt.b4" << std::endl; - break; - } - } - }*/ - case DBA_b4_Zone: { - if(zone == nullptr) - break; - zone->DBAWComplete(workpt.b1(), dbaw); - break; - } case DBA_b4_Entity: { Entity* entity = entity_list.GetID(workpt.w2_3()); if (!entity)