Przeglądaj źródła

Fix #509 - quest crash cleanup, AddHate fixed for non spell function cal, fixed all quests being hidden in journal, reduced time to update quest journal from 300ms to 50ms

Emagi 1 rok temu
rodzic
commit
7299addd47

+ 7 - 46
EQ2/source/WorldServer/Commands/Commands.cpp

@@ -2107,7 +2107,7 @@ void Commands::Process(int32 index, EQ2_16BitString* command_parms, Client* clie
 							lua_interface->RunItemScript(item->GetItemScript(), "examined", item, client->GetPlayer());
 							lua_interface->RunItemScript(item->GetItemScript(), "examined", item, client->GetPlayer());
 						else if(item->generic_info.offers_quest_id > 0){ //leave the current functionality in place if it doesnt have an item script
 						else if(item->generic_info.offers_quest_id > 0){ //leave the current functionality in place if it doesnt have an item script
 							Quest* quest = master_quest_list.GetQuest(item->generic_info.offers_quest_id, false);
 							Quest* quest = master_quest_list.GetQuest(item->generic_info.offers_quest_id, false);
-							if(quest && client->GetPlayer()->GetCompletedQuest(item->generic_info.offers_quest_id) == 0 && client->GetPlayer()->GetQuest(item->generic_info.offers_quest_id) == 0)
+							if(quest && client->GetPlayer()->HasQuestBeenCompleted(item->generic_info.offers_quest_id) == 0 && client->GetPlayer()->HasActiveQuest(item->generic_info.offers_quest_id) == 0)
 								client->AddPendingQuest(new Quest(quest)); // copy quest since we pulled the master quest to see if it existed or not
 								client->AddPendingQuest(new Quest(quest)); // copy quest since we pulled the master quest to see if it existed or not
 						}
 						}
 					}
 					}
@@ -3033,15 +3033,7 @@ void Commands::Process(int32 index, EQ2_16BitString* command_parms, Client* clie
 			if(sep && sep->arg[0] && sep->IsNumber(0))
 			if(sep && sep->arg[0] && sep->IsNumber(0))
 				quest_id = atoul(sep->arg[0]);
 				quest_id = atoul(sep->arg[0]);
 			if(quest_id > 0){
 			if(quest_id > 0){
-				Quest* quest = client->GetPendingQuest(quest_id);
-				if(quest){
-					client->RemovePendingQuest(quest);
-					if(lua_interface)
-						lua_interface->CallQuestFunction(quest, "Declined", client->GetPlayer());
-					lua_interface->SetLuaUserDataStale(quest);
-					safe_delete(quest);
-					client->GetCurrentZone()->SendQuestUpdates(client);
-				}
+				client->RemovePendingQuest(quest_id);
 			}
 			}
 			break;
 			break;
 								   }
 								   }
