Browse Source

- Reward / Temp Reward now stack count by item id when putting in player inventory, not single item
* Current caveat is the display in the reward box shows them as individual items, the count display was not working.
- Crash fix for Client::GetPendingQuestAcceptance, accepting quest reward after deleting quest
- Addressed temporary quest reward continuously trying to assign reward when quest was deleted
- Fixed sql escape issue with GM /castspell search_string

Emagi 1 year ago
parent
commit
40b156387a

+ 35 - 29
EQ2/source/WorldServer/Quests.cpp

@@ -886,32 +886,11 @@ EQ2Packet* Quest::OfferQuest(int16 version, Player* player){
 		if(reward_comment.length() > 0)
 			packet->setDataByName("text", reward_comment.c_str());
 		if(reward_items.size() > 0){
-			packet->setArrayLengthByName("num_rewards", reward_items.size());
-			Item* item = 0;
-			for(int32 i=0;i<reward_items.size();i++){
-				item = reward_items[i];
-				packet->setArrayDataByName("reward_id", item->details.item_id, i);
-				if(version < 860)
-					packet->setItemArrayDataByName("item", item, player, i, 0, -1);
-				else if (version < 1193)
-					packet->setItemArrayDataByName("item", item, player, i);
-				else
-					packet->setItemArrayDataByName("item", item, player, i, 0, 2);
-			}
+			player->GetClient()->PopulateQuestRewardItems(&reward_items, packet);
 		}
 		if(selectable_reward_items.size() > 0){
-			packet->setArrayLengthByName("num_select_rewards", selectable_reward_items.size());
-			Item* item = 0;
-			for(int32 i=0;i<selectable_reward_items.size();i++){
-				item = selectable_reward_items[i];
-				packet->setArrayDataByName("select_reward_id", item->details.item_id, i);
-				if(version < 860)
-					packet->setItemArrayDataByName("select_item", item, player, i, 0, -1);
-				else if (version < 1193)
-					packet->setItemArrayDataByName("select_item", item, player, i);
-				else
-					packet->setItemArrayDataByName("select_item", item, player, i, 0, 2);
-			}
+			player->GetClient()->PopulateQuestRewardItems(&selectable_reward_items, packet, std::string("num_select_rewards"), 
+										std::string("select_reward_id"), std::string("select_item"));
 		}
 		map<int32, sint32>* reward_factions = GetRewardFactions();
 		if (reward_factions && reward_factions->size() > 0) {
@@ -1462,23 +1441,50 @@ void Quest::AddPrereqItem(Item* item){
 	prereq_items.push_back(item);
 }
 
+void Quest::AddRewardItemVec(vector<Item*>* items, Item* item, bool combine_items) {
+	if(!items || !item)
+		return;
+	
+	bool stacked = false;
+
+	if(combine_items) {
+		for(int32 i=0;i<items->size();i++) {
+			Item* cur_item = (Item*)items->at(i);
+			if(cur_item->stack_count > 1) {
+				if(cur_item->details.item_id == item->details.item_id && cur_item->details.count+1 < cur_item->stack_count) {
+					if(!cur_item->details.count) // sometimes the count is 0, so we want it to be 2 now
+						cur_item->details.count = 2;
+					else
+						cur_item->details.count += 1;
+					stacked = true;
+					break;
+				}
+			}
+		}
+	}
+	
+	if(!stacked) {
+		items->push_back(item);
+	}
+}
+
 void Quest::AddSelectableRewardItem(Item* item){
-	selectable_reward_items.push_back(item);
+	AddRewardItemVec(&selectable_reward_items, item, false);
 }
 
 void Quest::AddRewardItem(Item* item){
-	reward_items.push_back(item);
+	AddRewardItemVec(&reward_items, item);
 }
 
 void Quest::AddTmpRewardItem(Item* item){
-	tmp_reward_items.push_back(item);
+	AddRewardItemVec(&tmp_reward_items, item);
 }
 
-void Quest::GetTmpRewardItemsByID(std::vector<int32>* items) {
+void Quest::GetTmpRewardItemsByID(std::vector<Item*>* items) {
 	if(!items)
 		return;
 	for(int32 i=0;i<tmp_reward_items.size();i++)
-		items->push_back(tmp_reward_items[i]->details.item_id);
+		items->push_back(tmp_reward_items[i]);
 }
 
 void Quest::AddRewardCoins(int32 copper, int32 silver, int32 gold, int32 plat){

+ 2 - 1
EQ2/source/WorldServer/Quests.h

@@ -140,7 +140,8 @@ public:
 
 	void				AddRewardItem(Item* item);
 	void				AddTmpRewardItem(Item* item);
-	void				GetTmpRewardItemsByID(std::vector<int32>* items);
+	void				GetTmpRewardItemsByID(std::vector<Item*>* items);
+	void				AddRewardItemVec(vector<Item*>* items, Item* item, bool combine_items = true);
 	void				AddSelectableRewardItem(Item* item);
 	void				AddRewardCoins(int32 copper, int32 silver, int32 gold, int32 plat);
 	void                AddRewardCoinsMax(int64 coins);

+ 11 - 4
EQ2/source/WorldServer/WorldDatabase.cpp

@@ -1892,7 +1892,7 @@ void WorldDatabase::LoadCharacterQuestRewards(Client* client) {
 void WorldDatabase::LoadCharacterQuestTemporaryRewards(Client* client, int32 quest_id) {
 		Query query;
 	MYSQL_ROW row;
-	MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT item_id FROM character_quest_temporary_rewards where char_id = %u and quest_id = %u", client->GetCharacterID(), quest_id);
+	MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT item_id, count FROM character_quest_temporary_rewards where char_id = %u and quest_id = %u", client->GetCharacterID(), quest_id);
 	int8 count = 0;
 	if(result)
 	{
@@ -1903,7 +1903,9 @@ void WorldDatabase::LoadCharacterQuestTemporaryRewards(Client* client, int32 que
 			if(quest) {
 				Item* item = master_item_list.GetItem(item_id);
 				if(item) {
-					quest->AddTmpRewardItem(new Item(item));
+					Item* tmpItem = new Item(item);
+					tmpItem->details.count = atoul(row[1]);
+					quest->AddTmpRewardItem(tmpItem);
 				}
 			}
 		}
@@ -7206,13 +7208,16 @@ void WorldDatabase::LoadCharacterLUAHistory(int32 char_id, Player* player) {
 
 void WorldDatabase::FindSpell(Client* client, char* findString)
 {
+	
+	char* find_escaped = getEscapeString(findString);
+	
 	DatabaseResult result;
 		if (!database_new.Select(&result, "SELECT s.`id`, ts.spell_id, ts.index, `name`, `tier` "
 			"FROM (spells s, spell_tiers st) "
 			"LEFT JOIN spell_ts_ability_index ts "
 			"ON s.`id` = ts.spell_id "
 			"WHERE s.id = st.spell_id and s.name like '%%%s%%' AND s.is_active = 1 "
-			"ORDER BY s.`id`, `tier` limit 50", findString))
+			"ORDER BY s.`id`, `tier` limit 50", find_escaped))
 		{
 			// error
 		}
@@ -7226,8 +7231,10 @@ void WorldDatabase::FindSpell(Client* client, char* findString)
 				int8 tier = result.GetInt8Str("tier");
 				client->Message(CHANNEL_COLOR_YELLOW, "%i (%i): %s", spell_id, tier, spell_name.c_str());
 			}
-			client->Message(CHANNEL_COLOR_YELLOW, "End Spell Results for %s", findString);
+			client->Message(CHANNEL_COLOR_YELLOW, "End Spell Results for %s", find_escaped);
 		}
+		
+	safe_delete_array(find_escaped);
 }
 
 void WorldDatabase::LoadChestTraps() {

+ 67 - 48
EQ2/source/WorldServer/client.cpp

@@ -5613,7 +5613,8 @@ void Client::ProcessQuestUpdates() {
 		tmp_quest_rewards.insert(tmp_quest_rewards.begin(), quest_pending_reward.begin(), quest_pending_reward.begin()+1);
 		MQuestPendingUpdates.releasewritelock(__FUNCTION__, __LINE__);
 		
-		for (itr = tmp_quest_rewards.begin(); itr != tmp_quest_rewards.end(); itr++) {
+		bool delete_first = false;
+		for (itr = tmp_quest_rewards.begin(); itr != tmp_quest_rewards.end();) {
 			int32 questID = (*itr)->quest_id;
 			Quest* quest = 0;
 			if((*itr)->is_collection && GetPlayer()->GetPendingCollectionReward()) {
@@ -5622,6 +5623,7 @@ void Client::ProcessQuestUpdates() {
 				(*itr)->has_displayed = true;
 				
 				UpdateCharacterRewardData((*itr));
+				break;
 			}
 			else if(questID > 0 && (quest = GetPlayer()->GetAnyQuest(questID))) {
 				quest->SetQuestTemporaryState((*itr)->is_temporary, (*itr)->description);
@@ -5637,7 +5639,13 @@ void Client::ProcessQuestUpdates() {
 				// only able to display one reward at a time
 				break;
 			} else {
-				LogWrite(CCLIENT__ERROR, 0, "Client", "Quest ID %u missing for Player %s, skipping quest id from tmp_quest_rewards.", questID, GetPlayer()->GetName());
+				delete_first = true;
+				LogWrite(CCLIENT__ERROR, 0, "Client", "Quest ID %u missing for Player %s, deleting quest id from tmp_quest_rewards.", questID, GetPlayer()->GetName());
+				break;
+			}
+			
+			if(delete_first) {
+				RemoveQueuedQuestReward();
 			}
 		}
 	} else {
@@ -6039,12 +6047,12 @@ Quest* Client::GetPendingQuestAcceptance(int32 item_id) {
 	int32 questID = 0;
 	Quest* quest = 0;
 	MPendingQuestAccept.lock();
-	for (itr = pending_quest_accept.begin(); itr != pending_quest_accept.end(); itr++) {
+	for (itr = pending_quest_accept.begin(); itr != pending_quest_accept.end();) {
 		questID = *itr;
 		quest = GetPlayer()->GetAnyQuest(questID);
 		if(!quest) {
 			LogWrite(CCLIENT__ERROR, 0, "Client", "Quest ID %u missing for Player %s, removing quest id from pending_quest_accept.", questID, GetPlayer()->GetName());
-			pending_quest_accept.erase(itr);
+			itr = pending_quest_accept.erase(itr);
 			continue;
 		}
 		if(quest->GetQuestTemporaryState())
@@ -6069,6 +6077,8 @@ Quest* Client::GetPendingQuestAcceptance(int32 item_id) {
 			pending_quest_accept.erase(itr);
 			break;
 		}
+		
+		itr++;
 	}
 	MPendingQuestAccept.unlock();
 
@@ -6264,6 +6274,50 @@ void Client::DisplayQuestRewards(Quest* quest, int64 coin, vector<Item*>* reward
 	}
 }
 
+void Client::PopulateQuestRewardItems(vector <Item*>* items, PacketStruct* packet, 
+										std::string num_rewards_str, std::string reward_id_str, std::string item_str) {
+	if(!items || !packet)
+		return;
+	
+	if (items) {
+		int32 total_item_count = 0;
+		for(int s=0;s<items->size();s++) {
+			Item* tmpItem = items->at(s);
+			if(tmpItem) {
+				if(tmpItem->details.count > 1) {
+					total_item_count += tmpItem->details.count;
+				}
+				else {
+					total_item_count += 1;
+				}
+			}
+		}
+		packet->setArrayLengthByName(num_rewards_str.c_str(), total_item_count);
+		int16 count = 0;
+		int16 pos = 0;
+		for (int32 i = 0; i < items->size();) {
+			packet->setArrayDataByName(reward_id_str.c_str(), items->at(i)->details.item_id, pos);
+			if (version < 860)
+				packet->setItemArrayDataByName(item_str.c_str(), items->at(i), player, pos, 0, -1);
+			else if (version < 1193)
+				packet->setItemArrayDataByName(item_str.c_str(), items->at(i), player, pos);
+			else
+				packet->setItemArrayDataByName(item_str.c_str(), items->at(i), player, pos, 0, 2);
+			
+			pos++;
+			
+			if(count >= items->at(i)->details.count-1) {
+				count = 0;
+			}
+			else if(items->at(i)->details.count > 1) {
+				count++;
+				continue;
+			}
+			
+			i++;
+		}
+	}
+}
 void Client::DisplayQuestComplete(Quest* quest, bool tempReward, std::string customDescription, bool was_displayed) {	
 	if (!quest)
 		return;
@@ -6313,51 +6367,16 @@ void Client::DisplayQuestComplete(Quest* quest, bool tempReward, std::string cus
 			packet->setDataByName("status_points", quest->GetStatusPoints());
 		}
 
-		vector<Item*>* items = quest->GetTmpRewardItems();
-
-		if(tempReward)
-		{
-			if (items) {
-				packet->setArrayLengthByName("num_rewards", items->size());
-				for (int32 i = 0; i < items->size(); i++) {
-					packet->setArrayDataByName("reward_id", items->at(i)->details.item_id, i);
-					if (version < 860)
-						packet->setItemArrayDataByName("item", items->at(i), player, i, 0, -1);
-					else if (version < 1193)
-						packet->setItemArrayDataByName("item", items->at(i), player, i);
-					else
-						packet->setItemArrayDataByName("item", items->at(i), player, i, 0, 2);
-				}
-			}
+		if(tempReward) {
+			PopulateQuestRewardItems(quest->GetTmpRewardItems(), packet);
 		}
 		else
 		{
 			vector<Item*>* items2 = quest->GetSelectableRewardItems();
-			vector<Item*>* items = quest->GetRewardItems();
-			if (items) {
-				packet->setArrayLengthByName("num_rewards", items->size());
-				for (int32 i = 0; i < items->size(); i++) {
-					packet->setArrayDataByName("reward_id", items->at(i)->details.item_id, i);
-					if (version < 860)
-						packet->setItemArrayDataByName("item", items->at(i), player, i, 0, -1);
-					else if (version < 1193)
-						packet->setItemArrayDataByName("item", items->at(i), player, i);
-					else
-						packet->setItemArrayDataByName("item", items->at(i), player, i, 0, 2);
-				}
-			}
-			if (items2 && items2->size() > 0) {
-				packet->setArrayLengthByName("num_select_rewards", items2->size());
-				for (int32 i = 0; i < items2->size(); i++) {
-					packet->setArrayDataByName("select_reward_id", items2->at(i)->details.item_id, i);
-					if (version < 860)
-						packet->setItemArrayDataByName("select_item", items2->at(i), player, i, 0, -1);
-					else if (version < 1193)
-						packet->setItemArrayDataByName("select_item", items2->at(i), player, i);
-					else
-						packet->setItemArrayDataByName("select_item", items2->at(i), player, i, 0, 2);
-				}
-			}
+			PopulateQuestRewardItems(quest->GetRewardItems(), packet);
+			PopulateQuestRewardItems(quest->GetSelectableRewardItems(), packet, std::string("num_select_rewards"), 
+										std::string("select_reward_id"), std::string("select_item"));
+			
 			map<int32, sint32>* reward_factions = quest->GetRewardFactions();
 			if (reward_factions && reward_factions->size() > 0) {
 				packet->setArrayLengthByName("num_factions", reward_factions->size());
@@ -11290,7 +11309,7 @@ void Client::SaveQuestRewardData(bool force_refresh) {
 				(*itr)->db_saved = true;
 				(*itr)->db_index = index;
 				if((*itr)->is_temporary) {
-					std::vector<int32> items;
+					std::vector<Item*> items;
 					Quest* quest = GetPlayer()->GetAnyQuest(questID);
 					if(quest) {
 						quest->GetTmpRewardItemsByID(&items);
@@ -11299,8 +11318,8 @@ void Client::SaveQuestRewardData(bool force_refresh) {
 								GetCharacterID(), questID);
 						}
 						for(int i=0;i<items.size();i++) {
-							query.AddQueryAsync(GetCharacterID(), &database, Q_REPLACE, "replace into character_quest_temporary_rewards (char_id, quest_id, item_id) values(%u, %u, %u)", 
-								GetCharacterID(), questID, items[i]);
+							query.AddQueryAsync(GetCharacterID(), &database, Q_REPLACE, "replace into character_quest_temporary_rewards (char_id, quest_id, item_id, count) values(%u, %u, %u, %u)", 
+								GetCharacterID(), questID, items[i]->details.item_id, items[i]->details.count);
 						}
 					}
 				}

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

@@ -296,6 +296,7 @@ public:
 	void	SendQuestUpdateStep(Quest* quest, int32 step, bool display_quest_helper = true);
 	void	SendQuestUpdateStepImmediately(Quest* quest, int32 step, bool display_quest_helper = true);
 	void	DisplayQuestRewards(Quest* quest, int64 coin, vector<Item*>* rewards=0, vector<Item*>* selectable_rewards=0, map<int32, sint32>* factions=0, const char* header="Quest Reward!", int32 status_points=0, const char* text=0, bool was_displayed = false);
+	void	PopulateQuestRewardItems(vector <Item*>* items, PacketStruct* packet, std::string num_rewards_str = "num_rewards", std::string reward_id_str = "reward_id" , std::string item_str = "item");
 	void	DisplayQuestComplete(Quest* quest, bool tempReward = false, std::string customDescription = string(""), bool was_displayed = false);
 	void	DisplayRandomizeFeatures(int32 features);
 	void	AcceptQuestReward(Quest* quest, int32 item_id);

+ 2 - 0
EQ2/source/common/EQStream.cpp

@@ -457,7 +457,9 @@ void EQStream::ProcessPacket(EQProtocolPacket *p, EQProtocolPacket* lastp)
 					NextInSeq++;
 					
 					if(crypto->getRC4Key()==0 && p && p->size >= 69){
+					#ifdef DEBUG_EMBEDDED_PACKETS
 						DumpPacket(p->pBuffer, p->size);
+					#endif
 						processRSAKey(p);
 						break;
 					}