Loading...   

  • Created By Uleat On: 08:23 PM January 22, 2019
  • Link

 common/emu_constants.h      |  2 +-
 common/eq_packet_structs.h  | 12 ++++++++++++
 common/patches/rof.cpp      | 20 +++++++++++++-------
 common/patches/rof2.cpp     | 20 +++++++++++++-------
 common/patches/sod.cpp      | 11 ++++++++++-
 common/patches/sof.cpp      | 11 ++++++++++-
 common/patches/titanium.cpp | 11 ++++++++++-
 common/patches/uf.cpp       | 12 ++++++++++--
 world/client.cpp            | 10 ++++------
 world/worlddb.cpp           |  1 +
 zone/client_packet.cpp      | 24 +++++++++++++++++-------
 zone/command.cpp            | 11 ++++++++++-
 zone/questmgr.cpp           | 12 ++++++++++--
 zone/spells.cpp             | 15 ++++++++-------
 zone/zonedb.cpp             | 18 +++++++++++-------
 15 files changed, 140 insertions(+), 50 deletions(-)

diff --git a/common/emu_constants.h b/common/emu_constants.h
index 6fe6f8ec..e3869570 100644
--- a/common/emu_constants.h
+++ b/common/emu_constants.h
@@ -243,7 +243,7 @@ namespace EQEmu
 		};
 
 		using RoF2::spells::SPELL_ID_MAX;
-		using SoD::spells::SPELLBOOK_SIZE;
+		using RoF2::spells::SPELLBOOK_SIZE;
 		using UF::spells::SPELL_GEM_COUNT; // RoF+ clients define more than UF client..but, they are not valid beyond UF
 
 		using RoF2::spells::LONG_BUFFS;
diff --git a/common/eq_packet_structs.h b/common/eq_packet_structs.h
index 8e0d4d0d..a5d86d14 100644
--- a/common/eq_packet_structs.h
+++ b/common/eq_packet_structs.h
@@ -1091,6 +1091,18 @@ struct PlayerProfile_Struct
 /*19559*/	uint8				unknown19595[5];	// ***Placeholder (6/29/2005)
 /*19564*/	uint32				RestTimer;
 /*19568*/
+
+	// All player profile packets are translated and this overhead is ignored in out-bound packets
+	PlayerProfile_Struct() : m_player_profile_version(EQEmu::versions::MobVersion::Unknown) { }
+
+	EQEmu::versions::MobVersion PlayerProfileVersion() { return m_player_profile_version; }
+	void SetPlayerProfileVersion(EQEmu::versions::MobVersion mob_version) { m_player_profile_version = EQEmu::versions::ValidateMobVersion(mob_version); }
+	void SetPlayerProfileVersion(EQEmu::versions::ClientVersion client_version) { SetPlayerProfileVersion(EQEmu::versions::ConvertClientVersionToMobVersion(client_version)); }
+
+// private:
+	// No need for gm flag since pp already has one
+	// No need for lookup pointer since this struct is not tied to any one system
+	EQEmu::versions::MobVersion m_player_profile_version; // kept public for now so checksum can calc sizeof (client_packet.cpp:1586)
 };
 
 
diff --git a/common/patches/rof.cpp b/common/patches/rof.cpp
index 5a87748a..e0a2441a 100644
--- a/common/patches/rof.cpp
+++ b/common/patches/rof.cpp
@@ -2126,14 +2126,20 @@ namespace RoF
 
 		outapp->WriteUInt32(spells::SPELLBOOK_SIZE);		// Spellbook slots
 