@@ -4180,7 +4172,6 @@ void Commands::Process(int32 index, EQ2_16BitString* command_parms, Client* clie
 			int32 unknown = 0;
 			int32 unknown = 0;
 			int32 selectable_item_id = 0;
 			int32 selectable_item_id = 0;
 			//Quest *quest = 0;
 			//Quest *quest = 0;
-			Collection *collection = 0;
 			/* no idea what the first argument is for (faction maybe?)
 			/* no idea what the first argument is for (faction maybe?)
 			   if the reward has a selectable item reward, it's sent as the second argument
 			   if the reward has a selectable item reward, it's sent as the second argument
 			   if neither of these are included in the reward, there is no sep
 			   if neither of these are included in the reward, there is no sep
@@ -4198,38 +4189,8 @@ void Commands::Process(int32 index, EQ2_16BitString* command_parms, Client* clie
 			int32 item_id = 0;
 			int32 item_id = 0;
 			if(sep && sep->arg[0][0] && sep->IsNumber(0))
 			if(sep && sep->arg[0][0] && sep->IsNumber(0))
 				item_id = atoul(sep->arg[0]);
 				item_id = atoul(sep->arg[0]);
-			Quest* quest = client->GetPendingQuestAcceptance(item_id);
-			if(quest){
-				client->AcceptQuestReward(quest, item_id);
-				break;
-			}
-			bool collectedItems = false;
-			if (client->GetPlayer()->HasPendingItemRewards()) {
-				vector<Item*> items = client->GetPlayer()->GetPendingItemRewards();
-				if (items.size() > 0) {
-					collectedItems = true;
-					for (int i = 0; i < items.size(); i++) {
-						client->GetPlayer()->AddItem(new Item(items[i]));
-					}
-					client->GetPlayer()->ClearPendingItemRewards();
-					client->GetPlayer()->SetActiveReward(false);
-				}
-				map<int32, Item*> selectable_item = client->GetPlayer()->GetPendingSelectableItemReward(item_id);
-				if (selectable_item.size() > 0) {
-					collectedItems = true;
-					map<int32, Item*>::iterator itr;
-					for (itr = selectable_item.begin(); itr != selectable_item.end(); itr++) {
-						client->GetPlayer()->AddItem(new Item(itr->second));
-						client->GetPlayer()->ClearPendingSelectableItemRewards(itr->first);
-					}
-					client->GetPlayer()->SetActiveReward(false);
-				}
-			}
-			else if (collection = player->GetPendingCollectionReward())
-			{
-				client->AcceptCollectionRewards(collection, (selectable_item_id > 0) ? selectable_item_id : item_id);
-				collectedItems = true;
-			}
+
+			bool collectedItems = client->GetPlayer()->AcceptQuestReward(item_id, selectable_item_id);
 			
 			
 			if (collectedItems) {
 			if (collectedItems) {
 				EQ2Packet* outapp = client->GetPlayer()->SendInventoryUpdate(client->GetVersion());
 				EQ2Packet* outapp = client->GetPlayer()->SendInventoryUpdate(client->GetVersion());
@@ -11837,9 +11798,9 @@ void Commands::Command_ShareQuest(Client* client, Seperator* sep)
 	if (sep && sep->arg[0] && sep->IsNumber(0)) {
 	if (sep && sep->arg[0] && sep->IsNumber(0)) {
 		int32 quest_id = atoul(sep->arg[0]);
 		int32 quest_id = atoul(sep->arg[0]);
 		
 		
-		Quest* playerQuest = client->GetPlayer()->GetQuest(quest_id);
-		if(playerQuest) {
-		Quest* quest = master_quest_list.GetQuest(playerQuest->GetQuestID(), false);
+		bool hasQuest = client->GetPlayer()->HasAnyQuest(quest_id);
+		if(hasQuest) {
+		Quest* quest = master_quest_list.GetQuest(quest_id, false);
 			if(quest) {
 			if(quest) {
 				GroupMemberInfo* gmi = client->GetPlayer()->GetGroupMemberInfo();
 				GroupMemberInfo* gmi = client->GetPlayer()->GetGroupMemberInfo();
 				if (gmi && gmi->group_id) {
 				if (gmi && gmi->group_id) {

+ 27 - 9
EQ2/source/WorldServer/LuaFunctions.cpp

@@ -1362,6 +1362,7 @@ int EQ2Emu_lua_SpellHeal(lua_State* state) {
 
 
 	LuaSpell* luaspell = lua_interface->GetCurrentSpell(state);
 	LuaSpell* luaspell = lua_interface->GetCurrentSpell(state);
 	if(!luaspell || luaspell->resisted) {
 	if(!luaspell || luaspell->resisted) {
+		lua_interface->ResetFunctionStack(state);
 		return 0;
 		return 0;
 	}
 	}
 	Spawn* caster = luaspell->caster;
 	Spawn* caster = luaspell->caster;
@@ -1410,6 +1411,7 @@ int EQ2Emu_lua_SpellHealPct(lua_State* state) {
 
 
 	LuaSpell* luaspell = lua_interface->GetCurrentSpell(state);
 	LuaSpell* luaspell = lua_interface->GetCurrentSpell(state);
 	if(!luaspell || luaspell->resisted) {
 	if(!luaspell || luaspell->resisted) {
+		lua_interface->ResetFunctionStack(state);
 		return 0;
 		return 0;
 	}
 	}
 	Spawn* caster = luaspell->caster;
 	Spawn* caster = luaspell->caster;
@@ -1723,7 +1725,8 @@ int EQ2Emu_lua_AddHate(lua_State* state) {
 	bool send_packet = lua_interface->GetInt8Value(state, 4) == 1 ? true : false;
 	bool send_packet = lua_interface->GetInt8Value(state, 4) == 1 ? true : false;
 	LuaSpell* luaspell = lua_interface->GetCurrentSpell(state);
 	LuaSpell* luaspell = lua_interface->GetCurrentSpell(state);
 	
 	
-	if(!luaspell || luaspell->resisted) {
+	if(luaspell && luaspell->resisted) {
+		lua_interface->ResetFunctionStack(state);
 		return 0;
 		return 0;
 	}
 	}
 	
 	
@@ -1847,6 +1850,7 @@ int EQ2Emu_lua_SpellDamage(lua_State* state) {
 	Spawn* target = lua_interface->GetSpawn(state);
 	Spawn* target = lua_interface->GetSpawn(state);
 	LuaSpell* luaspell = lua_interface->GetCurrentSpell(state);
 	LuaSpell* luaspell = lua_interface->GetCurrentSpell(state);
 	if(!luaspell || luaspell->resisted) {
 	if(!luaspell || luaspell->resisted) {
+		lua_interface->ResetFunctionStack(state);
 		return 0;
 		return 0;
 	}
 	}
 	Spawn* caster = luaspell->caster;
 	Spawn* caster = luaspell->caster;
@@ -2282,6 +2286,7 @@ int EQ2Emu_lua_AddSpellBonus(lua_State* state) {
 	LuaSpell* luaspell = lua_interface->GetCurrentSpell(state);
 	LuaSpell* luaspell = lua_interface->GetCurrentSpell(state);
 	
 	
 	if(!luaspell || luaspell->resisted) {
 	if(!luaspell || luaspell->resisted) {
+		lua_interface->ResetFunctionStack(state);
 		return 0;
 		return 0;
 	}
 	}
 
 
@@ -2375,6 +2380,7 @@ int EQ2Emu_lua_AddSpawnSpellBonus(lua_State* state) {
 	}
 	}
 	
 	
 	if(luaspell->resisted) {
 	if(luaspell->resisted) {
+		lua_interface->ResetFunctionStack(state);
 		return 0;
 		return 0;
 	}
 	}
 
 
@@ -2476,6 +2482,7 @@ int EQ2Emu_lua_AddSkillBonus(lua_State* state) {
 		int32 spell_id = 0;
 		int32 spell_id = 0;
 		if (luaspell && luaspell->spell && luaspell->caster) {
 		if (luaspell && luaspell->spell && luaspell->caster) {
 			if(luaspell->resisted) {
 			if(luaspell->resisted) {
+				lua_interface->ResetFunctionStack(state);
 				return 0;
 				return 0;
 			}
 			}
 			spell_id = luaspell->spell->GetSpellID();
 			spell_id = luaspell->spell->GetSpellID();
@@ -2537,6 +2544,7 @@ int EQ2Emu_lua_RemoveSkillBonus(lua_State* state) {
 		int32 spell_id = 0;
 		int32 spell_id = 0;
 		if (luaspell && luaspell->spell) {
 		if (luaspell && luaspell->spell) {
 			if(luaspell->resisted) {
 			if(luaspell->resisted) {
+				lua_interface->ResetFunctionStack(state);
 				return 0;
 				return 0;
 			}
 			}
 			spell_id = luaspell->spell->GetSpellID();
 			spell_id = luaspell->spell->GetSpellID();
@@ -2591,6 +2599,7 @@ int EQ2Emu_lua_AddControlEffect(lua_State* state) {
 	LuaSpell* luaspell = lua_interface->GetCurrentSpell(state);
 	LuaSpell* luaspell = lua_interface->GetCurrentSpell(state);
 	
 	
 	if(luaspell && luaspell->resisted) {
 	if(luaspell && luaspell->resisted) {
+		lua_interface->ResetFunctionStack(state);
 		return 0;
 		return 0;
 	}
 	}
 	
 	
@@ -3635,7 +3644,7 @@ int EQ2Emu_lua_HasCompletedQuest(lua_State* state) {
 	int32 quest_id = lua_interface->GetInt32Value(state, 2);
 	int32 quest_id = lua_interface->GetInt32Value(state, 2);
 	lua_interface->ResetFunctionStack(state);
 	lua_interface->ResetFunctionStack(state);
 	if (player && player->IsPlayer() && quest_id > 0) {
 	if (player && player->IsPlayer() && quest_id > 0) {
-		lua_interface->SetBooleanValue(state, (((Player*)player)->GetCompletedQuest(quest_id) != 0));
+		lua_interface->SetBooleanValue(state, (((Player*)player)->HasQuestBeenCompleted(quest_id) != 0));
 		return 1;
 		return 1;
 	}
 	}
 	return 0;
 	return 0;
@@ -3659,10 +3668,25 @@ int EQ2Emu_lua_OfferQuest(lua_State* state) {
 	Spawn* player = lua_interface->GetSpawn(state, 2);
 	Spawn* player = lua_interface->GetSpawn(state, 2);
 	int32 quest_id = lua_interface->GetInt32Value(state, 3);
 	int32 quest_id = lua_interface->GetInt32Value(state, 3);
 	bool forced = lua_interface->GetBooleanValue(state, 4);
 	bool forced = lua_interface->GetBooleanValue(state, 4);
+	bool override_receive_quest_check = lua_interface->GetBooleanValue(state, 5);
 	lua_interface->ResetFunctionStack(state);
 	lua_interface->ResetFunctionStack(state);
 
 
 	/* NPC is allowed to be null */
 	/* NPC is allowed to be null */
 	if (player && player->IsPlayer() && quest_id > 0) {
 	if (player && player->IsPlayer() && quest_id > 0) {
+		if(!((Player*)player)->CanReceiveQuest(quest_id)) {
+				if(override_receive_quest_check || player->GetClient() && player->GetClient()->GetAdminStatus() >= 200) {
+					if(override_receive_quest_check) {
+						lua_interface->LogError("%s: LUA OfferQuest player %s should not be able to receive quest %u, override as OfferQuest has override_receive_quest_check = true.", lua_interface->GetScriptName(state), player->GetName(), quest_id);
+					}
+					else {
+						lua_interface->LogError("%s: LUA OfferQuest player %s should not be able to receive quest %u, override as player is admin (status >= 200).", lua_interface->GetScriptName(state), player->GetName(), quest_id);
+					}
+				}
+				else {
+					lua_interface->LogError("%s: LUA OfferQuest player %s cannot receive the quest %u, failed CanReceiveQuest.", lua_interface->GetScriptName(state), player->GetName(), quest_id);
+					return 0;
+				}
+		}
 		Quest* master_quest = master_quest_list.GetQuest(quest_id, false);
 		Quest* master_quest = master_quest_list.GetQuest(quest_id, false);
 		if (master_quest) {
 		if (master_quest) {
 			Client* client = ((Player*)player)->GetClient();
 			Client* client = ((Player*)player)->GetClient();
@@ -10082,13 +10106,7 @@ int EQ2Emu_lua_GetQuestCompleteCount(lua_State* state) {
 		return 0;
 		return 0;
 	}
 	}
 
 
-	Quest* quest = ((Player*)player)->GetCompletedQuest(quest_id);
-	if (!quest) {
-		lua_interface->SetInt32Value(state, 0);
-		return 1;
-	}
-
-	lua_interface->SetInt32Value(state, quest->GetCompleteCount());
+	lua_interface->SetInt32Value(state, ((Player*)player)->GetQuestCompletedCount(quest_id));
 	return 1;
 	return 1;
 }
 }
 
 

+ 245 - 2
EQ2/source/WorldServer/Player.cpp

@@ -4325,10 +4325,10 @@ PacketStruct* Player::GetQuestJournalPacket(bool all_quests, int16 version, int3
 	if(packet){
 	if(packet){
 		int16 total_quests_num = 0;
 		int16 total_quests_num = 0;
 		int16 total_completed_quests = 0;
 		int16 total_completed_quests = 0;
+		MPlayerQuests.readlock(__FUNCTION__, __LINE__);
 		map<int32, Quest*> total_quests = player_quests;
 		map<int32, Quest*> total_quests = player_quests;
 		if(all_quests && completed_quests.size() > 0)
 		if(all_quests && completed_quests.size() > 0)
 			total_quests.insert(completed_quests.begin(), completed_quests.end());
 			total_quests.insert(completed_quests.begin(), completed_quests.end());
-		MPlayerQuests.readlock(__FUNCTION__, __LINE__);
 		if(total_quests.size() > 0){
 		if(total_quests.size() > 0){
 			map<string, int16> quest_types;
 			map<string, int16> quest_types;
 			map<int32, Quest*>::iterator itr;
 			map<int32, Quest*>::iterator itr;
@@ -4428,6 +4428,9 @@ PacketStruct* Player::GetQuestJournalPacket(bool all_quests, int16 version, int3
 
 
 					if (quest->IsHidden() && !quest->GetTurnedIn())
 					if (quest->IsHidden() && !quest->GetTurnedIn())
 						display_status = QUEST_DISPLAY_STATUS_HIDDEN;
 						display_status = QUEST_DISPLAY_STATUS_HIDDEN;
+					else if(!quest->IsHidden()) {
+						display_status += QUEST_DISPLAY_STATUS_SHOW;
+					}
 					else if(quest->CanShareQuestCriteria(GetClient(),false)) {
 					else if(quest->CanShareQuestCriteria(GetClient(),false)) {
 						display_status += QUEST_DISPLAY_STATUS_CAN_SHARE;
 						display_status += QUEST_DISPLAY_STATUS_CAN_SHARE;
 					}
 					}
@@ -4733,6 +4736,47 @@ Quest* Player::GetCompletedQuest(int32 quest_id){
 	return 0;
 	return 0;
 }
 }
 
 
+bool Player::HasQuestBeenCompleted(int32 quest_id){
+	bool ret = false;
+	MPlayerQuests.readlock(__FUNCTION__, __LINE__);
+	if(completed_quests.count(quest_id) > 0)
+		ret = true;
+	MPlayerQuests.releasereadlock(__FUNCTION__, __LINE__);
+	
+	return ret;
+}
+
+bool Player::HasActiveQuest(int32 quest_id){
+	bool ret = false;
+	MPlayerQuests.readlock(__FUNCTION__, __LINE__);
+	if(player_quests.count(quest_id) > 0)
+		ret = true;
+	MPlayerQuests.releasereadlock(__FUNCTION__, __LINE__);
+	
+	return ret;
+}
+
+bool Player::HasAnyQuest(int32 quest_id){
+	bool ret = false;
+	MPlayerQuests.readlock(__FUNCTION__, __LINE__);
+	if(player_quests.count(quest_id) > 0)
+		ret = true;
+	if(completed_quests.count(quest_id) > 0)
+		ret = true;
+	MPlayerQuests.releasereadlock(__FUNCTION__, __LINE__);
+	
+	return ret;
+}
+
+int32 Player::GetQuestCompletedCount(int32 quest_id) {
+	int32 count = 0;
+	MPlayerQuests.readlock(__FUNCTION__, __LINE__);
+	Quest* quest = GetCompletedQuest(quest_id);
+	count = quest->GetCompleteCount();
+	MPlayerQuests.releasereadlock(__FUNCTION__, __LINE__);
+	return count;
+}
+
 Quest* Player::GetQuest(int32 quest_id){
 Quest* Player::GetQuest(int32 quest_id){
 	if(player_quests.count(quest_id) > 0)
 	if(player_quests.count(quest_id) > 0)
 		return player_quests[quest_id];
 		return player_quests[quest_id];
@@ -4740,12 +4784,19 @@ Quest* Player::GetQuest(int32 quest_id){
 }
 }
 
 
 void Player::AddCompletedQuest(Quest* quest){
 void Player::AddCompletedQuest(Quest* quest){
+	Quest* existing = GetCompletedQuest(quest->GetQuestID());
+	MPlayerQuests.writelock(__FUNCTION__, __LINE__);
 	completed_quests[quest->GetQuestID()] = quest;
 	completed_quests[quest->GetQuestID()] = quest;
+	if(existing && existing != quest) {
+		safe_delete(existing);
+	}
+	
 	quest->SetSaveNeeded(true);
 	quest->SetSaveNeeded(true);
 	quest->SetTurnedIn(true);
 	quest->SetTurnedIn(true);
 	if(quest->GetCompletedDescription())
 	if(quest->GetCompletedDescription())
 		quest->SetDescription(string(quest->GetCompletedDescription()));
 		quest->SetDescription(string(quest->GetCompletedDescription()));
 	quest->SetUpdateRequired(true);
 	quest->SetUpdateRequired(true);
+	MPlayerQuests.releasewritelock(__FUNCTION__, __LINE__);
 }
 }
 
 
 bool Player::CheckQuestRemoveFlag(Spawn* spawn){
 bool Player::CheckQuestRemoveFlag(Spawn* spawn){
@@ -4831,7 +4882,7 @@ bool Player::CanReceiveQuest(int32 quest_id, int8* ret){
 	if (!quest)
 	if (!quest)
 		passed = false;
 		passed = false;
 	//check if quest is already completed, and not repeatable
 	//check if quest is already completed, and not repeatable
-	else if (GetCompletedQuest(quest_id) && !quest->IsRepeatable())
+	else if (HasQuestBeenCompleted(quest_id) && !quest->IsRepeatable())
 		passed = false;
 		passed = false;
 	//check if the player already has this quest
 	//check if the player already has this quest
 	else if (player_quests.count(quest_id) > 0)
 	else if (player_quests.count(quest_id) > 0)
@@ -4853,6 +4904,7 @@ bool Player::CanReceiveQuest(int32 quest_id, int8* ret){
 
 
 
 
 	// Check quest pre req
 	// Check quest pre req
+	MPlayerQuests.readlock(__FUNCTION__, __LINE__);
 	vector<int32>* prereq_quests = quest->GetPrereqQuests();
 	vector<int32>* prereq_quests = quest->GetPrereqQuests();
 	if(passed && prereq_quests && prereq_quests->size() > 0){
 	if(passed && prereq_quests && prereq_quests->size() > 0){
 		for(int32 x=0;x<prereq_quests->size();x++){
 		for(int32 x=0;x<prereq_quests->size();x++){
@@ -4862,6 +4914,7 @@ bool Player::CanReceiveQuest(int32 quest_id, int8* ret){
 			}
 			}
 		}
 		}
 	}
 	}
+	MPlayerQuests.releasereadlock(__FUNCTION__, __LINE__);
 
 
 	//Check Prereq Classes
 	//Check Prereq Classes
 	vector<int8>* prereq_classes = quest->GetPrereqClasses();
 	vector<int8>* prereq_classes = quest->GetPrereqClasses();
@@ -4949,6 +5002,196 @@ bool Player::CanReceiveQuest(int32 quest_id, int8* ret){
 	return passed;
 	return passed;
 }
 }
 
 
+bool Player::UpdateQuestReward(int32 quest_id, QuestRewardData* qrd) {
+	if(!GetClient())
+		return false;
+	
+	MPlayerQuests.readlock(__FUNCTION__, __LINE__);
+	Quest* quest = GetAnyQuest(quest_id);
+	
+	if(!quest) {
+		MPlayerQuests.releasereadlock(__FUNCTION__, __LINE__);
+		return false;
+	}
+	
+	quest->SetQuestTemporaryState(qrd->is_temporary, qrd->description);
+	if(qrd->is_temporary) {
+		quest->SetStatusTmpReward(qrd->tmp_status);
+		quest->SetCoinTmpReward(qrd->tmp_coin);
+	}
+	MPlayerQuests.releasereadlock(__FUNCTION__, __LINE__);
+	
+	GetClient()->GiveQuestReward(quest, qrd->has_displayed);
+	SetActiveReward(true);
+	
+	return true;
+}
+
+
+Quest* Player::PendingQuestAcceptance(int32 quest_id, int32 item_id, bool* quest_exists) {
+	vector<Item*>* items = 0;
+	bool ret = false;
+	MPlayerQuests.readlock(__FUNCTION__, __LINE__);
+	Quest* quest = GetAnyQuest(quest_id);
+	if(!quest) {
+		if(quest_exists) {
+			*quest_exists = false;
+		}
+		MPlayerQuests.releasereadlock(__FUNCTION__, __LINE__);
+		return nullptr;
+	}
+	
+	if(quest_exists) {
+		*quest_exists = true;
+	}
+	if(quest->GetQuestTemporaryState())
+		items = quest->GetTmpRewardItems();
+	else
+		items = quest->GetRewardItems();
+	if (item_id == 0) {
+		ret = true;
+	}
+	else {
+		items = quest->GetSelectableRewardItems();
+		if (items && items->size() > 0) {
+			for (int32 i = 0; i < items->size(); i++) {
+				if (items->at(i)->details.item_id == item_id) {
+					ret = true;
+					break;
+				}
+			}
+		}
+	}
+	MPlayerQuests.releasereadlock(__FUNCTION__, __LINE__);
+
+	return quest;
+}
+
+
+bool Player::AcceptQuestReward(int32 item_id, int32 selectable_item_id) {
+	if(!GetClient()) {
+		return false;
+	}
+	
+	Collection *collection = 0;
+	MPlayerQuests.readlock(__FUNCTION__, __LINE__);
+	Quest* quest = client->GetPendingQuestAcceptance(item_id);
+	if(quest){
+		GetClient()->AcceptQuestReward(quest, item_id);
+		MPlayerQuests.releasereadlock(__FUNCTION__, __LINE__);
+		return true;
+	}
+	bool collectedItems = false;
+	if (client->GetPlayer()->HasPendingItemRewards()) {
+		vector<Item*> items = client->GetPlayer()->GetPendingItemRewards();
+		if (items.size() > 0) {
+			collectedItems = true;
+			for (int i = 0; i < items.size(); i++) {
+				client->GetPlayer()->AddItem(new Item(items[i]));
+			}
+			client->GetPlayer()->ClearPendingItemRewards();
+			client->GetPlayer()->SetActiveReward(false);
+		}
+		map<int32, Item*> selectable_item = client->GetPlayer()->GetPendingSelectableItemReward(item_id);
+		if (selectable_item.size() > 0) {
+			collectedItems = true;
+			map<int32, Item*>::iterator itr;
+			for (itr = selectable_item.begin(); itr != selectable_item.end(); itr++) {
+				client->GetPlayer()->AddItem(new Item(itr->second));
+				client->GetPlayer()->ClearPendingSelectableItemRewards(itr->first);
+			}
+			client->GetPlayer()->SetActiveReward(false);
+		}
+	}
+	else if (collection = GetPendingCollectionReward())
+	{
+		client->AcceptCollectionRewards(collection, (selectable_item_id > 0) ? selectable_item_id : item_id);
+		collectedItems = true;
+	}
+	MPlayerQuests.releasereadlock(__FUNCTION__, __LINE__);
+	
+	return collectedItems;
+}
+
+
+bool Player::SendQuestStepUpdate(int32 quest_id, int32 quest_step_id, bool display_quest_helper) {	
+	MPlayerQuests.readlock(__FUNCTION__, __LINE__);
+	Quest* quest = GetAnyQuest(quest_id);
+	if(!quest) {
+		MPlayerQuests.releasereadlock(__FUNCTION__, __LINE__);
+		return false;
+	}
+	QuestStep* quest_step = quest->GetQuestStep(quest_step_id);
+	if (quest_step) {
+		if(GetClient()) {
+			GetClient()->QueuePacket(quest->QuestJournalReply(GetClient()->GetVersion(), GetClient()->GetNameCRC(), this, quest_step, 1, false, false, display_quest_helper));
+		}
+		quest_step->WasUpdated(false);
+	}
+	if(quest->GetTurnedIn() && GetClient()) //update the journal so the old quest isn't the one displayed in the client's quest helper
+		GetClient()->SendQuestJournal();
+		
+	MPlayerQuests.releasereadlock(__FUNCTION__, __LINE__);
+}
+
+void Player::SendQuest(int32 quest_id) {
+	if(!GetClient()) {
+		return;
+	}
+
+	MPlayerQuests.readlock(__FUNCTION__, __LINE__);
+	Quest* quest = GetQuest(quest_id);
+	if (quest)
+		GetClient()->QueuePacket(quest->QuestJournalReply(GetClient()->GetVersion(), GetClient()->GetNameCRC(), this));
+	else {
+		quest = GetCompletedQuest(quest_id);
+		
+		if (quest)
+			GetClient()->QueuePacket(quest->QuestJournalReply(GetClient()->GetVersion(), GetClient()->GetNameCRC(), this, 0, 1, true));
+	}
+	MPlayerQuests.releasereadlock(__FUNCTION__, __LINE__);
+}
+
+
+void Player::UpdateQuestCompleteCount(int32 quest_id) {
+	if(!GetClient()) {
+		return;
+	}
+	
+	MPlayerQuests.readlock(__FUNCTION__, __LINE__);
+	// If character has already completed this quest once update the given date in the database
+	Quest* quest = GetQuest(id);
+	Quest* quest2 = GetCompletedQuest(id);
+	if (quest && quest2) {
+		quest->SetCompleteCount(quest2->GetCompleteCount());
+		database.SaveCharRepeatableQuest(GetClient(), id, quest->GetCompleteCount());
+	}
+	MPlayerQuests.releasereadlock(__FUNCTION__, __LINE__);
+}
+
+void Player::GetQuestTemporaryRewards(int32 quest_id, std::vector<Item*>* items) {
+	MPlayerQuests.readlock(__FUNCTION__, __LINE__);
+	Quest* quest = GetAnyQuest(quest_id);
+	if(quest) {
+		quest->GetTmpRewardItemsByID(items);
+	}
+	MPlayerQuests.releasereadlock(__FUNCTION__, __LINE__);
+}
+
+void Player::AddQuestTemporaryReward(int32 quest_id, int32 item_id, int16 item_count) {
+	MPlayerQuests.readlock(__FUNCTION__, __LINE__);
+	Quest* quest = GetAnyQuest(quest_id);
+	if(quest) {
+		Item* item = master_item_list.GetItem(item_id);
+		if(item) {
+			Item* tmpItem = new Item(item);
+			tmpItem->details.count = item_count;
+			quest->AddTmpRewardItem(tmpItem);
+		}
+	}
+	MPlayerQuests.releasereadlock(__FUNCTION__, __LINE__);
+}
+
 bool Player::ShouldSendSpawn(Spawn* spawn){
 bool Player::ShouldSendSpawn(Spawn* spawn){
 	if(spawn->IsDeletedSpawn() || IsSendingSpawn(spawn->GetID()) || IsRemovingSpawn(spawn->GetID()))
 	if(spawn->IsDeletedSpawn() || IsSendingSpawn(spawn->GetID()) || IsRemovingSpawn(spawn->GetID()))
 		return false;
 		return false;

+ 29 - 2
EQ2/source/WorldServer/Player.h

@@ -243,6 +243,18 @@ struct SpawnQueueState {
 	int16 index_id;
 	int16 index_id;
 };
 };
 
 
+struct QuestRewardData {
+	int32 quest_id;
+	bool is_temporary;
+	std::string description;
+	bool is_collection;
+	bool has_displayed;
+	int64 tmp_coin;
+	int32 tmp_status;
+	bool db_saved;
+	int32 db_index;
+};
+
 class PlayerLoginAppearance {
 class PlayerLoginAppearance {
 public:
 public:
 	PlayerLoginAppearance() { appearanceList = new map<int8, LoginAppearances>; }
 	PlayerLoginAppearance() { appearanceList = new map<int8, LoginAppearances>; }
@@ -694,6 +706,16 @@ public:
 	vector<Quest*>* CheckQuestsFailures();
 	vector<Quest*>* CheckQuestsFailures();
 	bool CheckQuestRemoveFlag(Spawn* spawn);
 	bool CheckQuestRemoveFlag(Spawn* spawn);
 	int8 CheckQuestFlag(Spawn* spawn);
 	int8 CheckQuestFlag(Spawn* spawn);
+	bool UpdateQuestReward(int32 quest_id, QuestRewardData* qrd);
+	Quest* PendingQuestAcceptance(int32 quest_id, int32 item_id, bool* quest_exists);
+	bool AcceptQuestReward(int32 item_id, int32 selectable_item_id);
+	
+	bool SendQuestStepUpdate(int32 quest_id, int32 quest_step_id, bool display_quest_helper);
+	void SendQuest(int32 quest_id);
+	void UpdateQuestCompleteCount(int32 quest_id);
+	void GetQuestTemporaryRewards(int32 quest_id, std::vector<Item*>* items);
+	void AddQuestTemporaryReward(int32 quest_id, int32 item_id, int16 item_count);
+	
 	bool CheckQuestRequired(Spawn* spawn);
 	bool CheckQuestRequired(Spawn* spawn);
 	void AddQuestRequiredSpawn(Spawn* spawn, int32 quest_id);
 	void AddQuestRequiredSpawn(Spawn* spawn, int32 quest_id);
 	void AddHistoryRequiredSpawn(Spawn* spawn, int32 event_id);
 	void AddHistoryRequiredSpawn(Spawn* spawn, int32 event_id);
@@ -704,9 +726,11 @@ public:
 	map<int32, vector<int32>*>   player_spawn_history_required;
 	map<int32, vector<int32>*>   player_spawn_history_required;
 	Mutex				m_playerSpawnQuestsRequired;
 	Mutex				m_playerSpawnQuestsRequired;
 	Mutex				m_playerSpawnHistoryRequired;
 	Mutex				m_playerSpawnHistoryRequired;
-	Quest*  GetAnyQuest(int32 quest_id);
-	Quest*	GetCompletedQuest(int32 quest_id);
+	bool	HasQuestBeenCompleted(int32 quest_id);
+	int32	GetQuestCompletedCount(int32 quest_id);
 	void	AddCompletedQuest(Quest* quest);
 	void	AddCompletedQuest(Quest* quest);
+	bool	HasActiveQuest(int32 quest_id);
+	bool	HasAnyQuest(int32 quest_id);
 	map<int32, Quest*>	pending_quests;
 	map<int32, Quest*>	pending_quests;
 	map<int32, Quest*>	player_quests;
 	map<int32, Quest*>	player_quests;
 	map<int32, Quest*>*	GetPlayerQuests();
 	map<int32, Quest*>*	GetPlayerQuests();
@@ -1201,6 +1225,9 @@ private:
 	int32 current_language_id;
 	int32 current_language_id;
 	
 	
 	bool active_reward;
 	bool active_reward;
+	
+	Quest*  GetAnyQuest(int32 quest_id);
+	Quest*	GetCompletedQuest(int32 quest_id);
 };
 };
 #pragma pack()
 #pragma pack()
 #endif
 #endif

+ 2 - 3
EQ2/source/WorldServer/PlayerGroups.cpp

@@ -208,8 +208,7 @@ bool PlayerGroup::ShareQuestWithGroup(Client* quest_sharer, Quest* quest) {
 	for(itr = m_members.begin(); itr != m_members.end(); itr++) {
 	for(itr = m_members.begin(); itr != m_members.end(); itr++) {
 		GroupMemberInfo* info = *itr;
 		GroupMemberInfo* info = *itr;
 		if(info && info->client && info->client->GetCurrentZone()) {
 		if(info && info->client && info->client->GetCurrentZone()) {
-			if( quest_sharer != info->client && info->client->GetPlayer()->GetCompletedQuest(quest->GetQuestID()) == 0 && 
-				info->client->GetPlayer()->GetQuest(quest->GetQuestID()) == 0 ) {
+			if( quest_sharer != info->client && info->client->GetPlayer()->HasAnyQuest(quest->GetQuestID()) == 0 ) {
 				info->client->AddPendingQuest(new Quest(quest));
 				info->client->AddPendingQuest(new Quest(quest));
 				info->client->Message(CHANNEL_COLOR_YELLOW, "%s has shared the quest %s with you.", quest_sharer->GetPlayer()->GetName(), quest->GetName());
 				info->client->Message(CHANNEL_COLOR_YELLOW, "%s has shared the quest %s with you.", quest_sharer->GetPlayer()->GetName(), quest->GetName());
 			}
 			}
@@ -580,7 +579,7 @@ bool PlayerGroupManager::HasGroupCompletedQuest(int32 group_id, int32 quest_id)
 		for (itr = members->begin(); itr != members->end(); itr++) {
 		for (itr = members->begin(); itr != members->end(); itr++) {
 			info = *itr;
 			info = *itr;
 			if (info->client) {
 			if (info->client) {
-				bool isComplete = info->client->GetPlayer()->GetCompletedQuest(quest_id);
+				bool isComplete = info->client->GetPlayer()->HasQuestBeenCompleted(quest_id);
 				if(!isComplete)
 				if(!isComplete)
 				{
 				{
 					questComplete = isComplete;
 					questComplete = isComplete;

+ 2 - 2
EQ2/source/WorldServer/Quests.cpp

@@ -1826,12 +1826,12 @@ void Quest::SetQuestTemporaryState(bool tempState, std::string customDescription
 
 
 bool Quest::CanShareQuestCriteria(Client* quest_sharer, bool display_client_msg) {
 bool Quest::CanShareQuestCriteria(Client* quest_sharer, bool display_client_msg) {
 	Quest* clientQuest = quest_sharer->GetPlayer()->GetQuest(GetQuestID()); // gets active quest if available
 	Quest* clientQuest = quest_sharer->GetPlayer()->GetQuest(GetQuestID()); // gets active quest if available
-	if(((GetQuestShareableFlag() & QUEST_SHAREABLE_COMPLETED) == 0) && quest_sharer->GetPlayer()->GetCompletedQuest(GetQuestID())) {
+	if(((GetQuestShareableFlag() & QUEST_SHAREABLE_COMPLETED) == 0) && quest_sharer->GetPlayer()->HasQuestBeenCompleted(GetQuestID())) {
 		if(display_client_msg)
 		if(display_client_msg)
 			quest_sharer->SimpleMessage(CHANNEL_COLOR_RED, "You cannot share this quest after it is already completed.");
 			quest_sharer->SimpleMessage(CHANNEL_COLOR_RED, "You cannot share this quest after it is already completed.");
 		return false;
 		return false;
 	}
 	}
-	else if((GetQuestShareableFlag() == QUEST_SHAREABLE_COMPLETED) && !quest_sharer->GetPlayer()->GetCompletedQuest(GetQuestID())) {
+	else if((GetQuestShareableFlag() == QUEST_SHAREABLE_COMPLETED) && !quest_sharer->GetPlayer()->HasQuestBeenCompleted(GetQuestID())) {
 		if(display_client_msg)
 		if(display_client_msg)
 			quest_sharer->SimpleMessage(CHANNEL_COLOR_RED, "You cannot share this quest until it is completed.");
 			quest_sharer->SimpleMessage(CHANNEL_COLOR_RED, "You cannot share this quest until it is completed.");
 		return false;
 		return false;

+ 1 - 0
EQ2/source/WorldServer/Rules/Rules.cpp

@@ -184,6 +184,7 @@ void RuleManager::Init()
 	/* CLIENT */
 	/* CLIENT */
 	RULE_INIT(R_Client, ShowWelcomeScreen, "0");
 	RULE_INIT(R_Client, ShowWelcomeScreen, "0");
 	RULE_INIT(R_Client, GroupSpellsTimer, "1000");
 	RULE_INIT(R_Client, GroupSpellsTimer, "1000");
+	RULE_INIT(R_Client, QuestQueueTimer, "50"); // in milliseconds
 
 
 	/* FACTION */
 	/* FACTION */
 	RULE_INIT(R_Faction, AllowFactionBasedCombat, "1");
 	RULE_INIT(R_Faction, AllowFactionBasedCombat, "1");

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

@@ -151,6 +151,7 @@ enum RuleType {
 	EditorIncludeID,
 	EditorIncludeID,
 	EditorOfficialServer,
 	EditorOfficialServer,
 	GroupSpellsTimer,
 	GroupSpellsTimer,
+	QuestQueueTimer,
 	SavePaperdollImage,
 	SavePaperdollImage,
 	SaveHeadshotImage,
 	SaveHeadshotImage,
 	SendPaperdollImagesToLogin,
 	SendPaperdollImagesToLogin,

+ 1 - 1
EQ2/source/WorldServer/Spawn.cpp

@@ -3556,7 +3556,7 @@ bool Spawn::MeetsSpawnAccessRequirements(Player* player){
 							break;
 							break;
 						}
 						}
 					}
 					}
-					else if (player->GetCompletedQuest(itr->first)) {
+					else if (player->HasQuestBeenCompleted(itr->first)) {
 						ret = true;
 						ret = true;
 						break;
 						break;
 					}
 					}

+ 2 - 9
EQ2/source/WorldServer/WorldDatabase.cpp

@@ -1916,15 +1916,8 @@ void WorldDatabase::LoadCharacterQuestTemporaryRewards(Client* client, int32 que
 		while(result && (row = mysql_fetch_row(result)))
 		while(result && (row = mysql_fetch_row(result)))
 		{
 		{
 			int32 item_id = atoul(row[0]);
 			int32 item_id = atoul(row[0]);
-			Quest* quest = client->GetPlayer()->GetAnyQuest(quest_id);
-			if(quest) {
-				Item* item = master_item_list.GetItem(item_id);
-				if(item) {
-					Item* tmpItem = new Item(item);
-					tmpItem->details.count = atoul(row[1]);
-					quest->AddTmpRewardItem(tmpItem);
-				}
-			}
+			int16 item_count = atoul(row[1]);
+			client->GetPlayer()->AddQuestTemporaryReward(quest_id, item_id, item_count);
 		}
 		}
 	}
 	}
 }
 }

+ 59 - 103
EQ2/source/WorldServer/client.cpp

@@ -1253,14 +1253,7 @@ bool Client::HandlePacket(EQApplicationPacket* app) {
 			break;
 			break;
 		int32 quest_id = 0;
 		int32 quest_id = 0;
 		memcpy(&quest_id, app->pBuffer, sizeof(int32));
 		memcpy(&quest_id, app->pBuffer, sizeof(int32));
-		Quest* quest = GetActiveQuest(quest_id);
-		if (quest)
-			QueuePacket(quest->QuestJournalReply(GetVersion(), GetNameCRC(), player));
-		else {
-			quest = player->GetCompletedQuest(quest_id);
-			if (quest)
-				QueuePacket(quest->QuestJournalReply(GetVersion(), GetNameCRC(), player, 0, 1, true));
-		}
+		GetPlayer()->SendQuest(quest_id);
 		break;
 		break;
 	}
 	}
 	case OP_QuestJournalSetVisibleMsg: {
 	case OP_QuestJournalSetVisibleMsg: {
@@ -3248,7 +3241,11 @@ bool Client::Process(bool zone_process) {
 		LogWrite(CCLIENT__DEBUG, 1, "Client", "%s, ProcessQuestUpdates", __FUNCTION__, __LINE__);
 		LogWrite(CCLIENT__DEBUG, 1, "Client", "%s, ProcessQuestUpdates", __FUNCTION__, __LINE__);
 		ProcessQuestUpdates();
 		ProcessQuestUpdates();
 	}
 	}
-	if (last_update_time > 0 && last_update_time < (Timer::GetCurrentTime2() - 300)) {
+	int32 queue_timer_delay = rule_manager.GetGlobalRule(R_Client, QuestQueueTimer)->GetInt32();
+	if(queue_timer_delay < 10) {
+		queue_timer_delay = 10;
+	}
+	if (last_update_time > 0 && last_update_time < (Timer::GetCurrentTime2() - queue_timer_delay)) {
 		LogWrite(CCLIENT__DEBUG, 1, "Client", "%s, CheckQuestQueue", __FUNCTION__, __LINE__);
 		LogWrite(CCLIENT__DEBUG, 1, "Client", "%s, CheckQuestQueue", __FUNCTION__, __LINE__);
 		CheckQuestQueue();
 		CheckQuestQueue();
 	}
 	}
@@ -5810,7 +5807,6 @@ void Client::ProcessQuestUpdates() {
 		bool delete_first = false;
 		bool delete_first = false;
 		for (itr = tmp_quest_rewards.begin(); itr != tmp_quest_rewards.end();) {
 		for (itr = tmp_quest_rewards.begin(); itr != tmp_quest_rewards.end();) {
 			int32 questID = (*itr)->quest_id;
 			int32 questID = (*itr)->quest_id;
-			Quest* quest = 0;
 			if((*itr)->is_collection && GetPlayer()->GetPendingCollectionReward()) {
 			if((*itr)->is_collection && GetPlayer()->GetPendingCollectionReward()) {
 				DisplayCollectionComplete(GetPlayer()->GetPendingCollectionReward());
 				DisplayCollectionComplete(GetPlayer()->GetPendingCollectionReward());
 				GetPlayer()->SetActiveReward(true);
 				GetPlayer()->SetActiveReward(true);
@@ -5819,16 +5815,8 @@ void Client::ProcessQuestUpdates() {
 				UpdateCharacterRewardData((*itr));
 				UpdateCharacterRewardData((*itr));
 				break;
 				break;
 			}
 			}
-			else if(questID > 0 && (quest = GetPlayer()->GetAnyQuest(questID))) {
-				quest->SetQuestTemporaryState((*itr)->is_temporary, (*itr)->description);
-				if((*itr)->is_temporary) {
-					quest->SetStatusTmpReward((*itr)->tmp_status);
-					quest->SetCoinTmpReward((*itr)->tmp_coin);
-				}
-				GiveQuestReward(quest, (*itr)->has_displayed);
-				GetPlayer()->SetActiveReward(true);
+			else if(questID > 0 && GetPlayer()->UpdateQuestReward(questID, (*itr))) {
 				(*itr)->has_displayed = true;
 				(*itr)->has_displayed = true;
-				
 				UpdateCharacterRewardData((*itr));
 				UpdateCharacterRewardData((*itr));
 				// only able to display one reward at a time
 				// only able to display one reward at a time
 				break;
 				break;
@@ -5861,20 +5849,11 @@ void Client::CheckQuestQueue() {
 	MQuestQueue.writelock();
 	MQuestQueue.writelock();
 	last_update_time = 0;
 	last_update_time = 0;
 	vector<QueuedQuest*>::iterator itr;
 	vector<QueuedQuest*>::iterator itr;
-	QueuedQuest* queued_quest = 0;
 	for (itr = quest_queue.begin(); itr != quest_queue.end(); itr++) {
 	for (itr = quest_queue.begin(); itr != quest_queue.end(); itr++) {
-		queued_quest = *itr;
-		
-		Quest* quest = GetPlayer()->GetAnyQuest(queued_quest->quest_id);
-		if(quest) {
-			SendQuestUpdateStepImmediately(quest, queued_quest->step, queued_quest->display_quest_helper);
-			if(quest->GetTurnedIn()) //update the journal so the old quest isn't the one displayed in the client's quest helper
-				SendQuestJournal();
+		if(!GetPlayer()->SendQuestStepUpdate((*itr)->quest_id, (*itr)->step, (*itr)->display_quest_helper)) {
+			LogWrite(CCLIENT__ERROR, 0, "Client", "Queued Quest ID %u missing for Player %s, cannot send quest step update.", (*itr)->quest_id, GetPlayer()->GetName());
 		}
 		}
-		else {
-			LogWrite(CCLIENT__ERROR, 0, "Client", "Queued Quest ID %u missing for Player %s, cannot send quest step update.", queued_quest->quest_id, GetPlayer()->GetName());
-		}
-		safe_delete(queued_quest);
+		safe_delete((*itr));
 	}
 	}
 	quest_queue.clear();
 	quest_queue.clear();
 	MQuestQueue.releasewritelock();
 	MQuestQueue.releasewritelock();
@@ -5974,59 +5953,56 @@ void Client::CheckPlayerQuestsSpellUpdate(Spell* spell) {
 
 
 void Client::AddPendingQuest(Quest* quest, bool forced) {
 void Client::AddPendingQuest(Quest* quest, bool forced) {
 	if (version <= 283 || forced) { //this client doesn't ask if you want the quest, so auto accept
 	if (version <= 283 || forced) { //this client doesn't ask if you want the quest, so auto accept
+		MPendingQuestAccept.lock();
 		player->pending_quests[quest->GetQuestID()] = quest;
 		player->pending_quests[quest->GetQuestID()] = quest;
+		MPendingQuestAccept.unlock();
 		AcceptQuest(quest->GetQuestID());
 		AcceptQuest(quest->GetQuestID());
 	}
 	}
 	else {
 	else {
+		MPendingQuestAccept.lock();
 		player->pending_quests[quest->GetQuestID()] = quest;
 		player->pending_quests[quest->GetQuestID()] = quest;
+		MPendingQuestAccept.unlock();
 		EQ2Packet* outapp = quest->OfferQuest(GetVersion(), player);
 		EQ2Packet* outapp = quest->OfferQuest(GetVersion(), player);
 		//DumpPacket(outapp);
 		//DumpPacket(outapp);
 		QueuePacket(outapp);
 		QueuePacket(outapp);
 	}
 	}
 }
 }
 
 
-Quest* Client::GetActiveQuest(int32 quest_id) {
-	Quest* quest = 0;
-	GetPlayer()->MPlayerQuests.readlock(__FUNCTION__, __LINE__);
-	if (player->player_quests.count(quest_id) > 0) {
-		LogWrite(CCLIENT__DEBUG, 0, "Client", "Found %u active quests for char_id: %u", player->player_quests.count(quest_id), player->GetCharacterID());
-		quest = player->player_quests[quest_id];
-	}
-	GetPlayer()->MPlayerQuests.releasereadlock(__FUNCTION__, __LINE__);
-	
-	return quest;
-}
-
-void Client::AcceptQuest(int32 id) {
-	Quest* quest = GetPendingQuest(id);
-	if (quest) {
-		RemovePendingQuest(quest);
+void Client::AcceptQuest(int32 quest_id) {
+	MPendingQuestAccept.lock();
+	if (player->pending_quests.count(quest_id) > 0) {
+		Quest* quest = player->pending_quests[quest_id];	
+		player->pending_quests.erase(quest->GetQuestID());
 		AddPlayerQuest(quest);
 		AddPlayerQuest(quest);
 		GetCurrentZone()->SendQuestUpdates(this);
 		GetCurrentZone()->SendQuestUpdates(this);
 
 
-		// If character has already completed this quest once update the given date in the database
-		if (GetPlayer()->GetCompletedPlayerQuests()->count(id) > 0) {
-			Quest* quest2 = GetPlayer()->GetCompletedQuest(id);
-			if (quest2)
-				quest->SetCompleteCount(quest2->GetCompleteCount());
-			database.SaveCharRepeatableQuest(this, id, quest->GetCompleteCount());
-		}
+		GetPlayer()->UpdateQuestCompleteCount(quest_id);
 	}
 	}
+	MPendingQuestAccept.unlock();
 }
 }
 
 
-Quest* Client::GetPendingQuest(int32 id) {
-	if (player->pending_quests.count(id) > 0) {
-		LogWrite(CCLIENT__DEBUG, 0, "Client", "Found %u pending quests for char_id: %u", player->pending_quests.count(id), player->GetCharacterID());
-
-		return player->pending_quests[id];
+void Client::RemovePendingQuest(int32 quest_id) {
+	bool send_updates = false;
+	MPendingQuestAccept.lock();
+	
+	if (player->pending_quests.count(quest_id) > 0) {
+		Quest* quest = player->pending_quests[quest_id];	
+		player->pending_quests.erase(quest_id);
+		
+		if(lua_interface) {
+			lua_interface->CallQuestFunction(quest, "Declined", GetPlayer());
+			lua_interface->SetLuaUserDataStale(quest);
+		}
+		
+		safe_delete(quest);
+		
+		send_updates = true;
 	}
 	}
+	MPendingQuestAccept.unlock();
 
 
-	return 0;
-}
-
-void Client::RemovePendingQuest(Quest* quest) {
-	player->pending_quests.erase(quest->GetQuestID());
-
+	if(send_updates) {
+		GetCurrentZone()->SendQuestUpdates(this);
+	}
 }
 }
 
 
 void Client::SetPlayerQuest(Quest* quest, map<int32, int32>* progress) {
 void Client::SetPlayerQuest(Quest* quest, map<int32, int32>* progress) {
@@ -6236,37 +6212,22 @@ void Client::ReloadQuests() {
 Quest* Client::GetPendingQuestAcceptance(int32 item_id) {
 Quest* Client::GetPendingQuestAcceptance(int32 item_id) {
 	bool found_quest = false;
 	bool found_quest = false;
 	vector<int32>::iterator itr;
 	vector<int32>::iterator itr;
-	vector<Item*>* items = 0;
 	int32 questID = 0;
 	int32 questID = 0;
-	Quest* quest = 0;
+	Quest* quest = nullptr;
 	MPendingQuestAccept.lock();
 	MPendingQuestAccept.lock();
 	for (itr = pending_quest_accept.begin(); itr != pending_quest_accept.end();) {
 	for (itr = pending_quest_accept.begin(); itr != pending_quest_accept.end();) {
 		questID = *itr;
 		questID = *itr;
-		quest = GetPlayer()->GetAnyQuest(questID);
-		if(!quest) {
+		
+		bool quest_exists = false;
+		quest = GetPlayer()->PendingQuestAcceptance(questID, item_id, &quest_exists);
+		
+		if(!quest_exists) {
 			LogWrite(CCLIENT__ERROR, 0, "Client", "Quest ID %u missing for Player %s, removing quest id from pending_quest_accept.", questID, GetPlayer()->GetName());
 			LogWrite(CCLIENT__ERROR, 0, "Client", "Quest ID %u missing for Player %s, removing quest id from pending_quest_accept.", questID, GetPlayer()->GetName());
 			itr = pending_quest_accept.erase(itr);
 			itr = pending_quest_accept.erase(itr);
+			quest = nullptr;
 			continue;
 			continue;
 		}
 		}
-		if(quest->GetQuestTemporaryState())
-			items = quest->GetTmpRewardItems();
-		else
-			items = quest->GetRewardItems();
-		if (item_id == 0) {
-			found_quest = true;
-		}
-		else {
-			items = quest->GetSelectableRewardItems();
-			if (items && items->size() > 0) {
-				for (int32 i = 0; i < items->size(); i++) {
-					if (items->at(i)->details.item_id == item_id) {
-						found_quest = true;
-						break;
-					}
-				}
-			}
-		}
-		if (found_quest) {
+		else if (quest) {
 			pending_quest_accept.erase(itr);
 			pending_quest_accept.erase(itr);
 			break;
 			break;
 		}
 		}
@@ -6275,9 +6236,7 @@ Quest* Client::GetPendingQuestAcceptance(int32 item_id) {
 	}
 	}
 	MPendingQuestAccept.unlock();
 	MPendingQuestAccept.unlock();
 
 
-	if (found_quest)
-		return quest;
-	return 0;
+	return quest;
 }
 }
 
 
 void Client::AcceptQuestReward(Quest* quest, int32 item_id) {
 void Client::AcceptQuestReward(Quest* quest, int32 item_id) {
@@ -8976,7 +8935,7 @@ void Client::ProcessTeleport(Spawn* spawn, vector<TransportDestination*>* destin
 				if (destination->max_level > 0 && GetPlayer()->GetLevel() > destination->max_level)
 				if (destination->max_level > 0 && GetPlayer()->GetLevel() > destination->max_level)
 					continue;
 					continue;
 				// Check quest complete
 				// Check quest complete
-				if (destination->req_quest_complete > 0 && GetPlayer()->GetCompletedQuest(destination->req_quest_complete) == 0)
+				if (destination->req_quest_complete > 0 && GetPlayer()->HasQuestBeenCompleted(destination->req_quest_complete) == 0)
 					continue;
 					continue;
 				// Check req quest and step
 				// Check req quest and step
 				if (destination->req_quest > 0 && destination->req_quest_step > 0 && GetPlayer()->GetQuestStep(destination->req_quest) != destination->req_quest_step)
 				if (destination->req_quest > 0 && destination->req_quest_step > 0 && GetPlayer()->GetQuestStep(destination->req_quest) != destination->req_quest_step)
@@ -11581,17 +11540,14 @@ void Client::SaveQuestRewardData(bool force_refresh) {
 				(*itr)->db_index = index;
 				(*itr)->db_index = index;
 				if((*itr)->is_temporary) {
 				if((*itr)->is_temporary) {
 					std::vector<Item*> items;
 					std::vector<Item*> items;
-					Quest* quest = GetPlayer()->GetAnyQuest(questID);
-					if(quest) {
-						quest->GetTmpRewardItemsByID(&items);
-						if(!force_refresh && items.size() > 0) {
-							query.AddQueryAsync(GetCharacterID(), &database, Q_REPLACE, "delete from character_quest_temporary_rewards where char_id = %u and quest_id = %u", 
-								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, count) values(%u, %u, %u, %u)", 
-								GetCharacterID(), questID, items[i]->details.item_id, items[i]->details.count);
-						}
+					GetPlayer()->GetQuestTemporaryRewards(questID, &items);
+					if(!force_refresh && items.size() > 0) {
+						query.AddQueryAsync(GetCharacterID(), &database, Q_REPLACE, "delete from character_quest_temporary_rewards where char_id = %u and quest_id = %u", 
+							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, count) values(%u, %u, %u, %u)", 
+							GetCharacterID(), questID, items[i]->details.item_id, items[i]->details.count);
 					}
 					}
 				}
 				}
 			}
 			}

+ 4 - 16
EQ2/source/WorldServer/client.h

@@ -146,17 +146,6 @@ struct WaypointInfo {
 	int8 type;
 	int8 type;
 };
 };
 
 
-struct QuestRewardData {
-	int32 quest_id;
-	bool is_temporary;
-	std::string description;
-	bool is_collection;
-	bool has_displayed;
-	int64 tmp_coin;
-	int32 tmp_status;
-	bool db_saved;
-	int32 db_index;
-};
 
 
 class Client {
 class Client {
 public:
 public:
@@ -288,9 +277,8 @@ public:
 	void	CheckPlayerQuestsSpellUpdate(Spell* spell);
 	void	CheckPlayerQuestsSpellUpdate(Spell* spell);
 	void	CheckPlayerQuestsLocationUpdate();
 	void	CheckPlayerQuestsLocationUpdate();
 	void	AddPendingQuest(Quest* quest, bool forced = false);
 	void	AddPendingQuest(Quest* quest, bool forced = false);
-	void	AcceptQuest(int32 id);
-	Quest*	GetPendingQuest(int32 id);
-	void	RemovePendingQuest(Quest* quest);
+	void	AcceptQuest(int32 quest_id);
+	void	RemovePendingQuest(int32 quest_id);
 	void	SetPlayerQuest(Quest* quest, map<int32, int32>* progress);
 	void	SetPlayerQuest(Quest* quest, map<int32, int32>* progress);
 	void	AddPlayerQuest(Quest* quest, bool call_accepted = true, bool send_packets = true);
 	void	AddPlayerQuest(Quest* quest, bool call_accepted = true, bool send_packets = true);
 	void	RemovePlayerQuest(int32 id, bool send_update = true, bool delete_quest = true);
 	void	RemovePlayerQuest(int32 id, bool send_update = true, bool delete_quest = true);
@@ -305,7 +293,6 @@ public:
 	void	DisplayRandomizeFeatures(int32 features);
 	void	DisplayRandomizeFeatures(int32 features);
 	void	AcceptQuestReward(Quest* quest, int32 item_id);
 	void	AcceptQuestReward(Quest* quest, int32 item_id);
 	Quest*	GetPendingQuestAcceptance(int32 item_id);
 	Quest*	GetPendingQuestAcceptance(int32 item_id);
-	Quest*	GetActiveQuest(int32 quest_id);
 	void	DisplayConversation(int32 conversation_id, int32 spawn_id, vector<ConversationOption>* conversations, const char* text, const char* mp3, int32 key1, int32 key2, int8 language = 0, int8 can_close = 1);
 	void	DisplayConversation(int32 conversation_id, int32 spawn_id, vector<ConversationOption>* conversations, const char* text, const char* mp3, int32 key1, int32 key2, int8 language = 0, int8 can_close = 1);
 	void	DisplayConversation(Item* item, vector<ConversationOption>* conversations, const char* text, int8 type, const char* mp3 = 0, int32 key1 = 0, int32 key2 = 0, int8 language = 0, int8 can_close = 1);
 	void	DisplayConversation(Item* item, vector<ConversationOption>* conversations, const char* text, int8 type, const char* mp3 = 0, int32 key1 = 0, int32 key2 = 0, int8 language = 0, int8 can_close = 1);
 	void	DisplayConversation(Spawn* src, int8 type, vector<ConversationOption>* conversations, const char* text, const char* mp3 = 0, int32 key1 = 0, int32 key2 = 0, int8 language = 0, int8 can_close = 1);
 	void	DisplayConversation(Spawn* src, int8 type, vector<ConversationOption>* conversations, const char* text, const char* mp3 = 0, int32 key1 = 0, int32 key2 = 0, int8 language = 0, int8 can_close = 1);
@@ -588,11 +575,12 @@ public:
 	bool	RemoveRecipeFromPlayer(int32 recipe_id);
 	bool	RemoveRecipeFromPlayer(int32 recipe_id);
 	
 	
 	void	SaveSpells();
 	void	SaveSpells();
+	
+	void	GiveQuestReward(Quest* quest, bool has_displayed = false);
 private:
 private:
 	void	AddRecipeToPlayerPack(Recipe* recipe, PacketStruct* packet, int16* i);
 	void	AddRecipeToPlayerPack(Recipe* recipe, PacketStruct* packet, int16* i);
 	void    SavePlayerImages();
 	void    SavePlayerImages();
 	void	SkillChanged(Skill* skill, int16 previous_value, int16 new_value);
 	void	SkillChanged(Skill* skill, int16 previous_value, int16 new_value);
-	void	GiveQuestReward(Quest* quest, bool has_displayed = false);
 	void	SetStepComplete(int32 quest_id, int32 step);
 	void	SetStepComplete(int32 quest_id, int32 step);
 	void	AddStepProgress(int32 quest_id, int32 step, int32 progress);
 	void	AddStepProgress(int32 quest_id, int32 step, int32 progress);
 	
 	

+ 1 - 1
EQ2/source/WorldServer/zoneserver.cpp

@@ -2581,7 +2581,7 @@ void ZoneServer::AddLoot(NPC* npc, Spawn* killer){
 									{
 									{
 										player = (Player*)killer;
 										player = (Player*)killer;
 										// player has already completed the quest
 										// player has already completed the quest
-										if(player->GetCompletedQuest(drop->no_drop_quest_completed_id) && !player->GetGroupMemberInfo())
+										if(player->HasQuestBeenCompleted(drop->no_drop_quest_completed_id) && !player->GetGroupMemberInfo())
 										{
 										{
 											LogWrite(PLAYER__DEBUG, 0, "Player", "%s: Player has completed quest %u, skipping loot item %u", npc->GetName(), drop->no_drop_quest_completed_id, drop->item_id);
 											LogWrite(PLAYER__DEBUG, 0, "Player", "%s: Player has completed quest %u, skipping loot item %u", npc->GetName(), drop->no_drop_quest_completed_id, drop->item_id);
 											continue;
 											continue;