Browse Source

Support for knowledge book sorting, begins resolution for issue #48

Requires SQL update:
update commands set handler=511 where command='knowledgewindow_sort';

- Support for ordering knowledge books by alphabetical, category, and level.  There is some quirky sorting if you try sorting multiple times on category/level, to be addressed.

MaxLevel only checkbox is not implemented
patterns are not implemented
Image 3 years ago
parent
commit
ad3e0ba069

+ 16 - 0
EQ2/source/WorldServer/Commands/Commands.cpp

@@ -2704,6 +2704,22 @@ void Commands::Process(int32 index, EQ2_16BitString* command_parms, Client* clie
 			}
 			break;
 		}
+		case COMMAND_KNOWLEDGEWINDOWSORT: {
+			if (sep && sep->GetArgNumber() == 4)
+			{
+				int32 book = atoul(sep->arg[0]); // 0 - spells, 1 - combat, 2 - abilities, 3 - tradeskill
+				int32 sort_by = atoul(sep->arg[1]); // 0 - alpha, 1 - level, 2 - category
+				int32 order = atoul(sep->arg[2]); // 0 - ascending, 1 - descending
+				int32 pattern = atoul(sep->arg[3]); // 0 - zigzag, 1 - down, 2 - across
+				client->GetPlayer()->ResortSpellBook(sort_by, order, pattern, book);
+				ClientPacketFunctions::SendSkillSlotMappings(client);
+			}
+			else
+			{
+				client->Message(CHANNEL_COLOR_YELLOW, "Syntax: /knowledgewindow_sort [book] [sort_by] [order] [pattern]");
+			}
+			break;
+		}
 		case COMMAND_ATTACK:
 		case COMMAND_AUTO_ATTACK:{
 			int8 type = 1;

+ 1 - 0
EQ2/source/WorldServer/Commands/Commands.h

@@ -873,6 +873,7 @@ private:
 #define COMMAND_OPEN					508
 #define COMMAND_CASTSPELL				509
 #define COMMAND_DISARM					510
+#define COMMAND_KNOWLEDGEWINDOWSORT		511
 
 #define GET_AA_XML						751
 #define ADD_AA							752

+ 132 - 10
EQ2/source/WorldServer/Player.cpp

@@ -1986,6 +1986,7 @@ void Player::AddSpellBookEntry(int32 spell_id, int8 tier, sint32 slot, int32 typ
 	spell->save_needed = save_needed;
 	spell->recast = 0;
 	spell->recast_available = 0;
+	spell->player = this;
 	MSpellsBook.lock();
 	spells.push_back(spell);
 	MSpellsBook.unlock();
@@ -2010,6 +2011,127 @@ void Player::RemoveSpellBookEntry(int32 spell_id, bool remove_passives_from_list
 	MSpellsBook.unlock();
 }
 
+void Player::ResortSpellBook(int32 sort_by, int32 order, int32 pattern, int32 book_type)
+{
+	//sort_by : 0 - alpha, 1 - level, 2 - category
+	//order : 0 - ascending, 1 - descending
+	//pattern : 0 - zigzag, 1 - down, 2 - across
+	MSpellsBook.lock();
+	switch (sort_by)
+	{
+	case 0:
+		if (!order)
+			stable_sort(spells.begin(), spells.end(), SortSpellEntryByName);
+		else
+			stable_sort(spells.begin(), spells.end(), SortSpellEntryByNameReverse);
+		break;
+	case 1:
+		if (!order)
+			stable_sort(spells.begin(), spells.end(), SortSpellEntryByLevel);
+		else
+			stable_sort(spells.begin(), spells.end(), SortSpellEntryByLevelReverse);
+		break;
+	case 2:
+		if (!order)
+			stable_sort(spells.begin(), spells.end(), SortSpellEntryByCategory);
+		else
+			stable_sort(spells.begin(), spells.end(), SortSpellEntryByCategoryReverse);
+		break;
+	}
+
+	vector<SpellBookEntry*>::iterator itr;
+	SpellBookEntry* spell = 0;
+	int i = 0;
+	for (itr = spells.begin(); itr != spells.end(); itr++) {
+		spell = *itr;
+
+		if (spell->type != book_type || spell->slot == -1)
+			continue;
+
+		spell->slot = i;
+		i++;
+	}
+	MSpellsBook.unlock();
+}
+
+bool Player::SortSpellEntryByName(SpellBookEntry* s1, SpellBookEntry* s2)
+{
+	Spell* spell1 = master_spell_list.GetSpell(s1->spell_id, s1->tier);
+	Spell* spell2 = master_spell_list.GetSpell(s2->spell_id, s2->tier);
+
+	if (!spell1 || !spell2)
+		return false;
+
+	return (string(spell1->GetName()) < string(spell2->GetName()));
+}
+
+bool Player::SortSpellEntryByCategory(SpellBookEntry* s1, SpellBookEntry* s2)
+{
+	Spell* spell1 = master_spell_list.GetSpell(s1->spell_id, s1->tier);
+	Spell* spell2 = master_spell_list.GetSpell(s2->spell_id, s2->tier);
+
+	if (!spell1 || !spell2)
+		return false;
+
+	return (spell1->GetSpellIconBackdrop() < spell2->GetSpellIconBackdrop());
+}
+
+bool Player::SortSpellEntryByLevel(SpellBookEntry* s1, SpellBookEntry* s2)
+{
+	Spell* spell1 = master_spell_list.GetSpell(s1->spell_id, s1->tier);
+	Spell* spell2 = master_spell_list.GetSpell(s2->spell_id, s2->tier);
+
+	if (!spell1 || !spell2)
+		return false;
+
+	int16 lvl1 = spell1->GetLevelRequired(s1->player);
+	int16 lvl2 = spell2->GetLevelRequired(s2->player);
+	if (lvl1 == 0xFFFF)
+		lvl1 = 0;
+	if (lvl2 == 0xFFFF)
+		lvl2 = 0;
+
+	return (lvl1 < lvl2);
+}
+
+bool Player::SortSpellEntryByNameReverse(SpellBookEntry* s1, SpellBookEntry* s2)
+{
+	Spell* spell1 = master_spell_list.GetSpell(s1->spell_id, s1->tier);
+	Spell* spell2 = master_spell_list.GetSpell(s2->spell_id, s2->tier);
+
+	if (!spell1 || !spell2)
+		return false;
+
+	return (string(spell2->GetName()) < string(spell1->GetName()));
+}
+
+bool Player::SortSpellEntryByCategoryReverse(SpellBookEntry* s1, SpellBookEntry* s2)
+{
+	Spell* spell1 = master_spell_list.GetSpell(s1->spell_id, s1->tier);
+	Spell* spell2 = master_spell_list.GetSpell(s2->spell_id, s2->tier);
+	if (!spell1 || !spell2)
+		return false;
+	return (spell2->GetSpellIconBackdrop() < spell1->GetSpellIconBackdrop());
+}
+
+bool Player::SortSpellEntryByLevelReverse(SpellBookEntry* s1, SpellBookEntry* s2)
+{
+	Spell* spell1 = master_spell_list.GetSpell(s1->spell_id, s1->tier);
+	Spell* spell2 = master_spell_list.GetSpell(s2->spell_id, s2->tier);
+
+	if (!spell1 || !spell2)
+		return false;
+
+	int16 lvl1 = spell1->GetLevelRequired(s1->player);
+	int16 lvl2 = spell2->GetLevelRequired(s2->player);
+	if (lvl1 == 0xFFFF)
+		lvl1 = 0;
+	if (lvl2 == 0xFFFF)
+		lvl2 = 0;
+
+	return (lvl2 < lvl1);
+}
+
 int8 Player::GetSpellSlot(int32 spell_id){
 	MSpellsBook.lock();
 	vector<SpellBookEntry*>::iterator itr;
@@ -2349,22 +2471,22 @@ EQ2Packet* Player::GetSpellBookUpdatePacket(int16 version){
 
 		if(count > 0){
 			packet->setArrayLengthByName("spell_count", count);
-			if(count > spell_count){
+			if (count > spell_count) {
 				uchar* tmp = 0;
-				if(spell_orig_packet){
-					tmp = new uchar[count*total_bytes];
-					memset(tmp, 0, total_bytes*count);
-					memcpy(tmp, spell_orig_packet, spell_count*total_bytes);
+				if (spell_orig_packet) {
+					tmp = new uchar[count * total_bytes];
+					memset(tmp, 0, total_bytes * count);
+					memcpy(tmp, spell_orig_packet, spell_count * total_bytes);
 					safe_delete_array(spell_orig_packet);
 					safe_delete_array(spell_xor_packet);
 					spell_orig_packet = tmp;
 				}
-				else{
-					spell_orig_packet = new uchar[count*total_bytes];
-					memset(spell_orig_packet, 0, total_bytes*count);
+				else {
+					spell_orig_packet = new uchar[count * total_bytes];
+					memset(spell_orig_packet, 0, total_bytes * count);
 				}
-				spell_xor_packet = new uchar[count*total_bytes];
-				memset(spell_xor_packet, 0, count*total_bytes);
+				spell_xor_packet = new uchar[count * total_bytes];
+				memset(spell_xor_packet, 0, count * total_bytes);
 				spell_count = count;
 			}
 			MSpellsBook.lock();

+ 10 - 0
EQ2/source/WorldServer/Player.h

@@ -161,6 +161,7 @@ struct SpellBookEntry{
 	int16	recast;
 	int32	timer;
 	bool	save_needed;
+	Player* player;
 };
 
 #define QUICKBAR_NORMAL		1
@@ -686,6 +687,15 @@ public:
 	void				SetPendingCollectionReward(Collection *collection) { pending_collection_reward = collection; }
 	Collection *		GetPendingCollectionReward() { return pending_collection_reward; }
 	void RemoveSpellBookEntry(int32 spell_id, bool remove_passives_from_list = true);
+	void ResortSpellBook(int32 sort_by, int32 order, int32 pattern, int32 book_type);
+
+	static bool SortSpellEntryByName(SpellBookEntry* s1, SpellBookEntry* s2);
+	static bool SortSpellEntryByCategory(SpellBookEntry* s1, SpellBookEntry* s2);
+	static bool SortSpellEntryByLevel(SpellBookEntry* s1, SpellBookEntry* s2);
+	static bool SortSpellEntryByNameReverse(SpellBookEntry* s1, SpellBookEntry* s2);
+	static bool SortSpellEntryByCategoryReverse(SpellBookEntry* s1, SpellBookEntry* s2);
+	static bool SortSpellEntryByLevelReverse(SpellBookEntry* s1, SpellBookEntry* s2);
+
 	int8 GetSpellSlot(int32 spell_id);
 	void				AddTitle(int32 title_id, const char *name, int8 prefix, bool save_needed = false);
 	void				AddAAEntry(int16 template_id, int8 tab_id, int32 aa_id, int16 order, int8 treeid);

+ 6 - 6
EQ2/source/WorldServer/Spells.cpp

@@ -148,15 +148,15 @@ void Spell::AddSpellLuaDataString(string value, string value2,string helper) {
 	MSpellInfo.unlock();
 }
 
-int16 Spell::GetLevelRequired(Client* client){
+int16 Spell::GetLevelRequired(Player* player){
 	int16 ret = 0xFFFF;
-	if(!client)
+	if(!player)
 		return ret;
 	LevelArray* level = 0;
 	vector<LevelArray*>::iterator itr;
 	for(itr = levels.begin(); itr != levels.end(); itr++){
 		level = *itr;
-		if(level && level->adventure_class == client->GetPlayer()->GetAdventureClass()){
+		if(level && level->adventure_class == player->GetAdventureClass()){
 			ret = level->spell_level/10;
 			break;
 		}
@@ -208,7 +208,7 @@ void Spell::SetAAPacketInformation(PacketStruct* packet, AltAdvanceData* data, C
 
 
 		if (client && spell->type != 2) {
-			sint8 spell_text_color = client->GetPlayer()->GetArrowColor(GetLevelRequired(client));
+			sint8 spell_text_color = client->GetPlayer()->GetArrowColor(GetLevelRequired(client->GetPlayer()));
 			if (spell_text_color != ARROW_COLOR_WHITE && spell_text_color != ARROW_COLOR_RED && spell_text_color != ARROW_COLOR_GRAY)
 				spell_text_color = ARROW_COLOR_WHITE;
 			spell_text_color -= 6;
@@ -408,7 +408,7 @@ void Spell::SetAAPacketInformation(PacketStruct* packet, AltAdvanceData* data, C
 		packet->setSubstructDataByName("spell_info", "next_mastery_skill", spell2->mastery_skill);
 		packet->setSubstructDataByName("spell_info", "next_duration_flag", spell2->duration_until_cancel);
 		if (client && spell->type != 2) {
-			sint8 spell_text_color = client->GetPlayer()->GetArrowColor(GetLevelRequired(client));
+			sint8 spell_text_color = client->GetPlayer()->GetArrowColor(GetLevelRequired(client->GetPlayer()));
 			if (spell_text_color != ARROW_COLOR_WHITE && spell_text_color != ARROW_COLOR_RED && spell_text_color != ARROW_COLOR_GRAY)
 				spell_text_color = ARROW_COLOR_WHITE;
 			spell_text_color -= 6;
@@ -592,7 +592,7 @@ void Spell::SetAAPacketInformation(PacketStruct* packet, AltAdvanceData* data, C
 		packet->setSubstructDataByName("spell_info", "mastery_skill", spell->mastery_skill);
 		packet->setSubstructDataByName("spell_info", "duration_flag", spell->duration_until_cancel);
 		if (client && spell->type != 2) {
-			sint8 spell_text_color = client->GetPlayer()->GetArrowColor(GetLevelRequired(client));
+			sint8 spell_text_color = client->GetPlayer()->GetArrowColor(GetLevelRequired(client->GetPlayer()));
 			if (spell_text_color != ARROW_COLOR_WHITE && spell_text_color != ARROW_COLOR_RED && spell_text_color != ARROW_COLOR_GRAY)
 				spell_text_color = ARROW_COLOR_WHITE;
 			spell_text_color -= 6;

+ 1 - 1
EQ2/source/WorldServer/Spells.h

@@ -306,7 +306,7 @@ public:
 	int16 GetSpellIcon();
 	int16 GetSpellIconBackdrop();
 	int16 GetSpellIconHeroicOp();
-	int16 GetLevelRequired(Client* client);
+	int16 GetLevelRequired(Player* player);
 	int16 GetHPRequired(Spawn* spawn);
 	int16 GetPowerRequired(Spawn* spawn);
 	int16 GetSavageryRequired(Spawn* spawn);