-		for (uint32 r = 0; r < EQEmu::spells::SPELLBOOK_SIZE; r++)
-		{
-			outapp->WriteUInt32(emu->spell_book[r]);
+		// RoF has no defined packet struct to allow memcpy use..
+		if (spells::SPELLBOOK_SIZE <= EQEmu::spells::SPELLBOOK_SIZE) {
+			for (uint32 r = 0; r < spells::SPELLBOOK_SIZE; r++) {
+				outapp->WriteUInt32(emu->spell_book[r]);
+			}
 		}
-		// zeroes for the rest of the spellbook slots
-		for (uint32 r = 0; r < spells::SPELLBOOK_SIZE - EQEmu::spells::SPELLBOOK_SIZE; r++)
-		{
-			outapp->WriteUInt32(0xFFFFFFFFU);
+		else {
+			for (uint32 r = 0; r < EQEmu::spells::SPELLBOOK_SIZE; r++) {
+				outapp->WriteUInt32(emu->spell_book[r]);
+			}
+			// invalidate the rest of the spellbook slots
+			for (uint32 r = EQEmu::spells::SPELLBOOK_SIZE; r < spells::SPELLBOOK_SIZE; r++) {
+				outapp->WriteUInt32(0xFFFFFFFFU);
+			}
 		}
 
 		outapp->WriteUInt32(spells::SPELL_GEM_COUNT);		// Memorised spell slots
diff --git a/common/patches/rof2.cpp b/common/patches/rof2.cpp
index 74453f1f..e8914b94 100644
--- a/common/patches/rof2.cpp
+++ b/common/patches/rof2.cpp
@@ -2202,14 +2202,20 @@ namespace RoF2
 
 		outapp->WriteUInt32(spells::SPELLBOOK_SIZE);		// Spellbook slots
 
-		for (uint32 r = 0; r < EQEmu::spells::SPELLBOOK_SIZE; r++)
-		{
-			outapp->WriteUInt32(emu->spell_book[r]);
+		// RoF2 has no defined packet struct to allow memcpy use..
+		if (spells::SPELLBOOK_SIZE <= EQEmu::spells::SPELLBOOK_SIZE) {
+			for (uint32 r = 0; r < spells::SPELLBOOK_SIZE; r++) {
+				outapp->WriteUInt32(emu->spell_book[r]);
+			}
 		}
-		// zeroes for the rest of the spellbook slots
-		for (uint32 r = 0; r < spells::SPELLBOOK_SIZE - EQEmu::spells::SPELLBOOK_SIZE; r++)
-		{
-			outapp->WriteUInt32(0xFFFFFFFFU);
+		else {
+			for (uint32 r = 0; r < EQEmu::spells::SPELLBOOK_SIZE; r++) {
+				outapp->WriteUInt32(emu->spell_book[r]);
+			}
+			// invalidate the rest of the spellbook slots
+			for (uint32 r = EQEmu::spells::SPELLBOOK_SIZE; r < spells::SPELLBOOK_SIZE; r++) {
+				outapp->WriteUInt32(0xFFFFFFFFU);
+			}
 		}
 
 		outapp->WriteUInt32(spells::SPELL_GEM_COUNT);		// Memorised spell slots
diff --git a/common/patches/sod.cpp b/common/patches/sod.cpp
index e64510d0..155e5aea 100644
--- a/common/patches/sod.cpp
+++ b/common/patches/sod.cpp
@@ -1492,7 +1492,16 @@ namespace SoD
 		OUT(WIS);
 		OUT(face);
 		//	OUT(unknown02264[47]);
-		OUT_array(spell_book, spells::SPELLBOOK_SIZE);
+
+		if (spells::SPELLBOOK_SIZE <= EQEmu::spells::SPELLBOOK_SIZE) {
+			memcpy(eq->spell_book, emu->spell_book, (sizeof(uint32) * spells::SPELLBOOK_SIZE));
+		}
+		else {
+			memcpy(eq->spell_book, emu->spell_book, (sizeof(uint32) * EQEmu::spells::SPELLBOOK_SIZE));
+			// invalidate the rest of the spellbook slots
+			memset(eq->spell_book, 0xFF, (sizeof(uint32) * (spells::SPELLBOOK_SIZE - EQEmu::spells::SPELLBOOK_SIZE)));
+		}
+
 		//	OUT(unknown4184[128]);
 		OUT_array(mem_spells, spells::SPELL_GEM_COUNT);
 		//	OUT(unknown04396[32]);
diff --git a/common/patches/sof.cpp b/common/patches/sof.cpp
index a1141f99..c50b0709 100644
--- a/common/patches/sof.cpp
+++ b/common/patches/sof.cpp
@@ -1156,7 +1156,16 @@ namespace SoF
 		OUT(WIS);
 		OUT(face);
 		//	OUT(unknown02264[47]);
-		OUT_array(spell_book, spells::SPELLBOOK_SIZE);
+
+		if (spells::SPELLBOOK_SIZE <= EQEmu::spells::SPELLBOOK_SIZE) {
+			memcpy(eq->spell_book, emu->spell_book, (sizeof(uint32) * spells::SPELLBOOK_SIZE));
+		}
+		else {
+			memcpy(eq->spell_book, emu->spell_book, (sizeof(uint32) * EQEmu::spells::SPELLBOOK_SIZE));
+			// invalidate the rest of the spellbook slots
+			memset(eq->spell_book, 0xFF, (sizeof(uint32) * (spells::SPELLBOOK_SIZE - EQEmu::spells::SPELLBOOK_SIZE)));
+		}
+
 		//	OUT(unknown4184[128]);
 		OUT_array(mem_spells, spells::SPELL_GEM_COUNT);
 		//	OUT(unknown04396[32]);
diff --git a/common/patches/titanium.cpp b/common/patches/titanium.cpp
index 9220875a..0febf9c8 100644
--- a/common/patches/titanium.cpp
+++ b/common/patches/titanium.cpp
@@ -1012,7 +1012,16 @@ namespace Titanium
 		OUT(WIS);
 		OUT(face);
 		//	OUT(unknown02264[47]);
-		OUT_array(spell_book, spells::SPELLBOOK_SIZE);
+
+		if (spells::SPELLBOOK_SIZE <= EQEmu::spells::SPELLBOOK_SIZE) {
+			memcpy(eq->spell_book, emu->spell_book, (sizeof(uint32) * spells::SPELLBOOK_SIZE));
+		}
+		else {
+			memcpy(eq->spell_book, emu->spell_book, (sizeof(uint32) * EQEmu::spells::SPELLBOOK_SIZE));
+			// invalidate the rest of the spellbook slots
+			memset(eq->spell_book, 0xFF, (sizeof(uint32) * (spells::SPELLBOOK_SIZE - EQEmu::spells::SPELLBOOK_SIZE)));
+		}
+
 		//	OUT(unknown4184[448]);
 		OUT_array(mem_spells, spells::SPELL_GEM_COUNT);
 		//	OUT(unknown04396[32]);
diff --git a/common/patches/uf.cpp b/common/patches/uf.cpp
index 9e87a757..2f514020 100644
--- a/common/patches/uf.cpp
+++ b/common/patches/uf.cpp
@@ -1724,8 +1724,16 @@ namespace UF
 		OUT(WIS);
 		OUT(face);
 		//	OUT(unknown02264[47]);
-		memset(eq->spell_book, 0xFF, sizeof(uint32)* spells::SPELLBOOK_SIZE);
-		OUT_array(spell_book, 480U);
+		
+		if (spells::SPELLBOOK_SIZE <= EQEmu::spells::SPELLBOOK_SIZE) {
+			memcpy(eq->spell_book, emu->spell_book, (sizeof(uint32) * spells::SPELLBOOK_SIZE));
+		}
+		else {
+			memcpy(eq->spell_book, emu->spell_book, (sizeof(uint32) * EQEmu::spells::SPELLBOOK_SIZE));
+			// invalidate the rest of the spellbook slots
+			memset(eq->spell_book, 0xFF, (sizeof(uint32) * (spells::SPELLBOOK_SIZE - EQEmu::spells::SPELLBOOK_SIZE)));
+		}
+
 		//	OUT(unknown4184[128]);
 		OUT_array(mem_spells, spells::SPELL_GEM_COUNT);
 		//	OUT(unknown04396[32]);
diff --git a/world/client.cpp b/world/client.cpp
index 822b648b..06bceb52 100644
--- a/world/client.cpp
+++ b/world/client.cpp
@@ -1446,6 +1446,7 @@ bool Client::OPCharCreate(char *name, CharCreate_Struct *cc)
 	ExtendedProfile_Struct ext;
 	EQEmu::InventoryProfile inv;
 
+	pp.SetPlayerProfileVersion(EQEmu::versions::ConvertClientVersionToMobVersion(EQEmu::versions::ConvertClientVersionBitToClientVersion(m_ClientVersionBit)));
 	inv.SetInventoryVersion(EQEmu::versions::ConvertClientVersionBitToClientVersion(m_ClientVersionBit));
 	inv.SetGMInventory(false); // character cannot have gm flag at this point
 
@@ -1528,12 +1529,9 @@ bool Client::OPCharCreate(char *name, CharCreate_Struct *cc)
 
 //	strcpy(pp.servername, WorldConfig::get()->ShortName.c_str());
 
-
-	for (i = 0; i < EQEmu::spells::SPELLBOOK_SIZE; i++)
-		pp.spell_book[i] = 0xFFFFFFFF;
-
-	for(i = 0; i < EQEmu::spells::SPELL_GEM_COUNT; i++)
-		pp.mem_spells[i] = 0xFFFFFFFF;
+	memset(pp.spell_book, 0xFF, (sizeof(uint32) * EQEmu::spells::SPELLBOOK_SIZE));
+	
+	memset(pp.mem_spells, 0xFF, (sizeof(uint32) * EQEmu::spells::SPELL_GEM_COUNT));
 
 	for(i = 0; i < BUFF_COUNT; i++)
 		pp.buffs[i].spellid = 0xFFFF;
diff --git a/world/worlddb.cpp b/world/worlddb.cpp
index 4daa7fa7..47354cc6 100644
--- a/world/worlddb.cpp
+++ b/world/worlddb.cpp
@@ -98,6 +98,7 @@ void WorldDatabase::GetCharSelectInfo(uint32 accountID, EQApplicationPacket **ou
 		PlayerProfile_Struct pp;
 		EQEmu::InventoryProfile inv;
 
+		pp.SetPlayerProfileVersion(EQEmu::versions::ConvertClientVersionToMobVersion(client_version));
 		inv.SetInventoryVersion(client_version);
 		inv.SetGMInventory(true); // charsel can not interact with items..but, no harm in setting to full expansion support
 
diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp
index 79707510..9c6137f1 100644
--- a/zone/client_packet.cpp
+++ b/zone/client_packet.cpp
@@ -530,10 +530,14 @@ void Client::CompleteConnect()
 		SendAppearancePacket(AT_GuildID, GuildID(), false);
 		SendAppearancePacket(AT_GuildRank, rank, false);
 	}
-	for (uint32 spellInt = 0; spellInt < EQEmu::spells::SPELLBOOK_SIZE; spellInt++) {
-		if (m_pp.spell_book[spellInt] < 3 || m_pp.spell_book[spellInt] > 50000)
+
+	const auto sbs = EQEmu::spells::DynamicLookup(ClientVersion(), GetGM())->SpellbookSize;
+	const auto smid = EQEmu::spells::DynamicLookup(ClientVersion(), GetGM())->SpellIdMax;
+	for (uint32 spellInt = 0; spellInt < sbs; ++spellInt) {
+		if (m_pp.spell_book[spellInt] < 3 || m_pp.spell_book[spellInt] > smid)
 			m_pp.spell_book[spellInt] = 0xFFFFFFFF;
 	}
+
 	//SendAATable();
 
 	if (GetHideMe()) Message(13, "[GM] You are currently hidden to all clients");
@@ -1144,6 +1148,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
 	SetClientVersion(Connection()->ClientVersion());
 	m_ClientVersionBit = EQEmu::versions::ConvertClientVersionToClientVersionBit(Connection()->ClientVersion());
 
+	m_pp.SetPlayerProfileVersion(m_ClientVersion);
 	m_inv.SetInventoryVersion(m_ClientVersion);
 
 	/* Antighost code
@@ -1233,7 +1238,6 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
 	database.LoadCharacterData(cid, &m_pp, &m_epp); /* Load Character Data from DB into PP as well as E_PP */
 	database.LoadCharacterSkills(cid, &m_pp); /* Load Character Skills */
 	database.LoadCharacterInspectMessage(cid, &m_inspect_message); /* Load Character Inspect Message */
-	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 */
 	database.LoadCharacterLanguages(cid, &m_pp); /* Load Character Languages */
@@ -1338,6 +1342,9 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
 	if (m_pp.gm && admin < minStatusToBeGM)
 		m_pp.gm = 0;
 
+	// moved so m_pp will reflect proper gm status
+	database.LoadCharacterSpellBook(cid, &m_pp); /* Load Character Spell Book */
+
 	/* Load Guild */
 	if (!IsInAGuild()) {
 		m_pp.guild_id = GUILD_NONE;
@@ -1577,8 +1584,8 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
 	if ((m_pp.RestTimer > RuleI(Character, RestRegenTimeToActivate)) && (m_pp.RestTimer > RuleI(Character, RestRegenRaidTimeToActivate)))
 		m_pp.RestTimer = 0;
 
-	/* This checksum should disappear once dynamic structs are in... each struct strategy will do it */
-	CRC32::SetEQChecksum((unsigned char*)&m_pp, sizeof(PlayerProfile_Struct) - 4);
+	/* This checksum should disappear once dynamic structs are in... each struct strategy will do it */ // looks to be in place now
+	CRC32::SetEQChecksum((unsigned char*)&m_pp, sizeof(PlayerProfile_Struct) - sizeof(m_pp.m_player_profile_version) - 4);
 
 	outapp = new EQApplicationPacket(OP_PlayerProfile, sizeof(PlayerProfile_Struct));
 
@@ -5253,7 +5260,7 @@ void Client::Handle_OP_DeleteSpell(const EQApplicationPacket *app)
 	EQApplicationPacket* outapp = app->Copy();
 	DeleteSpell_Struct* dss = (DeleteSpell_Struct*)outapp->pBuffer;
 
-	if (dss->spell_slot < 0 || dss->spell_slot > int(EQEmu::spells::SPELLBOOK_SIZE))
+	if (dss->spell_slot < 0 || dss->spell_slot >= EQEmu::spells::DynamicLookup(ClientVersion(), GetGM())->SpellbookSize)
 		return;
 
 	if (m_pp.spell_book[dss->spell_slot] != SPELLBOOK_UNKNOWN) {
@@ -13327,7 +13334,10 @@ void Client::Handle_OP_SwapSpell(const EQApplicationPacket *app)
 	const SwapSpell_Struct* swapspell = (const SwapSpell_Struct*)app->pBuffer;
 	int swapspelltemp;
 
-	if (swapspell->from_slot < 0 || swapspell->from_slot > EQEmu::spells::SPELLBOOK_SIZE || swapspell->to_slot < 0 || swapspell->to_slot > EQEmu::spells::SPELLBOOK_SIZE)
+	const auto sbs = EQEmu::spells::DynamicLookup(ClientVersion(), GetGM())->SpellbookSize;
+	if (swapspell->from_slot < 0 || swapspell->from_slot >= sbs)
+		return;
+	if (swapspell->to_slot < 0 || swapspell->to_slot >= sbs)
 		return;
 
 	swapspelltemp = m_pp.spell_book[swapspell->from_slot];
diff --git a/zone/command.cpp b/zone/command.cpp
index d6e28ddf..baab6068 100755
--- a/zone/command.cpp
+++ b/zone/command.cpp
@@ -6353,7 +6353,16 @@ void command_scribespells(Client *c, const Seperator *sep)
 		c->Message(0, "Scribing spells for %s.",  t->GetName());
 	Log(Logs::General, Logs::Normal, "Scribe spells request for %s from %s, levels: %u -> %u",  t->GetName(), c->GetName(), min_level, max_level);
 
-	for(curspell = 0, book_slot = t->GetNextAvailableSpellBookSlot(), count = 0; curspell < SPDAT_RECORDS && book_slot < EQEmu::spells::SPELLBOOK_SIZE; curspell++, book_slot = t->GetNextAvailableSpellBookSlot(book_slot))
+	const auto sbs = EQEmu::spells::DynamicLookup(t->ClientVersion(), t->GetGM())->SpellbookSize;
+	for (
+		curspell = 0,
+		book_slot = t->GetNextAvailableSpellBookSlot(),
+		count = 0; // ;
+		curspell < SPDAT_RECORDS &&
+		book_slot < sbs; // ;
+		curspell++,
+		book_slot = t->GetNextAvailableSpellBookSlot(book_slot)
+	)
 	{
 		if
 		(
diff --git a/zone/questmgr.cpp b/zone/questmgr.cpp
index 660ac327..222bb59f 100644
--- a/zone/questmgr.cpp
+++ b/zone/questmgr.cpp
@@ -984,8 +984,16 @@ uint16 QuestManager::scribespells(uint8 max_level, uint8 min_level) {
 	bool SpellGlobalCheckResult = 0;
 	bool SpellBucketCheckResult = 0;
 
-
-	for(spell_id = 0, book_slot = initiator->GetNextAvailableSpellBookSlot(), count = 0; spell_id < SPDAT_RECORDS && book_slot < EQEmu::spells::SPELLBOOK_SIZE; spell_id++, book_slot = initiator->GetNextAvailableSpellBookSlot(book_slot))
+	const auto sbs = EQEmu::spells::DynamicLookup(initiator->ClientVersion(), initiator->GetGM())->SpellbookSize;
+	for (
+		spell_id = 0,
+		book_slot = initiator->GetNextAvailableSpellBookSlot(),
+		count = 0; // ;
+		spell_id < SPDAT_RECORDS &&
+		book_slot < sbs; // ;
+		spell_id++,
+		book_slot = initiator->GetNextAvailableSpellBookSlot(book_slot)
+	)
 	{
 		if
 		(
diff --git a/zone/spells.cpp b/zone/spells.cpp
index c88522a5..5e1ccfdb 100644
--- a/zone/spells.cpp
+++ b/zone/spells.cpp
@@ -5025,7 +5025,7 @@ void Client::UnmemSpellAll(bool update_client)
 
 void Client::ScribeSpell(uint16 spell_id, int slot, bool update_client)
 {
-	if(slot >= EQEmu::spells::SPELLBOOK_SIZE || slot < 0)
+	if(slot >= EQEmu::spells::DynamicLookup(ClientVersion(), GetGM())->SpellbookSize || slot < 0)
 		return;
 
 	if(update_client)
@@ -5046,7 +5046,7 @@ void Client::ScribeSpell(uint16 spell_id, int slot, bool update_client)
 
 void Client::UnscribeSpell(int slot, bool update_client)
 {
-	if(slot >= EQEmu::spells::SPELLBOOK_SIZE || slot < 0)
+	if(slot >= EQEmu::spells::DynamicLookup(ClientVersion(), GetGM())->SpellbookSize || slot < 0)
 		return;
 
 	Log(Logs::Detail, Logs::Spells, "Spell %d erased from spell book slot %d", m_pp.spell_book[slot], slot);
@@ -5066,9 +5066,8 @@ void Client::UnscribeSpell(int slot, bool update_client)
 
 void Client::UnscribeSpellAll(bool update_client)
 {
-	int i;
-
-	for(i = 0; i < EQEmu::spells::SPELLBOOK_SIZE; i++)
+	const auto sbs = EQEmu::spells::DynamicLookup(ClientVersion(), GetGM())->SpellbookSize;
+	for(int i = 0; i < sbs; i++)
 	{
 		if(m_pp.spell_book[i] != 0xFFFFFFFF)
 			UnscribeSpell(i, update_client);
@@ -5102,7 +5101,8 @@ void Client::UntrainDiscAll(bool update_client)
 }
 
 int Client::GetNextAvailableSpellBookSlot(int starting_slot) {
-	for (int i = starting_slot; i < EQEmu::spells::SPELLBOOK_SIZE; i++) {	//using starting_slot should help speed this up when we're iterating through a bunch of spells
+	const auto sbs = EQEmu::spells::DynamicLookup(ClientVersion(), GetGM())->SpellbookSize;
+	for (int i = starting_slot; i < sbs; i++) {	//using starting_slot should help speed this up when we're iterating through a bunch of spells
 		if (!IsValidSpell(GetSpellByBookSlot(i)))
 			return i;
 	}
@@ -5111,7 +5111,8 @@ int Client::GetNextAvailableSpellBookSlot(int starting_slot) {
 }
 
 int Client::FindSpellBookSlotBySpellID(uint16 spellid) {
-	for(int i = 0; i < EQEmu::spells::SPELLBOOK_SIZE; i++) {
+	const auto sbs = EQEmu::spells::DynamicLookup(ClientVersion(), GetGM())->SpellbookSize;
+	for(int i = 0; i < sbs; i++) {
 		if(m_pp.spell_book[i] == spellid)
 			return i;
 	}
diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp
index 078fc7a4..bc33ba0e 100644
--- a/zone/zonedb.cpp
+++ b/zone/zonedb.cpp
@@ -1225,17 +1225,21 @@ bool ZoneDatabase::LoadCharacterSpellBook(uint32 character_id, PlayerProfile_Str
 		"`character_spells`		"
 		"WHERE `id` = %u ORDER BY `slot_id`", character_id);
 	auto results = database.QueryDatabase(query);
-	int i = 0;
+	
 	/* Initialize Spells */
-	for (i = 0; i < EQEmu::spells::SPELLBOOK_SIZE; i++){
-		pp->spell_book[i] = 0xFFFFFFFF;
-	}
+	
+	memset(pp->spell_book, 0xFF, (sizeof(uint32) * EQEmu::spells::SPELLBOOK_SIZE));
+
+	const auto sbs = EQEmu::spells::DynamicLookup(EQEmu::versions::ConvertMobVersionToClientVersion(pp->PlayerProfileVersion()), (pp->gm != 0))->SpellbookSize;
+	const auto smid = EQEmu::spells::DynamicLookup(EQEmu::versions::ConvertMobVersionToClientVersion(pp->PlayerProfileVersion()), (pp->gm != 0))->SpellbookSize;
 	for (auto row = results.begin(); row != results.end(); ++row) {
-		i = atoi(row[0]);
-		if (i < EQEmu::spells::SPELLBOOK_SIZE && atoi(row[1]) <= SPDAT_RECORDS){
-			pp->spell_book[i] = atoi(row[1]);
+		int idx = atoi(row[0]);
+		int id = atoi(row[1]);
+		if (idx < sbs && id <= smid && id <= SPDAT_RECORDS){
+			pp->spell_book[idx] = id;
 		}
 	}
+
 	return true;
 }
 

Raw Paste Data