Added support for race/size/element/min level/max level quest objectives (#5191)
* Added support for race/size/element/min level/max level quest objectives
* Enabled Butler for the Richards hunting quests (ep16.1)
Co-authored-by: Aleos <aleos89@users.noreply.github.com>
Thanks to @attackjom, @Balferian !
Took some parts from b67c688e79 (diff-f3653b71c45029581a98314726e4d8f5)
thanks to @exneval !
This commit is contained in:
parent
28632e8328
commit
5ba29be2a3
@ -30,8 +30,18 @@
|
|||||||
# 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" (optionnal), [0-23]"h" (required), [0-59]"mn" (optionnal), [0-59]"s" (optionnal) format.
|
||||||
# Please note the number before "d" only shift the exact timer to the given day(s).
|
# Please note the number before "d" only shift the exact timer to the given day(s).
|
||||||
# Targets: Quest objective target. (Default: null)
|
# Targets: Quest objective target. (Default: null)
|
||||||
# - Mob Monster to kill.
|
# The target can be a couple of node Mob/Count or of Id/Race/Size/Element/MinLevel/MaxLevel.
|
||||||
# Count Amount of monsters to kill.
|
# If Mob is supplied, Count is required and the other fields are ignored.
|
||||||
|
# If Id is supplied, at least one other field of Race/Size/Element/MinLevel/MaxLevel is required.
|
||||||
|
# If Id is supplied, Count is required for each new entry.
|
||||||
|
# - 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.
|
||||||
|
# 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)
|
||||||
# Drops: Quest item drop targets. (Default: null)
|
# Drops: Quest item drop targets. (Default: null)
|
||||||
# - Mob Monster to kill. 0 will apply to all monsters. (Default: 0)
|
# - Mob Monster to kill. 0 will apply to all monsters. (Default: 0)
|
||||||
# Item Item to drop.
|
# Item Item to drop.
|
||||||
|
@ -30,8 +30,18 @@
|
|||||||
# 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" (optionnal), [0-23]"h" (required), [0-59]"mn" (optionnal), [0-59]"s" (optionnal) format.
|
||||||
# Please note the number before "d" only shift the exact timer to the given day(s).
|
# Please note the number before "d" only shift the exact timer to the given day(s).
|
||||||
# Targets: Quest objective target. (Default: null)
|
# Targets: Quest objective target. (Default: null)
|
||||||
# - Mob Monster to kill.
|
# The target can be a couple of node Mob/Count or of Id/Race/Size/Element/MinLevel/MaxLevel.
|
||||||
# Count Amount of monsters to kill.
|
# If Mob is supplied, Count is required and the other fields are ignored.
|
||||||
|
# If Id is supplied, at least one other field of Race/Size/Element/MinLevel/MaxLevel is required.
|
||||||
|
# If Id is supplied, Count is required for each new entry.
|
||||||
|
# - 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.
|
||||||
|
# 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)
|
||||||
# Drops: Quest item drop targets. (Default: null)
|
# Drops: Quest item drop targets. (Default: null)
|
||||||
# - Mob Monster to kill. 0 will apply to all monsters. (Default: 0)
|
# - Mob Monster to kill. 0 will apply to all monsters. (Default: 0)
|
||||||
# Item Item to drop.
|
# Item Item to drop.
|
||||||
|
@ -30,8 +30,18 @@
|
|||||||
# 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" (optionnal), [0-23]"h" (required), [0-59]"mn" (optionnal), [0-59]"s" (optionnal) format.
|
||||||
# Please note the number before "d" only shift the exact timer to the given day(s).
|
# Please note the number before "d" only shift the exact timer to the given day(s).
|
||||||
# Targets: Quest objective target. (Default: null)
|
# Targets: Quest objective target. (Default: null)
|
||||||
# - Mob Monster to kill.
|
# The target can be a couple of node Mob/Count or of Id/Race/Size/Element/MinLevel/MaxLevel.
|
||||||
# Count Amount of monsters to kill.
|
# If Mob is supplied, Count is required and the other fields are ignored.
|
||||||
|
# If Id is supplied, at least one other field of Race/Size/Element/MinLevel/MaxLevel is required.
|
||||||
|
# If Id is supplied, Count is required for each new entry.
|
||||||
|
# - 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.
|
||||||
|
# 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)
|
||||||
# Drops: Quest item drop targets. (Default: null)
|
# Drops: Quest item drop targets. (Default: null)
|
||||||
# - Mob Monster to kill. 0 will apply to all monsters. (Default: 0)
|
# - Mob Monster to kill. 0 will apply to all monsters. (Default: 0)
|
||||||
# Item Item to drop.
|
# Item Item to drop.
|
||||||
|
@ -30,8 +30,18 @@
|
|||||||
# 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" (optionnal), [0-23]"h" (required), [0-59]"mn" (optionnal), [0-59]"s" (optionnal) format.
|
||||||
# Please note the number before "d" only shift the exact timer to the given day(s).
|
# Please note the number before "d" only shift the exact timer to the given day(s).
|
||||||
# Targets: Quest objective target. (Default: null)
|
# Targets: Quest objective target. (Default: null)
|
||||||
# - Mob Monster to kill.
|
# The target can be a couple of node Mob/Count or of Id/Race/Size/Element/MinLevel/MaxLevel.
|
||||||
# Count Amount of monsters to kill.
|
# If Mob is supplied, Count is required and the other fields are ignored.
|
||||||
|
# If Id is supplied, at least one other field of Race/Size/Element/MinLevel/MaxLevel is required.
|
||||||
|
# If Id is supplied, Count is required for each new entry.
|
||||||
|
# - 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.
|
||||||
|
# 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)
|
||||||
# Drops: Quest item drop targets. (Default: null)
|
# Drops: Quest item drop targets. (Default: null)
|
||||||
# - Mob Monster to kill. 0 will apply to all monsters. (Default: 0)
|
# - Mob Monster to kill. 0 will apply to all monsters. (Default: 0)
|
||||||
# Item Item to drop.
|
# Item Item to drop.
|
||||||
@ -2245,24 +2255,74 @@ Body:
|
|||||||
Title: The Royal Richard
|
Title: The Royal Richard
|
||||||
- Id: 5404
|
- Id: 5404
|
||||||
Title: "[Repeat]Warrior Discipline-Human"
|
Title: "[Repeat]Warrior Discipline-Human"
|
||||||
|
Targets:
|
||||||
|
- Id: 1
|
||||||
|
Count: 50
|
||||||
|
Race: DemiHuman
|
||||||
|
MinLevel: 140
|
||||||
- Id: 5405
|
- Id: 5405
|
||||||
Title: "[Repeat]Warrior Discipline-Animal"
|
Title: "[Repeat]Warrior Discipline-Animal"
|
||||||
|
Targets:
|
||||||
|
- Id: 1
|
||||||
|
Count: 50
|
||||||
|
Race: Brute
|
||||||
|
MinLevel: 140
|
||||||
- Id: 5406
|
- Id: 5406
|
||||||
Title: "[Repeat]Warrior Discipline-Insect"
|
Title: "[Repeat]Warrior Discipline-Insect"
|
||||||
|
Targets:
|
||||||
|
- Id: 1
|
||||||
|
Count: 50
|
||||||
|
Race: Insect
|
||||||
|
MinLevel: 140
|
||||||
- Id: 5407
|
- Id: 5407
|
||||||
Title: "[Repeat]Warrior Discipline-Fish"
|
Title: "[Repeat]Warrior Discipline-Fish"
|
||||||
|
Targets:
|
||||||
|
- Id: 1
|
||||||
|
Count: 50
|
||||||
|
Race: Fish
|
||||||
|
MinLevel: 140
|
||||||
- Id: 5408
|
- Id: 5408
|
||||||
Title: "[Repeat]Warrior Discipline-Plant"
|
Title: "[Repeat]Warrior Discipline-Plant"
|
||||||
|
Targets:
|
||||||
|
- Id: 1
|
||||||
|
Count: 50
|
||||||
|
Race: Plant
|
||||||
|
MinLevel: 140
|
||||||
- Id: 5409
|
- Id: 5409
|
||||||
Title: "[Repeat]Warrior Discipline-Devil"
|
Title: "[Repeat]Warrior Discipline-Devil"
|
||||||
|
Targets:
|
||||||
|
- Id: 1
|
||||||
|
Count: 50
|
||||||
|
Race: Demon
|
||||||
|
MinLevel: 140
|
||||||
- Id: 5410
|
- Id: 5410
|
||||||
Title: "[Repeat]Warrior Discipline-Angel"
|
Title: "[Repeat]Warrior Discipline-Angel"
|
||||||
|
Targets:
|
||||||
|
- Id: 1
|
||||||
|
Count: 50
|
||||||
|
Race: Angel
|
||||||
|
MinLevel: 140
|
||||||
- Id: 5411
|
- Id: 5411
|
||||||
Title: "[Repeat]Warrior Discipline-Immortal"
|
Title: "[Repeat]Warrior Discipline-Immortal"
|
||||||
|
Targets:
|
||||||
|
- Id: 1
|
||||||
|
Count: 50
|
||||||
|
Race: Undead
|
||||||
|
MinLevel: 140
|
||||||
- Id: 5412
|
- Id: 5412
|
||||||
Title: "[Repeat]Warrior Discipline-Intangible"
|
Title: "[Repeat]Warrior Discipline-Intangible"
|
||||||
|
Targets:
|
||||||
|
- Id: 1
|
||||||
|
Count: 50
|
||||||
|
Race: Formless
|
||||||
|
MinLevel: 140
|
||||||
- Id: 5413
|
- Id: 5413
|
||||||
Title: "[Repeat]Warrior Discipline-Dragon"
|
Title: "[Repeat]Warrior Discipline-Dragon"
|
||||||
|
Targets:
|
||||||
|
- Id: 1
|
||||||
|
Count: 50
|
||||||
|
Race: Dragon
|
||||||
|
MinLevel: 140
|
||||||
- Id: 5414
|
- Id: 5414
|
||||||
Title: "[Stand by]Warrior Discipline"
|
Title: "[Stand by]Warrior Discipline"
|
||||||
TimeLimit: 4h
|
TimeLimit: 4h
|
||||||
|
@ -13,8 +13,18 @@
|
|||||||
# 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" (optionnal), [0-23]"h" (required), [0-59]"mn" (optionnal), [0-59]"s" (optionnal) format.
|
||||||
# Please note the number before "d" only shift the exact timer to the given day(s).
|
# Please note the number before "d" only shift the exact timer to the given day(s).
|
||||||
# Targets: Quest objective target. (Default: null)
|
# Targets: Quest objective target. (Default: null)
|
||||||
# - Mob Monster to kill.
|
# The target can be a couple of node Mob/Count or of Id/Race/Size/Element/MinLevel/MaxLevel.
|
||||||
# Count Amount of monsters to kill.
|
# If Mob is supplied, Count is required and the other fields are ignored.
|
||||||
|
# If Id is supplied, at least one other field of Race/Size/Element/MinLevel/MaxLevel is required.
|
||||||
|
# If Id is supplied, Count is required for each new entry.
|
||||||
|
# - 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.
|
||||||
|
# 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)
|
||||||
# Drops: Quest item drop targets. (Default: null)
|
# Drops: Quest item drop targets. (Default: null)
|
||||||
# - Mob Monster to kill. 0 will apply to all monsters. (Default: 0)
|
# - Mob Monster to kill. 0 will apply to all monsters. (Default: 0)
|
||||||
# Item Item to drop.
|
# Item Item to drop.
|
||||||
|
@ -8622,10 +8622,6 @@ prt_cas_q,80,80,4 script Butler for the Richards 1_M_LIBRARYMASTER,{
|
|||||||
next;
|
next;
|
||||||
}
|
}
|
||||||
if (checkquest(.@quest_list[.@i],HUNTING) == 2) {
|
if (checkquest(.@quest_list[.@i],HUNTING) == 2) {
|
||||||
// todo src side
|
|
||||||
mes "This quest isn't enabled for now.";
|
|
||||||
close;
|
|
||||||
|
|
||||||
if (isbegin_quest(5403) == 1)
|
if (isbegin_quest(5403) == 1)
|
||||||
completequest 5403;// The Royal Richard
|
completequest 5403;// The Royal Richard
|
||||||
erasequest .@quest_list[.@i];
|
erasequest .@quest_list[.@i];
|
||||||
|
122
src/map/clif.cpp
122
src/map/clif.cpp
@ -17048,12 +17048,55 @@ static void clif_quest_len(int def_len, int info_len, int avail_quests, int *lim
|
|||||||
(*len_out) = ((*limit_out) * info_len) + def_len;
|
(*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;
|
||||||
|
|
||||||
|
switch(race) {
|
||||||
|
case RC_FORMLESS: race_name = "Formless"; break;
|
||||||
|
case RC_UNDEAD: race_name = "Undead"; break;
|
||||||
|
case RC_BRUTE: race_name = "Brute"; break;
|
||||||
|
case RC_PLANT: race_name = "Plant"; break;
|
||||||
|
case RC_INSECT: race_name = "Insect"; break;
|
||||||
|
case RC_FISH: race_name = "Fish"; break;
|
||||||
|
case RC_DEMON: race_name = "Demon"; break;
|
||||||
|
case RC_DEMIHUMAN: race_name = "Demihuman"; break;
|
||||||
|
case RC_ANGEL: race_name = "Angel"; break;
|
||||||
|
case RC_DRAGON: race_name = "Dragon"; break;
|
||||||
|
case RC_ALL: race_name = ""; break;
|
||||||
|
default: race_name = "unknown"; break;
|
||||||
|
}
|
||||||
|
switch(size) {
|
||||||
|
case SZ_SMALL: size_name = "Small"; break;
|
||||||
|
case SZ_MEDIUM: size_name = "Medium"; break;
|
||||||
|
case SZ_BIG: size_name = "Large"; break;
|
||||||
|
case SZ_ALL: size_name = ""; break;
|
||||||
|
default: size_name = "unknown"; break;
|
||||||
|
}
|
||||||
|
switch(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;
|
||||||
|
case ELE_FIRE: ele_name = "Fire Element"; break;
|
||||||
|
case ELE_WIND: ele_name = "Wind Element"; break;
|
||||||
|
case ELE_POISON: ele_name = "Poison Element"; break;
|
||||||
|
case ELE_HOLY: ele_name = "Holy Element"; break;
|
||||||
|
case ELE_DARK: ele_name = "Shadow Element"; break;
|
||||||
|
case ELE_GHOST: ele_name = "Ghost Element"; break;
|
||||||
|
case ELE_UNDEAD: ele_name = "Undead Element"; break;
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
/// Sends list of all quest states
|
/// Sends list of all quest states
|
||||||
/// 02b1 <packet len>.W <num>.L { <quest id>.L <active>.B }*num (ZC_ALL_QUEST_LIST)
|
/// 02b1 <packet len>.W <num>.L { <quest id>.L <active>.B }*num (ZC_ALL_QUEST_LIST)
|
||||||
/// 097a <packet len>.W <num>.L { <quest id>.L <active>.B <remaining time>.L <time>.L <count>.W { <mob_id>.L <killed>.W <total>.W <mob name>.24B }*count }*num (ZC_ALL_QUEST_LIST2)
|
/// 097a <packet len>.W <num>.L { <quest id>.L <active>.B <remaining time>.L <time>.L <count>.W { <mob_id>.L <killed>.W <total>.W <mob name>.24B }*count }*num (ZC_ALL_QUEST_LIST2)
|
||||||
/// 09f8 <packet len>.W <num>.L { <quest id>.L <active>.B <remaining time>.L <time>.L <count>.W { <hunt identification>.L <mob type>.L <mob_id>.L <min level>.W <max level>.W <killed>.W <total>.W <mob name>.24B }*count }*num (ZC_ALL_QUEST_LIST3)
|
/// 09f8 <packet len>.W <num>.L { <quest id>.L <active>.B <remaining time>.L <time>.L <count>.W { <hunt identification>.L <mob type>.L <mob_id>.L <min level>.W <max level>.W <killed>.W <total>.W <mob name>.24B }*count }*num (ZC_ALL_QUEST_LIST3)
|
||||||
void clif_quest_send_list(struct map_session_data *sd)
|
void clif_quest_send_list(struct map_session_data *sd)
|
||||||
{
|
{
|
||||||
|
nullpo_retv(sd);
|
||||||
|
|
||||||
int fd = sd->fd;
|
int fd = sd->fd;
|
||||||
int i;
|
int i;
|
||||||
int offset = 8;
|
int offset = 8;
|
||||||
@ -17095,25 +17138,32 @@ void clif_quest_send_list(struct map_session_data *sd)
|
|||||||
for (int j = 0; j < qi->objectives.size(); j++) {
|
for (int j = 0; j < qi->objectives.size(); j++) {
|
||||||
mob = mob_db(qi->objectives[j]->mob_id);
|
mob = mob_db(qi->objectives[j]->mob_id);
|
||||||
|
|
||||||
|
e_race race = qi->objectives[j]->race;
|
||||||
|
e_size size = qi->objectives[j]->size;
|
||||||
|
e_element element = qi->objectives[j]->element;
|
||||||
|
|
||||||
#if PACKETVER >= 20150513
|
#if PACKETVER >= 20150513
|
||||||
WFIFOL(fd, offset) = sd->quest_log[i].quest_id * 1000 + j;
|
WFIFOL(fd, offset) = sd->quest_log[i].quest_id * 1000 + j;
|
||||||
offset += 4;
|
offset += 4;
|
||||||
WFIFOL(fd, offset) = 0; // TODO: Find info - mobType
|
WFIFOL(fd, offset) = (race ? race : (size ? size : (element ? element : 0)));
|
||||||
offset += 4;
|
offset += 4;
|
||||||
#endif
|
#endif
|
||||||
WFIFOL(fd, offset) = qi->objectives[j]->mob_id;
|
WFIFOL(fd, offset) = ((mob && qi->objectives[j]->mob_id > 0) ? qi->objectives[j]->mob_id : MOBID_PORING);
|
||||||
offset += 4;
|
offset += 4;
|
||||||
#if PACKETVER >= 20150513
|
#if PACKETVER >= 20150513
|
||||||
WFIFOW(fd, offset) = 0; // TODO: Find info - levelMin
|
WFIFOW(fd, offset) = qi->objectives[j]->min_level;
|
||||||
offset += 2;
|
offset += 2;
|
||||||
WFIFOW(fd, offset) = 0; // TODO: Find info - levelMax
|
WFIFOW(fd, offset) = qi->objectives[j]->max_level;
|
||||||
offset += 2;
|
offset += 2;
|
||||||
#endif
|
#endif
|
||||||
WFIFOW(fd, offset) = sd->quest_log[i].count[j];
|
WFIFOW(fd, offset) = sd->quest_log[i].count[j];
|
||||||
offset += 2;
|
offset += 2;
|
||||||
WFIFOW(fd, offset) = qi->objectives[j]->count;
|
WFIFOW(fd, offset) = qi->objectives[j]->count;
|
||||||
offset += 2;
|
offset += 2;
|
||||||
safestrncpy((char*)WFIFOP(fd, offset), mob->jname, NAME_LENGTH);
|
if (mob && qi->objectives[j]->mob_id > 0)
|
||||||
|
safestrncpy((char *)WFIFOP(fd,offset), mob->jname, NAME_LENGTH);
|
||||||
|
else
|
||||||
|
safestrncpy((char *)WFIFOP(fd,offset), clif_mobtype_name(race, size, element).c_str(), NAME_LENGTH);
|
||||||
offset += NAME_LENGTH;
|
offset += NAME_LENGTH;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -17143,10 +17193,11 @@ void clif_quest_send_list(struct map_session_data *sd)
|
|||||||
/// 02b2 <packet len>.W <num>.L { <quest id>.L <start time>.L <expire time>.L <mobs>.W { <mob id>.L <mob count>.W <mob name>.24B }*3 }*num
|
/// 02b2 <packet len>.W <num>.L { <quest id>.L <start time>.L <expire time>.L <mobs>.W { <mob id>.L <mob count>.W <mob name>.24B }*3 }*num
|
||||||
void clif_quest_send_mission(struct map_session_data *sd)
|
void clif_quest_send_mission(struct map_session_data *sd)
|
||||||
{
|
{
|
||||||
|
nullpo_retv(sd);
|
||||||
|
|
||||||
int fd = sd->fd;
|
int fd = sd->fd;
|
||||||
int limit = 0;
|
int limit = 0;
|
||||||
int len = sd->avail_quests*104+8;
|
int len = sd->avail_quests*104+8;
|
||||||
struct mob_db *mob;
|
|
||||||
|
|
||||||
clif_quest_len(8, 14 + ((6 + NAME_LENGTH) * MAX_QUEST_OBJECTIVES), sd->avail_quests, &limit, &len);
|
clif_quest_len(8, 14 + ((6 + NAME_LENGTH) * MAX_QUEST_OBJECTIVES), sd->avail_quests, &limit, &len);
|
||||||
WFIFOHEAD(fd, len);
|
WFIFOHEAD(fd, len);
|
||||||
@ -17163,10 +17214,14 @@ void clif_quest_send_mission(struct map_session_data *sd)
|
|||||||
WFIFOW(fd, i*104+20) = static_cast<uint16>(qi->objectives.size());
|
WFIFOW(fd, i*104+20) = static_cast<uint16>(qi->objectives.size());
|
||||||
|
|
||||||
for (int j = 0 ; j < qi->objectives.size(); j++) {
|
for (int j = 0 ; j < qi->objectives.size(); j++) {
|
||||||
WFIFOL(fd, i*104+22+j*30) = qi->objectives[j]->mob_id;
|
struct mob_db *mob = mob_db(qi->objectives[j]->mob_id);
|
||||||
|
|
||||||
|
WFIFOL(fd, i*104+22+j*30) = (mob ? qi->objectives[j]->mob_id : MOBID_PORING);
|
||||||
WFIFOW(fd, i*104+26+j*30) = sd->quest_log[i].count[j];
|
WFIFOW(fd, i*104+26+j*30) = sd->quest_log[i].count[j];
|
||||||
mob = mob_db(qi->objectives[j]->mob_id);
|
if (mob && qi->objectives[j]->mob_id > 0)
|
||||||
safestrncpy(WFIFOCP(fd, i*104+28+j*30), mob->jname, NAME_LENGTH);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -17180,8 +17235,13 @@ void clif_quest_send_mission(struct map_session_data *sd)
|
|||||||
/// 09f9 <quest id>.L <active>.B <start time>.L <expire time>.L <mobs>.W { <hunt identification>.L <mob type>.L <mob id>.L <min level>.W <max level>.W <mob count>.W <mob name>.24B }*3 (ZC_ADD_QUEST_EX)
|
/// 09f9 <quest id>.L <active>.B <start time>.L <expire time>.L <mobs>.W { <hunt identification>.L <mob type>.L <mob id>.L <min level>.W <max level>.W <mob count>.W <mob name>.24B }*3 (ZC_ADD_QUEST_EX)
|
||||||
void clif_quest_add(struct map_session_data *sd, struct quest *qd)
|
void clif_quest_add(struct map_session_data *sd, struct quest *qd)
|
||||||
{
|
{
|
||||||
|
nullpo_retv(sd);
|
||||||
|
nullpo_retv(qd);
|
||||||
|
|
||||||
int fd = sd->fd;
|
int fd = sd->fd;
|
||||||
std::shared_ptr<s_quest_db> qi = quest_search(qd->quest_id);
|
std::shared_ptr<s_quest_db> qi = quest_search(qd->quest_id);
|
||||||
|
if (!qi)
|
||||||
|
return;
|
||||||
#if PACKETVER >= 20150513
|
#if PACKETVER >= 20150513
|
||||||
int cmd = 0x9f9;
|
int cmd = 0x9f9;
|
||||||
#else
|
#else
|
||||||
@ -17197,25 +17257,31 @@ void clif_quest_add(struct map_session_data *sd, struct quest *qd)
|
|||||||
WFIFOW(fd, 15) = static_cast<uint16>(qi->objectives.size());
|
WFIFOW(fd, 15) = static_cast<uint16>(qi->objectives.size());
|
||||||
|
|
||||||
for (int i = 0, offset = 17; i < qi->objectives.size(); i++) {
|
for (int i = 0, offset = 17; i < qi->objectives.size(); i++) {
|
||||||
struct mob_db *mob;
|
struct mob_db *mob = mob_db(qi->objectives[i]->mob_id);
|
||||||
|
e_race race = qi->objectives[i]->race;
|
||||||
|
e_size size = qi->objectives[i]->size;
|
||||||
|
e_element element = qi->objectives[i]->element;
|
||||||
|
|
||||||
#if PACKETVER >= 20150513
|
#if PACKETVER >= 20150513
|
||||||
WFIFOL(fd, offset) = qd->quest_id * 1000 + i;
|
WFIFOL(fd, offset) = qd->quest_id * 1000 + i;
|
||||||
offset += 4;
|
offset += 4;
|
||||||
WFIFOL(fd, offset) = 0; // TODO: Find info - mobType
|
WFIFOL(fd, offset) = (race ? race : (size ? size : (element ? element : 0))); // effect ?
|
||||||
offset += 4;
|
offset += 4;
|
||||||
#endif
|
#endif
|
||||||
WFIFOL(fd, offset) = qi->objectives[i]->mob_id;
|
WFIFOL(fd, offset) = ((mob && qi->objectives[i]->mob_id > 0) ? qi->objectives[i]->mob_id : MOBID_PORING); // 0 can't be used as it displays "Novice" job regardless of the clif_mobtype_name
|
||||||
offset += 4;
|
offset += 4;
|
||||||
#if PACKETVER >= 20150513
|
#if PACKETVER >= 20150513
|
||||||
WFIFOW(fd, offset) = 0; // TODO: Find info - levelMin
|
WFIFOW(fd, offset) = qi->objectives[i]->min_level;
|
||||||
offset += 2;
|
offset += 2;
|
||||||
WFIFOW(fd, offset) = 0; // TODO: Find info - levelMax
|
WFIFOW(fd, offset) = qi->objectives[i]->max_level;
|
||||||
offset += 2;
|
offset += 2;
|
||||||
#endif
|
#endif
|
||||||
WFIFOW(fd, offset) = qd->count[i];
|
WFIFOW(fd, offset) = qd->count[i];
|
||||||
offset += 2;
|
offset += 2;
|
||||||
mob = mob_db(qi->objectives[i]->mob_id);
|
if (mob && qi->objectives[i]->mob_id > 0)
|
||||||
safestrncpy(WFIFOCP(fd, offset), mob->jname, NAME_LENGTH);
|
safestrncpy((char *)WFIFOP(fd,offset), mob->jname, NAME_LENGTH);
|
||||||
|
else
|
||||||
|
safestrncpy((char *)WFIFOP(fd,offset), clif_mobtype_name(race, size, element).c_str(), NAME_LENGTH);
|
||||||
offset += NAME_LENGTH;
|
offset += NAME_LENGTH;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -17257,7 +17323,7 @@ void clif_quest_delete(struct map_session_data *sd, int quest_id)
|
|||||||
/// Notification of an update to the hunting mission counter
|
/// Notification of an update to the hunting mission counter
|
||||||
/// 02b5 <packet len>.W <mobs>.W { <quest id>.L <mob id>.L <total count>.W <current count>.W }*3 (ZC_UPDATE_MISSION_HUNT)
|
/// 02b5 <packet len>.W <mobs>.W { <quest id>.L <mob id>.L <total count>.W <current count>.W }*3 (ZC_UPDATE_MISSION_HUNT)
|
||||||
/// 09fa <packet len>.W <mobs>.W { <quest id>.L <hunt identification>.L <total count>.W <current count>.W }*3 (ZC_UPDATE_MISSION_HUNT_EX)
|
/// 09fa <packet len>.W <mobs>.W { <quest id>.L <hunt identification>.L <total count>.W <current count>.W }*3 (ZC_UPDATE_MISSION_HUNT_EX)
|
||||||
void clif_quest_update_objective(struct map_session_data *sd, struct quest *qd, int mobid)
|
void clif_quest_update_objective(struct map_session_data *sd, struct quest *qd)
|
||||||
{
|
{
|
||||||
int fd = sd->fd;
|
int fd = sd->fd;
|
||||||
int offset = 6;
|
int offset = 6;
|
||||||
@ -17274,21 +17340,19 @@ void clif_quest_update_objective(struct map_session_data *sd, struct quest *qd,
|
|||||||
WFIFOW(fd, 4) = static_cast<uint16>(qi->objectives.size());
|
WFIFOW(fd, 4) = static_cast<uint16>(qi->objectives.size());
|
||||||
|
|
||||||
for (int i = 0; i < qi->objectives.size(); i++) {
|
for (int i = 0; i < qi->objectives.size(); i++) {
|
||||||
if (mobid == 0 || mobid == qi->objectives[i]->mob_id) {
|
WFIFOL(fd, offset) = qd->quest_id;
|
||||||
WFIFOL(fd, offset) = qd->quest_id;
|
offset += 4;
|
||||||
offset += 4;
|
|
||||||
#if PACKETVER >= 20150513
|
#if PACKETVER >= 20150513
|
||||||
WFIFOL(fd, offset) = qd->quest_id * 1000 + i;
|
WFIFOL(fd, offset) = qd->quest_id * 1000 + i;
|
||||||
offset += 4;
|
offset += 4;
|
||||||
#else
|
#else
|
||||||
WFIFOL(fd, offset) = qi->objectives[i]->mob_id;
|
WFIFOL(fd, offset) = qi->objectives[i]->mob_id;
|
||||||
offset += 4;
|
offset += 4;
|
||||||
#endif
|
#endif
|
||||||
WFIFOW(fd, offset) = qi->objectives[i]->count;
|
WFIFOW(fd, offset) = qi->objectives[i]->count;
|
||||||
offset += 2;
|
offset += 2;
|
||||||
WFIFOW(fd, offset) = qd->count[i];
|
WFIFOW(fd, offset) = qd->count[i];
|
||||||
offset += 2;
|
offset += 2;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WFIFOW(fd, 2) = offset;
|
WFIFOW(fd, 2) = offset;
|
||||||
|
@ -930,7 +930,7 @@ void clif_quest_send_mission(struct map_session_data * sd);
|
|||||||
void clif_quest_add(struct map_session_data * sd, struct quest * qd);
|
void clif_quest_add(struct map_session_data * sd, struct quest * qd);
|
||||||
void clif_quest_delete(struct map_session_data * sd, int quest_id);
|
void clif_quest_delete(struct map_session_data * sd, int quest_id);
|
||||||
void clif_quest_update_status(struct map_session_data * sd, int quest_id, bool active);
|
void clif_quest_update_status(struct map_session_data * sd, int quest_id, bool active);
|
||||||
void clif_quest_update_objective(struct map_session_data * sd, struct quest * qd, int mobid);
|
void clif_quest_update_objective(struct map_session_data * sd, struct quest * qd);
|
||||||
void clif_quest_show_event(struct map_session_data *sd, struct block_list *bl, e_questinfo_types effect, e_questinfo_markcolor color);
|
void clif_quest_show_event(struct map_session_data *sd, struct block_list *bl, e_questinfo_types effect, e_questinfo_markcolor color);
|
||||||
void clif_displayexp(struct map_session_data *sd, unsigned int exp, char type, bool quest, bool lost);
|
void clif_displayexp(struct map_session_data *sd, unsigned int exp, char type, bool quest, bool lost);
|
||||||
|
|
||||||
|
@ -3009,9 +3009,9 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (sd->status.party_id)
|
if (sd->status.party_id)
|
||||||
map_foreachinallrange(quest_update_objective_sub, &md->bl, AREA_SIZE, BL_PC, sd->status.party_id, md->mob_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);
|
||||||
else if (sd->avail_quests)
|
else if (sd->avail_quests)
|
||||||
quest_update_objective(sd, md->mob_id);
|
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));
|
||||||
|
|
||||||
if (achievement_db.mobexists(md->mob_id)) {
|
if (achievement_db.mobexists(md->mob_id)) {
|
||||||
if (battle_config.achievement_mob_share > 0 && sd->status.party_id > 0)
|
if (battle_config.achievement_mob_share > 0 && sd->status.party_id > 0)
|
||||||
|
@ -94,7 +94,7 @@ enum MobDamageLogFlag
|
|||||||
MDLF_SELF
|
MDLF_SELF
|
||||||
};
|
};
|
||||||
|
|
||||||
enum size {
|
enum e_size : uint8 {
|
||||||
SZ_SMALL = 0,
|
SZ_SMALL = 0,
|
||||||
SZ_MEDIUM,
|
SZ_MEDIUM,
|
||||||
SZ_BIG,
|
SZ_BIG,
|
||||||
|
@ -105,26 +105,49 @@ uint64 QuestDatabase::parseBodyNode(const YAML::Node &node) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this->nodeExists(targetNode, "Mob"))
|
if (!this->nodeExists(targetNode, "Mob") && !this->nodeExists(targetNode, "Id")) {
|
||||||
continue;
|
this->invalidWarning(targetNode, "Missing Target 'Mob' or 'Id', skipping.\n");
|
||||||
|
|
||||||
std::string mob_name;
|
|
||||||
|
|
||||||
if (!this->asString(targetNode, "Mob", mob_name))
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
struct mob_db *mob = mobdb_search_aegisname(mob_name.c_str());
|
|
||||||
|
|
||||||
if (!mob) {
|
|
||||||
this->invalidWarning(targetNode["Mob"], "Mob %s does not exist, skipping.\n", mob_name.c_str());
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//std::shared_ptr<s_quest_objective> target = util::vector_find(quest->objectives, mob->vd.class_);
|
|
||||||
std::shared_ptr<s_quest_objective> target;
|
std::shared_ptr<s_quest_objective> target;
|
||||||
std::vector<std::shared_ptr<s_quest_objective>>::iterator it = std::find_if(quest->objectives.begin(), quest->objectives.end(), [&](std::shared_ptr<s_quest_objective> const &v) {
|
std::vector<std::shared_ptr<s_quest_objective>>::iterator it;
|
||||||
return (*v).mob_id == mob->vd.class_;
|
uint16 index = 0, mob_id = 0;
|
||||||
});
|
|
||||||
|
if (this->nodeExists(targetNode, "Mob")) {
|
||||||
|
|
||||||
|
std::string mob_name;
|
||||||
|
|
||||||
|
if (!this->asString(targetNode, "Mob", mob_name))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
struct mob_db *mob = mobdb_search_aegisname(mob_name.c_str());
|
||||||
|
|
||||||
|
if (!mob) {
|
||||||
|
this->invalidWarning(targetNode["Mob"], "Mob %s does not exist, skipping.\n", mob_name.c_str());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
mob_id = mob->vd.class_;
|
||||||
|
|
||||||
|
it = std::find_if(quest->objectives.begin(), quest->objectives.end(), [&](std::shared_ptr<s_quest_objective> const &v) {
|
||||||
|
return (*v).mob_id == mob_id;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (!this->asUInt16(targetNode, "Id", index)) {
|
||||||
|
this->invalidWarning(targetNode, "Missing 'Id', skipping.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (index == 0) {
|
||||||
|
this->invalidWarning(targetNode["Id"], "'Id' can't be 0, skipping.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
it = std::find_if(quest->objectives.begin(), quest->objectives.end(), [&](std::shared_ptr<s_quest_objective> const &v) {
|
||||||
|
return (*v).index == index;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (it != quest->objectives.end())
|
if (it != quest->objectives.end())
|
||||||
target = (*it);
|
target = (*it);
|
||||||
@ -136,11 +159,118 @@ uint64 QuestDatabase::parseBodyNode(const YAML::Node &node) {
|
|||||||
if (!targetExists) {
|
if (!targetExists) {
|
||||||
if (!this->nodeExists(targetNode, "Count")) {
|
if (!this->nodeExists(targetNode, "Count")) {
|
||||||
this->invalidWarning(targetNode["Count"], "Targets has no Count value specified, skipping.\n");
|
this->invalidWarning(targetNode["Count"], "Targets has no Count value specified, skipping.\n");
|
||||||
continue;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
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->invalidWarning(targetNode, "Targets is missing required field, skipping.\n");
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
target = std::make_shared<s_quest_objective>();
|
target = std::make_shared<s_quest_objective>();
|
||||||
target->mob_id = mob->vd.class_;
|
target->index = index;
|
||||||
|
target->mob_id = mob_id;
|
||||||
|
target->min_level = 0;
|
||||||
|
target->max_level = 0;
|
||||||
|
target->race = RC_ALL;
|
||||||
|
target->size = SZ_ALL;
|
||||||
|
target->element = ELE_ALL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this->nodeExists(targetNode, "Mob")) {
|
||||||
|
if (this->nodeExists(targetNode, "MinLevel")) {
|
||||||
|
uint16 level;
|
||||||
|
|
||||||
|
if (!this->asUInt16(targetNode, "MinLevel", level))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
target->min_level = level;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->nodeExists(targetNode, "MaxLevel")) {
|
||||||
|
uint16 level;
|
||||||
|
|
||||||
|
if (!this->asUInt16(targetNode, "MaxLevel", level))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (target->min_level > level) {
|
||||||
|
this->invalidWarning(targetNode["MaxLevel"], "%d's MinLevel is greater than MaxLevel. Defaulting MaxLevel to %d.\n", target->min_level, MAX_LEVEL);
|
||||||
|
level = MAX_LEVEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
target->max_level = level;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->nodeExists(targetNode, "Race")) {
|
||||||
|
std::string race;
|
||||||
|
|
||||||
|
if (!this->asString(targetNode, "Race", race))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
std::string race_constant = "RC_" + race;
|
||||||
|
int64 constant;
|
||||||
|
|
||||||
|
if (!script_get_constant(race_constant.c_str(), &constant)) {
|
||||||
|
this->invalidWarning(targetNode["Race"], "Invalid race %s, skipping.\n", race.c_str());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (constant < RC_FORMLESS || constant > RC_ALL || constant == RC_PLAYER_HUMAN || constant == RC_PLAYER_DORAM) {
|
||||||
|
this->invalidWarning(targetNode["Race"], "Unsupported race %s, skipping.\n", race.c_str());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
target->race = static_cast<e_race>(constant);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->nodeExists(targetNode, "Size")) {
|
||||||
|
std::string size_;
|
||||||
|
|
||||||
|
if (!this->asString(targetNode, "Size", size_))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
std::string size_constant = "Size_" + size_;
|
||||||
|
int64 constant;
|
||||||
|
|
||||||
|
if (!script_get_constant(size_constant.c_str(), &constant)) {
|
||||||
|
this->invalidWarning(targetNode["Size"], "Invalid size type %s, skipping.\n", size_.c_str());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (constant < SZ_SMALL || constant > SZ_ALL) {
|
||||||
|
this->invalidWarning(targetNode["size"], "Unsupported size %s, skipping.\n", size_.c_str());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
target->size = static_cast<e_size>(constant);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->nodeExists(targetNode, "Element")) {
|
||||||
|
std::string element;
|
||||||
|
|
||||||
|
if (!this->asString(targetNode, "Element", element))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
std::string element_constant = "Ele_" + element;
|
||||||
|
int64 constant;
|
||||||
|
|
||||||
|
if (!script_get_constant(element_constant.c_str(), &constant)) {
|
||||||
|
this->invalidWarning(targetNode["Element"], "Invalid element %s, skipping.\n", element.c_str());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (constant < ELE_NEUTRAL || constant > ELE_ALL) {
|
||||||
|
this->invalidWarning(targetNode["Element"], "Unsupported element %s, skipping.\n", element.c_str());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
target->element = static_cast<e_element>(constant);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if max_level is set, min_level is 1
|
||||||
|
if (target->min_level == 0 && target->max_level > 0)
|
||||||
|
target->min_level = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->nodeExists(targetNode, "Count")) {
|
if (this->nodeExists(targetNode, "Count")) {
|
||||||
@ -336,7 +466,7 @@ int quest_pc_login(struct map_session_data *sd)
|
|||||||
|
|
||||||
//@TODO[Haru]: Is this necessary? Does quest_send_mission not take care of this?
|
//@TODO[Haru]: Is this necessary? Does quest_send_mission not take care of this?
|
||||||
for (int i = 0; i < sd->avail_quests; i++)
|
for (int i = 0; i < sd->avail_quests; i++)
|
||||||
clif_quest_update_objective(sd, &sd->quest_log[i], 0);
|
clif_quest_update_objective(sd, &sd->quest_log[i]);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -406,7 +536,7 @@ int quest_add(struct map_session_data *sd, int quest_id)
|
|||||||
sd->save_quest = true;
|
sd->save_quest = true;
|
||||||
|
|
||||||
clif_quest_add(sd, &sd->quest_log[n]);
|
clif_quest_add(sd, &sd->quest_log[n]);
|
||||||
clif_quest_update_objective(sd, &sd->quest_log[n], 0);
|
clif_quest_update_objective(sd, &sd->quest_log[n]);
|
||||||
|
|
||||||
if( save_settings&CHARSAVE_QUEST )
|
if( save_settings&CHARSAVE_QUEST )
|
||||||
chrif_save(sd, CSAVE_NORMAL);
|
chrif_save(sd, CSAVE_NORMAL);
|
||||||
@ -456,7 +586,7 @@ int quest_change(struct map_session_data *sd, int qid1, int qid2)
|
|||||||
|
|
||||||
clif_quest_delete(sd, qid1);
|
clif_quest_delete(sd, qid1);
|
||||||
clif_quest_add(sd, &sd->quest_log[i]);
|
clif_quest_add(sd, &sd->quest_log[i]);
|
||||||
clif_quest_update_objective(sd, &sd->quest_log[i], 0);
|
clif_quest_update_objective(sd, &sd->quest_log[i]);
|
||||||
|
|
||||||
if( save_settings&CHARSAVE_QUEST )
|
if( save_settings&CHARSAVE_QUEST )
|
||||||
chrif_save(sd, CSAVE_NORMAL);
|
chrif_save(sd, CSAVE_NORMAL);
|
||||||
@ -509,47 +639,81 @@ int quest_delete(struct map_session_data *sd, int quest_id)
|
|||||||
* @param ap : Argument list, expecting:
|
* @param ap : Argument list, expecting:
|
||||||
* int Party ID
|
* int Party ID
|
||||||
* int Mob ID
|
* int Mob ID
|
||||||
|
* int Mob Level
|
||||||
|
* int Mob Race
|
||||||
|
* int Mob Size
|
||||||
|
* int Mob Element
|
||||||
*/
|
*/
|
||||||
int quest_update_objective_sub(struct block_list *bl, va_list ap)
|
int quest_update_objective_sub(struct block_list *bl, va_list ap)
|
||||||
{
|
{
|
||||||
struct map_session_data *sd;
|
|
||||||
int mob_id, party_id;
|
|
||||||
|
|
||||||
nullpo_ret(bl);
|
nullpo_ret(bl);
|
||||||
nullpo_ret(sd = (struct map_session_data *)bl);
|
|
||||||
|
|
||||||
party_id = va_arg(ap,int);
|
struct map_session_data *sd;
|
||||||
mob_id = va_arg(ap,int);
|
|
||||||
|
nullpo_ret(sd = (struct map_session_data *)bl);
|
||||||
|
|
||||||
if( !sd->avail_quests )
|
if( !sd->avail_quests )
|
||||||
return 0;
|
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 != party_id )
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
quest_update_objective(sd, mob_id);
|
quest_update_objective(sd, mob_id, mob_level, mob_race, mob_size, mob_element);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the quest objectives for a character after killing a monster, including the handling of quest-granted drops.
|
* Updates the quest objectives for a character after killing a monster, including the handling of quest-granted drops.
|
||||||
* @param sd : Character's data
|
* @param sd: Character's data
|
||||||
* @param mob_id : Monster ID
|
* @param mob_id: Monster ID
|
||||||
|
* @param mob_level: Monster Level
|
||||||
|
* @param mob_race: Monster Race
|
||||||
|
* @param mob_size: Monster Size
|
||||||
|
* @param mob_element: Monster Element
|
||||||
*/
|
*/
|
||||||
void quest_update_objective(struct map_session_data *sd, int mob_id)
|
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)
|
||||||
{
|
{
|
||||||
|
nullpo_retv(sd);
|
||||||
|
|
||||||
for (int i = 0; i < sd->avail_quests; i++) {
|
for (int i = 0; i < sd->avail_quests; i++) {
|
||||||
if (sd->quest_log[i].state == Q_COMPLETE) // Skip complete quests
|
if (sd->quest_log[i].state == Q_COMPLETE) // Skip complete quests
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
std::shared_ptr<s_quest_db> qi = quest_search(sd->quest_log[i].quest_id);
|
std::shared_ptr<s_quest_db> qi = quest_search(sd->quest_log[i].quest_id);
|
||||||
|
if (!qi)
|
||||||
|
continue;
|
||||||
|
|
||||||
// Process quest objectives
|
// Process quest objectives
|
||||||
for (int j = 0; j < qi->objectives.size(); j++) {
|
for (int j = 0; j < qi->objectives.size(); j++) {
|
||||||
if (qi->objectives[j]->mob_id == mob_id && sd->quest_log[i].count[j] < qi->objectives[j]->count) {
|
uint8 objective_check = 0; // Must pass all 5 checks
|
||||||
|
|
||||||
|
if (qi->objectives[j]->mob_id == mob_id)
|
||||||
|
objective_check = 5;
|
||||||
|
else if (qi->objectives[j]->mob_id == 0) {
|
||||||
|
if (qi->objectives[j]->min_level == 0 || qi->objectives[j]->min_level <= mob_level)
|
||||||
|
objective_check++;
|
||||||
|
if (qi->objectives[j]->max_level == 0 || qi->objectives[j]->max_level >= mob_level)
|
||||||
|
objective_check++;
|
||||||
|
if (qi->objectives[j]->race == RC_ALL || qi->objectives[j]->race == mob_race)
|
||||||
|
objective_check++;
|
||||||
|
if (qi->objectives[j]->size == SZ_ALL || qi->objectives[j]->size == mob_size)
|
||||||
|
objective_check++;
|
||||||
|
if (qi->objectives[j]->element == ELE_ALL || qi->objectives[j]->element == mob_element)
|
||||||
|
objective_check++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (objective_check == 5 && sd->quest_log[i].count[j] < qi->objectives[j]->count) {
|
||||||
sd->quest_log[i].count[j]++;
|
sd->quest_log[i].count[j]++;
|
||||||
sd->save_quest = true;
|
sd->save_quest = true;
|
||||||
clif_quest_update_objective(sd, &sd->quest_log[i], mob_id);
|
clif_quest_update_objective(sd, &sd->quest_log[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -562,21 +726,21 @@ void quest_update_objective(struct map_session_data *sd, int mob_id)
|
|||||||
if (!itemdb_exists(it->nameid))
|
if (!itemdb_exists(it->nameid))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
struct item item = {};
|
struct item entry = {};
|
||||||
|
|
||||||
item.nameid = it->nameid;
|
entry.nameid = it->nameid;
|
||||||
item.identify = itemdb_isidentified(it->nameid);
|
entry.identify = itemdb_isidentified(it->nameid);
|
||||||
item.amount = it->count;
|
entry.amount = it->count;
|
||||||
//#ifdef BOUND_ITEMS
|
//#ifdef BOUND_ITEMS
|
||||||
// item.bound = it.bound;
|
// entry.bound = it->bound;
|
||||||
//#endif
|
//#endif
|
||||||
// if (it.isGUID)
|
// if (it.isGUID)
|
||||||
// item.unique_id = pc_generate_unique_id(sd);
|
// item.unique_id = pc_generate_unique_id(sd);
|
||||||
|
|
||||||
char temp;
|
e_additem_result result;
|
||||||
|
|
||||||
if ((temp = pc_additem(sd, &item, 1, LOG_TYPE_QUEST)) != ADDITEM_SUCCESS) // Failed to obtain the item
|
if ((result = pc_additem(sd, &entry, 1, LOG_TYPE_QUEST)) != ADDITEM_SUCCESS) // Failed to obtain the item
|
||||||
clif_additem(sd, 0, 0, temp);
|
clif_additem(sd, 0, 0, result);
|
||||||
// else if (it.isAnnounced || itemdb_exists(it.nameid)->flag.broadcast)
|
// else if (it.isAnnounced || itemdb_exists(it.nameid)->flag.broadcast)
|
||||||
// intif_broadcast_obtain_special_item(sd, it.nameid, it.mob_id, ITEMOBTAIN_TYPE_MONSTER_ITEM);
|
// intif_broadcast_obtain_special_item(sd, it.nameid, it.mob_id, ITEMOBTAIN_TYPE_MONSTER_ITEM);
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#include "map.hpp"
|
#include "map.hpp"
|
||||||
|
|
||||||
struct map_session_data;
|
struct map_session_data;
|
||||||
|
enum e_size : uint8;
|
||||||
|
|
||||||
struct s_quest_dropitem {
|
struct s_quest_dropitem {
|
||||||
uint16 nameid;
|
uint16 nameid;
|
||||||
@ -25,8 +26,13 @@ struct s_quest_dropitem {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct s_quest_objective {
|
struct s_quest_objective {
|
||||||
|
uint16 index;
|
||||||
uint16 mob_id;
|
uint16 mob_id;
|
||||||
uint16 count;
|
uint16 count;
|
||||||
|
uint16 min_level, max_level;
|
||||||
|
e_race race;
|
||||||
|
e_size size;
|
||||||
|
e_element element;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct s_quest_db {
|
struct s_quest_db {
|
||||||
@ -64,7 +70,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_delete(struct map_session_data *sd, int quest_id);
|
||||||
int quest_change(struct map_session_data *sd, int qid1, int qid2);
|
int quest_change(struct map_session_data *sd, int qid1, int qid2);
|
||||||
int quest_update_objective_sub(struct block_list *bl, va_list ap);
|
int quest_update_objective_sub(struct block_list *bl, va_list ap);
|
||||||
void quest_update_objective(struct map_session_data *sd, int mob_id);
|
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);
|
||||||
int quest_update_status(struct map_session_data *sd, int quest_id, e_quest_state status);
|
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);
|
int quest_check(struct map_session_data *sd, int quest_id, e_quest_check_type type);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user