浏览代码

Quest type: hunting location (#5564)

Fixes #5490

Co-authored-by: Lemongrass3110 <lemongrass@kstp.at>
Balfear 4 年之前
父节点
当前提交
78093fb469
共有 10 个文件被更改,包括 144 次插入66 次删除
  1. 7 5
      db/import-tmpl/quest_db.yml
  2. 7 5
      db/pre-re/quest_db.yml
  3. 7 5
      db/quest_db.yml
  4. 7 5
      db/re/quest_db.yml
  5. 6 4
      doc/yaml/db/quest_db.yml
  6. 57 14
      src/map/clif.cpp
  7. 2 2
      src/map/mob.cpp
  8. 46 23
      src/map/quest.cpp
  9. 4 2
      src/map/quest.hpp
  10. 1 1
      src/tool/csv2yaml.cpp

+ 7 - 5
db/import-tmpl/quest_db.yml

@@ -27,7 +27,7 @@
 #   TimeLimit       Amount of time before the quest expires. (Default: 0)
 #                   Use a number following by "d" for day(s), "h" for hour(s), "mn" for minute(s), and "s" for second(s).
 #                   Specify with "+" for how long until the quest expires.
-#                   Specify without "+" for the exact time the quest expires using "d" (optionnal), [0-23]"h" (required), [0-59]"mn" (optionnal), [0-59]"s" (optionnal) format.
+#                   Specify without "+" for the exact time the quest expires using "d" (optional), [0-23]"h" (required), [0-59]"mn" (optional), [0-59]"s" (optional) format.
 #                   Please note the number before "d" only shift the exact timer to the given day(s).
 #   Targets:        Quest objective target. (Default: null)
 #                   The target can be a couple of node Mob/Count or of Id/Race/Size/Element/MinLevel/MaxLevel.
@@ -37,11 +37,13 @@
 #     - Mob         Monster to kill (aegis monster name).
 #       Count       Amount of monsters to kill. Set to 0 to skip the target on import.
 #       Id          Unique target index for the quest Id. Requires a positive number.
-#       Race        Monster race target (default All). Valids race are Angel, Brute, DemiHuman, Demon, Dragon, Fish, Formless, Insect, Plant, Undead, All.
-#       Size        Monster size target (default All). Valids size are Small, Medium, Large, All.
-#       Element     Monster element target (default All). Valids elements are Dark, Earth, Fire, Ghost, Holy, Neutral, Poison, Undead, Water, Wind, All.
+#       Race        Monster race target (default All). Valid races are Angel, Brute, DemiHuman, Demon, Dragon, Fish, Formless, Insect, Plant, Undead, All.
+#       Size        Monster size target (default All). Valid sizes are Small, Medium, Large, All.
+#       Element     Monster element target (default All). Valid elements are Dark, Earth, Fire, Ghost, Holy, Neutral, Poison, Undead, Water, Wind, All.
 #       MinLevel    Minimum monster level target. If not supplied but MaxLevel defined, MinLevel is 1. Set to 0 to ignore MinLevel on import. (Default: 0)
 #       MaxLevel    Maximum monster level target. Set to 0 to ignore MaxLevel on import. (Default: 0)
+#       Location    Name of hunting location from mapindex. (Default any location)
+#       MapName     Displayed map name in quest UI. (Default: empty string)
 #   Drops:          Quest item drop targets. (Default: null)
 #     - Mob         Monster to kill. 0 will apply to all monsters. (Default: 0)
 #       Item        Item to drop.
@@ -51,4 +53,4 @@
 
 Header:
   Type: QUEST_DB
-  Version: 1
+  Version: 2

+ 7 - 5
db/pre-re/quest_db.yml

@@ -27,7 +27,7 @@
 #   TimeLimit       Amount of time before the quest expires. (Default: 0)
 #                   Use a number following by "d" for day(s), "h" for hour(s), "mn" for minute(s), and "s" for second(s).
 #                   Specify with "+" for how long until the quest expires.
-#                   Specify without "+" for the exact time the quest expires using "d" (optionnal), [0-23]"h" (required), [0-59]"mn" (optionnal), [0-59]"s" (optionnal) format.
+#                   Specify without "+" for the exact time the quest expires using "d" (optional), [0-23]"h" (required), [0-59]"mn" (optional), [0-59]"s" (optional) format.
 #                   Please note the number before "d" only shift the exact timer to the given day(s).
 #   Targets:        Quest objective target. (Default: null)
 #                   The target can be a couple of node Mob/Count or of Id/Race/Size/Element/MinLevel/MaxLevel.
@@ -37,11 +37,13 @@
 #     - Mob         Monster to kill (aegis monster name).
 #       Count       Amount of monsters to kill. Set to 0 to skip the target on import.
 #       Id          Unique target index for the quest Id. Requires a positive number.
-#       Race        Monster race target (default All). Valids race are Angel, Brute, DemiHuman, Demon, Dragon, Fish, Formless, Insect, Plant, Undead, All.
-#       Size        Monster size target (default All). Valids size are Small, Medium, Large, All.
-#       Element     Monster element target (default All). Valids elements are Dark, Earth, Fire, Ghost, Holy, Neutral, Poison, Undead, Water, Wind, All.
+#       Race        Monster race target (default All). Valid races are Angel, Brute, DemiHuman, Demon, Dragon, Fish, Formless, Insect, Plant, Undead, All.
+#       Size        Monster size target (default All). Valid sizes are Small, Medium, Large, All.
+#       Element     Monster element target (default All). Valid elements are Dark, Earth, Fire, Ghost, Holy, Neutral, Poison, Undead, Water, Wind, All.
 #       MinLevel    Minimum monster level target. If not supplied but MaxLevel defined, MinLevel is 1. Set to 0 to ignore MinLevel on import. (Default: 0)
 #       MaxLevel    Maximum monster level target. Set to 0 to ignore MaxLevel on import. (Default: 0)
+#       Location    Name of hunting location from mapindex. (Default any location)
+#       MapName     Displayed map name in quest UI. (Default: empty string)
 #   Drops:          Quest item drop targets. (Default: null)
 #     - Mob         Monster to kill. 0 will apply to all monsters. (Default: 0)
 #       Item        Item to drop.
@@ -51,7 +53,7 @@
 
 Header:
   Type: QUEST_DB
-  Version: 1
+  Version: 2
 
 Body:
   - Id: 1000

+ 7 - 5
db/quest_db.yml

@@ -27,7 +27,7 @@
 #   TimeLimit       Amount of time before the quest expires. (Default: 0)
 #                   Use a number following by "d" for day(s), "h" for hour(s), "mn" for minute(s), and "s" for second(s).
 #                   Specify with "+" for how long until the quest expires.
-#                   Specify without "+" for the exact time the quest expires using "d" (optionnal), [0-23]"h" (required), [0-59]"mn" (optionnal), [0-59]"s" (optionnal) format.
+#                   Specify without "+" for the exact time the quest expires using "d" (optional), [0-23]"h" (required), [0-59]"mn" (optional), [0-59]"s" (optional) format.
 #                   Please note the number before "d" only shift the exact timer to the given day(s).
 #   Targets:        Quest objective target. (Default: null)
 #                   The target can be a couple of node Mob/Count or of Id/Race/Size/Element/MinLevel/MaxLevel.
@@ -37,11 +37,13 @@
 #     - Mob         Monster to kill (aegis monster name).
 #       Count       Amount of monsters to kill. Set to 0 to skip the target on import.
 #       Id          Unique target index for the quest Id. Requires a positive number.
-#       Race        Monster race target (default All). Valids race are Angel, Brute, DemiHuman, Demon, Dragon, Fish, Formless, Insect, Plant, Undead, All.
-#       Size        Monster size target (default All). Valids size are Small, Medium, Large, All.
-#       Element     Monster element target (default All). Valids elements are Dark, Earth, Fire, Ghost, Holy, Neutral, Poison, Undead, Water, Wind, All.
+#       Race        Monster race target (default All). Valid races are Angel, Brute, DemiHuman, Demon, Dragon, Fish, Formless, Insect, Plant, Undead, All.
+#       Size        Monster size target (default All). Valid sizes are Small, Medium, Large, All.
+#       Element     Monster element target (default All). Valid elements are Dark, Earth, Fire, Ghost, Holy, Neutral, Poison, Undead, Water, Wind, All.
 #       MinLevel    Minimum monster level target. If not supplied but MaxLevel defined, MinLevel is 1. Set to 0 to ignore MinLevel on import. (Default: 0)
 #       MaxLevel    Maximum monster level target. Set to 0 to ignore MaxLevel on import. (Default: 0)
+#       Location    Name of hunting location from mapindex. (Default any location)
+#       MapName     Displayed map name in quest UI. (Default: empty string)
 #   Drops:          Quest item drop targets. (Default: null)
 #     - Mob         Monster to kill. 0 will apply to all monsters. (Default: 0)
 #       Item        Item to drop.
@@ -51,7 +53,7 @@
 
 Header:
   Type: QUEST_DB
-  Version: 1
+  Version: 2
 
 Footer:
   Imports:

+ 7 - 5
db/re/quest_db.yml

@@ -27,7 +27,7 @@
 #   TimeLimit       Amount of time before the quest expires. (Default: 0)
 #                   Use a number following by "d" for day(s), "h" for hour(s), "mn" for minute(s), and "s" for second(s).
 #                   Specify with "+" for how long until the quest expires.
-#                   Specify without "+" for the exact time the quest expires using "d" (optionnal), [0-23]"h" (required), [0-59]"mn" (optionnal), [0-59]"s" (optionnal) format.
+#                   Specify without "+" for the exact time the quest expires using "d" (optional), [0-23]"h" (required), [0-59]"mn" (optional), [0-59]"s" (optional) format.
 #                   Please note the number before "d" only shift the exact timer to the given day(s).
 #   Targets:        Quest objective target. (Default: null)
 #                   The target can be a couple of node Mob/Count or of Id/Race/Size/Element/MinLevel/MaxLevel.
@@ -37,11 +37,13 @@
 #     - Mob         Monster to kill (aegis monster name).
 #       Count       Amount of monsters to kill. Set to 0 to skip the target on import.
 #       Id          Unique target index for the quest Id. Requires a positive number.
-#       Race        Monster race target (default All). Valids race are Angel, Brute, DemiHuman, Demon, Dragon, Fish, Formless, Insect, Plant, Undead, All.
-#       Size        Monster size target (default All). Valids size are Small, Medium, Large, All.
-#       Element     Monster element target (default All). Valids elements are Dark, Earth, Fire, Ghost, Holy, Neutral, Poison, Undead, Water, Wind, All.
+#       Race        Monster race target (default All). Valid races are Angel, Brute, DemiHuman, Demon, Dragon, Fish, Formless, Insect, Plant, Undead, All.
+#       Size        Monster size target (default All). Valid sizes are Small, Medium, Large, All.
+#       Element     Monster element target (default All). Valid elements are Dark, Earth, Fire, Ghost, Holy, Neutral, Poison, Undead, Water, Wind, All.
 #       MinLevel    Minimum monster level target. If not supplied but MaxLevel defined, MinLevel is 1. Set to 0 to ignore MinLevel on import. (Default: 0)
 #       MaxLevel    Maximum monster level target. Set to 0 to ignore MaxLevel on import. (Default: 0)
+#       Location    Name of hunting location from mapindex. (Default any location)
+#       MapName     Displayed map name in quest UI. (Default: empty string)
 #   Drops:          Quest item drop targets. (Default: null)
 #     - Mob         Monster to kill. 0 will apply to all monsters. (Default: 0)
 #       Item        Item to drop.
@@ -51,7 +53,7 @@
 
 Header:
   Type: QUEST_DB
-  Version: 1
+  Version: 2
 
 Body:
   - Id: 1000

+ 6 - 4
doc/yaml/db/quest_db.yml

@@ -10,7 +10,7 @@
 #   TimeLimit       Amount of time before the quest expires. (Default: 0)
 #                   Use a number following by "d" for day(s), "h" for hour(s), "mn" for minute(s), and "s" for second(s).
 #                   Specify with "+" for how long until the quest expires.
-#                   Specify without "+" for the exact time the quest expires using "d" (optionnal), [0-23]"h" (required), [0-59]"mn" (optionnal), [0-59]"s" (optionnal) format.
+#                   Specify without "+" for the exact time the quest expires using "d" (optional), [0-23]"h" (required), [0-59]"mn" (optional), [0-59]"s" (optional) format.
 #                   Please note the number before "d" only shift the exact timer to the given day(s).
 #   Targets:        Quest objective target. (Default: null)
 #                   The target can be a couple of node Mob/Count or of Id/Race/Size/Element/MinLevel/MaxLevel.
@@ -20,11 +20,13 @@
 #     - Mob         Monster to kill (aegis monster name).
 #       Count       Amount of monsters to kill. Set to 0 to skip the target on import.
 #       Id          Unique target index for the quest Id. Requires a positive number.
-#       Race        Monster race target (default All). Valids race are Angel, Brute, DemiHuman, Demon, Dragon, Fish, Formless, Insect, Plant, Undead, All.
-#       Size        Monster size target (default All). Valids size are Small, Medium, Large, All.
-#       Element     Monster element target (default All). Valids elements are Dark, Earth, Fire, Ghost, Holy, Neutral, Poison, Undead, Water, Wind, All.
+#       Race        Monster race target (default All). Valid races are Angel, Brute, DemiHuman, Demon, Dragon, Fish, Formless, Insect, Plant, Undead, All.
+#       Size        Monster size target (default All). Valid sizes are Small, Medium, Large, All.
+#       Element     Monster element target (default All). Valid elements are Dark, Earth, Fire, Ghost, Holy, Neutral, Poison, Undead, Water, Wind, All.
 #       MinLevel    Minimum monster level target. If not supplied but MaxLevel defined, MinLevel is 1. Set to 0 to ignore MinLevel on import. (Default: 0)
 #       MaxLevel    Maximum monster level target. Set to 0 to ignore MaxLevel on import. (Default: 0)
+#       Location    Name of hunting location from mapindex. (Default any location)
+#       MapName     Displayed map name in quest UI. (Default: empty string)
 #   Drops:          Quest item drop targets. (Default: null)
 #     - Mob         Monster to kill. 0 will apply to all monsters. (Default: 0)
 #       Item        Item to drop.

+ 57 - 14
src/map/clif.cpp

@@ -17198,10 +17198,10 @@ static void clif_quest_len(int def_len, int info_len, int avail_quests, int *lim
 	(*len_out) = ((*limit_out) * info_len) + def_len;
 }
 
-std::string clif_mobtype_name(e_race race, e_size size, e_element element) {
-	std::string race_name, size_name, ele_name;
+std::string clif_quest_string( std::shared_ptr<s_quest_objective> objective ){
+	std::string race_name;
 
-	switch(race) {
+	switch( objective->race ){
 		case RC_FORMLESS:	race_name = "Formless"; break;
 		case RC_UNDEAD:		race_name = "Undead"; break;
 		case RC_BRUTE:		race_name = "Brute"; break;
@@ -17212,17 +17212,27 @@ std::string clif_mobtype_name(e_race race, e_size size, e_element element) {
 		case RC_DEMIHUMAN:	race_name = "Demihuman"; break;
 		case RC_ANGEL:		race_name = "Angel"; break;
 		case RC_DRAGON:		race_name = "Dragon"; break;
+		default:
+			ShowWarning( "clif_quest_string: Unsupported race %d - using empty string...\n", objective->race );
+			// Fallthrough
 		case RC_ALL:		race_name = ""; break;
-		default:			race_name = "unknown"; break;
 	}
-	switch(size) {
+
+	std::string size_name;
+
+	switch( objective->size ){
 		case SZ_SMALL:	size_name = "Small"; break;
 		case SZ_MEDIUM:	size_name = "Medium"; break;
 		case SZ_BIG:	size_name = "Large"; break;
+		default:
+			ShowWarning( "clif_quest_string: Unsupported size %d - using empty string...\n", objective->size );
+			// Fallthrough
 		case SZ_ALL:	size_name = ""; break;
-		default:		size_name = "unknown"; break;
 	}
-	switch(element) {
+
+	std::string ele_name;
+
+	switch( objective->element ){
 		case ELE_NEUTRAL:	ele_name = "Neutral Element"; break;
 		case ELE_WATER:		ele_name = "Water Element"; break;
 		case ELE_EARTH:		ele_name = "Earth Element"; break;
@@ -17233,10 +17243,43 @@ std::string clif_mobtype_name(e_race race, e_size size, e_element element) {
 		case ELE_DARK:		ele_name = "Shadow Element"; break;
 		case ELE_GHOST:		ele_name = "Ghost Element"; break;
 		case ELE_UNDEAD:	ele_name = "Undead Element"; break;
+		default:
+			ShowWarning( "clif_quest_string: Unsupported element %d - using empty string...\n", objective->element );
+			// Fallthrough
 		case ELE_ALL:		ele_name = ""; break;
-		default:			ele_name = "unknown"; break;
 	}
-	return (race_name + (race_name.size() && size_name.size() ? ", " + size_name : size_name) + ((race_name.size() || size_name.size()) && ele_name.size() ? ", " + ele_name : ele_name));
+
+	std::string str;
+
+	if( !objective->map_name.empty() ){
+		str += objective->map_name;
+	}
+
+	if( !race_name.empty() ){
+		if( !str.empty() ){
+			str += ", ";
+		}
+
+		str += race_name;
+	}
+
+	if( !size_name.empty() ){
+		if( !str.empty() ){
+			str += ", ";
+		}
+
+		str += size_name;
+	}
+
+	if( !ele_name.empty() ){
+		if( !str.empty() ){
+			str += ", ";
+		}
+
+		str += ele_name;
+	}
+	
+	return str;
 }
 
 /// Sends list of all quest states
@@ -17311,9 +17354,9 @@ void clif_quest_send_list(struct map_session_data *sd)
 				WFIFOW(fd, offset) = qi->objectives[j]->count;
 				offset += 2;
 				if (mob && qi->objectives[j]->mob_id > 0)
-					safestrncpy((char *)WFIFOP(fd,offset), mob->jname, NAME_LENGTH);
+					safestrncpy(WFIFOCP(fd,offset), mob->jname, NAME_LENGTH);
 				else
-					safestrncpy((char *)WFIFOP(fd,offset), clif_mobtype_name(race, size, element).c_str(), NAME_LENGTH);
+					safestrncpy(WFIFOCP(fd,offset), clif_quest_string(qi->objectives[j]).c_str(), NAME_LENGTH);
 				offset += NAME_LENGTH;
 			}
 		}
@@ -17371,7 +17414,7 @@ void clif_quest_send_mission(struct map_session_data *sd)
 			if (mob && qi->objectives[j]->mob_id > 0)
 				safestrncpy(WFIFOCP(fd, i*104+28+j*30), mob->jname, NAME_LENGTH);
 			else
-				safestrncpy(WFIFOCP(fd, i*104+28+j*30), clif_mobtype_name(qi->objectives[j]->race, qi->objectives[j]->size, qi->objectives[j]->element).c_str(), NAME_LENGTH);
+				safestrncpy(WFIFOCP(fd, i*104+28+j*30), clif_quest_string(qi->objectives[j]).c_str(), NAME_LENGTH);
 		}
 	}
 
@@ -17429,9 +17472,9 @@ void clif_quest_add(struct map_session_data *sd, struct quest *qd)
 		WFIFOW(fd, offset) = qd->count[i];
 		offset += 2;
 		if (mob && qi->objectives[i]->mob_id > 0)
-			safestrncpy((char *)WFIFOP(fd,offset), mob->jname, NAME_LENGTH);
+			safestrncpy(WFIFOCP(fd,offset), mob->jname, NAME_LENGTH);
 		else
-			safestrncpy((char *)WFIFOP(fd,offset), clif_mobtype_name(race, size, element).c_str(), NAME_LENGTH);
+			safestrncpy(WFIFOCP(fd,offset), clif_quest_string(qi->objectives[i]).c_str(), NAME_LENGTH);
 		offset += NAME_LENGTH;
 	}
 

+ 2 - 2
src/map/mob.cpp

@@ -3078,9 +3078,9 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
 			}
 
 			if (sd->status.party_id)
-				map_foreachinallrange(quest_update_objective_sub, &md->bl, AREA_SIZE, BL_PC, sd->status.party_id, md->mob_id, md->level, status->race, status->size, status->def_ele);
+				map_foreachinallrange(quest_update_objective_sub, &md->bl, AREA_SIZE, BL_PC, sd->status.party_id, md);
 			else if (sd->avail_quests)
-				quest_update_objective(sd, md->mob_id, md->level, static_cast<e_race>(status->race), static_cast<e_size>(status->size), static_cast<e_element>(status->def_ele));
+				quest_update_objective(sd, md);
 
 			if (achievement_db.mobexists(md->mob_id)) {
 				if (battle_config.achievement_mob_share > 0 && sd->status.party_id > 0)

+ 46 - 23
src/map/quest.cpp

@@ -163,7 +163,8 @@ uint64 QuestDatabase::parseBodyNode(const YAML::Node &node) {
 				}
 
 				if (!this->nodeExists(targetNode, "Mob") && !this->nodeExists(targetNode, "MinLevel") && !this->nodeExists(targetNode, "MaxLevel") &&
-						!this->nodeExists(targetNode, "Race") && !this->nodeExists(targetNode, "Size") && !this->nodeExists(targetNode, "Element")) {
+						!this->nodeExists(targetNode, "Race") && !this->nodeExists(targetNode, "Size") && !this->nodeExists(targetNode, "Element") &&
+						!this->nodeExists(targetNode, "Location") && !this->nodeExists(targetNode, "MapName")) {
 					this->invalidWarning(targetNode, "Targets is missing required field, skipping.\n");
 					return 0;
 				}
@@ -176,6 +177,8 @@ uint64 QuestDatabase::parseBodyNode(const YAML::Node &node) {
 				target->race = RC_ALL;
 				target->size = SZ_ALL;
 				target->element = ELE_ALL;
+				target->mapid = -1;
+				target->map_name = "";
 			}
 
 			if (!this->nodeExists(targetNode, "Mob")) {
@@ -268,6 +271,31 @@ uint64 QuestDatabase::parseBodyNode(const YAML::Node &node) {
 					target->element = static_cast<e_element>(constant);
 				}
 
+				if (this->nodeExists(targetNode, "Location")) {
+					std::string location;
+
+					if (!this->asString(targetNode, "Location", location))
+						return 0;
+
+					uint16 mapindex = mapindex_name2idx(location.c_str(), nullptr);
+
+					if (mapindex == 0) {
+						this->invalidWarning(targetNode["Location"], "Map \"%s\" not found.\n", location.c_str());
+						return 0;
+					}
+
+					target->mapid = map_mapindex2mapid(mapindex);
+				}
+
+				if (this->nodeExists(targetNode, "MapName")) {
+					std::string map_name;
+
+					if (!this->asString(targetNode, "MapName", map_name))
+						return 0;
+
+					target->map_name = map_name;
+				}
+
 				// if max_level is set, min_level is 1
 				if (target->min_level == 0 && target->max_level > 0)
 					target->min_level = 1;
@@ -648,24 +676,17 @@ int quest_update_objective_sub(struct block_list *bl, va_list ap)
 {
 	nullpo_ret(bl);
 
-	struct map_session_data *sd;
+	struct map_session_data *sd = BL_CAST(BL_PC, bl);
 
-	nullpo_ret(sd = (struct map_session_data *)bl);
+	nullpo_ret(sd);
 
 	if( !sd->avail_quests )
 		return 0;
-
-	int party_id = va_arg(ap,int);
-	int mob_id = va_arg(ap, int);
-	int mob_level = va_arg(ap, int);
-	e_race mob_race = static_cast<e_race>(va_arg(ap, int));
-	e_size mob_size = static_cast<e_size>(va_arg(ap, int));
-	e_element mob_element = static_cast<e_element>(va_arg(ap, int));
 	
-	if( sd->status.party_id != party_id )
+	if( sd->status.party_id != va_arg(ap, int))
 		return 0;
 
-	quest_update_objective(sd, mob_id, mob_level, mob_race, mob_size, mob_element);
+	quest_update_objective(sd, va_arg(ap, struct mob_data*));
 
 	return 1;
 }
@@ -679,7 +700,7 @@ int quest_update_objective_sub(struct block_list *bl, va_list ap)
  * @param mob_size: Monster Size
  * @param mob_element: Monster Element
  */
-void quest_update_objective(struct map_session_data *sd, int mob_id, int mob_level, e_race mob_race, e_size mob_size, e_element mob_element)
+void quest_update_objective(struct map_session_data *sd, struct mob_data* md)
 {
 	nullpo_retv(sd);
 
@@ -693,24 +714,26 @@ void quest_update_objective(struct map_session_data *sd, int mob_id, int mob_lev
 
 		// Process quest objectives
 		for (int j = 0; j < qi->objectives.size(); j++) {
-			uint8 objective_check = 0; // Must pass all 5 checks
+			uint8 objective_check = 0; // Must pass all 6 checks
 
-			if (qi->objectives[j]->mob_id == mob_id)
-				objective_check = 5;
+			if (qi->objectives[j]->mob_id == md->mob_id)
+				objective_check = 6;
 			else if (qi->objectives[j]->mob_id == 0) {
-				if (qi->objectives[j]->min_level == 0 || qi->objectives[j]->min_level <= mob_level)
+				if (qi->objectives[j]->min_level == 0 || qi->objectives[j]->min_level <= md->level)
+					objective_check++;
+				if (qi->objectives[j]->max_level == 0 || qi->objectives[j]->max_level >= md->level)
 					objective_check++;
-				if (qi->objectives[j]->max_level == 0 || qi->objectives[j]->max_level >= mob_level)
+				if (qi->objectives[j]->race == RC_ALL || qi->objectives[j]->race == md->status.race)
 					objective_check++;
-				if (qi->objectives[j]->race == RC_ALL || qi->objectives[j]->race == mob_race)
+				if (qi->objectives[j]->size == SZ_ALL || qi->objectives[j]->size == md->status.size)
 					objective_check++;
-				if (qi->objectives[j]->size == SZ_ALL || qi->objectives[j]->size == mob_size)
+				if (qi->objectives[j]->element == ELE_ALL || qi->objectives[j]->element == md->status.def_ele)
 					objective_check++;
-				if (qi->objectives[j]->element == ELE_ALL || qi->objectives[j]->element == mob_element)
+				if (qi->objectives[j]->mapid < 0 || (qi->objectives[j]->mapid == sd->bl.m && md->spawn_timer != INVALID_TIMER))
 					objective_check++;
 			}
 
-			if (objective_check == 5 && sd->quest_log[i].count[j] < qi->objectives[j]->count)  {
+			if (objective_check == 6 && sd->quest_log[i].count[j] < qi->objectives[j]->count)  {
 				sd->quest_log[i].count[j]++;
 				sd->save_quest = true;
 				clif_quest_update_objective(sd, &sd->quest_log[i]);
@@ -719,7 +742,7 @@ void quest_update_objective(struct map_session_data *sd, int mob_id, int mob_lev
 
 		// Process quest-granted extra drop bonuses
 		for (const auto &it : qi->dropitem) {
-			if (it->mob_id != 0 && it->mob_id != mob_id)
+			if (it->mob_id != 0 && it->mob_id != md->mob_id)
 				continue;
 			if (it->rate < 10000 && rnd()%10000 >= it->rate)
 				continue; // TODO: Should this be affected by server rates?

+ 4 - 2
src/map/quest.hpp

@@ -33,6 +33,8 @@ struct s_quest_objective {
 	e_race race;
 	e_size size;
 	e_element element;
+	int16 mapid;
+	std::string map_name;
 };
 
 struct s_quest_db {
@@ -53,7 +55,7 @@ enum e_quest_check_type : uint8 {
 
 class QuestDatabase : public TypesafeYamlDatabase<uint32, s_quest_db> {
 public:
-	QuestDatabase() : TypesafeYamlDatabase("QUEST_DB", 1) {
+	QuestDatabase() : TypesafeYamlDatabase("QUEST_DB", 2) {
 
 	}
 
@@ -70,7 +72,7 @@ int quest_add(struct map_session_data *sd, int quest_id);
 int quest_delete(struct map_session_data *sd, int quest_id);
 int quest_change(struct map_session_data *sd, int qid1, int qid2);
 int quest_update_objective_sub(struct block_list *bl, va_list ap);
-void quest_update_objective(struct map_session_data *sd, int mob_id, int mob_level, e_race mob_race, e_size mob_size, e_element mob_element);
+void quest_update_objective(struct map_session_data *sd, struct mob_data* md);
 int quest_update_status(struct map_session_data *sd, int quest_id, e_quest_state status);
 int quest_check(struct map_session_data *sd, int quest_id, e_quest_check_type type);
 

+ 1 - 1
src/tool/csv2yaml.cpp

@@ -499,7 +499,7 @@ int do_init( int argc, char** argv ){
 		return 0;
 	}
 
-	if (!process("QUEST_DB", 1, root_paths, "quest_db", [](const std::string &path, const std::string &name_ext) -> bool {
+	if (!process("QUEST_DB", 2, root_paths, "quest_db", [](const std::string &path, const std::string &name_ext) -> bool {
 		return sv_readdb(path.c_str(), name_ext.c_str(), ',', 3 + MAX_QUEST_OBJECTIVES * 2 + MAX_QUEST_DROPS * 3, 100, -1, &quest_read_db, false);
 	})) {
 		return 0;