summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Hercules.xcodeproj/project.pbxproj12
-rw-r--r--conf/common/inter-server.conf1
-rw-r--r--db/achievement_rank_db.conf43
-rw-r--r--db/constants.conf48
-rw-r--r--db/pre-re/achievement_db.conf6079
-rw-r--r--db/pre-re/item_db.conf33
-rw-r--r--db/re/achievement_db.conf6769
-rw-r--r--db/re/item_db.conf167
-rw-r--r--db/re/mob_db.conf387
-rw-r--r--doc/constants.md70
-rw-r--r--sql-files/item_db.sql4
-rw-r--r--sql-files/item_db_re.sql15
-rw-r--r--sql-files/main.sql25
-rw-r--r--sql-files/mob_db_re.sql8
-rw-r--r--sql-files/upgrades/2018-06-03--00-10.sql40
-rw-r--r--sql-files/upgrades/2018-06-03--17-16.sql24
-rw-r--r--sql-files/upgrades/2018-07-24--03-23.sql2
-rw-r--r--sql-files/upgrades/index.txt2
-rw-r--r--src/char/HPMchar.c2
-rw-r--r--src/char/Makefile.in8
-rw-r--r--src/char/char.c27
-rw-r--r--src/char/char.h1
-rw-r--r--src/char/int_achievement.c252
-rw-r--r--src/char/int_achievement.h53
-rw-r--r--src/char/inter.c6
-rw-r--r--src/char/mapif.c120
-rw-r--r--src/char/mapif.h5
-rw-r--r--src/common/HPMDataCheck.h22
-rw-r--r--src/common/HPMSymbols.inc.h14
-rw-r--r--src/common/mmo.h20
-rw-r--r--src/map/HPMmap.c1
-rw-r--r--src/map/Makefile.in4
-rw-r--r--src/map/achievement.c1983
-rw-r--r--src/map/achievement.h289
-rw-r--r--src/map/atcommand.c6
-rw-r--r--src/map/chat.c5
-rw-r--r--src/map/chrif.c2
-rw-r--r--src/map/clif.c357
-rw-r--r--src/map/clif.h8
-rw-r--r--src/map/intif.c103
-rw-r--r--src/map/intif.h5
-rw-r--r--src/map/map.c4
-rw-r--r--src/map/map.h11
-rw-r--r--src/map/mob.c7
-rw-r--r--src/map/npc.c4
-rw-r--r--src/map/packets.h4
-rw-r--r--src/map/packets_struct.h66
-rw-r--r--src/map/party.c4
-rw-r--r--src/map/pc.c48
-rw-r--r--src/map/pc.h8
-rw-r--r--src/map/pet.c7
-rw-r--r--src/map/script.c86
-rw-r--r--src/map/unit.c2
-rw-r--r--src/plugins/HPMHooking.c2
-rw-r--r--src/plugins/HPMHooking/HPMHooking.Defs.inc150
-rw-r--r--src/plugins/HPMHooking/HPMHooking_char.HPMHooksCore.inc49
-rw-r--r--src/plugins/HPMHooking/HPMHooking_char.HookingPoints.inc15
-rw-r--r--src/plugins/HPMHooking/HPMHooking_char.Hooks.inc331
-rw-r--r--src/plugins/HPMHooking/HPMHooking_char.sources.inc1
-rw-r--r--src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc245
-rw-r--r--src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc62
-rw-r--r--src/plugins/HPMHooking/HPMHooking_map.Hooks.inc1613
-rw-r--r--src/plugins/HPMHooking/HPMHooking_map.sources.inc1
-rw-r--r--vcproj-12/char-server.vcxproj2
-rw-r--r--vcproj-12/char-server.vcxproj.filters6
-rw-r--r--vcproj-12/map-server.vcxproj2
-rw-r--r--vcproj-12/map-server.vcxproj.filters6
-rw-r--r--vcproj-14/char-server.vcxproj2
-rw-r--r--vcproj-14/char-server.vcxproj.filters6
-rw-r--r--vcproj-14/map-server.vcxproj2
-rw-r--r--vcproj-14/map-server.vcxproj.filters6
-rw-r--r--vcproj-15/char-server.vcxproj2
-rw-r--r--vcproj-15/char-server.vcxproj.filters6
-rw-r--r--vcproj-15/map-server.vcxproj2
-rw-r--r--vcproj-15/map-server.vcxproj.filters6
75 files changed, 19696 insertions, 94 deletions
diff --git a/Hercules.xcodeproj/project.pbxproj b/Hercules.xcodeproj/project.pbxproj
index bb3149d3a..44ff7b53f 100644
--- a/Hercules.xcodeproj/project.pbxproj
+++ b/Hercules.xcodeproj/project.pbxproj
@@ -171,6 +171,8 @@
A5F7946C191CA34E002293AB /* sysinfo.c in Sources */ = {isa = PBXBuildFile; fileRef = A5F79469191CA34E002293AB /* sysinfo.c */; };
A5F7946D191CA34E002293AB /* sysinfo.c in Sources */ = {isa = PBXBuildFile; fileRef = A5F79469191CA34E002293AB /* sysinfo.c */; };
A5F7946E191CA34E002293AB /* sysinfo.c in Sources */ = {isa = PBXBuildFile; fileRef = A5F79469191CA34E002293AB /* sysinfo.c */; };
+ D0647BA51E793E7300D0843D /* int_achievement.c in Sources */ = {isa = PBXBuildFile; fileRef = D0647BA31E793E7300D0843D /* int_achievement.c */; };
+ D0647BA81E793E8200D0843D /* achievement.c in Sources */ = {isa = PBXBuildFile; fileRef = D0647BA61E793E8200D0843D /* achievement.c */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
@@ -444,6 +446,10 @@
A5F7946A191CA34E002293AB /* sysinfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sysinfo.h; path = src/common/sysinfo.h; sourceTree = "<group>"; };
A5F7946B191CA34E002293AB /* sysinfo.inc */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 4; name = sysinfo.inc; path = src/common/sysinfo.inc; sourceTree = "<group>"; };
A5F79476191CA3F4002293AB /* sysinfogen.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = sysinfogen.sh; sourceTree = "<group>"; };
+ D0647BA31E793E7300D0843D /* int_achievement.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = int_achievement.c; path = src/char/int_achievement.c; sourceTree = SOURCE_ROOT; };
+ D0647BA41E793E7300D0843D /* int_achievement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = int_achievement.h; path = src/char/int_achievement.h; sourceTree = SOURCE_ROOT; };
+ D0647BA61E793E8200D0843D /* achievement.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = achievement.c; path = src/map/achievement.c; sourceTree = SOURCE_ROOT; };
+ D0647BA71E793E8200D0843D /* achievement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = achievement.h; path = src/map/achievement.h; sourceTree = SOURCE_ROOT; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -561,6 +567,8 @@
A5467AD81A16FD08008AFAA6 /* geoip.h */,
A5B894AB1A03CDFA005AD22E /* HPMchar.c */,
A5B894AC1A03CDFA005AD22E /* HPMchar.h */,
+ D0647BA31E793E7300D0843D /* int_achievement.c */,
+ D0647BA41E793E7300D0843D /* int_achievement.h */,
A56CC745185657D9009EB79C /* int_auction.c */,
A56CC746185657D9009EB79C /* int_auction.h */,
A530267D202D792F0060E394 /* int_clan.c */,
@@ -600,6 +608,8 @@
A56CC67D18564357009EB79C /* map-server */ = {
isa = PBXGroup;
children = (
+ D0647BA61E793E8200D0843D /* achievement.c */,
+ D0647BA71E793E8200D0843D /* achievement.h */,
A56CC76A18565812009EB79C /* atcommand.c */,
A56CC76B18565812009EB79C /* atcommand.h */,
A56CC76C18565812009EB79C /* battle.c */,
@@ -1191,6 +1201,7 @@
A56CC6E5185643BB009EB79C /* memmgr.c in Sources */,
A56CC6E2185643BB009EB79C /* HPM.c in Sources */,
A56CC765185657D9009EB79C /* int_pet.c in Sources */,
+ D0647BA51E793E7300D0843D /* int_achievement.c in Sources */,
A56CC769185657D9009EB79C /* pincode.c in Sources */,
A56CC6F1185643BB009EB79C /* mutex.c in Sources */,
A56CC762185657D9009EB79C /* int_mail.c in Sources */,
@@ -1288,6 +1299,7 @@
A56CC6D1185643BB009EB79C /* core.c in Sources */,
A56CC7D118565812009EB79C /* npc.c in Sources */,
A56CC6D4185643BB009EB79C /* db.c in Sources */,
+ D0647BA81E793E8200D0843D /* achievement.c in Sources */,
A56CC704185643BB009EB79C /* showmsg.c in Sources */,
A56CC6E0185643BB009EB79C /* grfio.c in Sources */,
A56CC70D185643BB009EB79C /* strlib.c in Sources */,
diff --git a/conf/common/inter-server.conf b/conf/common/inter-server.conf
index 3310c9e5c..1e738c587 100644
--- a/conf/common/inter-server.conf
+++ b/conf/common/inter-server.conf
@@ -84,6 +84,7 @@ inter_configuration: {
hotkey_db: "hotkey"
scdata_db: "sc_data"
cart_db: "cart_inventory"
+ achievement_db: "char_achievements"
inventory_db: "inventory"
charlog_db: "charlog"
storage_db: "storage"
diff --git a/db/achievement_rank_db.conf b/db/achievement_rank_db.conf
new file mode 100644
index 000000000..e19194fad
--- /dev/null
+++ b/db/achievement_rank_db.conf
@@ -0,0 +1,43 @@
+//================= Hercules Database ==========================================
+//= _ _ _
+//= | | | | | |
+//= | |_| | ___ _ __ ___ _ _| | ___ ___
+//= | _ |/ _ \ '__/ __| | | | |/ _ \/ __|
+//= | | | | __/ | | (__| |_| | | __/\__ \
+//= \_| |_/\___|_| \___|\__,_|_|\___||___/
+//================= License ====================================================
+//= This file is part of Hercules.
+//= http://herc.ws - http://github.com/HerculesWS/Hercules
+//=
+//= Copyright (C) 2018 Hercules Dev Team
+//=
+//= Hercules is free software: you can redistribute it and/or modify
+//= it under the terms of the GNU General Public License as published by
+//= the Free Software Foundation, either version 3 of the License, or
+//= (at your option) any later version.
+//=
+//= This program is distributed in the hope that it will be useful,
+//= but WITHOUT ANY WARRANTY; without even the implied warranty of
+//= MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+//= GNU General Public License for more details.
+//=
+//= You should have received a copy of the GNU General Public License
+//= along with this program. If not, see <http://www.gnu.org/licenses/>.
+//==============================================================================
+//= Achievement Rank Database
+//==============================================================================
+
+achievement_rank_db:
+{
+ Rank1: 18
+ Rank2: 31
+ Rank3: 49
+ Rank4: 73
+ Rank5: 135
+ Rank6: 104
+ Rank7: 140
+ Rank8: 214
+ Rank9: 305
+ Rank10: 257
+ Rank11: 300
+}
diff --git a/db/constants.conf b/db/constants.conf
index b7bc24985..c3b1fdb57 100644
--- a/db/constants.conf
+++ b/db/constants.conf
@@ -3931,4 +3931,52 @@ constants_db: {
HAT_EF_QSCARABA: 54
HAT_EF_FSTONE: 55
HAT_EF_MAGICCIRCLE: 56
+
+ comment__: "Achievement Types"
+ ACH_QUEST: 0
+ ACH_KILL_PC_TOTAL: 1
+ ACH_KILL_PC_JOB: 2
+ ACH_KILL_PC_JOBTYPE: 3
+ ACH_KILL_MOB_CLASS: 4
+ ACH_DAMAGE_PC_MAX: 5
+ ACH_DAMAGE_PC_TOTAL: 6
+ ACH_DAMAGE_PC_REC_MAX: 7
+ ACH_DAMAGE_PC_REC_TOTAL: 8
+ ACH_DAMAGE_MOB_MAX: 9
+ ACH_DAMAGE_MOB_TOTAL: 10
+ ACH_DAMAGE_MOB_REC_MAX: 11
+ ACH_DAMAGE_MOB_REC_TOTAL: 12
+ ACH_JOB_CHANGE: 13
+ ACH_STATUS: 14
+ ACH_STATUS_BY_JOB: 15
+ ACH_STATUS_BY_JOBTYPE: 16
+ ACH_CHATROOM_CREATE_DEAD: 17
+ ACH_CHATROOM_CREATE: 18
+ ACH_CHATROOM_MEMBERS: 19
+ ACH_FRIEND_ADD: 20
+ ACH_PARTY_CREATE: 21
+ ACH_PARTY_JOIN: 22
+ ACH_MARRY: 23
+ ACH_ADOPT_BABY: 24
+ ACH_ADOPT_PARENT: 25
+ ACH_ZENY_HOLD: 26
+ ACH_ZENY_GET_ONCE: 27
+ ACH_ZENY_GET_TOTAL: 28
+ ACH_ZENY_SPEND_ONCE: 29
+ ACH_ZENY_SPEND_TOTAL: 30
+ ACH_EQUIP_REFINE_SUCCESS: 31
+ ACH_EQUIP_REFINE_FAILURE: 32
+ ACH_EQUIP_REFINE_SUCCESS_TOTAL: 33
+ ACH_EQUIP_REFINE_FAILURE_TOTAL: 34
+ ACH_EQUIP_REFINE_SUCCESS_WLV: 35
+ ACH_EQUIP_REFINE_FAILURE_WLV: 36
+ ACH_EQUIP_REFINE_SUCCESS_ID: 37
+ ACH_EQUIP_REFINE_FAILURE_ID: 38
+ ACH_ITEM_GET_COUNT: 39
+ ACH_ITEM_GET_COUNT_ITEMTYPE: 40
+ ACH_ITEM_GET_WORTH: 41
+ ACH_ITEM_SELL_WORTH: 42
+ ACH_PET_CREATE: 43
+ ACH_ACHIEVE: 44
+ ACH_ACHIEVEMENT_RANK: 45
}
diff --git a/db/pre-re/achievement_db.conf b/db/pre-re/achievement_db.conf
new file mode 100644
index 000000000..db63ed4a8
--- /dev/null
+++ b/db/pre-re/achievement_db.conf
@@ -0,0 +1,6079 @@
+//================= Hercules Database =====================================
+//= _ _ _
+//= | | | | | |
+//= | |_| | ___ _ __ ___ _ _| | ___ ___
+//= | _ |/ _ \ '__/ __| | | | |/ _ \/ __|
+//= | | | | __/ | | (__| |_| | | __/\__ \
+//= \_| |_/\___|_| \___|\__,_|_|\___||___/
+//================= License ===============================================
+//= This file is part of Hercules.
+//= http://herc.ws - http://github.com/HerculesWS/Hercules
+//=
+//= Copyright (C) 2018 Hercules Dev Team
+//=
+//= Hercules is free software: you can redistribute it and/or modify
+//= it under the terms of the GNU General Public License as published by
+//= the Free Software Foundation, either version 3 of the License, or
+//= (at your option) any later version.
+//=
+//= This program is distributed in the hope that it will be useful,
+//= but WITHOUT ANY WARRANTY; without even the implied warranty of
+//= MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+//= GNU General Public License for more details.
+//=
+//= You should have received a copy of the GNU General Public License
+//= along with this program. If not, see <http://www.gnu.org/licenses/>.
+//=========================================================================
+//= Achievement Database
+//=========================================================================
+
+achievement_db: (
+/*****************************************************************
+ * Entry Structure
+ *****************************************************************
+{
+ Id: (int) Unique ID of the achievement representing it's client-side equivalent.
+ Name: (string) Name/Title of the Achievement.
+ Type: (string) Validation type for the achievement.
+ [Type] [Validation Description] (Trigger)
+ ACH_QUEST: Specific achievement objective update (Script).
+ ACH_KILL_PC_TOTAL: (Accumulative) Total kill count. (Player kill)
+ ACH_KILL_PC_JOB: Kill a player of the specified job. (Player Kill)
+ ACH_KILL_PC_JOBTYPE: Kill a player of the specified job type. (Player Kill)
+ ACH_KILL_MOB_CLASS: Kill a particular mob class. (Mob Kill)
+ ACH_DAMAGE_PC_MAX: Maximum damage caused on a player. (Player Damage)
+ ACH_DAMAGE_PC_TOTAL: (Accumulative) Damage on players. (Player Damage)
+ ACH_DAMAGE_PC_REC_MAX: Maximum damage received by a player. (Receive Player Damage)
+ ACH_DAMAGE_PC_REC_TOTAL: (Accumulative) Damage received by players. (Receive Player Damage)
+ ACH_DAMAGE_MOB_MAX: Maximum damage caused on a monster. (Monster Damage)
+ ACH_DAMAGE_MOB_TOTAL: (Accumulative) Damage caused on monsters. (Monster Damage)
+ ACH_DAMAGE_MOB_REC_MAX: Maximum damage received by a monster. (Receive Monster Damage)
+ ACH_DAMAGE_MOB_REC_TOTAL: (Accumulative) Damage received by monsters. (Receive Monster Damage)
+ ACH_JOB_CHANGE: Change to a specific job. (Job Change)
+ ACH_STATUS: Acquire a specific amount of a particular status type. (Stat Change)
+ ACH_STATUS_BY_JOB: Acquire a specific amount of a status type as a job class. (Stat Change)
+ ACH_STATUS_BY_JOBTYPE: Acquire a specific amount of a status type as a job type. (Stat Change)
+ ACH_CHATROOM_CREATE_DEAD: (Accumulative) Create a chatroom when dead. (Chatroom Creation)
+ ACH_CHATROOM_CREATE: (Accumulative) Create a chatroom. (Chatroom Creation)
+ ACH_CHATROOM_MEMBERS: Gather 'n' members in a chatroom. (Chatroom Join)
+ ACH_FRIEND_ADD: Add a specific number of friends. (Friend Addition)
+ ACH_PARTY_CREATE: (Accumulative) Create a specific number of parties. (Party Creation)
+ ACH_PARTY_JOIN: (Accumulative) Join a specific number of parties. (Party Join)
+ ACH_MARRY: (Accumulative) Marry a specified number of times. (Marriage)
+ ACH_ADOPT_BABY: (Accumulative) Get Adopted. (Adoption)
+ ACH_ADOPT_PARENT: (Accumulative) Adopt a Baby. (Adoption)
+ ACH_ZENY_HOLD: Hold a specific amount of zeny in your inventory. (Gain Zeny)
+ ACH_ZENY_GET_ONCE: Gain a specific amount of zeny in one transaction. (Gain Zeny)
+ ACH_ZENY_GET_TOTAL: (Accumulative) Gain a specific amount of zeny in total. (Gain Zeny)
+ ACH_ZENY_SPEND_ONCE: Spend a specific amount of zeny in one transaction. (Pay Zeny)
+ ACH_ZENY_SPEND_TOTAL: (Accumulative) Spend a specific amount of zeny in total. (Pay Zeny)
+ ACH_EQUIP_REFINE_SUCCESS: Refine an item to +N. (Successful Refine)
+ ACH_EQUIP_REFINE_FAILURE: Fail to refine an item of +N refine. (Failed Refine)
+ ACH_EQUIP_REFINE_SUCCESS_TOTAL: (Accumulative) Refine an item successfully N times. (Success Refine)
+ ACH_EQUIP_REFINE_FAILURE_TOTAL: (Accumulative) Fail to refine an item N times. (Failed Refine)
+ ACH_EQUIP_REFINE_SUCCESS_WLV: Refine a Weapon of a particular Level to +N. (Success Refine)
+ ACH_EQUIP_REFINE_FAILURE_WLV: Fail to refine a Weapon of a particular level from +N. (Failed Refine)
+ ACH_EQUIP_REFINE_SUCCESS_ID: Refine a particular Item successfully to +N. (Success Refine)
+ ACH_EQUIP_REFINE_FAILURE_ID: Fail to refine a particular item successfully from +N. (Failed Refine)
+ ACH_ITEM_GET_COUNT: Acquire N amount of an item of a particular ID. (Acquire Item)
+ ACH_ITEM_GET_COUNT_ITEMTYPE: Acquire N amount of items of a particular type mask. (Acquire Item)
+ ACH_ITEM_GET_WORTH: Acquire an item of buy value N. (Acquire Item)
+ ACH_ITEM_SELL_WORTH: Sell an item of sell value N. (NPC Sell Item)
+ ACH_PET_CREATE: Successfully tame a pet of a particular mob class. (Successful Pet Tame)
+ ACH_ACHIEVE: Achieve an Achievement. (Achievement Completion)
+ ACH_ACHIEVEMENT_RANK: Achieve an Achievement Rank. (Achievement Rank Increase)
+ Objectives: { [Mandatory Field] Objectives of an achievement. Up to 10 objectives per achievement.
+ To comply with the client's order of objectives, this list must be in order.
+ *1: {
+ Description: (string) [Mandatory Field] Description of a particular objective.
+ Criteria: { This is a field for achievements whose objectives must meet
+ certain criteria before evaluating the player's progress for it.
+ MobId: (mixed) MonsterId required for an objective.
+ For types such as ACH_KILL_MOB_CLASS and ACH_PET_CREATE. Can be either int or string constant.
+ JobId: (mixed) Array or Single entry of JobIds.
+ For types - ACH_KILL_PC_JOBTYPE, ACH_JOB_CHANGE or ACH_STATUS_BY_JOBTYPE.
+ Can be either a numeric or string constant.
+ ItemId: (mixed) ItemId required for an objective.
+ For Types such as ACH_ITEM_GET_COUNT. Can be either int or string constant.
+ StatusType: (mixed) Status Type required for an objective.
+ For Types such as ACH_STATUS, ACH_STATUS_BY_JOB, ACH_STATUS_BY_JOBTYPE.
+ Types -
+ "SP_STR" - Strength
+ "SP_AGI" - Agility
+ "SP_VIT" - Vitality
+ "SP_INT" - Intelligence
+ "SP_DEX" - Dexterity
+ "SP_LUK" - Luck
+ "SP_BASELEVEL" - Base Level
+ "SP_JOBLEVEL" - Job Level
+ Can be either int or string constant.
+ ItemType: (mixed) Item type that is required for this achievement.
+ For Types such as ACH_ITEM_GET_COUNT_ITEMTYPE.
+ Can be either int, string or list.
+ Refer "Item types" Constants from constants.conf
+ WeaponLevel: (int) Weapon Level that is required for this achievement. (Eg. 0, 1, 2, 3 or 4).
+ For Types such as ACH_EQUIP_REFINE_SUCCESS_WLV and ACH_EQUIP_REFINE_FAILURE_WLV.
+ Achieve: (int) AchievementID to be achieved.
+ For Type - ACH_ACHIEVE.
+ }
+ Goal: (int) Target amount to be met for the completion of the objective. Default is 1.
+ }
+ ...
+ *10: {...}
+ }
+ Rewards: {
+ Bonus: <""> (script) Script code bonus to be given as a reward for an achievement.
+ Items: { Item rewards per achievement. With a maximum defined in mmo.h as MAX_ACHEIVEMENT_ITEM_REWARDS.
+ Apple: 1 (int) Item ID (int or string constant) : Amount (int)
+ }
+ TitleId: (int) ID of the Title (from the Title System) awarded.
+ }
+ Points: (int) Points per achievement given on it's successful completion.
+}
+ *****************************************************************/
+{
+ Id: 110000
+ Name: "At this time I live to eat"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Bring the food to Bigfoot at this hour"
+ }
+ }
+ Points: 10
+},
+{
+ Id: 110001
+ Name: "A fan of this polarity"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Lady of the house"
+ }
+ *2: {
+ Description: "Beautiful fine anak"
+ }
+ *3: {
+ Description: "Mistress in ambience"
+ }
+ *4: {
+ Description: "Beautiful wife and children"
+ }
+ *5: {
+ Description: "Down town Bachelor"
+ }
+ *6: {
+ Description: "Great act ability anak"
+ }
+ *7: {
+ Description: "Great attack power bachelor"
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120001
+ Name: "North Prontera Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding north prontera field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120002
+ Name: "North Prontera Field Exploration(2)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding north prontera field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120003
+ Name: "North Prontera Field Exploration(3)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding north prontera field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120004
+ Name: "West Prontera Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding west prontera field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120005
+ Name: "West Prontera Field Exploration(2)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding west prontera field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120006
+ Name: "East Prontera Field Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding east prontera field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120007
+ Name: "South Prontera Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding south prontera field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120008
+ Name: "South Prontera Field Exploration(2)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding south prontera field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120009
+ Name: "South Prontera Field Exploration(3)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding south prontera field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120010
+ Name: "South Prontera Field Exploration(4)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding south prontera field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120011
+ Name: "East Geffen Field Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding east geffen field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120012
+ Name: "Southeast Geffen Field Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding southeast geffen field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120013
+ Name: "Northwest Geffen Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding northwest geffen field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120014
+ Name: "Northwest Geffen Field Exploration(2)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding northwest geffen field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120015
+ Name: "Northwest Geffen Field Exploration(3)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding northwest geffen field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120016
+ Name: "South Geffen Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding south geffen field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120017
+ Name: "South Geffen Field Exploration(2)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding south geffen field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120018
+ Name: "Sograt Desert Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding sograt desert field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120019
+ Name: "Sograt Desert Field Exploration(2)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding sograt desert field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120020
+ Name: "Sograt Desert Field Exploration(3)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding sograt desert field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120021
+ Name: "Sograt Desert Field Exploration(4)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding sograt desert field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120022
+ Name: "Sograt Desert Field Exploration(5)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding sograt desert field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120023
+ Name: "Sograt Desert Field Exploration(6)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding sograt desert field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120024
+ Name: "Southwest Payon Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding southwest payon field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120025
+ Name: "Southwest Payon Field Exploration(2)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding southwest payon field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120026
+ Name: "Southwest Payon Field Exploration(3)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding southwest payon field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120027
+ Name: "Southwest Payon Field Exploration(4)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding southwest payon field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120028
+ Name: "East Payon Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding east payon field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120029
+ Name: "East Payon Field Exploration(2)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding east payon field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120030
+ Name: "East Payon Field Exploration(3)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding east payon field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120031
+ Name: "East Payon Field Exploration(4)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding east payon field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120032
+ Name: "North Mjolnir Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding north mjolnir field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120033
+ Name: "North Mjolnir Field Exploration(2)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding north mjolnir field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120034
+ Name: "North Mjolnir Field Exploration(3)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding north mjolnir field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120035
+ Name: "North Mjolnir Field Exploration(4)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding north mjolnir field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120036
+ Name: "North Mjolnir Field Exploration(5)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding north mjolnir field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120037
+ Name: "South Mjolnir Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding south mjolnir field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120038
+ Name: "South Mjolnir Field Exploration(2)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding south mjolnir field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120039
+ Name: "South Mjolnir Field Exploration(3)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding south mjolnir field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120040
+ Name: "South Mjolnir Field Exploration(4)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding south mjolnir field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120041
+ Name: "South Mjolnir Field Exploration(5)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding south mjolnir field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120042
+ Name: "South Mjolnir Field Exploration(6)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding south mjolnir field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120043
+ Name: "South Aldebaran Field Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding south aldebaran field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120044
+ Name: "Comodo Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding comodo field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120045
+ Name: "Comodo Field Exploration(2)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding comodo field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120046
+ Name: "Comodo Field Exploration(3)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding comodo field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120047
+ Name: "Comodo Field Exploration(4)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding comodo field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120048
+ Name: "Comodo Field Exploration(5)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding comodo field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120049
+ Name: "Comodo Field Exploration(6)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding comodo field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120050
+ Name: "Comodo Field Exploration(7)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding comodo field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120051
+ Name: "Comodo Field Exploration(8)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding comodo field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120052
+ Name: "Border Checkpoint Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding border checkpoint field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120053
+ Name: "Border Checkpoint Field Exploration(2)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding border checkpoint field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120054
+ Name: "Kiel Hyre Mansion Field Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding kiel hyre mansion field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120055
+ Name: "El Mes Plateau Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding el mes plateau field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120056
+ Name: "El Mes Plateau Field Exploration(2)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding el mes plateau field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120057
+ Name: "El Mes Plateau Field Exploration(3)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding el mes plateau field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120058
+ Name: "El Mes Gorge Field Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding el mes gorge field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120059
+ Name: "Kiel Hyre Academy Field Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding kiel hyre academy field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120060
+ Name: "Guard Camp Field Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding guard camp field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120061
+ Name: "Yuno Field Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding yuno field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120062
+ Name: "Front of Thanatos Tower Field Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding front of thanatos tower field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120063
+ Name: "Hugel Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding hugel field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120064
+ Name: "Hugel Field Exploration(2)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding hugel field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120065
+ Name: "Hugel Field Exploration(3)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding hugel field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120066
+ Name: "Abyss Lake Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding abyss lake field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120067
+ Name: "Einbroch Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding Einbroch field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120068
+ Name: "Einbroch Field Exploration(2)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding Einbroch field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120069
+ Name: "Einbroch Field Exploration(3)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding Einbroch field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120070
+ Name: "Einbroch Field Exploration(4)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding Einbroch field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120071
+ Name: "Einbroch Field Exploration(5)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding Einbroch field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120072
+ Name: "Einbroch Field Exploration(6)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding Einbroch field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120073
+ Name: "Einbroch Field Exploration(7)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding Einbroch field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120074
+ Name: "Einbroch Field Exploration(8)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding Einbroch field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120075
+ Name: "Lighthalzen Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding lighthalzen field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120076
+ Name: "Lighthalzen Field Exploration(2)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding lighthalzen field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120077
+ Name: "Lighthalzen Field Exploration(3)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding lighthalzen field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120078
+ Name: "Rachel Audhumbla Plains Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding rachel audhumbla plains field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120079
+ Name: "Rachel Plains Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding rachel plains field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120080
+ Name: "Rachel Plains Field Exploration(2)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding rachel plains field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120081
+ Name: "Rachel Plains Field Exploration(3)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding rachel plains field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120082
+ Name: "Rachel Audhumbla Grassland Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding rachel audhumbla grassland field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120083
+ Name: "Rachel Audhumbla Grassland Field Exploration(2)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding rachel audhumbla grassland field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120084
+ Name: "Portus Luna Field Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding portus luna field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120085
+ Name: "Veins Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding veins field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120086
+ Name: "Veins Field Exploration(2)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding veins field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120087
+ Name: "Veins Field Exploration(3)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding veins field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120088
+ Name: "Veins Field Exploration(4)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding veins field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120089
+ Name: "Veins Field Exploration(5)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding veins field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120090
+ Name: "Eclage Field Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding eclage field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120091
+ Name: "North Bitfrost Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding north bitfrost field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120092
+ Name: "South Bitfrost Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding south bitfrost field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120093
+ Name: "Splendide Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding splendide field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120094
+ Name: "Splendide Field Exploration(2)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding splendide field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120095
+ Name: "Splendide Field Exploration(3)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding splendide field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120096
+ Name: "Manuk Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding manuk field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120097
+ Name: "Manuk Field Exploration(2)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding manuk field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120098
+ Name: "Manuk Field Exploration(3)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding manuk field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120099
+ Name: "Outskirts of Kamidal Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding outskirts of kamidal field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120100
+ Name: "Outskirts of Kamidal Field Exploration(2)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding outskirts of kamidal field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120101
+ Name: "Amatsu Field Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding amatsu field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120102
+ Name: "Kunlun Field Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding kunlun field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120103
+ Name: "Gonryun Field Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding gonryun field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120104
+ Name: "Ayothaya Field Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding ayothaya field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120105
+ Name: "Moscovia Field Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding moscovia field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120106
+ Name: "Brasilis Field Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding brasilis field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120107
+ Name: "Dewata Field Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding dewata field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120108
+ Name: "Malaya Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding malaya field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120109
+ Name: "Malaya Field Exploration(2)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding malaya field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120110
+ Name: "Abbey Underground Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding abbey underground dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120111
+ Name: "Abyss Lake Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding abyss lake dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120112
+ Name: "Clock Tower Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding clock tower dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120113
+ Name: "Amatsu Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding amatsu dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120114
+ Name: "Ant Hell Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding ant hell dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120115
+ Name: "Ayothaya Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding ayothaya dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120116
+ Name: "Comodo Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding comodo dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120117
+ Name: "Brasilis Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding brasilis dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120118
+ Name: "Clock Tower Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding clock tower dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120119
+ Name: "Istana Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding istana dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120120
+ Name: "Scaraba Hole Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding scaraba hole dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120121
+ Name: "Bitfrost Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding bitfrost dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120122
+ Name: "Einbroch Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding einbroch dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120123
+ Name: "Geffen Underground Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding geffen underground dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120124
+ Name: "Glastheim Dungeon Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding glastheim dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120125
+ Name: "Glastheim Dungeon Exploration(2)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding glastheim dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120126
+ Name: "Glastheim Dungeon Exploration(3)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding glastheim dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120127
+ Name: "Glastheim Dungeon Exploration(4)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding glastheim dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120128
+ Name: "Kunlun Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding Kunlun dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120129
+ Name: "Rachel Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding rachel dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120130
+ Name: "Sphinx Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding sphinx dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120131
+ Name: "Izlude Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding izlude dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120132
+ Name: "Robot Factory Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding robot factory dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120133
+ Name: "Bio Lab Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding bio lab dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120134
+ Name: "Gonryun Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding gonryun dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120135
+ Name: "Nogg Road Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding nogg road dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120136
+ Name: "Coal Mine Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding Coal mine dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120137
+ Name: "Pyramid Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding pyramid dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120138
+ Name: "Orc Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding orc dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120139
+ Name: "Payon Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding payon dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120140
+ Name: "Labyrinth Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding labyrinth dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120141
+ Name: "Undersea Tunnel Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding undersea tunnel dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120142
+ Name: "Thanatos Tower Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding thanatos tower dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120143
+ Name: "Thor Volcano Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding thor volcano dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120144
+ Name: "Sunken Ship Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding sunken ship dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120145
+ Name: "Turtle Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding turtle dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120146
+ Name: "Toy Factory Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding toy factory dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 127001
+ Name: "Prontera Contribution"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Stranger"
+ Goal: 3000
+ }
+ *2: {
+ Description: "Village Freshman"
+ Goal: 6000
+ }
+ *3: {
+ Description: "Neighbor"
+ Goal: 12000
+ }
+ *4: {
+ Description: "Celebrity"
+ Goal: 20000
+ }
+ *5: {
+ Description: "City Dictator"
+ Goal: 1000
+ }
+ }
+ Points: 10
+},
+{
+ Id: 127002
+ Name: "Geffen Contribution"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Stranger"
+ Goal: 3000
+ }
+ *2: {
+ Description: "Village Freshman"
+ Goal: 6000
+ }
+ *3: {
+ Description: "Neighbor"
+ Goal: 12000
+ }
+ *4: {
+ Description: "Celebrity"
+ Goal: 20000
+ }
+ *5: {
+ Description: "City Dictator"
+ Goal: 1000
+ }
+ }
+ Points: 10
+},
+{
+ Id: 127003
+ Name: "Morocc Contribution"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Stranger"
+ Goal: 3000
+ }
+ *2: {
+ Description: "Village Freshman"
+ Goal: 6000
+ }
+ *3: {
+ Description: "Neighbor"
+ Goal: 12000
+ }
+ *4: {
+ Description: "Celebrity"
+ Goal: 20000
+ }
+ *5: {
+ Description: "City Dictator"
+ Goal: 1000
+ }
+ }
+ Points: 10
+},
+{
+ Id: 127004
+ Name: "Payon Contribution"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Stranger"
+ Goal: 3000
+ }
+ *2: {
+ Description: "Village Freshman"
+ Goal: 6000
+ }
+ *3: {
+ Description: "Neighbor"
+ Goal: 12000
+ }
+ *4: {
+ Description: "Celebrity"
+ Goal: 20000
+ }
+ *5: {
+ Description: "City Dictator"
+ Goal: 1000
+ }
+ }
+ Points: 10
+},
+{
+ Id: 127005
+ Name: "Yuno Contribution"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Stranger"
+ Goal: 3000
+ }
+ *2: {
+ Description: "Village Freshman"
+ Goal: 6000
+ }
+ *3: {
+ Description: "Neighbor"
+ Goal: 12000
+ }
+ *4: {
+ Description: "Celebrity"
+ Goal: 20000
+ }
+ *5: {
+ Description: "City Dictator"
+ Goal: 1000
+ }
+ }
+ Points: 10
+},
+{
+ Id: 127006
+ Name: "Lighthalzen Contribution"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Stranger"
+ Goal: 3000
+ }
+ *2: {
+ Description: "Village Freshman"
+ Goal: 6000
+ }
+ *3: {
+ Description: "Neighbor"
+ Goal: 12000
+ }
+ *4: {
+ Description: "Celebrity"
+ Goal: 20000
+ }
+ *5: {
+ Description: "City Dictator"
+ Goal: 1000
+ }
+ }
+ Points: 10
+},
+{
+ Id: 127007
+ Name: "Einbroch Contribution"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Stranger"
+ Goal: 3000
+ }
+ *2: {
+ Description: "Village Freshman"
+ Goal: 6000
+ }
+ *3: {
+ Description: "Neighbor"
+ Goal: 12000
+ }
+ *4: {
+ Description: "Celebrity"
+ Goal: 20000
+ }
+ *5: {
+ Description: "City Dictator"
+ Goal: 1000
+ }
+ }
+ Points: 10
+},
+{
+ Id: 127008
+ Name: "Rachel Contribution"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Stranger"
+ Goal: 3000
+ }
+ *2: {
+ Description: "Village Freshman"
+ Goal: 6000
+ }
+ *3: {
+ Description: "Neighbor"
+ Goal: 12000
+ }
+ *4: {
+ Description: "Celebrity"
+ Goal: 20000
+ }
+ *5: {
+ Description: "City Dictator"
+ Goal: 1000
+ }
+ }
+ Points: 10
+},
+{
+ Id: 127009
+ Name: "Veins Contribution"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Stranger"
+ Goal: 3000
+ }
+ *2: {
+ Description: "Village Freshman"
+ Goal: 6000
+ }
+ *3: {
+ Description: "Neighbor"
+ Goal: 12000
+ }
+ *4: {
+ Description: "Celebrity"
+ Goal: 20000
+ }
+ *5: {
+ Description: "City Dictator"
+ Goal: 1000
+ }
+ }
+ Points: 10
+},
+{
+ Id: 128008
+ Name: "Bold Adventurer"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 1 Baphomet"
+ Criteria: {
+ MobId: "BAPHOMET"
+ }
+ Goal: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 128009
+ Name: "Baphomet Hatred"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 10 Baphomet"
+ Criteria: {
+ MobId: "BAPHOMET"
+ }
+ Goal: 10
+ }
+ }
+ Points: 20
+},
+{
+ Id: 128010
+ Name: "Goat's Nemesis"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 50 Baphomet"
+ Criteria: {
+ MobId: "BAPHOMET"
+ }
+ Goal: 50
+ }
+ }
+ Points: 50
+},
+{
+ Id: 128047
+ Name: "Endless Tower challenger"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 1 Naght Sieger"
+ Criteria: {
+ MobId: "NAGHT_SIEGER"
+ }
+ Goal: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 128048
+ Name: "Endless Tower Slayer"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 10 Naght Sieger"
+ Criteria: {
+ MobId: "NAGHT_SIEGER"
+ }
+ Goal: 10
+ }
+ }
+ Points: 20
+},
+{
+ Id: 128049
+ Name: "Lord of the tower"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 50 Naght Sieger"
+ Criteria: {
+ MobId: "NAGHT_SIEGER"
+ }
+ Goal: 50
+ }
+ }
+ Points: 50
+},
+{
+ Id: 129001
+ Name: "Prontera Explorer"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "North Prontera Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120001
+ }
+ }
+ *2: {
+ Description: "North Prontera Field Exploration(2) completed"
+ Criteria: {
+ Achieve: 120002
+ }
+ }
+ *3: {
+ Description: "North Prontera Field Exploration(3) completed"
+ Criteria: {
+ Achieve: 120003
+ }
+ }
+ *4: {
+ Description: "West Prontera Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120004
+ }
+ }
+ *5: {
+ Description: "West Prontera Field Exploration(2) completed"
+ Criteria: {
+ Achieve: 120005
+ }
+ }
+ *6: {
+ Description: "East Prontera Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120006
+ }
+ }
+ *7: {
+ Description: "South Prontera Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120007
+ }
+ }
+ *8: {
+ Description: "South Prontera Field Exploration(2) completed"
+ Criteria: {
+ Achieve: 120008
+ }
+ }
+ *9: {
+ Description: "South Prontera Field Exploration(3) completed"
+ Criteria: {
+ Achieve: 120009
+ }
+ }
+ *10: {
+ Description: "South Prontera Field Exploration(4) completed"
+ Criteria: {
+ Achieve: 120010
+ }
+ }
+ }
+ Rewards: {
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 129002
+ Name: "Geffen Explorer"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "East Geffen Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120011
+ }
+ }
+ *2: {
+ Description: "Southeast Geffen Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120012
+ }
+ }
+ *3: {
+ Description: "Northwest Geffen Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120013
+ }
+ }
+ *4: {
+ Description: "Northwest Geffen Field Exploration(2) completed"
+ Criteria: {
+ Achieve: 120014
+ }
+ }
+ *5: {
+ Description: "Northwest Geffen Field Exploration(3) completed"
+ Criteria: {
+ Achieve: 120015
+ }
+ }
+ *6: {
+ Description: "South Geffen Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120016
+ }
+ }
+ *7: {
+ Description: "South Geffen Field Exploration(2) completed"
+ Criteria: {
+ Achieve: 120017
+ }
+ }
+ }
+ Rewards: {
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 129003
+ Name: "Sograt Desert Explorer"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Sograt Desert Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120018
+ }
+ }
+ *2: {
+ Description: "Sograt Desert Field Exploration(2) completed"
+ Criteria: {
+ Achieve: 120019
+ }
+ }
+ *3: {
+ Description: "Sograt Desert Field Exploration(3) completed"
+ Criteria: {
+ Achieve: 120020
+ }
+ }
+ *4: {
+ Description: "Sograt Desert Field Exploration(4) completed"
+ Criteria: {
+ Achieve: 120021
+ }
+ }
+ *5: {
+ Description: "Sograt Desert Field Exploration(5) completed"
+ Criteria: {
+ Achieve: 120022
+ }
+ }
+ *6: {
+ Description: "Sograt Desert Field Exploration(6) completed"
+ Criteria: {
+ Achieve: 120023
+ }
+ }
+ }
+ Rewards: {
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 129004
+ Name: "Payon Explorer"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Southwest Payon Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120024
+ }
+ }
+ *2: {
+ Description: "Southwest Payon Field Exploration(2) completed"
+ Criteria: {
+ Achieve: 120025
+ }
+ }
+ *3: {
+ Description: "Southwest Payon Field Exploration(3) completed"
+ Criteria: {
+ Achieve: 120026
+ }
+ }
+ *4: {
+ Description: "Southwest Payon Field Exploration(4) completed"
+ Criteria: {
+ Achieve: 120027
+ }
+ }
+ *5: {
+ Description: "East Payon Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120028
+ }
+ }
+ *6: {
+ Description: "East Payon Field Exploration(2) completed"
+ Criteria: {
+ Achieve: 120029
+ }
+ }
+ *7: {
+ Description: "East Payon Field Exploration(3) completed"
+ Criteria: {
+ Achieve: 120030
+ }
+ }
+ *8: {
+ Description: "East Payon Field Exploration(4) completed"
+ Criteria: {
+ Achieve: 120031
+ }
+ }
+ }
+ Rewards: {
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 129005
+ Name: "North Mjolnir Explorer"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "North Mjolnir Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120032
+ }
+ }
+ *2: {
+ Description: "North Mjolnir Field Exploration(2) completed"
+ Criteria: {
+ Achieve: 120033
+ }
+ }
+ *3: {
+ Description: "North Mjolnir Field Exploration(3) completed"
+ Criteria: {
+ Achieve: 120034
+ }
+ }
+ *4: {
+ Description: "North Mjolnir Field Exploration(4) completed"
+ Criteria: {
+ Achieve: 120035
+ }
+ }
+ *5: {
+ Description: "North Mjolnir Field Exploration(5) completed"
+ Criteria: {
+ Achieve: 120036
+ }
+ }
+ }
+ Rewards: {
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 129006
+ Name: "South Mjolnir Explorer"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "South Mjolnir Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120037
+ }
+ }
+ *2: {
+ Description: "South Mjolnir Field Exploration(2) completed"
+ Criteria: {
+ Achieve: 120038
+ }
+ }
+ *3: {
+ Description: "South Mjolnir Field Exploration(3) completed"
+ Criteria: {
+ Achieve: 120039
+ }
+ }
+ *4: {
+ Description: "South Mjolnir Field Exploration(4) completed"
+ Criteria: {
+ Achieve: 120040
+ }
+ }
+ *5: {
+ Description: "South Mjolnir Field Exploration(5) completed"
+ Criteria: {
+ Achieve: 120041
+ }
+ }
+ *6: {
+ Description: "South Mjolnir Field Exploration(6) completed"
+ Criteria: {
+ Achieve: 120042
+ }
+ }
+ *7: {
+ Description: "South Aldebaran Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120043
+ }
+ }
+ }
+ Rewards: {
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 129007
+ Name: "Comodo Explorer"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Comodo Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120044
+ }
+ }
+ *2: {
+ Description: "Comodo Field Exploration(2) completed"
+ Criteria: {
+ Achieve: 120045
+ }
+ }
+ *3: {
+ Description: "Comodo Field Exploration(3) completed"
+ Criteria: {
+ Achieve: 120046
+ }
+ }
+ *4: {
+ Description: "Comodo Field Exploration(4) completed"
+ Criteria: {
+ Achieve: 120047
+ }
+ }
+ *5: {
+ Description: "Comodo Field Exploration(5) completed"
+ Criteria: {
+ Achieve: 120048
+ }
+ }
+ *6: {
+ Description: "Comodo Field Exploration(6) completed"
+ Criteria: {
+ Achieve: 120049
+ }
+ }
+ *7: {
+ Description: "Comodo Field Exploration(7) completed"
+ Criteria: {
+ Achieve: 120050
+ }
+ }
+ *8: {
+ Description: "Comodo Field Exploration(8) completed"
+ Criteria: {
+ Achieve: 120051
+ }
+ }
+ }
+ Rewards: {
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 129008
+ Name: "Rune Midgard Explorer"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Prontera Explorer"
+ Criteria: {
+ Achieve: 129001
+ }
+ }
+ *2: {
+ Description: "Geffen Explorer"
+ Criteria: {
+ Achieve: 129002
+ }
+ }
+ *3: {
+ Description: "Sograt Desert Explorer"
+ Criteria: {
+ Achieve: 129003
+ }
+ }
+ *4: {
+ Description: "Payon Explorer"
+ Criteria: {
+ Achieve: 129004
+ }
+ }
+ *5: {
+ Description: "North Mjolnir Explorer"
+ Criteria: {
+ Achieve: 129005
+ }
+ }
+ *6: {
+ Description: "South Mjolnir Explorer"
+ Criteria: {
+ Achieve: 129006
+ }
+ }
+ *7: {
+ Description: "Comodo Explorer"
+ Criteria: {
+ Achieve: 129007
+ }
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Violet_Box: 1
+ }
+ }
+ Points: 50
+},
+{
+ Id: 129009
+ Name: "Yuno Explorer"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Border Checkpoint Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120052
+ }
+ }
+ *2: {
+ Description: "Border Checkpoint Field Exploration(2) completed"
+ Criteria: {
+ Achieve: 120053
+ }
+ }
+ *3: {
+ Description: "Kiel Hyre Mansion Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120054
+ }
+ }
+ *4: {
+ Description: "El Mes Plateau Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120055
+ }
+ }
+ *5: {
+ Description: "El Mes Plateau Field Exploration(2) completed"
+ Criteria: {
+ Achieve: 120056
+ }
+ }
+ *6: {
+ Description: "El Mes Plateau Field Exploration(3) completed"
+ Criteria: {
+ Achieve: 120057
+ }
+ }
+ *7: {
+ Description: "El Mes Gorge Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120058
+ }
+ }
+ *8: {
+ Description: "Kiel Hyre Academy Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120059
+ }
+ }
+ *9: {
+ Description: "Guard Camp Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120060
+ }
+ }
+ *10: {
+ Description: "Yuno Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120061
+ }
+ }
+ }
+ Rewards: {
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 129010
+ Name: "Hugel Explorer"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Front of Thanatos Tower Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120062
+ }
+ }
+ *2: {
+ Description: "Hugel Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120063
+ }
+ }
+ *3: {
+ Description: "Hugel Field Exploration(2) completed"
+ Criteria: {
+ Achieve: 120064
+ }
+ }
+ *4: {
+ Description: "Hugel Field Exploration(3) completed"
+ Criteria: {
+ Achieve: 120065
+ }
+ }
+ *5: {
+ Description: "Abyss Lake Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120066
+ }
+ }
+ }
+ Rewards: {
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 129011
+ Name: "Einbroch Explorer"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Einbroch Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120067
+ }
+ }
+ *2: {
+ Description: "Einbroch Field Exploration(2) completed"
+ Criteria: {
+ Achieve: 120068
+ }
+ }
+ *3: {
+ Description: "Einbroch Field Exploration(3) completed"
+ Criteria: {
+ Achieve: 120069
+ }
+ }
+ *4: {
+ Description: "Einbroch Field Exploration(4) completed"
+ Criteria: {
+ Achieve: 120070
+ }
+ }
+ *5: {
+ Description: "Einbroch Field Exploration(5) completed"
+ Criteria: {
+ Achieve: 120071
+ }
+ }
+ *6: {
+ Description: "Einbroch Field Exploration(6) completed"
+ Criteria: {
+ Achieve: 120072
+ }
+ }
+ *7: {
+ Description: "Einbroch Field Exploration(7) completed"
+ Criteria: {
+ Achieve: 120073
+ }
+ }
+ *8: {
+ Description: "Einbroch Field Exploration(8) completed"
+ Criteria: {
+ Achieve: 120074
+ }
+ }
+ }
+ Rewards: {
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 129012
+ Name: "Lighthalzen Explorer"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Lighthalzen Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120075
+ }
+ }
+ *2: {
+ Description: "Lighthalzen Field Exploration(2) completed"
+ Criteria: {
+ Achieve: 120076
+ }
+ }
+ *3: {
+ Description: "Lighthalzen Field Exploration(3) completed"
+ Criteria: {
+ Achieve: 120077
+ }
+ }
+ }
+ Rewards: {
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 129013
+ Name: "Schwarzwald Explorer"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Yuno Explorer"
+ Criteria: {
+ Achieve: 129009
+ }
+ }
+ *2: {
+ Description: "Hugel Explorer"
+ Criteria: {
+ Achieve: 129010
+ }
+ }
+ *3: {
+ Description: "Einbroch Explorer"
+ Criteria: {
+ Achieve: 129011
+ }
+ }
+ *4: {
+ Description: "Lighthalzen Explorer"
+ Criteria: {
+ Achieve: 129012
+ }
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Violet_Box: 1
+ }
+ }
+ Points: 50
+},
+{
+ Id: 129014
+ Name: "Rachel Explorer"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Rachel Audhumbla Plains Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120078
+ }
+ }
+ *2: {
+ Description: "Rachel Plains Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120079
+ }
+ }
+ *3: {
+ Description: "Rachel Plains Field Exploration(2) completed"
+ Criteria: {
+ Achieve: 120080
+ }
+ }
+ *4: {
+ Description: "Rachel Plains Field Exploration(3) completed"
+ Criteria: {
+ Achieve: 120081
+ }
+ }
+ *5: {
+ Description: "Rachel Audhumbla Grassland Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120082
+ }
+ }
+ *6: {
+ Description: "Rachel Audhumbla Grassland Field Exploration(2) completed"
+ Criteria: {
+ Achieve: 120083
+ }
+ }
+ *7: {
+ Description: "Portus Luna Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120084
+ }
+ }
+ }
+ Rewards: {
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 129015
+ Name: "Veins Explorer"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Veins Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120085
+ }
+ }
+ *2: {
+ Description: "Veins Field Exploration(2) completed"
+ Criteria: {
+ Achieve: 120086
+ }
+ }
+ *3: {
+ Description: "Veins Field Exploration(3) completed"
+ Criteria: {
+ Achieve: 120087
+ }
+ }
+ *4: {
+ Description: "Veins Field Exploration(4) completed"
+ Criteria: {
+ Achieve: 120088
+ }
+ }
+ *5: {
+ Description: "Veins Field Exploration(5) completed"
+ Criteria: {
+ Achieve: 120089
+ }
+ }
+ }
+ Rewards: {
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 129016
+ Name: "Arunafeltz Explorer"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Rachel Explorer"
+ Criteria: {
+ Achieve: 129014
+ }
+ }
+ *2: {
+ Description: "Veins Explorer"
+ Criteria: {
+ Achieve: 129015
+ }
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Violet_Box: 1
+ }
+ }
+ Points: 50
+},
+{
+ Id: 129017
+ Name: "Laphine Explorer"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Eclage Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120090
+ }
+ }
+ *2: {
+ Description: "North Bitfrost Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120091
+ }
+ }
+ *3: {
+ Description: "South Bitfrost Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120092
+ }
+ }
+ *4: {
+ Description: "Splendide Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120093
+ }
+ }
+ *5: {
+ Description: "Splendide Field Exploration(2) completed"
+ Criteria: {
+ Achieve: 120094
+ }
+ }
+ *6: {
+ Description: "Splendide Field Exploration(3) completed"
+ Criteria: {
+ Achieve: 120095
+ }
+ }
+ }
+ Rewards: {
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 129018
+ Name: "Manuk Explorer"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Manuk Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120096
+ }
+ }
+ *2: {
+ Description: "Manuk Field Exploration(2) completed"
+ Criteria: {
+ Achieve: 120097
+ }
+ }
+ *3: {
+ Description: "Manuk Field Exploration(3) completed"
+ Criteria: {
+ Achieve: 120098
+ }
+ }
+ *4: {
+ Description: "Outskirts of Kamidal Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120099
+ }
+ }
+ *5: {
+ Description: "Outskirts of Kamidal Field Exploration(2) completed"
+ Criteria: {
+ Achieve: 120100
+ }
+ }
+ }
+ Rewards: {
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 129019
+ Name: "Eclage Explorer"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Laphine Explorer"
+ Criteria: {
+ Achieve: 129017
+ }
+ }
+ *2: {
+ Description: "Manuk Explorer"
+ Criteria: {
+ Achieve: 129018
+ }
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Violet_Box: 1
+ }
+ }
+ Points: 50
+},
+{
+ Id: 129020
+ Name: "Localizing fields explorer"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Amatsu Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120101
+ }
+ }
+ *2: {
+ Description: "Kunlun Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120102
+ }
+ }
+ *3: {
+ Description: "Gonryun Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120103
+ }
+ }
+ *4: {
+ Description: "Ayothaya Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120104
+ }
+ }
+ *5: {
+ Description: "Moscovia Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120105
+ }
+ }
+ *6: {
+ Description: "Brasilis Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120106
+ }
+ }
+ *7: {
+ Description: "Dewata Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120107
+ }
+ }
+ *8: {
+ Description: "Malaya Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120108
+ }
+ }
+ *9: {
+ Description: "Malaya Field Exploration(2) completed"
+ Criteria: {
+ Achieve: 120109
+ }
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Violet_Box: 1
+ }
+ }
+ Points: 50
+},
+{
+ Id: 130000
+ Name: "Socialite debut"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Visit Heine Royal Family and start conversation"
+ }
+ *2: {
+ Description: "Visit Nerius Royal Family and start conversation"
+ }
+ *3: {
+ Description: "Visit Walter Royal Family and start conversation"
+ }
+ *4: {
+ Description: "Visit Wigner Royal Family and start conversation"
+ }
+ *5: {
+ Description: "Visit Richard Royal Family and start conversation"
+ }
+ *6: {
+ Description: "Visit Gaebolg Royal Family and start conversation"
+ }
+ *7: {
+ Description: "Visit Lugenburg Royal Family and start conversation"
+ }
+ }
+ Rewards: {
+ TitleId: 1034
+ }
+ Points: 10
+},
+{
+ Id: 170000
+ Name: "Song chamber is not an accident"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Listen the secret song of five recomended court musician"
+ }
+ }
+ Points: 10
+},
+{
+ Id: 190000
+ Name: "Alliance workers of merchant city"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Novice Amethyst class"
+ Goal: 1
+ }
+ *2: {
+ Description: "Expert Sardonyx class"
+ Goal: 10
+ }
+ *3: {
+ Description: "Competence Person Aquamarine class"
+ Goal: 30
+ }
+ *4: {
+ Description: "Sparkling Diamond class"
+ Goal: 100
+ }
+ }
+ Points: 50
+},
+{
+ Id: 200000
+ Name: "Acquire the first aura!"
+ Type: "ACH_STATUS"
+ Objectives: {
+ *1: {
+ Description: "Base level 99"
+ Criteria: {
+ StatusType: "SP_BASELEVEL"
+ }
+ Goal: 99
+ }
+ }
+ Rewards: {
+ TitleId: 1000
+ Bonus: <" specialeffect(EF_BLESSING, AREA, playerattached()); sc_start SC_BLESSING, 30000, 1; ">
+ Items: {
+ White_Slim_Pot_Box2: 1
+ }
+ }
+ Points: 50
+},
+{
+ Id: 200001
+ Name: "Acquire the second aura!"
+ Type: "ACH_STATUS"
+ Objectives: {
+ *1: {
+ Description: "Base level 150"
+ Criteria: {
+ StatusType: "SP_BASELEVEL"
+ }
+ Goal: 150
+ }
+ }
+ Rewards: {
+ TitleId: 1001
+ Bonus: <" specialeffect(EF_BLESSING, AREA, playerattached()); sc_start SC_BLESSING, 30000, 1; ">
+ Items: {
+ Dark_Snake_Lord_Hat: 1
+ }
+ }
+ Points: 60
+},
+/*
+{
+ Id: 200002
+ Name: "Acquire the third aura!"
+ Type: "ACH_STATUS"
+ Objectives: {
+ *1: {
+ Description: "Base level 175"
+ Criteria: {
+ StatusType: "SP_BASELEVEL"
+ }
+ Goal: 175
+ }
+ }
+ Rewards: {
+ TitleId: 1002
+ Bonus: <" specialeffect(EF_BLESSING, AREA, playerattached()); sc_start SC_BLESSING, 30000, 1; ">
+ Items: {
+ Advanced_Jao_King_Hat: 1
+ }
+ }
+ Points: 70
+},
+*/
+{
+ Id: 200003
+ Name: "Master Job level!"
+ Type: "ACH_STATUS"
+ Objectives: {
+ *1: {
+ Description: "Job level 50"
+ Criteria: {
+ StatusType: "SP_JOBLEVEL"
+ }
+ Goal: 50
+ }
+ }
+ Rewards: {
+ TitleId: 1003
+ Bonus: <" specialeffect(EF_BLESSING, AREA, playerattached()); sc_start SC_BLESSING, 30000, 1; ">
+ Items: {
+ Old_Violet_Box: 1
+ }
+ }
+ Points: 30
+},
+/*
+{
+ Id: 200004
+ Name: "Grandmaster Job level!"
+ Type: "ACH_STATUS"
+ Objectives: {
+ *1: {
+ Description: "Job level 70"
+ Criteria: {
+ StatusType: "SP_JOBLEVEL"
+ }
+ Goal: 70
+ }
+ }
+ Rewards: {
+ TitleId: 1004
+ Bonus: <" specialeffect(EF_BLESSING, AREA, playerattached()); sc_start SC_BLESSING, 30000, 1; ">
+ Items: {
+ Old_Card_Album_: 1
+ }
+ }
+ Points: 50
+},
+*/
+{
+ Id: 200005
+ Name: "Official Adventurer"
+ Type: "ACH_JOB_CHANGE"
+ Objectives: {
+ *1: {
+ Description: "Job change to first class"
+ Criteria: {
+ JobId: [ "Job_Swordman", "Job_Mage", "Job_Archer", "Job_Acolyte", "Job_Merchant", "Job_Thief" ]
+ }
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ }
+ Points: 10
+},
+{
+ Id: 200006
+ Name: "First step of job change!"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "First step of job change"
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ }
+ Points: 20
+},
+{
+ Id: 200007
+ Name: "Veteran Adventurer! (1)"
+ Type: "ACH_JOB_CHANGE"
+ Objectives: {
+ *1: {
+ Description: "Job change to 2-1 classes"
+ Criteria: {
+ JobId: [ "Job_Knight", "Job_Priest", "Job_Wizard", "Job_Blacksmith", "Job_Hunter", "Job_Assassin" ]
+ }
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ }
+ Points: 25
+},
+{
+ Id: 200008
+ Name: "Veteran Adventurer! (2)"
+ Type: "ACH_JOB_CHANGE"
+ Objectives: {
+ *1: {
+ Description: "Job change to 2-2 classes"
+ Criteria: {
+ JobId: [ "Job_Crusader", "Job_Sage", "Job_Bard", "Job_Dancer", "Job_Alchemist", "Job_Rogue" ]
+ }
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ }
+ Points: 25
+},
+{
+ Id: 200009
+ Name: "Warrior (1)"
+ Type: "ACH_JOB_CHANGE"
+ Objectives: {
+ *1: {
+ Description: "Job change to transcendent 2-1 classes"
+ Criteria: {
+ JobId: [ "Job_Lord_Knight", "Job_High_Wizard", "Job_Sniper", "Job_High_Priest", "Job_Whitesmith", "Job_Assassin_Cross" ]
+ }
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ }
+ Points: 30
+},
+{
+ Id: 200010
+ Name: "Warrior (2)"
+ Type: "ACH_JOB_CHANGE"
+ Objectives: {
+ *1: {
+ Description: "Job change to transcendent 2-2 classes"
+ Criteria: {
+ JobId: [ "Job_Paladin", "Job_Professor", "Job_Clown", "Job_Gypsy", "Job_Champion", "Job_Creator", "Job_Stalker" ]
+ }
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ }
+ Points: 30
+},
+{
+ Id: 200011
+ Name: "Elite Adventurer! (1)"
+ Type: "ACH_JOB_CHANGE"
+ Objectives: {
+ *1: {
+ Description: "Job change to 3-1 classes"
+ Criteria: {
+ JobId: [ "Job_Rune_Knight", "Job_Warlock", "Job_Ranger", "Job_Arch_Bishop", "Job_Mechanic", "Job_Guillotine_Cross" ]
+ }
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Abrasive_Box_10: 1
+ }
+ }
+ Points: 50
+},
+{
+ Id: 200012
+ Name: "Transcendentaler! (1)"
+ Type: "ACH_JOB_CHANGE"
+ Objectives: {
+ *1: {
+ Description: "Job change to 3-1 classes after transcendent"
+ Criteria: {
+ JobId: [ "Job_Rune_Knight_T", "Job_Warlock_T", "Job_Ranger_T", "Job_Arch_Bishop_T", "Job_Mechanic_T", "Job_Guillotine_Cross_T" ]
+ }
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Abrasive_Box_10: 1
+ }
+ }
+ Points: 60
+},
+{
+ Id: 200013
+ Name: "Elite Adventurer! (2)"
+ Type: "ACH_JOB_CHANGE"
+ Objectives: {
+ *1: {
+ Description: "Job change to 3-2 classes"
+ Criteria: {
+ JobId: [ "Job_Royal_Guard", "Job_Sorcerer", "Job_Minstrel", "Job_Wanderer", "Job_Sura", "Job_Genetic", "Job_Shadow_Chaser" ]
+ }
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Abrasive_Box_10: 1
+ }
+ }
+ Points: 50
+},
+{
+ Id: 200014
+ Name: "Transcendentaler! (2)"
+ Type: "ACH_JOB_CHANGE"
+ Objectives: {
+ *1: {
+ Description: "Job change to 3-2 classes after transcendent"
+ Criteria: {
+ JobId: [ "Job_Royal_Guard_T", "Job_Sorcerer_T", "Job_Minstrel_T", "Job_Wanderer_T", "Job_Sura_T", "Job_Genetic_T", "Job_Shadow_Chaser_T" ]
+ }
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Abrasive_Box_10: 1
+ }
+ }
+ Points: 60
+},
+{
+ Id: 200015
+ Name: "The way of exceptional character"
+ Type: "ACH_JOB_CHANGE"
+ Objectives: {
+ *1: {
+ Description: "Job change to expanded classes"
+ Criteria: {
+ JobId: [ "Job_Taekwon", "Job_Gunslinger", "Job_Ninja", "Job_Summoner" ]
+ }
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ }
+ Points: 10
+},
+{
+ Id: 200016
+ Name: "This is My way!"
+ Type: "ACH_JOB_CHANGE"
+ Objectives: {
+ *1: {
+ Description: "Expanded 2nd classes"
+ Criteria: {
+ JobId: [ "Job_Star_Gladiator", "Job_Soul_Linker", "Job_Rebellion", "Job_Kagerou", "Job_Oboro" ]
+ }
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Abrasive_Box_10: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 200017
+ Name: "Bearish Power!"
+ Type: "ACH_STATUS"
+ Objectives: {
+ *1: {
+ Description: "Achieve base STR 90º"
+ Criteria: {
+ StatusType: "SP_STR"
+ }
+ Goal: 90
+ }
+ }
+ Points: 10
+},
+{
+ Id: 200018
+ Name: "Overflowing Magic!"
+ Type: "ACH_STATUS"
+ Objectives: {
+ *1: {
+ Description: "Achieve base INT 90"
+ Criteria: {
+ StatusType: "SP_INT"
+ }
+ Goal: 90
+ }
+ }
+ Points: 10
+},
+{
+ Id: 200019
+ Name: "Healthy Body and Mental Health!"
+ Type: "ACH_STATUS"
+ Objectives: {
+ *1: {
+ Description: "Achieve base VIT 90"
+ Criteria: {
+ StatusType: "SP_VIT"
+ }
+ Goal: 90
+ }
+ }
+ Points: 10
+},
+{
+ Id: 200020
+ Name: "Speed of Light"
+ Type: "ACH_STATUS"
+ Objectives: {
+ *1: {
+ Description: "Achieve base AGI 90"
+ Criteria: {
+ StatusType: "SP_AGI"
+ }
+ Goal: 90
+ }
+ }
+ Points: 10
+},
+{
+ Id: 200021
+ Name: "Hawk Eyes"
+ Type: "ACH_STATUS"
+ Objectives: {
+ *1: {
+ Description: "Achieve base DEX 90"
+ Criteria: {
+ StatusType: "SP_DEX"
+ }
+ Goal: 90
+ }
+ }
+ Points: 10
+},
+{
+ Id: 200022
+ Name: "Maximum Luck"
+ Type: "ACH_STATUS"
+ Objectives: {
+ *1: {
+ Description: "Achieve base LUK 90"
+ Criteria: {
+ StatusType: "SP_LUK"
+ }
+ Goal: 90
+ }
+ }
+ Points: 10
+},
+{
+ Id: 200023
+ Name: "Dragonlike Power!"
+ Type: "ACH_STATUS"
+ Objectives: {
+ *1: {
+ Description: "Achieve base STR 125"
+ Criteria: {
+ StatusType: "SP_STR"
+ }
+ Goal: 125
+ }
+ }
+ Rewards: {
+ Bonus: <" sc_start SC_GIANTGROWTH, 180000, 1; ">
+ }
+ Points: 20
+},
+{
+ Id: 200024
+ Name: "Magic Insanity"
+ Type: "ACH_STATUS"
+ Objectives: {
+ *1: {
+ Description: "Achieve base INT 125"
+ Criteria: {
+ StatusType: "SP_INT"
+ }
+ Goal: 125
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_HASTEUP, AREA, playerattached()); sc_start2 SC_MAGIC_CANDY, 60000, 30, 70; ">
+ }
+ Points: 20
+},
+{
+ Id: 200025
+ Name: "Rock Alloy"
+ Type: "ACH_STATUS"
+ Objectives: {
+ *1: {
+ Description: "Achieve base VIT 125"
+ Criteria: {
+ StatusType: "SP_VIT"
+ }
+ Goal: 125
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_HEAL3, AREA, playerattached()); sc_start2 SC_S_LIFEPOTION, 600000, -5, 5; ">
+ }
+ Points: 20
+},
+{
+ Id: 200026
+ Name: "Speed of Light"
+ Type: "ACH_STATUS"
+ Objectives: {
+ *1: {
+ Description: "Achieve base AGI 125"
+ Criteria: {
+ StatusType: "SP_AGI"
+ }
+ Goal: 125
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_STEAL, AREA, playerattached()); sc_start SC_PLUSAVOIDVALUE, 60000, 20; ">
+ }
+ Points: 20
+},
+{
+ Id: 200027
+ Name: "Falcon's Eyes"
+ Type: "ACH_STATUS"
+ Objectives: {
+ *1: {
+ Description: "Achieve base DEX 125"
+ Criteria: {
+ StatusType: "SP_DEX"
+ }
+ Goal: 125
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_MAGICALATTHIT, AREA, playerattached()); sc_start SC_CRITICALPERCENT, 300000, 30; ">
+ }
+ Points: 20
+},
+{
+ Id: 200028
+ Name: "Lucky Fever"
+ Type: "ACH_STATUS"
+ Objectives: {
+ *1: {
+ Description: "Achieve base LUK 125"
+ Criteria: {
+ StatusType: "SP_LUK"
+ }
+ Goal: 125
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_GLORIA, AREA, playerattached()); sc_start SC_GLORIA, 15000, 0; ">
+ }
+ Points: 20
+},
+{
+ Id: 200029
+ Name: "Incarnation of Love and Hate"
+ Type: "ACH_STATUS_BY_JOB"
+ Objectives: {
+ *1: {
+ Description: "Achieve 99 base level as Novice"
+ Criteria: {
+ StatusType: "SP_BASELEVEL"
+ JobId: "Job_Novice"
+ }
+ Goal: 99
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_BLESSING, AREA, playerattached()); sc_start SC_BLESSING, 30000, 1; ">
+ Items: {
+ Abrasive_Box_10: 1
+ }
+ }
+ Points: 30
+},
+{
+ Id: 200030
+ Name: "I really love it!"
+ Type: "ACH_STATUS_BY_JOBTYPE"
+ Objectives: {
+ *1: {
+ Description: "Achieve 99 base level as 1st classes"
+ Criteria: {
+ StatusType: "SP_BASELEVEL"
+ JobId: ["Job_Swordman", "Job_Mage", "Job_Archer", "Job_Acolyte", "Job_Merchant", "Job_Thief"]
+ }
+ Goal: 99
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_BLESSING, AREA, playerattached()); sc_start(SC_BLESSING, 30000, 1); ">
+ Items: {
+ Bubble_Gum_Box_10: 1
+ }
+ }
+ Points: 30
+},
+{
+ Id: 200031
+ Name: "Reborn in Valhalla!"
+ Type: "ACH_JOB_CHANGE"
+ Objectives: {
+ *1: {
+ Description: "Job change to transcendent Novice"
+ Criteria: {
+ JobId: "Job_Novice_High"
+ }
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Special_Gift_Box: 1
+ }
+ }
+ Points: 10
+},
+/*{
+ Id: 200032
+ Name: "Start of Another Adventure"
+ Type: "ACH_STATUS_BY_JOB"
+ Objectives: {
+ *1: {
+ Description: "Achieve Base Level 100"
+ Criteria: {
+ StatusType: "SP_BASELEVEL"
+ JobId: "" // Rebirth?
+ }
+ Goal: 100
+ }
+ }
+ Rewards: {
+ Items: {
+ ID23585: 1 (Non-Existent Item)
+ }
+ }
+ Points: 10
+},*/
+{
+ Id: 220000
+ Name: "Community begin"
+ Type: "ACH_CHATROOM_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Create a chatroom"
+ }
+ }
+ Points: 10
+},
+{
+ Id: 220001
+ Name: "A mouth only moment"
+ Type: "ACH_CHATROOM_CREATE_DEAD"
+ Objectives: {
+ *1: {
+ Description: "Create a chatroom when KO'ed"
+ }
+ }
+ Points: 10
+},
+{
+ Id: 220002
+ Name: "Admiring the chatter"
+ Type: "ACH_CHATROOM_MEMBERS"
+ Objectives: {
+ *1: {
+ Description: "Fill the chatroom with 20 people"
+ }
+ }
+ Points: 10
+},
+{
+ Id: 220003
+ Name: "My friend's friend~"
+ Type: "ACH_FRIEND_ADD"
+ Objectives: {
+ *1: {
+ Description: "Add 1 person as a friend"
+ }
+ }
+ Points: 10
+},
+{
+ Id: 220004
+ Name: "A competition of popularity"
+ Type: "ACH_FRIEND_ADD"
+ Objectives: {
+ *1: {
+ Description: "Add 10 person as a friend"
+ }
+ }
+ Points: 10
+},
+{
+ Id: 220005
+ Name: "Let's Party~"
+ Type: "ACH_PARTY_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Create a party"
+ }
+ }
+ Points: 10
+},
+{
+ Id: 220006
+ Name: "Married with who..?"
+ Type: "ACH_MARRY"
+ Objectives: {
+ *1: {
+ Description: "Succeed on marriage"
+ }
+ }
+ Rewards: {
+ TitleId: 1022
+ }
+ Points: 20
+},
+{
+ Id: 220007
+ Name: "Can you grow?"
+ Type: "ACH_ADOPT_PARENT"
+ Objectives: {
+ *1: {
+ Description: "Adopted by parents"
+ }
+ }
+ Rewards: {
+ TitleId: 1032
+ }
+ Points: 20
+},
+{
+ Id: 220008
+ Name: "Being a parent"
+ Type: "ACH_ADOPT_BABY"
+ Objectives: {
+ *1: {
+ Description: "Adopt a child"
+ }
+ }
+ Rewards: {
+ TitleId: 1033
+ }
+ Points: 20
+},
+{
+ Id: 220009
+ Name: "Activating the market economy (1)"
+ Type: "ACH_ZENY_SPEND_TOTAL"
+ Objectives: {
+ *1: {
+ Description: "Spend 10000 zeny on vending merchant"
+ Goal: 10000
+ }
+ }
+ Points: 10
+},
+{
+ Id: 220010
+ Name: "Activating the market economy (2)"
+ Type: "ACH_ZENY_SPEND_TOTAL"
+ Objectives: {
+ *1: {
+ Description: "Spend 100000 zeny on vending merchant"
+ Goal: 1000000
+ }
+ }
+ Points: 15
+},
+{
+ Id: 220011
+ Name: "Activating the market economy (3)"
+ Type: "ACH_ZENY_SPEND_TOTAL"
+ Objectives: {
+ *1: {
+ Description: "Spend 500000 zeny on vending merchant"
+ Goal: 5000000
+ }
+ }
+ Points: 20
+},
+{
+ Id: 220012
+ Name: "Activating the market economy (4)"
+ Type: "ACH_ZENY_SPEND_TOTAL"
+ Objectives: {
+ *1: {
+ Description: "Spend 1.000000 zeny on vending merchant"
+ Goal: 100000000
+ }
+ }
+ Points: 30
+},
+{
+ Id: 220013
+ Name: "Activating the market economy (5)"
+ Type: "ACH_ZENY_SPEND_TOTAL"
+ Objectives: {
+ *1: {
+ Description: "Spend 5.000000 zeny on vending merchant"
+ Goal: 500000000
+ }
+ }
+ Points: 50
+},
+{
+ Id: 220014
+ Name: "I can't quit from refining! (1)"
+ Type: "ACH_EQUIP_REFINE_SUCCESS_WLV"
+ Objectives: {
+ *1: {
+ Description: "Succeed on refining level 1 weapon to +7"
+ Criteria: {
+ ItemType: "IT_WEAPON"
+ WeaponLevel: 1
+ }
+ Goal: 7
+ }
+ }
+ Points: 10
+},
+{
+ Id: 220015
+ Name: "I can't quit from refining! (2)"
+ Type: "ACH_EQUIP_REFINE_SUCCESS_WLV"
+ Objectives: {
+ *1: {
+ Description: "Succeed on refining level 1 weapon to +12"
+ Criteria: {
+ ItemType: "IT_WEAPON"
+ WeaponLevel: 1
+ }
+ Goal: 12
+ }
+ }
+ Points: 15
+},
+{
+ Id: 220016
+ Name: "I can't quit from refining! (3)"
+ Type: "ACH_EQUIP_REFINE_SUCCESS_WLV"
+ Objectives: {
+ *1: {
+ Description: "Succeed on refining level 2 weapon to +7"
+ Criteria: {
+ ItemType: "IT_WEAPON"
+ WeaponLevel: 2
+ }
+ Goal: 7
+ }
+ }
+ Points: 10
+},
+{
+ Id: 220017
+ Name: "I can't quit from refining! (4)"
+ Type: "ACH_EQUIP_REFINE_SUCCESS_WLV"
+ Objectives: {
+ *1: {
+ Description: "Succeed on refining level 2 weapon to +12"
+ Criteria: {
+ ItemType: "IT_WEAPON"
+ WeaponLevel: 2
+ }
+ Goal: 12
+ }
+ }
+ Points: 15
+},
+{
+ Id: 220018
+ Name: "I can't quit from refining! (5)"
+ Type: "ACH_EQUIP_REFINE_SUCCESS_WLV"
+ Objectives: {
+ *1: {
+ Description: "Succeed on refining level 3 weapon to +7"
+ Criteria: {
+ ItemType: "IT_WEAPON"
+ WeaponLevel: 3
+ }
+ Goal: 7
+ }
+ }
+ Points: 15
+},
+{
+ Id: 220019
+ Name: "I can't quit from refining! (6)"
+ Type: "ACH_EQUIP_REFINE_SUCCESS_WLV"
+ Objectives: {
+ *1: {
+ Description: "Succeed on refining level 3 weapon to +12"
+ Criteria: {
+ ItemType: "IT_WEAPON"
+ WeaponLevel: 3
+ }
+ Goal: 12
+ }
+ }
+ Points: 20
+},
+{
+ Id: 220020
+ Name: "I can't quit from refining! (7)"
+ Type: "ACH_EQUIP_REFINE_SUCCESS_WLV"
+ Objectives: {
+ *1: {
+ Description: "Succeed on refining level 4 weapon to +7"
+ Criteria: {
+ ItemType: "IT_WEAPON"
+ WeaponLevel: 4
+ }
+ Goal: 7
+ }
+ }
+ Points: 20
+},
+{
+ Id: 220021
+ Name: "I can't quit from refining! (8)"
+ Type: "ACH_EQUIP_REFINE_SUCCESS_WLV"
+ Objectives: {
+ *1: {
+ Description: "Succeed on refining level 4 weapon to +12"
+ Criteria: {
+ ItemType: "IT_WEAPON"
+ WeaponLevel: 4
+ }
+ Goal: 12
+ }
+ }
+ Points: 30
+},
+{
+ Id: 220022
+ Name: "Human's greed has no ending.."
+ Type: "ACH_EQUIP_REFINE_FAILURE_TOTAL"
+ Objectives: {
+ *1: {
+ Description: "Experience the fail of refining"
+ Criteria: {
+ ItemType: ["IT_WEAPON", "IT_ARMOR"]
+ }
+ }
+ }
+ Points: 10
+},
+{
+ Id: 220023
+ Name: "I found it! (1)"
+ Type: "ACH_ITEM_GET_WORTH"
+ Objectives: {
+ *1: {
+ Description: "Obtain an item with worth of more than 100 zeny"
+ Goal: 100
+ }
+ }
+ Points: 10
+},
+{
+ Id: 220024
+ Name: "I found it! (2)"
+ Type: "ACH_ITEM_GET_WORTH"
+ Objectives: {
+ *1: {
+ Description: "Obtain an item with worth of more than 1000 zeny"
+ Goal: 1000
+ }
+ }
+ Points: 10
+},
+{
+ Id: 220025
+ Name: "I found it! (3)"
+ Type: "ACH_ITEM_GET_WORTH"
+ Objectives: {
+ *1: {
+ Description: "Obtain an item with worth of more than 5000 zeny"
+ Goal: 5000
+ }
+ }
+ Points: 15
+},
+{
+ Id: 220026
+ Name: "I found it! (4)"
+ Type: "ACH_ITEM_GET_WORTH"
+ Objectives: {
+ *1: {
+ Description: "Obtain an item with worth of more than 10000 zeny"
+ Goal: 10000
+ }
+ }
+ Points: 15
+},
+{
+ Id: 220027
+ Name: "I found it! (5)"
+ Type: "ACH_ITEM_GET_WORTH"
+ Objectives: {
+ *1: {
+ Description: "Obtain an item with worth of more than 50000 zeny"
+ Goal: 50000
+ }
+ }
+ Points: 20
+},
+{
+ Id: 220028
+ Name: "I found it! (6)"
+ Type: "ACH_ITEM_GET_WORTH"
+ Objectives: {
+ *1: {
+ Description: "Obtain an item with worth of more than 100000 zeny"
+ Goal: 100000
+ }
+ }
+ Points: 20
+},
+{
+ Id: 220029
+ Name: "I found it! (7)"
+ Type: "ACH_ITEM_GET_WORTH"
+ Objectives: {
+ *1: {
+ Description: "Obtain an item with worth of more than 150000 zeny"
+ Goal: 150000
+ }
+ }
+ Points: 30
+},
+{
+ Id: 220030
+ Name: "Rich King (1)"
+ Type: "ACH_ZENY_HOLD"
+ Objectives: {
+ *1: {
+ Description: "Hold more than 10000 zeny in pocket"
+ Goal: 10000
+ }
+ }
+ Points: 10
+},
+{
+ Id: 220031
+ Name: "Rich King (2)"
+ Type: "ACH_ZENY_HOLD"
+ Objectives: {
+ *1: {
+ Description: "Hold more than 100000 zeny in pocket"
+ Goal: 100000
+ }
+ }
+ Points: 15
+},
+{
+ Id: 220032
+ Name: "Rich King (3)"
+ Type: "ACH_ZENY_HOLD"
+ Objectives: {
+ *1: {
+ Description: "Hold more than 1000000 zeny in pocket"
+ Goal: 1000000
+ }
+ }
+ Points: 20
+},
+{
+ Id: 220033
+ Name: "Rich King (4)"
+ Type: "ACH_ZENY_HOLD"
+ Objectives: {
+ *1: {
+ Description: "Hold more than 10000000 zeny in pocket"
+ Goal: 10000000
+ }
+ }
+ Points: 25
+},
+{
+ Id: 220034
+ Name: "Rich King (5)"
+ Type: "ACH_ZENY_HOLD"
+ Objectives: {
+ *1: {
+ Description: "Hold more than 100000000 zeny in pocket"
+ Goal: 100000000
+ }
+ }
+ Points: 30
+},
+{
+ Id: 220035
+ Name: "Rich King (6)"
+ Type: "ACH_ZENY_HOLD"
+ Objectives: {
+ *1: {
+ Description: "Hold more than 1000000000 zeny in pocket"
+ Goal: 1000000000
+ }
+ }
+ Points: 40
+},
+{
+ Id: 230101
+ Name: "Poring - taming"
+ Type: "ACH_PET_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Succeed on Taming Poring"
+ Criteria: {
+ MobId: "PORING"
+ }
+ }
+ }
+ Points: 10
+},
+{
+ Id: 230102
+ Name: "Drops - taming"
+ Type: "ACH_PET_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Succeed on Taming Drops"
+ Criteria: {
+ MobId: "DROPS"
+ }
+ }
+ }
+ Points: 10
+},
+{
+ Id: 230103
+ Name: "Poporing - taming"
+ Type: "ACH_PET_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Succeed on Taming Poporing"
+ Criteria: {
+ MobId: "POPORING"
+ }
+ }
+ }
+ Points: 10
+},
+/*
+{
+ Id: 230104
+ Name: "Novice Poring - taming"
+ Type: "ACH_PET_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Succeed on Taming Novice Poring"
+ Criteria: {
+ MobId: "LITTLE_PORING"
+ }
+ }
+ }
+ Points: 10
+},
+*/
+{
+ Id: 230111
+ Name: "Chonchon - taming"
+ Type: "ACH_PET_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Succeed on Taming Chonchon"
+ Criteria: {
+ MobId: "CHONCHON"
+ }
+ }
+ }
+ Points: 10
+},
+{
+ Id: 230112
+ Name: "Steel Chonchon - taming"
+ Type: "ACH_PET_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Succeed on Taming Steel Chonchon"
+ Criteria: {
+ MobId: "STEEL_CHONCHON"
+ }
+ }
+ }
+ Points: 10
+},
+{
+ Id: 230113
+ Name: "Hunter Fly - taming"
+ Type: "ACH_PET_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Succeed on Taming Hunter Fly"
+ Criteria: {
+ MobId: "HUNTER_FLY"
+ }
+ }
+ }
+ Points: 10
+},
+{
+ Id: 230114
+ Name: "Rocker - taming"
+ Type: "ACH_PET_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Succeed on Taming Rocker"
+ Criteria: {
+ MobId: "ROCKER"
+ }
+ }
+ }
+ Points: 10
+},
+{
+ Id: 230115
+ Name: "Spore - taming"
+ Type: "ACH_PET_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Succeed on Taming Spore"
+ Criteria: {
+ MobId: "SPORE"
+ }
+ }
+ }
+ Points: 10
+},
+{
+ Id: 230116
+ Name: "Poison Spore - taming"
+ Type: "ACH_PET_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Succeed on Taming Poison Spore"
+ Criteria: {
+ MobId: "POISON_SPORE"
+ }
+ }
+ }
+ Points: 10
+},
+{
+ Id: 230121
+ Name: "Lunatic - taming"
+ Type: "ACH_PET_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Succeed on Taming Lunatic"
+ Criteria: {
+ MobId: "LUNATIC"
+ }
+ }
+ }
+ Points: 10
+},
+{
+ Id: 230122
+ Name: "Picky - taming"
+ Type: "ACH_PET_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Succeed on Taming Picky"
+ Criteria: {
+ MobId: "PICKY"
+ }
+ }
+ }
+ Points: 10
+},
+{
+ Id: 230123
+ Name: "Savage Bebe - taming"
+ Type: "ACH_PET_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Succeed on Taming Savage Bebe"
+ Criteria: {
+ MobId: "SAVAGE_BABE"
+ }
+ }
+ }
+ Points: 10
+},
+/*
+{
+ Id: 230124
+ Name: "Baby Desert Wolf - taming"
+ Type: "ACH_PET_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Succeed on Taming Baby Desert Wolf"
+ Criteria: {
+ MobId: "M_DESERT_WOLF_B"
+ }
+ }
+ }
+ Points: 10
+},
+*/
+{
+ Id: 230125
+ Name: "Smokie - taming"
+ Type: "ACH_PET_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Succeed on Taming Smokie"
+ Criteria: {
+ MobId: "SMOKIE"
+ }
+ }
+ }
+ Points: 10
+},
+{
+ Id: 230126
+ Name: "Yoyo - taming"
+ Type: "ACH_PET_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Succeed on Taming Yoyo"
+ Criteria: {
+ MobId: "YOYO"
+ }
+ }
+ }
+ Points: 10
+},
+{
+ Id: 230127
+ Name: "Peco Peco - taming"
+ Type: "ACH_PET_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Succeed on Taming Peco Peco"
+ Criteria: {
+ MobId: "PECOPECO"
+ }
+ }
+ }
+ Points: 10
+},
+{
+ Id: 230128
+ Name: "Petite - taming"
+ Type: "ACH_PET_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Succeed on Taming Petite"
+ Criteria: {
+ MobId: "PETIT"
+ }
+ }
+ }
+ Points: 10
+},
+{
+ Id: 230141
+ Name: "Munak - taming"
+ Type: "ACH_PET_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Succeed on Taming Munak"
+ Criteria: {
+ MobId: "MUNAK"
+ }
+ }
+ }
+ Points: 10
+},
+{
+ Id: 230142
+ Name: "Isis - taming"
+ Type: "ACH_PET_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Succeed on Taming Isis"
+ Criteria: {
+ MobId: "ISIS"
+ }
+ }
+ }
+ Points: 10
+},
+{
+ Id: 230143
+ Name: "Sohee - taming"
+ Type: "ACH_PET_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Succeed on Taming Sohee"
+ Criteria: {
+ MobId: "SOHEE"
+ }
+ }
+ }
+ Points: 10
+},
+{
+ Id: 230144
+ Name: "Zherlthsh - taming"
+ Type: "ACH_PET_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Succeed on Taming Zherlthsh"
+ Criteria: {
+ MobId: "ZHERLTHSH"
+ }
+ }
+ }
+ Points: 10
+},
+{
+ Id: 230145
+ Name: "Alice - taming"
+ Type: "ACH_PET_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Succeed on Taming Alice"
+ Criteria: {
+ MobId: "ALICE"
+ }
+ }
+ }
+ Points: 10
+},
+{
+ Id: 230146
+ Name: "Succubus - taming"
+ Type: "ACH_PET_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Succeed on Taming Succubus"
+ Criteria: {
+ MobId: "SUCCUBUS"
+ }
+ }
+ }
+ Points: 10
+},
+{
+ Id: 230147
+ Name: "Loli Ruri - taming"
+ Type: "ACH_PET_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Succeed on Taming Loli Ruri"
+ Criteria: {
+ MobId: "LOLI_RURI"
+ }
+ }
+ }
+ Points: 10
+},
+{
+ Id: 230201
+ Name: "Exploring Poring's life (1)"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Hunt 10 Poring"
+ Criteria: {
+ MobId: "PORING"
+ }
+ Goal: 10
+ }
+ *2: {
+ Description: "Hunt 10 Drops"
+ Criteria: {
+ MobId: "DROPS"
+ }
+ Goal: 10
+ }
+ *3: {
+ Description: "Hunt 10 Poporing"
+ Criteria: {
+ MobId: "POPORING"
+ }
+ Goal: 10
+ }
+ *4: {
+ Description: "Hunt 10 Marin"
+ Criteria: {
+ MobId: "MARIN"
+ }
+ Goal: 10
+ }
+/* Renewal Monster
+ *5: {
+ Description: "Hunt 10 Novice Poring"
+ Criteria: {
+ MobId: "LITTLE_PORING"
+ }
+ Goal: 10
+ }
+*/
+ }
+ Points: 10
+},
+
+{
+ Id: 230202
+ Name: "Exploring Poring's life (2)"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Hunt 1 Mastering"
+ Criteria: {
+ MobId: "MASTERING"
+ }
+ Goal: 1
+ }
+ *2: {
+ Description: "Hunt 1 Devilring"
+ Criteria: {
+ MobId: "DEVILING"
+ }
+ Goal: 1
+ }
+ *3: {
+ Description: "Hunt 1 Angelring"
+ Criteria: {
+ MobId: "ANGELING"
+ }
+ Goal: 1
+ }
+ *4: {
+ Description: "Hunt 1 Arch Angelring"
+ Criteria: {
+ MobId: "ARCHANGELING"
+ }
+ Goal: 1
+ }
+ *5: {
+ Description: "Hunt 1 Ghostring"
+ Criteria: {
+ MobId: "GHOSTRING"
+ }
+ Goal: 1
+ }
+ }
+ Points: 15
+},
+{
+ Id: 230203
+ Name: "Exploring Poring's life (3)"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Hunt 5 Metalring"
+ Criteria: {
+ MobId: "METALING"
+ }
+ Goal: 5
+ }
+ *2: {
+ Description: "Hunt 5 Heavy Metalring"
+ Criteria: {
+ MobId: "METALING"
+ }
+ Goal: 5
+ }
+ *3: {
+ Description: "Hunt 5 Magmaring"
+ Criteria: {
+ MobId: "MAGMARING"
+ }
+ Goal: 5
+ }
+ }
+ Points: 20
+},
+{
+ Id: 240000
+ Name: "Complete challenges after first introduction"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Complete challenges after first introduction"
+ }
+ }
+ Points: 10
+},
+{
+ Id: 240001
+ Name: "Achieve Level 1"
+ Type: "ACH_ACHIEVEMENT_RANK"
+ Objectives: {
+ *1: {
+ Description: "Achieving Rank 1"
+ Goal: 1
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 240002
+ Name: "Achieve Level 2"
+ Type: "ACH_ACHIEVEMENT_RANK"
+ Objectives: {
+ *1: {
+ Description: "Achieving Rank 2"
+ Goal: 2
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 240003
+ Name: "Achieve Level 3"
+ Type: "ACH_ACHIEVEMENT_RANK"
+ Objectives: {
+ *1: {
+ Description: "Achieving Rank 3"
+ Goal: 3
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 240004
+ Name: "Achieve Level 4"
+ Type: "ACH_ACHIEVEMENT_RANK"
+ Objectives: {
+ *1: {
+ Description: "Achieving Rank 4"
+ Goal: 4
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 240005
+ Name: "Achieve Level 5"
+ Type: "ACH_ACHIEVEMENT_RANK"
+ Objectives: {
+ *1: {
+ Description: "Achieving Rank 5"
+ Goal: 5
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 240006
+ Name: "Achieve Level 6"
+ Type: "ACH_ACHIEVEMENT_RANK"
+ Objectives: {
+ *1: {
+ Description: "Achieving Rank 6"
+ Goal: 6
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 240007
+ Name: "Achieve Level 7"
+ Type: "ACH_ACHIEVEMENT_RANK"
+ Objectives: {
+ *1: {
+ Description: "Achieving Rank 7"
+ Goal: 7
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 240008
+ Name: "Achieve Level 8"
+ Type: "ACH_ACHIEVEMENT_RANK"
+ Objectives: {
+ *1: {
+ Description: "Achieving Rank 8"
+ Goal: 8
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 240009
+ Name: "Achieve Level 9"
+ Type: "ACH_ACHIEVEMENT_RANK"
+ Objectives: {
+ *1: {
+ Description: "Achieving Rank 9"
+ Goal: 9
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 240010
+ Name: "Achieve Level 10"
+ Type: "ACH_ACHIEVEMENT_RANK"
+ Objectives: {
+ *1: {
+ Description: "Achieving Rank 10"
+ Goal: 10
+ }
+ }
+ Rewards: {
+ TitleId: 1023
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 240011
+ Name: "Achieve Level 11"
+ Type: "ACH_ACHIEVEMENT_RANK"
+ Objectives: {
+ *1: {
+ Description: "Achieving Rank 11"
+ Goal: 11
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 240012
+ Name: "Achieve Level 12"
+ Type: "ACH_ACHIEVEMENT_RANK"
+ Objectives: {
+ *1: {
+ Description: "Achieving Rank 12"
+ Goal: 12
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 240013
+ Name: "Achieve Level 13"
+ Type: "ACH_ACHIEVEMENT_RANK"
+ Objectives: {
+ *1: {
+ Description: "Achieving Rank 13"
+ Goal: 13
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 240014
+ Name: "Achieve Level 14"
+ Type: "ACH_ACHIEVEMENT_RANK"
+ Objectives: {
+ *1: {
+ Description: "Achieving Rank 14"
+ Goal: 14
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 240015
+ Name: "Achieve Level 15"
+ Type: "ACH_ACHIEVEMENT_RANK"
+ Objectives: {
+ *1: {
+ Description: "Achieving Rank 15"
+ Goal: 15
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 240016
+ Name: "Achieve Level 16"
+ Type: "ACH_ACHIEVEMENT_RANK"
+ Objectives: {
+ *1: {
+ Description: "Achieving Rank 16"
+ Goal: 16
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 240017
+ Name: "Achieve Level 17"
+ Type: "ACH_ACHIEVEMENT_RANK"
+ Objectives: {
+ *1: {
+ Description: "Achieving Rank 17"
+ Goal: 17
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 240018
+ Name: "Achieve Level 18"
+ Type: "ACH_ACHIEVEMENT_RANK"
+ Objectives: {
+ *1: {
+ Description: "Achieving Rank 18"
+ Goal: 18
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 240019
+ Name: "Achieve Level 19"
+ Type: "ACH_ACHIEVEMENT_RANK"
+ Objectives: {
+ *1: {
+ Description: "Achieving Rank 19"
+ Goal: 19
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 240020
+ Name: "Achieve Level 20"
+ Type: "ACH_ACHIEVEMENT_RANK"
+ Objectives: {
+ *1: {
+ Description: "Achieving Rank 20"
+ Goal: 20
+ }
+ }
+ Rewards: {
+ TitleId: 1024
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 10
+},
+/*****************************************************************
+ Postlude
+ Entries with criteria that must be read before itself.
+ *****************************************************************/
+{
+ Id: 230100
+ Name: "Poring is Love"
+ Type: "ACH_ACHIEVE"
+ Objectives: {
+ *1: {
+ Description: "Complete 'Poring - taming' challenge"
+ Criteria: {
+ Achieve: 230101
+ }
+ }
+ *2: {
+ Description: "Complete 'Drops - taming' challenge"
+ Criteria: {
+ Achieve: 230102
+ }
+ }
+ *3: {
+ Description: "Complete 'Poporing - taming' challenge"
+ Criteria: {
+ Achieve: 230103
+ }
+ }
+/* Renewal Monster
+ *4: {
+ Description: "Complete 'Novice Poring - taming' challenge"
+ Criteria: {
+ Achieve: 230104
+ }
+ }
+*/
+ }
+ Rewards: {
+ TitleId: 1025
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ }
+ Points: 50
+},
+{
+ Id: 230110
+ Name: "Entomologist"
+ Type: "ACH_ACHIEVE"
+ Objectives: {
+ *1: {
+ Description: "Complete 'Chonchon - taming' challenge"
+ Criteria: {
+ Achieve: 230111
+ }
+ }
+ *2: {
+ Description: "Complete 'Steel Chonchon - taming' challenge"
+ Criteria: {
+ Achieve: 230112
+ }
+ }
+ *3: {
+ Description: "Complete 'Hunter Fly - taming' challenge"
+ Criteria: {
+ Achieve: 230113
+ }
+ }
+ *4: {
+ Description: "Complete 'Rocker - taming' challenge"
+ Criteria: {
+ Achieve: 230114
+ }
+ }
+ *5: {
+ Description: "Complete 'Spore - taming' challenge"
+ Criteria: {
+ Achieve: 230115
+ }
+ }
+ *6: {
+ Description: "Complete 'Poison Spore - taming' challenge"
+ Criteria: {
+ Achieve: 230116
+ }
+ }
+ }
+ Rewards: {
+ TitleId: 1026
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ }
+ Points: 50
+},
+{
+ Id: 230120
+ Name: "Animals are also our friend"
+ Type: "ACH_ACHIEVE"
+ Objectives: {
+ *1: {
+ Description: "Complete 'Lunatic - taming' challenge"
+ Criteria: {
+ Achieve: 230121
+ }
+ }
+ *2: {
+ Description: "Complete 'Picky - taming' challenge"
+ Criteria: {
+ Achieve: 230122
+ }
+ }
+ *3: {
+ Description: "Complete 'Savage Bebe - taming' challenge"
+ Criteria: {
+ Achieve: 230123
+ }
+ }
+ *4: {
+ Description: "Complete 'Smokie - taming' challenge"
+ Criteria: {
+ Achieve: 230125
+ }
+ }
+ *5: {
+ Description: "Complete 'Yoyo - taming' challenge"
+ Criteria: {
+ Achieve: 230126
+ }
+ }
+ *6: {
+ Description: "Complete 'Peco Peco - taming' challenge"
+ Criteria: {
+ Achieve: 230127
+ }
+ }
+ *7: {
+ Description: "Complete 'Petite - taming' challenge"
+ Criteria: {
+ Achieve: 230128
+ }
+ }
+/* Renewal Monster
+ *8: {
+ Description: "Complete 'Baby Desert Wolf - taming' challenge"
+ Criteria: {
+ Achieve: 230124
+ }
+ }
+*/
+ }
+ Rewards: {
+ TitleId: 1027
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ }
+ Points: 50
+},
+{
+ Id: 230140
+ Name: "Monster Girls Unite!!"
+ Type: "ACH_ACHIEVE"
+ Objectives: {
+ *1: {
+ Description: "Complete 'Munak - taming' challenge"
+ Criteria: {
+ Achieve: 230141
+ }
+ }
+ *2: {
+ Description: "Complete 'Isis - taming' challenge"
+ Criteria: {
+ Achieve: 230142
+ }
+ }
+ *3: {
+ Description: "Complete 'Sohee - taming' challenge"
+ Criteria: {
+ Achieve: 230143
+ }
+ }
+ *4: {
+ Description: "Complete 'Zherlthsh - taming' challenge"
+ Criteria: {
+ Achieve: 230144
+ }
+ }
+ *5: {
+ Description: "Complete 'Alice - taming' challenge"
+ Criteria: {
+ Achieve: 230145
+ }
+ }
+ *6: {
+ Description: "Complete 'Succubus - taming' challenge"
+ Criteria: {
+ Achieve: 230146
+ }
+ }
+ *7: {
+ Description: "Complete 'Loli Ruri - taming' challenge"
+ Criteria: {
+ Achieve: 230147
+ }
+ }
+ }
+ Rewards: {
+ TitleId: 1029
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ }
+ Points: 50
+},
+{
+ Id: 230200
+ Name: "Poring seeker"
+ Type: "ACH_ACHIEVE"
+ Objectives: {
+ *1: {
+ Description: "Complete 'Exploring Poring's life (1)' challenge"
+ Criteria: {
+ Achieve: 230201
+ }
+ }
+ *2: {
+ Description: "Complete 'Exploring Poring's life (2)' challenge"
+ Criteria: {
+ Achieve: 230202
+ }
+ }
+ *3: {
+ Description: "Complete 'Exploring Poring's life (3)' challenge"
+ Criteria: {
+ Achieve: 230203
+ }
+ }
+ }
+ Points: 10
+},
+)
diff --git a/db/pre-re/item_db.conf b/db/pre-re/item_db.conf
index 55ddcbd3b..3f3b6d622 100644
--- a/db/pre-re/item_db.conf
+++ b/db/pre-re/item_db.conf
@@ -93846,6 +93846,24 @@ item_db: (
AegisName: "FRed_Wing_Hat_Box"
},
*/
+{
+ Id: 16483
+ AegisName: "Abrasive_Box_10"
+ Name: "Abrasive Box (10)"
+ Type: "IT_USABLE"
+ Buy: 20
+ Weight: 10
+ Script: <" getitem(E_Abrasive, 10); ">
+},
+{
+ Id: 16504
+ AegisName: "Bubble_Gum_Box_10"
+ Name: "Bubble Gum Box(10)"
+ Type: "IT_CASH"
+ Buy: 10
+ Weight: 10
+ Script: <" getitem(Bubble_Gum, 10); ">
+},
/*
Id: 16543
AegisName: "Snowman_Hat_Box"
@@ -94588,6 +94606,14 @@ item_db: (
">
},
{
+ Id: 22808
+ AegisName: "Special_Gift_Box"
+ Name: "Special Gift Box"
+ Type: "IT_USABLE"
+ Buy: 10
+ Weight: 100
+},
+{
Id: 22837
AegisName: "Integer_Time"
Name: "Integer Time"
@@ -94605,4 +94631,11 @@ item_db: (
}
Script: <" TmpRouletteBronze += 1; ">
},
+{
+ Id: 22876
+ AegisName: "Old_Money_Pocket"
+ Name: "Old Money Pocket"
+ Type: "IT_USABLE"
+ Script: <" Zeny += rand(500, 550); ">
+},
)
diff --git a/db/re/achievement_db.conf b/db/re/achievement_db.conf
new file mode 100644
index 000000000..e54a1d924
--- /dev/null
+++ b/db/re/achievement_db.conf
@@ -0,0 +1,6769 @@
+//================= Hercules Database =====================================
+//= _ _ _
+//= | | | | | |
+//= | |_| | ___ _ __ ___ _ _| | ___ ___
+//= | _ |/ _ \ '__/ __| | | | |/ _ \/ __|
+//= | | | | __/ | | (__| |_| | | __/\__ \
+//= \_| |_/\___|_| \___|\__,_|_|\___||___/
+//================= License ===============================================
+//= This file is part of Hercules.
+//= http://herc.ws - http://github.com/HerculesWS/Hercules
+//=
+//= Copyright (C) 2018 Hercules Dev Team
+//=
+//= Hercules is free software: you can redistribute it and/or modify
+//= it under the terms of the GNU General Public License as published by
+//= the Free Software Foundation, either version 3 of the License, or
+//= (at your option) any later version.
+//=
+//= This program is distributed in the hope that it will be useful,
+//= but WITHOUT ANY WARRANTY; without even the implied warranty of
+//= MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+//= GNU General Public License for more details.
+//=
+//= You should have received a copy of the GNU General Public License
+//= along with this program. If not, see <http://www.gnu.org/licenses/>.
+//=========================================================================
+//= Achievement Database
+//=========================================================================
+
+achievement_db: (
+/*****************************************************************
+ * Entry Structure
+ *****************************************************************
+{
+ Id: (int) Unique ID of the achievement representing it's client-side equivalent.
+ Name: (string) Name/Title of the Achievement.
+ Type: (string) Validation type for the achievement.
+ [Type] [Validation Description] (Trigger)
+ ACH_QUEST: Specific achievement objective update (Script).
+ ACH_KILL_PC_TOTAL: (Accumulative) Total kill count. (Player kill)
+ ACH_KILL_PC_JOB: Kill a player of the specified job. (Player Kill)
+ ACH_KILL_PC_JOBTYPE: Kill a player of the specified job type. (Player Kill)
+ ACH_KILL_MOB_CLASS: Kill a particular mob class. (Mob Kill)
+ ACH_DAMAGE_PC_MAX: Maximum damage caused on a player. (Player Damage)
+ ACH_DAMAGE_PC_TOTAL: (Accumulative) Damage on players. (Player Damage)
+ ACH_DAMAGE_PC_REC_MAX: Maximum damage received by a player. (Receive Player Damage)
+ ACH_DAMAGE_PC_REC_TOTAL: (Accumulative) Damage received by players. (Receive Player Damage)
+ ACH_DAMAGE_MOB_MAX: Maximum damage caused on a monster. (Monster Damage)
+ ACH_DAMAGE_MOB_TOTAL: (Accumulative) Damage caused on monsters. (Monster Damage)
+ ACH_DAMAGE_MOB_REC_MAX: Maximum damage received by a monster. (Receive Monster Damage)
+ ACH_DAMAGE_MOB_REC_TOTAL: (Accumulative) Damage received by monsters. (Receive Monster Damage)
+ ACH_JOB_CHANGE: Change to a specific job. (Job Change)
+ ACH_STATUS: Acquire a specific amount of a particular status type. (Stat Change)
+ ACH_STATUS_BY_JOB: Acquire a specific amount of a status type as a job class. (Stat Change)
+ ACH_STATUS_BY_JOBTYPE: Acquire a specific amount of a status type as a job type. (Stat Change)
+ ACH_CHATROOM_CREATE_DEAD: (Accumulative) Create a chatroom when dead. (Chatroom Creation)
+ ACH_CHATROOM_CREATE: (Accumulative) Create a chatroom. (Chatroom Creation)
+ ACH_CHATROOM_MEMBERS: Gather 'n' members in a chatroom. (Chatroom Join)
+ ACH_FRIEND_ADD: Add a specific number of friends. (Friend Addition)
+ ACH_PARTY_CREATE: (Accumulative) Create a specific number of parties. (Party Creation)
+ ACH_PARTY_JOIN: (Accumulative) Join a specific number of parties. (Party Join)
+ ACH_MARRY: (Accumulative) Marry a specified number of times. (Marriage)
+ ACH_ADOPT_BABY: (Accumulative) Get Adopted. (Adoption)
+ ACH_ADOPT_PARENT: (Accumulative) Adopt a Baby. (Adoption)
+ ACH_ZENY_HOLD: Hold a specific amount of zeny in your inventory. (Gain Zeny)
+ ACH_ZENY_GET_ONCE: Gain a specific amount of zeny in one transaction. (Gain Zeny)
+ ACH_ZENY_GET_TOTAL: (Accumulative) Gain a specific amount of zeny in total. (Gain Zeny)
+ ACH_ZENY_SPEND_ONCE: Spend a specific amount of zeny in one transaction. (Pay Zeny)
+ ACH_ZENY_SPEND_TOTAL: (Accumulative) Spend a specific amount of zeny in total. (Pay Zeny)
+ ACH_EQUIP_REFINE_SUCCESS: Refine an item to +N. (Successful Refine)
+ ACH_EQUIP_REFINE_FAILURE: Fail to refine an item of +N refine. (Failed Refine)
+ ACH_EQUIP_REFINE_SUCCESS_TOTAL: (Accumulative) Refine an item successfully N times. (Success Refine)
+ ACH_EQUIP_REFINE_FAILURE_TOTAL: (Accumulative) Fail to refine an item N times. (Failed Refine)
+ ACH_EQUIP_REFINE_SUCCESS_WLV: Refine a Weapon of a particular Level to +N. (Success Refine)
+ ACH_EQUIP_REFINE_FAILURE_WLV: Fail to refine a Weapon of a particular level from +N. (Failed Refine)
+ ACH_EQUIP_REFINE_SUCCESS_ID: Refine a particular Item successfully to +N. (Success Refine)
+ ACH_EQUIP_REFINE_FAILURE_ID: Fail to refine a particular item successfully from +N. (Failed Refine)
+ ACH_ITEM_GET_COUNT: Acquire N amount of an item of a particular ID. (Acquire Item)
+ ACH_ITEM_GET_COUNT_ITEMTYPE: Acquire N amount of items of a particular type mask. (Acquire Item)
+ ACH_ITEM_GET_WORTH: Acquire an item of buy value N. (Acquire Item)
+ ACH_ITEM_SELL_WORTH: Sell an item of sell value N. (NPC Sell Item)
+ ACH_PET_CREATE: Successfully tame a pet of a particular mob class. (Successful Pet Tame)
+ ACH_ACHIEVE: Achieve an Achievement. (Achievement Completion)
+ ACH_ACHIEVEMENT_RANK: Achieve an Achievement Rank. (Achievement Rank Increase)
+ Objectives: { [Mandatory Field] Objectives of an achievement. Up to 10 objectives per achievement.
+ To comply with the client's order of objectives, this list must be in order.
+ *1: {
+ Description: (string) [Mandatory Field] Description of a particular objective.
+ Criteria: { This is a field for achievements whose objectives must meet
+ certain criteria before evaluating the player's progress for it.
+ MobId: (mixed) MonsterId required for an objective.
+ For types such as ACH_KILL_MOB_CLASS and ACH_PET_CREATE. Can be either int or string constant.
+ JobId: (mixed) Array or Single entry of JobIds.
+ For types - ACH_KILL_PC_JOBTYPE, ACH_JOB_CHANGE or ACH_STATUS_BY_JOBTYPE.
+ Can be either a numeric or string constant.
+ ItemId: (mixed) ItemId required for an objective.
+ For Types such as ACH_ITEM_GET_COUNT. Can be either int or string constant.
+ StatusType: (mixed) Status Type required for an objective.
+ For Types such as ACH_STATUS, ACH_STATUS_BY_JOB, ACH_STATUS_BY_JOBTYPE.
+ Types -
+ "SP_STR" - Strength
+ "SP_AGI" - Agility
+ "SP_VIT" - Vitality
+ "SP_INT" - Intelligence
+ "SP_DEX" - Dexterity
+ "SP_LUK" - Luck
+ "SP_BASELEVEL" - Base Level
+ "SP_JOBLEVEL" - Job Level
+ Can be either int or string constant.
+ ItemType: (mixed) Item type that is required for this achievement.
+ For Types such as ACH_ITEM_GET_COUNT_ITEMTYPE.
+ Can be either int, string or list.
+ Refer "Item types" Constants from constants.conf
+ WeaponLevel: (int) Weapon Level that is required for this achievement. (Eg. 0, 1, 2, 3 or 4).
+ For Types such as ACH_EQUIP_REFINE_SUCCESS_WLV and ACH_EQUIP_REFINE_FAILURE_WLV.
+ Achieve: (int) AchievementID to be achieved.
+ For Type - ACH_ACHIEVE.
+ }
+ Goal: (int) Target amount to be met for the completion of the objective. Default is 1.
+ }
+ ...
+ *10: {...}
+ }
+ Rewards: {
+ Bonus: <""> (script) Script code bonus to be given as a reward for an achievement.
+ Items: { Item rewards per achievement. With a maximum defined in mmo.h as MAX_ACHEIVEMENT_ITEM_REWARDS.
+ Apple: 1 (int) Item ID (int or string constant) : Amount (int)
+ }
+ TitleId: (int) ID of the Title (from the Title System) awarded.
+ }
+ Points: (int) Points per achievement given on it's successful completion.
+}
+ *****************************************************************/
+{
+ Id: 110000
+ Name: "At this time I live to eat"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Bring the food to Bigfoot at this hour"
+ }
+ }
+ Points: 10
+},
+{
+ Id: 110001
+ Name: "A fan of this polarity"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Lady of the house"
+ }
+ *2: {
+ Description: "Beautiful fine anak"
+ }
+ *3: {
+ Description: "Mistress in ambience"
+ }
+ *4: {
+ Description: "Beautiful wife and children"
+ }
+ *5: {
+ Description: "Down town Bachelor"
+ }
+ *6: {
+ Description: "Great act ability anak"
+ }
+ *7: {
+ Description: "Great attack power bachelor"
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120001
+ Name: "North Prontera Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding north prontera field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120002
+ Name: "North Prontera Field Exploration(2)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding north prontera field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120003
+ Name: "North Prontera Field Exploration(3)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding north prontera field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120004
+ Name: "West Prontera Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding west prontera field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120005
+ Name: "West Prontera Field Exploration(2)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding west prontera field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120006
+ Name: "East Prontera Field Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding east prontera field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120007
+ Name: "South Prontera Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding south prontera field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120008
+ Name: "South Prontera Field Exploration(2)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding south prontera field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120009
+ Name: "South Prontera Field Exploration(3)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding south prontera field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120010
+ Name: "South Prontera Field Exploration(4)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding south prontera field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120011
+ Name: "East Geffen Field Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding east geffen field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120012
+ Name: "Southeast Geffen Field Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding southeast geffen field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120013
+ Name: "Northwest Geffen Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding northwest geffen field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120014
+ Name: "Northwest Geffen Field Exploration(2)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding northwest geffen field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120015
+ Name: "Northwest Geffen Field Exploration(3)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding northwest geffen field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120016
+ Name: "South Geffen Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding south geffen field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120017
+ Name: "South Geffen Field Exploration(2)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding south geffen field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120018
+ Name: "Sograt Desert Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding sograt desert field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120019
+ Name: "Sograt Desert Field Exploration(2)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding sograt desert field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120020
+ Name: "Sograt Desert Field Exploration(3)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding sograt desert field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120021
+ Name: "Sograt Desert Field Exploration(4)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding sograt desert field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120022
+ Name: "Sograt Desert Field Exploration(5)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding sograt desert field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120023
+ Name: "Sograt Desert Field Exploration(6)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding sograt desert field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120024
+ Name: "Southwest Payon Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding southwest payon field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120025
+ Name: "Southwest Payon Field Exploration(2)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding southwest payon field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120026
+ Name: "Southwest Payon Field Exploration(3)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding southwest payon field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120027
+ Name: "Southwest Payon Field Exploration(4)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding southwest payon field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120028
+ Name: "East Payon Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding east payon field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120029
+ Name: "East Payon Field Exploration(2)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding east payon field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120030
+ Name: "East Payon Field Exploration(3)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding east payon field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120031
+ Name: "East Payon Field Exploration(4)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding east payon field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120032
+ Name: "North Mjolnir Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding north mjolnir field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120033
+ Name: "North Mjolnir Field Exploration(2)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding north mjolnir field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120034
+ Name: "North Mjolnir Field Exploration(3)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding north mjolnir field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120035
+ Name: "North Mjolnir Field Exploration(4)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding north mjolnir field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120036
+ Name: "North Mjolnir Field Exploration(5)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding north mjolnir field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120037
+ Name: "South Mjolnir Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding south mjolnir field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120038
+ Name: "South Mjolnir Field Exploration(2)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding south mjolnir field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120039
+ Name: "South Mjolnir Field Exploration(3)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding south mjolnir field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120040
+ Name: "South Mjolnir Field Exploration(4)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding south mjolnir field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120041
+ Name: "South Mjolnir Field Exploration(5)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding south mjolnir field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120042
+ Name: "South Mjolnir Field Exploration(6)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding south mjolnir field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120043
+ Name: "South Aldebaran Field Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding south aldebaran field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120044
+ Name: "Comodo Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding comodo field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120045
+ Name: "Comodo Field Exploration(2)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding comodo field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120046
+ Name: "Comodo Field Exploration(3)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding comodo field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120047
+ Name: "Comodo Field Exploration(4)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding comodo field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120048
+ Name: "Comodo Field Exploration(5)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding comodo field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120049
+ Name: "Comodo Field Exploration(6)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding comodo field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120050
+ Name: "Comodo Field Exploration(7)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding comodo field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120051
+ Name: "Comodo Field Exploration(8)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding comodo field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120052
+ Name: "Border Checkpoint Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding border checkpoint field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120053
+ Name: "Border Checkpoint Field Exploration(2)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding border checkpoint field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120054
+ Name: "Kiel Hyre Mansion Field Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding kiel hyre mansion field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120055
+ Name: "El Mes Plateau Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding el mes plateau field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120056
+ Name: "El Mes Plateau Field Exploration(2)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding el mes plateau field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120057
+ Name: "El Mes Plateau Field Exploration(3)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding el mes plateau field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120058
+ Name: "El Mes Gorge Field Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding el mes gorge field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120059
+ Name: "Kiel Hyre Academy Field Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding kiel hyre academy field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120060
+ Name: "Guard Camp Field Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding guard camp field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120061
+ Name: "Yuno Field Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding yuno field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120062
+ Name: "Front of Thanatos Tower Field Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding front of thanatos tower field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120063
+ Name: "Hugel Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding hugel field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120064
+ Name: "Hugel Field Exploration(2)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding hugel field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120065
+ Name: "Hugel Field Exploration(3)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding hugel field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120066
+ Name: "Abyss Lake Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding abyss lake field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120067
+ Name: "Einbroch Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding Einbroch field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120068
+ Name: "Einbroch Field Exploration(2)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding Einbroch field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120069
+ Name: "Einbroch Field Exploration(3)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding Einbroch field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120070
+ Name: "Einbroch Field Exploration(4)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding Einbroch field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120071
+ Name: "Einbroch Field Exploration(5)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding Einbroch field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120072
+ Name: "Einbroch Field Exploration(6)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding Einbroch field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120073
+ Name: "Einbroch Field Exploration(7)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding Einbroch field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120074
+ Name: "Einbroch Field Exploration(8)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding Einbroch field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120075
+ Name: "Lighthalzen Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding lighthalzen field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120076
+ Name: "Lighthalzen Field Exploration(2)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding lighthalzen field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120077
+ Name: "Lighthalzen Field Exploration(3)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding lighthalzen field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120078
+ Name: "Rachel Audhumbla Plains Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding rachel audhumbla plains field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120079
+ Name: "Rachel Plains Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding rachel plains field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120080
+ Name: "Rachel Plains Field Exploration(2)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding rachel plains field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120081
+ Name: "Rachel Plains Field Exploration(3)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding rachel plains field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120082
+ Name: "Rachel Audhumbla Grassland Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding rachel audhumbla grassland field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120083
+ Name: "Rachel Audhumbla Grassland Field Exploration(2)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding rachel audhumbla grassland field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120084
+ Name: "Portus Luna Field Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding portus luna field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120085
+ Name: "Veins Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding veins field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120086
+ Name: "Veins Field Exploration(2)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding veins field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120087
+ Name: "Veins Field Exploration(3)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding veins field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120088
+ Name: "Veins Field Exploration(4)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding veins field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120089
+ Name: "Veins Field Exploration(5)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding veins field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120090
+ Name: "Eclage Field Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding eclage field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120091
+ Name: "North Bitfrost Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding north bitfrost field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120092
+ Name: "South Bitfrost Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding south bitfrost field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120093
+ Name: "Splendide Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding splendide field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120094
+ Name: "Splendide Field Exploration(2)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding splendide field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120095
+ Name: "Splendide Field Exploration(3)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding splendide field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120096
+ Name: "Manuk Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding manuk field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120097
+ Name: "Manuk Field Exploration(2)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding manuk field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120098
+ Name: "Manuk Field Exploration(3)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding manuk field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120099
+ Name: "Outskirts of Kamidal Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding outskirts of kamidal field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120100
+ Name: "Outskirts of Kamidal Field Exploration(2)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding outskirts of kamidal field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120101
+ Name: "Amatsu Field Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding amatsu field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120102
+ Name: "Kunlun Field Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding kunlun field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120103
+ Name: "Gonryun Field Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding gonryun field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120104
+ Name: "Ayothaya Field Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding ayothaya field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120105
+ Name: "Moscovia Field Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding moscovia field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120106
+ Name: "Brasilis Field Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding brasilis field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120107
+ Name: "Dewata Field Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding dewata field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120108
+ Name: "Malaya Field Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding malaya field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120109
+ Name: "Malaya Field Exploration(2)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding malaya field"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 120110
+ Name: "Abbey Underground Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding abbey underground dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120111
+ Name: "Abyss Lake Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding abyss lake dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120112
+ Name: "Clock Tower Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding clock tower dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120113
+ Name: "Amatsu Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding amatsu dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120114
+ Name: "Ant Hell Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding ant hell dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120115
+ Name: "Ayothaya Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding ayothaya dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120116
+ Name: "Comodo Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding comodo dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120117
+ Name: "Brasilis Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding brasilis dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120118
+ Name: "Clock Tower Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding clock tower dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120119
+ Name: "Istana Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding istana dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120120
+ Name: "Scaraba Hole Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding scaraba hole dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120121
+ Name: "Bitfrost Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding bitfrost dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120122
+ Name: "Einbroch Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding einbroch dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120123
+ Name: "Geffen Underground Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding geffen underground dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120124
+ Name: "Glastheim Dungeon Exploration(1)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding glastheim dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120125
+ Name: "Glastheim Dungeon Exploration(2)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding glastheim dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120126
+ Name: "Glastheim Dungeon Exploration(3)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding glastheim dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120127
+ Name: "Glastheim Dungeon Exploration(4)"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding glastheim dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120128
+ Name: "Kunlun Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding Kunlun dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120129
+ Name: "Rachel Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding rachel dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120130
+ Name: "Sphinx Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding sphinx dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120131
+ Name: "Izlude Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding izlude dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120132
+ Name: "Robot Factory Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding robot factory dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120133
+ Name: "Bio Lab Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding bio lab dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120134
+ Name: "Gonryun Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding gonryun dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120135
+ Name: "Nogg Road Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding nogg road dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120136
+ Name: "Coal Mine Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding Coal mine dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120137
+ Name: "Pyramid Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding pyramid dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120138
+ Name: "Orc Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding orc dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120139
+ Name: "Payon Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding payon dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120140
+ Name: "Labyrinth Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding labyrinth dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120141
+ Name: "Undersea Tunnel Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding undersea tunnel dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120142
+ Name: "Thanatos Tower Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding thanatos tower dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120143
+ Name: "Thor Volcano Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding thor volcano dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120144
+ Name: "Sunken Ship Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding sunken ship dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120145
+ Name: "Turtle Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding turtle dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 120146
+ Name: "Toy Factory Dungeon Exploration"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Discover the treasure surrounding toy factory dungeon"
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Money_Pocket: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 127001
+ Name: "Prontera Contribution"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Stranger"
+ Goal: 3000
+ }
+ *2: {
+ Description: "Village Freshman"
+ Goal: 6000
+ }
+ *3: {
+ Description: "Neighbor"
+ Goal: 12000
+ }
+ *4: {
+ Description: "Celebrity"
+ Goal: 20000
+ }
+ *5: {
+ Description: "City Dictator"
+ Goal: 1000
+ }
+ }
+ Points: 10
+},
+{
+ Id: 127002
+ Name: "Geffen Contribution"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Stranger"
+ Goal: 3000
+ }
+ *2: {
+ Description: "Village Freshman"
+ Goal: 6000
+ }
+ *3: {
+ Description: "Neighbor"
+ Goal: 12000
+ }
+ *4: {
+ Description: "Celebrity"
+ Goal: 20000
+ }
+ *5: {
+ Description: "City Dictator"
+ Goal: 1000
+ }
+ }
+ Points: 10
+},
+{
+ Id: 127003
+ Name: "Morocc Contribution"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Stranger"
+ Goal: 3000
+ }
+ *2: {
+ Description: "Village Freshman"
+ Goal: 6000
+ }
+ *3: {
+ Description: "Neighbor"
+ Goal: 12000
+ }
+ *4: {
+ Description: "Celebrity"
+ Goal: 20000
+ }
+ *5: {
+ Description: "City Dictator"
+ Goal: 1000
+ }
+ }
+ Points: 10
+},
+{
+ Id: 127004
+ Name: "Payon Contribution"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Stranger"
+ Goal: 3000
+ }
+ *2: {
+ Description: "Village Freshman"
+ Goal: 6000
+ }
+ *3: {
+ Description: "Neighbor"
+ Goal: 12000
+ }
+ *4: {
+ Description: "Celebrity"
+ Goal: 20000
+ }
+ *5: {
+ Description: "City Dictator"
+ Goal: 1000
+ }
+ }
+ Points: 10
+},
+{
+ Id: 127005
+ Name: "Yuno Contribution"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Stranger"
+ Goal: 3000
+ }
+ *2: {
+ Description: "Village Freshman"
+ Goal: 6000
+ }
+ *3: {
+ Description: "Neighbor"
+ Goal: 12000
+ }
+ *4: {
+ Description: "Celebrity"
+ Goal: 20000
+ }
+ *5: {
+ Description: "City Dictator"
+ Goal: 1000
+ }
+ }
+ Points: 10
+},
+{
+ Id: 127006
+ Name: "Lighthalzen Contribution"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Stranger"
+ Goal: 3000
+ }
+ *2: {
+ Description: "Village Freshman"
+ Goal: 6000
+ }
+ *3: {
+ Description: "Neighbor"
+ Goal: 12000
+ }
+ *4: {
+ Description: "Celebrity"
+ Goal: 20000
+ }
+ *5: {
+ Description: "City Dictator"
+ Goal: 1000
+ }
+ }
+ Points: 10
+},
+{
+ Id: 127007
+ Name: "Einbroch Contribution"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Stranger"
+ Goal: 3000
+ }
+ *2: {
+ Description: "Village Freshman"
+ Goal: 6000
+ }
+ *3: {
+ Description: "Neighbor"
+ Goal: 12000
+ }
+ *4: {
+ Description: "Celebrity"
+ Goal: 20000
+ }
+ *5: {
+ Description: "City Dictator"
+ Goal: 1000
+ }
+ }
+ Points: 10
+},
+{
+ Id: 127008
+ Name: "Rachel Contribution"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Stranger"
+ Goal: 3000
+ }
+ *2: {
+ Description: "Village Freshman"
+ Goal: 6000
+ }
+ *3: {
+ Description: "Neighbor"
+ Goal: 12000
+ }
+ *4: {
+ Description: "Celebrity"
+ Goal: 20000
+ }
+ *5: {
+ Description: "City Dictator"
+ Goal: 1000
+ }
+ }
+ Points: 10
+},
+{
+ Id: 127009
+ Name: "Veins Contribution"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Stranger"
+ Goal: 3000
+ }
+ *2: {
+ Description: "Village Freshman"
+ Goal: 6000
+ }
+ *3: {
+ Description: "Neighbor"
+ Goal: 12000
+ }
+ *4: {
+ Description: "Celebrity"
+ Goal: 20000
+ }
+ *5: {
+ Description: "City Dictator"
+ Goal: 1000
+ }
+ }
+ Points: 10
+},
+{
+ Id: 128000
+ Name: "Uninvited Guest"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 1 Celine Kimmy"
+ Criteria: {
+ MobId: "XM_CELINE_KIMI"
+ }
+ Goal: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 128001
+ Name: "Strange Guest"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 10 Celine Kimmy"
+ Criteria: {
+ MobId: "XM_CELINE_KIMI"
+ }
+ Goal: 10
+ }
+ }
+ Points: 10
+},
+{
+ Id: 128002
+ Name: "Get along with map..."
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 25 Celine Kimmy"
+ Criteria: {
+ MobId: "XM_CELINE_KIMI"
+ }
+ Goal: 25
+ }
+ }
+ Points: 20
+},
+{
+ Id: 128003
+ Name: "Welcomed Guest"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 50 Celine Kimmy"
+ Criteria: {
+ MobId: "XM_CELINE_KIMI"
+ }
+ Goal: 50
+ }
+ }
+ Points: 30
+},
+{
+ Id: 128004
+ Name: "Kimmy's best friend"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 100 Celine Kimmy"
+ Criteria: {
+ MobId: "XM_CELINE_KIMI"
+ }
+ Goal: 100
+ }
+ }
+ Points: 50
+},
+{
+ Id: 128005
+ Name: "Novice Angler"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 1 Bakonawa"
+ Criteria: {
+ MobId: "BAKONAWA_1"
+ }
+ Goal: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 128006
+ Name: "Juicy Hunter"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 10 Bakonawa"
+ Criteria: {
+ MobId: "BAKONAWA_1"
+ }
+ Goal: 10
+ }
+ }
+ Points: 20
+},
+{
+ Id: 128007
+ Name: "Rhythm Master"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 50 Bakonawa"
+ Criteria: {
+ MobId: "BAKONAWA_1"
+ }
+ Goal: 50
+ }
+ }
+ Points: 50
+},
+{
+ Id: 128008
+ Name: "Bold Adventurer"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 1 Baphomet"
+ Criteria: {
+ MobId: "BAPHOMET"
+ }
+ Goal: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 128009
+ Name: "Baphomet Hatred"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 10 Baphomet"
+ Criteria: {
+ MobId: "BAPHOMET"
+ }
+ Goal: 10
+ }
+ }
+ Points: 20
+},
+{
+ Id: 128010
+ Name: "Goat's Nemesis"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 50 Baphomet"
+ Criteria: {
+ MobId: "BAPHOMET"
+ }
+ Goal: 50
+ }
+ }
+ Points: 50
+},
+{
+ Id: 128011
+ Name: "Ordinary Tourist"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 1 Grim Reaper Ankou"
+ Criteria: {
+ MobId: "GRIM_REAPER_ANKOU"
+ }
+ Goal: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 128012
+ Name: "Backcountry Expert"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 10 Grim Reaper Ankou"
+ Criteria: {
+ MobId: "GRIM_REAPER_ANKOU"
+ }
+ Goal: 10
+ }
+ }
+ Points: 20
+},
+{
+ Id: 128013
+ Name: "Able to eat more like this"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 50 Grim Reaper Ankou"
+ Criteria: {
+ MobId: "GRIM_REAPER_ANKOU"
+ }
+ Goal: 50
+ }
+ }
+ Points: 50
+},
+{
+ Id: 128014
+ Name: "Digest hard meat"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 1 Buwaya"
+ Criteria: {
+ MobId: "BUWAYA"
+ }
+ Goal: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 128015
+ Name: "Master of Escape"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 10 Buwaya"
+ Criteria: {
+ MobId: "BUWAYA"
+ }
+ Goal: 10
+ }
+ }
+ Points: 20
+},
+{
+ Id: 128016
+ Name: "Immortal Hunter"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 50 Buwaya"
+ Criteria: {
+ MobId: "BUWAYA"
+ }
+ Goal: 50
+ }
+ }
+ Points: 50
+},
+/*{
+ Id: 128017
+ Name: "Stood up and overcame despair"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 1 God of Despair Morocc"
+ Criteria: {
+ MobId: "MM_MOROCC_ADT"
+ }
+ Goal: 1
+ }
+ }
+ Points: 10
+},*/
+/*{
+ Id: 128018
+ Name: "Ember of Hope"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 10 God of Despair Morocc"
+ Criteria: {
+ MobId: "MM_MOROCC_ADT"
+ }
+ Goal: 10
+ }
+ }
+ Points: 10
+},*/
+/*{
+ Id: 128019
+ Name: "Pouring Aurora"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 25 God of Despair Morocc"
+ Criteria: {
+ MobId: "MM_MOROCC_ADT"
+ }
+ Goal: 25
+ }
+ }
+ Points: 20
+},*/
+/*{
+ Id: 128020
+ Name: "Who is desperate? I am hopeless!"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 50 God of Despair Morocc"
+ Criteria: {
+ MobId: "MM_MOROCC_ADT"
+ }
+ Goal: 50
+ }
+ }
+ Points: 30
+},*/
+/*{
+ Id: 128021
+ Name: "I know god will save the world"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 100 God of Despair Morocc"
+ Criteria: {
+ MobId: "MM_MOROCC_ADT"
+ }
+ Goal: 100
+ }
+ }
+ Points: 50
+},*/
+/*{
+ Id: 128022
+ Name: "There was mercy in Morocc army"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 1 Morocc necromancer"
+ Criteria: {
+ MobId: "EP14_MORS_BOSSB"
+ }
+ Goal: 1
+ }
+ }
+ Points: 10
+},*/
+/*{
+ Id: 128023
+ Name: "There was fear in Morocc army"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate Morocc 10 necromancer"
+ Criteria: {
+ MobId: "EP14_MORS_BOSSB"
+ }
+ Goal: 10
+ }
+ }
+ Points: 20
+},*/
+/*{
+ Id: 128024
+ Name: "Guard of weak army"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate Morocc 50 necromancer"
+ Criteria: {
+ MobId: "EP14_MORS_BOSSB"
+ }
+ Goal: 50
+ }
+ }
+ Points: 50
+},*/
+{
+ Id: 128025
+ Name: "Audience with the queen"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 1 Faceworm Queen"
+ Criteria: {
+ MobId: "FACEWORM_QUEEN"
+ }
+ Goal: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 128026
+ Name: "Warm earth"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 1 Earth Faceworm Queen"
+ Criteria: {
+ MobId: "FACEWORM_QUEEN_G"
+ }
+ Goal: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 128027
+ Name: "Water is very good exactly"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 1 Water Faceworm Queen"
+ Criteria: {
+ MobId: "FACEWORM_QUEEN_B"
+ }
+ Goal: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 128028
+ Name: "Pleasant breeze"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 1 Wind Faceworm Queen"
+ Criteria: {
+ MobId: "FACEWORM_QUEEN_Y"
+ }
+ Goal: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 128029
+ Name: "Visitor of old castle"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 1 Amdarais"
+ Criteria: {
+ MobId: "MG_AMDARAIS"
+ }
+ Goal: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 128030
+ Name: "Lord of old castle"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 10 Amdarais"
+ Criteria: {
+ MobId: "MG_AMDARAIS"
+ }
+ Goal: 10
+ }
+ }
+ Points: 20
+},
+{
+ Id: 128031
+ Name: "Conqueror of old castle"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 50 Amdarais"
+ Criteria: {
+ MobId: "MG_AMDARAIS"
+ }
+ Goal: 50
+ }
+ }
+ Points: 50
+},
+/*{
+ Id: 128032
+ Name: "Haggard sucker"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 1 Amdarais (Superior)"
+ Criteria: {
+ MobId: "MG_AMDARAIS_H"
+ }
+ Goal: 1
+ }
+ }
+ Points: 10
+},*/
+/*{
+ Id: 128033
+ Name: "Hope of the Knight"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 10 Amdarais (Superior)"
+ Criteria: {
+ MobId: "MG_AMDARAIS_H"
+ }
+ Goal: 10
+ }
+ }
+ Points: 20
+},*/
+/*{
+ Id: 128034
+ Name: "Guardian of the Dawn"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 50 Amdarais (Superior)"
+ Criteria: {
+ MobId: "MG_AMDARAIS_H"
+ }
+ Goal: 50
+ }
+ }
+ Points: 50
+},*/
+{
+ Id: 128035
+ Name: "Time Traveler"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 1 Sarah Irene"
+ Criteria: {
+ MobId: "MM_SARAH"
+ }
+ Goal: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 128036
+ Name: "Restore ancient relic"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 10 Sarah Irene"
+ Criteria: {
+ MobId: "MM_SARAH"
+ }
+ Goal: 10
+ }
+ }
+ Points: 20
+},
+{
+ Id: 128037
+ Name: "Master of relic transport"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 50 Sarah Irene"
+ Criteria: {
+ MobId: "MM_SARAH"
+ }
+ Goal: 50
+ }
+ }
+ Points: 50
+},
+{
+ Id: 128038
+ Name: "Show Jailbreak to the captain"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 1 Ferlock"
+ Criteria: {
+ MobId: "E1_FELOCK"
+ }
+ Goal: 1
+ }
+ }
+ Points: 10
+},
+/*{
+ Id: 128039
+ Name: "Show Jailbreak to the weak captain"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 1 Ferlock"
+ Criteria: {
+ MobId: "E2_FELOCK"
+ }
+ Goal: 1
+ }
+ }
+ Points: 10
+},*/
+{
+ Id: 128040
+ Name: "Riot on board"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 10 Ferlock"
+ Criteria: {
+ MobId: "E1_FELOCK"
+ }
+ Goal: 10
+ }
+ }
+ Points: 20
+},
+{
+ Id: 128041
+ Name: "Turmoil on board"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 10 Ferlock"
+ Criteria: {
+ MobId: "E1_FELOCK"
+ }
+ Goal: 10
+ }
+ }
+ Points: 20
+},
+{
+ Id: 128042
+ Name: "Rebellion on board"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 50 Ferlock"
+ Criteria: {
+ MobId: "E1_FELOCK"
+ }
+ Goal: 50
+ }
+ }
+ Points: 50
+},
+/*{
+ Id: 128043
+ Name: "Revolt of Riot"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 50 Ferlock"
+ Criteria: {
+ MobId: "E2_FELOCK"
+ }
+ Goal: 50
+ }
+ }
+ Points: 50
+},*/
+{
+ Id: 128044
+ Name: "Magic tournament champion"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 1 Fenrir"
+ Criteria: {
+ MobId: "GEFFEN_FENRIR"
+ }
+ Goal: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 128045
+ Name: "Gladiator of Coliseum"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 10 Fenrir"
+ Criteria: {
+ MobId: "GEFFEN_FENRIR"
+ }
+ Goal: 10
+ }
+ }
+ Points: 20
+},
+{
+ Id: 128046
+ Name: "Slayer of Colosseum"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 50 Fenrir"
+ Criteria: {
+ MobId: "GEFFEN_FENRIR"
+ }
+ Goal: 50
+ }
+ }
+ Points: 50
+},
+{
+ Id: 128047
+ Name: "Endless Tower challenger"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 1 Naght Sieger"
+ Criteria: {
+ MobId: "NAGHT_SIEGER"
+ }
+ Goal: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 128048
+ Name: "Endless Tower Slayer"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 10 Naght Sieger"
+ Criteria: {
+ MobId: "NAGHT_SIEGER"
+ }
+ Goal: 10
+ }
+ }
+ Points: 20
+},
+{
+ Id: 128049
+ Name: "Lord of the tower"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 50 Naght Sieger"
+ Criteria: {
+ MobId: "NAGHT_SIEGER"
+ }
+ Goal: 50
+ }
+ }
+ Points: 50
+},
+{
+ Id: 128050
+ Name: "Novice Exorcist"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 1 Bangungot Doll"
+ Criteria: {
+ MobId: "BANGUNGOT_3"
+ }
+ Goal: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 128051
+ Name: "Experienced Exorcist"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 10 Bangungot Doll"
+ Criteria: {
+ MobId: "BANGUNGOT_3"
+ }
+ Goal: 10
+ }
+ }
+ Points: 20
+},
+{
+ Id: 128052
+ Name: "Legendary Exorcist"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Eliminate 50 Bangungot Doll"
+ Criteria: {
+ MobId: "BANGUNGOT_3"
+ }
+ Goal: 50
+ }
+ }
+ Points: 50
+},
+{
+ Id: 129001
+ Name: "Prontera Explorer"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "North Prontera Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120001
+ }
+ }
+ *2: {
+ Description: "North Prontera Field Exploration(2) completed"
+ Criteria: {
+ Achieve: 120002
+ }
+ }
+ *3: {
+ Description: "North Prontera Field Exploration(3) completed"
+ Criteria: {
+ Achieve: 120003
+ }
+ }
+ *4: {
+ Description: "West Prontera Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120004
+ }
+ }
+ *5: {
+ Description: "West Prontera Field Exploration(2) completed"
+ Criteria: {
+ Achieve: 120005
+ }
+ }
+ *6: {
+ Description: "East Prontera Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120006
+ }
+ }
+ *7: {
+ Description: "South Prontera Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120007
+ }
+ }
+ *8: {
+ Description: "South Prontera Field Exploration(2) completed"
+ Criteria: {
+ Achieve: 120008
+ }
+ }
+ *9: {
+ Description: "South Prontera Field Exploration(3) completed"
+ Criteria: {
+ Achieve: 120009
+ }
+ }
+ *10: {
+ Description: "South Prontera Field Exploration(4) completed"
+ Criteria: {
+ Achieve: 120010
+ }
+ }
+ }
+ Rewards: {
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 129002
+ Name: "Geffen Explorer"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "East Geffen Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120011
+ }
+ }
+ *2: {
+ Description: "Southeast Geffen Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120012
+ }
+ }
+ *3: {
+ Description: "Northwest Geffen Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120013
+ }
+ }
+ *4: {
+ Description: "Northwest Geffen Field Exploration(2) completed"
+ Criteria: {
+ Achieve: 120014
+ }
+ }
+ *5: {
+ Description: "Northwest Geffen Field Exploration(3) completed"
+ Criteria: {
+ Achieve: 120015
+ }
+ }
+ *6: {
+ Description: "South Geffen Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120016
+ }
+ }
+ *7: {
+ Description: "South Geffen Field Exploration(2) completed"
+ Criteria: {
+ Achieve: 120017
+ }
+ }
+ }
+ Rewards: {
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 129003
+ Name: "Sograt Desert Explorer"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Sograt Desert Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120018
+ }
+ }
+ *2: {
+ Description: "Sograt Desert Field Exploration(2) completed"
+ Criteria: {
+ Achieve: 120019
+ }
+ }
+ *3: {
+ Description: "Sograt Desert Field Exploration(3) completed"
+ Criteria: {
+ Achieve: 120020
+ }
+ }
+ *4: {
+ Description: "Sograt Desert Field Exploration(4) completed"
+ Criteria: {
+ Achieve: 120021
+ }
+ }
+ *5: {
+ Description: "Sograt Desert Field Exploration(5) completed"
+ Criteria: {
+ Achieve: 120022
+ }
+ }
+ *6: {
+ Description: "Sograt Desert Field Exploration(6) completed"
+ Criteria: {
+ Achieve: 120023
+ }
+ }
+ }
+ Rewards: {
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 129004
+ Name: "Payon Explorer"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Southwest Payon Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120024
+ }
+ }
+ *2: {
+ Description: "Southwest Payon Field Exploration(2) completed"
+ Criteria: {
+ Achieve: 120025
+ }
+ }
+ *3: {
+ Description: "Southwest Payon Field Exploration(3) completed"
+ Criteria: {
+ Achieve: 120026
+ }
+ }
+ *4: {
+ Description: "Southwest Payon Field Exploration(4) completed"
+ Criteria: {
+ Achieve: 120027
+ }
+ }
+ *5: {
+ Description: "East Payon Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120028
+ }
+ }
+ *6: {
+ Description: "East Payon Field Exploration(2) completed"
+ Criteria: {
+ Achieve: 120029
+ }
+ }
+ *7: {
+ Description: "East Payon Field Exploration(3) completed"
+ Criteria: {
+ Achieve: 120030
+ }
+ }
+ *8: {
+ Description: "East Payon Field Exploration(4) completed"
+ Criteria: {
+ Achieve: 120031
+ }
+ }
+ }
+ Rewards: {
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 129005
+ Name: "North Mjolnir Explorer"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "North Mjolnir Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120032
+ }
+ }
+ *2: {
+ Description: "North Mjolnir Field Exploration(2) completed"
+ Criteria: {
+ Achieve: 120033
+ }
+ }
+ *3: {
+ Description: "North Mjolnir Field Exploration(3) completed"
+ Criteria: {
+ Achieve: 120034
+ }
+ }
+ *4: {
+ Description: "North Mjolnir Field Exploration(4) completed"
+ Criteria: {
+ Achieve: 120035
+ }
+ }
+ *5: {
+ Description: "North Mjolnir Field Exploration(5) completed"
+ Criteria: {
+ Achieve: 120036
+ }
+ }
+ }
+ Rewards: {
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 129006
+ Name: "South Mjolnir Explorer"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "South Mjolnir Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120037
+ }
+ }
+ *2: {
+ Description: "South Mjolnir Field Exploration(2) completed"
+ Criteria: {
+ Achieve: 120038
+ }
+ }
+ *3: {
+ Description: "South Mjolnir Field Exploration(3) completed"
+ Criteria: {
+ Achieve: 120039
+ }
+ }
+ *4: {
+ Description: "South Mjolnir Field Exploration(4) completed"
+ Criteria: {
+ Achieve: 120040
+ }
+ }
+ *5: {
+ Description: "South Mjolnir Field Exploration(5) completed"
+ Criteria: {
+ Achieve: 120041
+ }
+ }
+ *6: {
+ Description: "South Mjolnir Field Exploration(6) completed"
+ Criteria: {
+ Achieve: 120042
+ }
+ }
+ *7: {
+ Description: "South Aldebaran Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120043
+ }
+ }
+ }
+ Rewards: {
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 129007
+ Name: "Comodo Explorer"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Comodo Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120044
+ }
+ }
+ *2: {
+ Description: "Comodo Field Exploration(2) completed"
+ Criteria: {
+ Achieve: 120045
+ }
+ }
+ *3: {
+ Description: "Comodo Field Exploration(3) completed"
+ Criteria: {
+ Achieve: 120046
+ }
+ }
+ *4: {
+ Description: "Comodo Field Exploration(4) completed"
+ Criteria: {
+ Achieve: 120047
+ }
+ }
+ *5: {
+ Description: "Comodo Field Exploration(5) completed"
+ Criteria: {
+ Achieve: 120048
+ }
+ }
+ *6: {
+ Description: "Comodo Field Exploration(6) completed"
+ Criteria: {
+ Achieve: 120049
+ }
+ }
+ *7: {
+ Description: "Comodo Field Exploration(7) completed"
+ Criteria: {
+ Achieve: 120050
+ }
+ }
+ *8: {
+ Description: "Comodo Field Exploration(8) completed"
+ Criteria: {
+ Achieve: 120051
+ }
+ }
+ }
+ Rewards: {
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 129008
+ Name: "Rune Midgard Explorer"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Prontera Explorer"
+ Criteria: {
+ Achieve: 129001
+ }
+ }
+ *2: {
+ Description: "Geffen Explorer"
+ Criteria: {
+ Achieve: 129002
+ }
+ }
+ *3: {
+ Description: "Sograt Desert Explorer"
+ Criteria: {
+ Achieve: 129003
+ }
+ }
+ *4: {
+ Description: "Payon Explorer"
+ Criteria: {
+ Achieve: 129004
+ }
+ }
+ *5: {
+ Description: "North Mjolnir Explorer"
+ Criteria: {
+ Achieve: 129005
+ }
+ }
+ *6: {
+ Description: "South Mjolnir Explorer"
+ Criteria: {
+ Achieve: 129006
+ }
+ }
+ *7: {
+ Description: "Comodo Explorer"
+ Criteria: {
+ Achieve: 129007
+ }
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Violet_Box: 1
+ }
+ }
+ Points: 50
+},
+{
+ Id: 129009
+ Name: "Yuno Explorer"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Border Checkpoint Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120052
+ }
+ }
+ *2: {
+ Description: "Border Checkpoint Field Exploration(2) completed"
+ Criteria: {
+ Achieve: 120053
+ }
+ }
+ *3: {
+ Description: "Kiel Hyre Mansion Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120054
+ }
+ }
+ *4: {
+ Description: "El Mes Plateau Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120055
+ }
+ }
+ *5: {
+ Description: "El Mes Plateau Field Exploration(2) completed"
+ Criteria: {
+ Achieve: 120056
+ }
+ }
+ *6: {
+ Description: "El Mes Plateau Field Exploration(3) completed"
+ Criteria: {
+ Achieve: 120057
+ }
+ }
+ *7: {
+ Description: "El Mes Gorge Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120058
+ }
+ }
+ *8: {
+ Description: "Kiel Hyre Academy Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120059
+ }
+ }
+ *9: {
+ Description: "Guard Camp Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120060
+ }
+ }
+ *10: {
+ Description: "Yuno Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120061
+ }
+ }
+ }
+ Rewards: {
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 129010
+ Name: "Hugel Explorer"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Front of Thanatos Tower Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120062
+ }
+ }
+ *2: {
+ Description: "Hugel Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120063
+ }
+ }
+ *3: {
+ Description: "Hugel Field Exploration(2) completed"
+ Criteria: {
+ Achieve: 120064
+ }
+ }
+ *4: {
+ Description: "Hugel Field Exploration(3) completed"
+ Criteria: {
+ Achieve: 120065
+ }
+ }
+ *5: {
+ Description: "Abyss Lake Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120066
+ }
+ }
+ }
+ Rewards: {
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 129011
+ Name: "Einbroch Explorer"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Einbroch Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120067
+ }
+ }
+ *2: {
+ Description: "Einbroch Field Exploration(2) completed"
+ Criteria: {
+ Achieve: 120068
+ }
+ }
+ *3: {
+ Description: "Einbroch Field Exploration(3) completed"
+ Criteria: {
+ Achieve: 120069
+ }
+ }
+ *4: {
+ Description: "Einbroch Field Exploration(4) completed"
+ Criteria: {
+ Achieve: 120070
+ }
+ }
+ *5: {
+ Description: "Einbroch Field Exploration(5) completed"
+ Criteria: {
+ Achieve: 120071
+ }
+ }
+ *6: {
+ Description: "Einbroch Field Exploration(6) completed"
+ Criteria: {
+ Achieve: 120072
+ }
+ }
+ *7: {
+ Description: "Einbroch Field Exploration(7) completed"
+ Criteria: {
+ Achieve: 120073
+ }
+ }
+ *8: {
+ Description: "Einbroch Field Exploration(8) completed"
+ Criteria: {
+ Achieve: 120074
+ }
+ }
+ }
+ Rewards: {
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 129012
+ Name: "Lighthalzen Explorer"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Lighthalzen Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120075
+ }
+ }
+ *2: {
+ Description: "Lighthalzen Field Exploration(2) completed"
+ Criteria: {
+ Achieve: 120076
+ }
+ }
+ *3: {
+ Description: "Lighthalzen Field Exploration(3) completed"
+ Criteria: {
+ Achieve: 120077
+ }
+ }
+ }
+ Rewards: {
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 129013
+ Name: "Schwarzwald Explorer"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Yuno Explorer"
+ Criteria: {
+ Achieve: 129009
+ }
+ }
+ *2: {
+ Description: "Hugel Explorer"
+ Criteria: {
+ Achieve: 129010
+ }
+ }
+ *3: {
+ Description: "Einbroch Explorer"
+ Criteria: {
+ Achieve: 129011
+ }
+ }
+ *4: {
+ Description: "Lighthalzen Explorer"
+ Criteria: {
+ Achieve: 129012
+ }
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Violet_Box: 1
+ }
+ }
+ Points: 50
+},
+{
+ Id: 129014
+ Name: "Rachel Explorer"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Rachel Audhumbla Plains Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120078
+ }
+ }
+ *2: {
+ Description: "Rachel Plains Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120079
+ }
+ }
+ *3: {
+ Description: "Rachel Plains Field Exploration(2) completed"
+ Criteria: {
+ Achieve: 120080
+ }
+ }
+ *4: {
+ Description: "Rachel Plains Field Exploration(3) completed"
+ Criteria: {
+ Achieve: 120081
+ }
+ }
+ *5: {
+ Description: "Rachel Audhumbla Grassland Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120082
+ }
+ }
+ *6: {
+ Description: "Rachel Audhumbla Grassland Field Exploration(2) completed"
+ Criteria: {
+ Achieve: 120083
+ }
+ }
+ *7: {
+ Description: "Portus Luna Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120084
+ }
+ }
+ }
+ Rewards: {
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 129015
+ Name: "Veins Explorer"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Veins Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120085
+ }
+ }
+ *2: {
+ Description: "Veins Field Exploration(2) completed"
+ Criteria: {
+ Achieve: 120086
+ }
+ }
+ *3: {
+ Description: "Veins Field Exploration(3) completed"
+ Criteria: {
+ Achieve: 120087
+ }
+ }
+ *4: {
+ Description: "Veins Field Exploration(4) completed"
+ Criteria: {
+ Achieve: 120088
+ }
+ }
+ *5: {
+ Description: "Veins Field Exploration(5) completed"
+ Criteria: {
+ Achieve: 120089
+ }
+ }
+ }
+ Rewards: {
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 129016
+ Name: "Arunafeltz Explorer"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Rachel Explorer"
+ Criteria: {
+ Achieve: 129014
+ }
+ }
+ *2: {
+ Description: "Veins Explorer"
+ Criteria: {
+ Achieve: 129015
+ }
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Violet_Box: 1
+ }
+ }
+ Points: 50
+},
+{
+ Id: 129017
+ Name: "Laphine Explorer"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Eclage Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120090
+ }
+ }
+ *2: {
+ Description: "North Bitfrost Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120091
+ }
+ }
+ *3: {
+ Description: "South Bitfrost Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120092
+ }
+ }
+ *4: {
+ Description: "Splendide Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120093
+ }
+ }
+ *5: {
+ Description: "Splendide Field Exploration(2) completed"
+ Criteria: {
+ Achieve: 120094
+ }
+ }
+ *6: {
+ Description: "Splendide Field Exploration(3) completed"
+ Criteria: {
+ Achieve: 120095
+ }
+ }
+ }
+ Rewards: {
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 129018
+ Name: "Manuk Explorer"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Manuk Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120096
+ }
+ }
+ *2: {
+ Description: "Manuk Field Exploration(2) completed"
+ Criteria: {
+ Achieve: 120097
+ }
+ }
+ *3: {
+ Description: "Manuk Field Exploration(3) completed"
+ Criteria: {
+ Achieve: 120098
+ }
+ }
+ *4: {
+ Description: "Outskirts of Kamidal Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120099
+ }
+ }
+ *5: {
+ Description: "Outskirts of Kamidal Field Exploration(2) completed"
+ Criteria: {
+ Achieve: 120100
+ }
+ }
+ }
+ Rewards: {
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 129019
+ Name: "Eclage Explorer"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Laphine Explorer"
+ Criteria: {
+ Achieve: 129017
+ }
+ }
+ *2: {
+ Description: "Manuk Explorer"
+ Criteria: {
+ Achieve: 129018
+ }
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Violet_Box: 1
+ }
+ }
+ Points: 50
+},
+{
+ Id: 129020
+ Name: "Localizing fields explorer"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Amatsu Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120101
+ }
+ }
+ *2: {
+ Description: "Kunlun Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120102
+ }
+ }
+ *3: {
+ Description: "Gonryun Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120103
+ }
+ }
+ *4: {
+ Description: "Ayothaya Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120104
+ }
+ }
+ *5: {
+ Description: "Moscovia Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120105
+ }
+ }
+ *6: {
+ Description: "Brasilis Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120106
+ }
+ }
+ *7: {
+ Description: "Dewata Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120107
+ }
+ }
+ *8: {
+ Description: "Malaya Field Exploration(1) completed"
+ Criteria: {
+ Achieve: 120108
+ }
+ }
+ *9: {
+ Description: "Malaya Field Exploration(2) completed"
+ Criteria: {
+ Achieve: 120109
+ }
+ }
+ }
+ Rewards: {
+ Items: {
+ Old_Violet_Box: 1
+ }
+ }
+ Points: 50
+},
+{
+ Id: 130000
+ Name: "Socialite debut"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Visit Heine Royal Family and start conversation"
+ }
+ *2: {
+ Description: "Visit Nerius Royal Family and start conversation"
+ }
+ *3: {
+ Description: "Visit Walter Royal Family and start conversation"
+ }
+ *4: {
+ Description: "Visit Wigner Royal Family and start conversation"
+ }
+ *5: {
+ Description: "Visit Richard Royal Family and start conversation"
+ }
+ *6: {
+ Description: "Visit Gaebolg Royal Family and start conversation"
+ }
+ *7: {
+ Description: "Visit Lugenburg Royal Family and start conversation"
+ }
+ }
+ Rewards: {
+ TitleId: 1034
+ }
+ Points: 10
+},
+{
+ Id: 170000
+ Name: "Song chamber is not an accident"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Listen the secret song of five recomended court musician"
+ }
+ }
+ Points: 10
+},
+{
+ Id: 190000
+ Name: "Alliance workers of merchant city"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Novice Amethyst class"
+ Goal: 1
+ }
+ *2: {
+ Description: "Expert Sardonyx class"
+ Goal: 10
+ }
+ *3: {
+ Description: "Competence Person Aquamarine class"
+ Goal: 30
+ }
+ *4: {
+ Description: "Sparkling Diamond class"
+ Goal: 100
+ }
+ }
+ Points: 50
+},
+{
+ Id: 200000
+ Name: "Acquire the first aura!"
+ Type: "ACH_STATUS"
+ Objectives: {
+ *1: {
+ Description: "Base level 99"
+ Criteria: {
+ StatusType: "SP_BASELEVEL"
+ }
+ Goal: 99
+ }
+ }
+ Rewards: {
+ TitleId: 1000
+ Bonus: <" specialeffect(EF_BLESSING, AREA, playerattached()); sc_start SC_BLESSING, 30000, 1; ">
+ Items: {
+ White_Slim_Pot_Box2: 1
+ }
+ }
+ Points: 50
+},
+{
+ Id: 200001
+ Name: "Acquire the second aura!"
+ Type: "ACH_STATUS"
+ Objectives: {
+ *1: {
+ Description: "Base level 150"
+ Criteria: {
+ StatusType: "SP_BASELEVEL"
+ }
+ Goal: 150
+ }
+ }
+ Rewards: {
+ TitleId: 1001
+ Bonus: <" specialeffect(EF_BLESSING, AREA, playerattached()); sc_start SC_BLESSING, 30000, 1; ">
+ Items: {
+ Dark_Snake_Lord_Hat: 1
+ }
+ }
+ Points: 60
+},
+{
+ Id: 200002
+ Name: "Acquire the third aura!"
+ Type: "ACH_STATUS"
+ Objectives: {
+ *1: {
+ Description: "Base level 175"
+ Criteria: {
+ StatusType: "SP_BASELEVEL"
+ }
+ Goal: 175
+ }
+ }
+ Rewards: {
+ TitleId: 1002
+ Bonus: <" specialeffect(EF_BLESSING, AREA, playerattached()); sc_start SC_BLESSING, 30000, 1; ">
+ Items: {
+ Advanced_Jao_King_Hat: 1
+ }
+ }
+ Points: 70
+},
+{
+ Id: 200003
+ Name: "Master Job level!"
+ Type: "ACH_STATUS"
+ Objectives: {
+ *1: {
+ Description: "Job level 50"
+ Criteria: {
+ StatusType: "SP_JOBLEVEL"
+ }
+ Goal: 50
+ }
+ }
+ Rewards: {
+ TitleId: 1003
+ Bonus: <" specialeffect(EF_BLESSING, AREA, playerattached()); sc_start SC_BLESSING, 30000, 1; ">
+ Items: {
+ Old_Violet_Box: 1
+ }
+ }
+ Points: 30
+},
+{
+ Id: 200004
+ Name: "Grandmaster Job level!"
+ Type: "ACH_STATUS"
+ Objectives: {
+ *1: {
+ Description: "Job level 70"
+ Criteria: {
+ StatusType: "SP_JOBLEVEL"
+ }
+ Goal: 70
+ }
+ }
+ Rewards: {
+ TitleId: 1004
+ Bonus: <" specialeffect(EF_BLESSING, AREA, playerattached()); sc_start SC_BLESSING, 30000, 1; ">
+ Items: {
+ Old_Card_Album_: 1
+ }
+ }
+ Points: 50
+},
+{
+ Id: 200005
+ Name: "Official Adventurer"
+ Type: "ACH_JOB_CHANGE"
+ Objectives: {
+ *1: {
+ Description: "Job change to first class"
+ Criteria: {
+ JobId: [ "Job_Swordman", "Job_Mage", "Job_Archer", "Job_Acolyte", "Job_Merchant", "Job_Thief" ]
+ }
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ }
+ Points: 10
+},
+{
+ Id: 200006
+ Name: "First step of job change!"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "First step of job change"
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ }
+ Points: 20
+},
+{
+ Id: 200007
+ Name: "Veteran Adventurer! (1)"
+ Type: "ACH_JOB_CHANGE"
+ Objectives: {
+ *1: {
+ Description: "Job change to 2-1 classes"
+ Criteria: {
+ JobId: [ "Job_Knight", "Job_Priest", "Job_Wizard", "Job_Blacksmith", "Job_Hunter", "Job_Assassin" ]
+ }
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ }
+ Points: 25
+},
+{
+ Id: 200008
+ Name: "Veteran Adventurer! (2)"
+ Type: "ACH_JOB_CHANGE"
+ Objectives: {
+ *1: {
+ Description: "Job change to 2-2 classes"
+ Criteria: {
+ JobId: [ "Job_Crusader", "Job_Sage", "Job_Bard", "Job_Dancer", "Job_Alchemist", "Job_Rogue" ]
+ }
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ }
+ Points: 25
+},
+{
+ Id: 200009
+ Name: "Warrior (1)"
+ Type: "ACH_JOB_CHANGE"
+ Objectives: {
+ *1: {
+ Description: "Job change to transcendent 2-1 classes"
+ Criteria: {
+ JobId: [ "Job_Lord_Knight", "Job_High_Wizard", "Job_Sniper", "Job_High_Priest", "Job_Whitesmith", "Job_Assassin_Cross" ]
+ }
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ }
+ Points: 30
+},
+{
+ Id: 200010
+ Name: "Warrior (2)"
+ Type: "ACH_JOB_CHANGE"
+ Objectives: {
+ *1: {
+ Description: "Job change to transcendent 2-2 classes"
+ Criteria: {
+ JobId: [ "Job_Paladin", "Job_Professor", "Job_Clown", "Job_Gypsy", "Job_Champion", "Job_Creator", "Job_Stalker" ]
+ }
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ }
+ Points: 30
+},
+{
+ Id: 200011
+ Name: "Elite Adventurer! (1)"
+ Type: "ACH_JOB_CHANGE"
+ Objectives: {
+ *1: {
+ Description: "Job change to 3-1 classes"
+ Criteria: {
+ JobId: [ "Job_Rune_Knight", "Job_Warlock", "Job_Ranger", "Job_Arch_Bishop", "Job_Mechanic", "Job_Guillotine_Cross" ]
+ }
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Abrasive_Box_10: 1
+ }
+ }
+ Points: 50
+},
+{
+ Id: 200012
+ Name: "Transcendentaler! (1)"
+ Type: "ACH_JOB_CHANGE"
+ Objectives: {
+ *1: {
+ Description: "Job change to 3-1 classes after transcendent"
+ Criteria: {
+ JobId: [ "Job_Rune_Knight_T", "Job_Warlock_T", "Job_Ranger_T", "Job_Arch_Bishop_T", "Job_Mechanic_T", "Job_Guillotine_Cross_T" ]
+ }
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Abrasive_Box_10: 1
+ }
+ }
+ Points: 60
+},
+{
+ Id: 200013
+ Name: "Elite Adventurer! (2)"
+ Type: "ACH_JOB_CHANGE"
+ Objectives: {
+ *1: {
+ Description: "Job change to 3-2 classes"
+ Criteria: {
+ JobId: [ "Job_Royal_Guard", "Job_Sorcerer", "Job_Minstrel", "Job_Wanderer", "Job_Sura", "Job_Genetic", "Job_Shadow_Chaser" ]
+ }
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Abrasive_Box_10: 1
+ }
+ }
+ Points: 50
+},
+{
+ Id: 200014
+ Name: "Transcendentaler! (2)"
+ Type: "ACH_JOB_CHANGE"
+ Objectives: {
+ *1: {
+ Description: "Job change to 3-2 classes after transcendent"
+ Criteria: {
+ JobId: [ "Job_Royal_Guard_T", "Job_Sorcerer_T", "Job_Minstrel_T", "Job_Wanderer_T", "Job_Sura_T", "Job_Genetic_T", "Job_Shadow_Chaser_T" ]
+ }
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Abrasive_Box_10: 1
+ }
+ }
+ Points: 60
+},
+{
+ Id: 200015
+ Name: "The way of exceptional character"
+ Type: "ACH_JOB_CHANGE"
+ Objectives: {
+ *1: {
+ Description: "Job change to expanded classes"
+ Criteria: {
+ JobId: [ "Job_Taekwon", "Job_Gunslinger", "Job_Ninja", "Job_Summoner" ]
+ }
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ }
+ Points: 10
+},
+{
+ Id: 200016
+ Name: "This is My way!"
+ Type: "ACH_JOB_CHANGE"
+ Objectives: {
+ *1: {
+ Description: "Expanded 2nd classes"
+ Criteria: {
+ JobId: [ "Job_Star_Gladiator", "Job_Soul_Linker", "Job_Rebellion", "Job_Kagerou", "Job_Oboro" ]
+ }
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Abrasive_Box_10: 1
+ }
+ }
+ Points: 20
+},
+{
+ Id: 200017
+ Name: "Bearish Power!"
+ Type: "ACH_STATUS"
+ Objectives: {
+ *1: {
+ Description: "Achieve base STR 90º"
+ Criteria: {
+ StatusType: "SP_STR"
+ }
+ Goal: 90
+ }
+ }
+ Points: 10
+},
+{
+ Id: 200018
+ Name: "Overflowing Magic!"
+ Type: "ACH_STATUS"
+ Objectives: {
+ *1: {
+ Description: "Achieve base INT 90"
+ Criteria: {
+ StatusType: "SP_INT"
+ }
+ Goal: 90
+ }
+ }
+ Points: 10
+},
+{
+ Id: 200019
+ Name: "Healthy Body and Mental Health!"
+ Type: "ACH_STATUS"
+ Objectives: {
+ *1: {
+ Description: "Achieve base VIT 90"
+ Criteria: {
+ StatusType: "SP_VIT"
+ }
+ Goal: 90
+ }
+ }
+ Points: 10
+},
+{
+ Id: 200020
+ Name: "Speed of Light"
+ Type: "ACH_STATUS"
+ Objectives: {
+ *1: {
+ Description: "Achieve base AGI 90"
+ Criteria: {
+ StatusType: "SP_AGI"
+ }
+ Goal: 90
+ }
+ }
+ Points: 10
+},
+{
+ Id: 200021
+ Name: "Hawk Eyes"
+ Type: "ACH_STATUS"
+ Objectives: {
+ *1: {
+ Description: "Achieve base DEX 90"
+ Criteria: {
+ StatusType: "SP_DEX"
+ }
+ Goal: 90
+ }
+ }
+ Points: 10
+},
+{
+ Id: 200022
+ Name: "Maximum Luck"
+ Type: "ACH_STATUS"
+ Objectives: {
+ *1: {
+ Description: "Achieve base LUK 90"
+ Criteria: {
+ StatusType: "SP_LUK"
+ }
+ Goal: 90
+ }
+ }
+ Points: 10
+},
+{
+ Id: 200023
+ Name: "Dragonlike Power!"
+ Type: "ACH_STATUS"
+ Objectives: {
+ *1: {
+ Description: "Achieve base STR 125"
+ Criteria: {
+ StatusType: "SP_STR"
+ }
+ Goal: 125
+ }
+ }
+ Rewards: {
+ Bonus: <" sc_start SC_GIANTGROWTH, 180000, 1; ">
+ }
+ Points: 20
+},
+{
+ Id: 200024
+ Name: "Magic Insanity"
+ Type: "ACH_STATUS"
+ Objectives: {
+ *1: {
+ Description: "Achieve base INT 125"
+ Criteria: {
+ StatusType: "SP_INT"
+ }
+ Goal: 125
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_HASTEUP, AREA, playerattached()); sc_start2 SC_MAGIC_CANDY, 60000, 30, 70; ">
+ }
+ Points: 20
+},
+{
+ Id: 200025
+ Name: "Rock Alloy"
+ Type: "ACH_STATUS"
+ Objectives: {
+ *1: {
+ Description: "Achieve base VIT 125"
+ Criteria: {
+ StatusType: "SP_VIT"
+ }
+ Goal: 125
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_HEAL3, AREA, playerattached()); sc_start2 SC_S_LIFEPOTION, 600000, -5, 5; ">
+ }
+ Points: 20
+},
+{
+ Id: 200026
+ Name: "Speed of Light"
+ Type: "ACH_STATUS"
+ Objectives: {
+ *1: {
+ Description: "Achieve base AGI 125"
+ Criteria: {
+ StatusType: "SP_AGI"
+ }
+ Goal: 125
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_STEAL, AREA, playerattached()); sc_start SC_PLUSAVOIDVALUE, 60000, 20; ">
+ }
+ Points: 20
+},
+{
+ Id: 200027
+ Name: "Falcon's Eyes"
+ Type: "ACH_STATUS"
+ Objectives: {
+ *1: {
+ Description: "Achieve base DEX 125"
+ Criteria: {
+ StatusType: "SP_DEX"
+ }
+ Goal: 125
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_MAGICALATTHIT, AREA, playerattached()); sc_start SC_CRITICALPERCENT, 300000, 30; ">
+ }
+ Points: 20
+},
+{
+ Id: 200028
+ Name: "Lucky Fever"
+ Type: "ACH_STATUS"
+ Objectives: {
+ *1: {
+ Description: "Achieve base LUK 125"
+ Criteria: {
+ StatusType: "SP_LUK"
+ }
+ Goal: 125
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_GLORIA, AREA, playerattached()); sc_start SC_GLORIA, 15000, 0; ">
+ }
+ Points: 20
+},
+{
+ Id: 200029
+ Name: "Incarnation of Love and Hate"
+ Type: "ACH_STATUS_BY_JOB"
+ Objectives: {
+ *1: {
+ Description: "Achieve 99 base level as Novice"
+ Criteria: {
+ StatusType: "SP_BASELEVEL"
+ JobId: "Job_Novice"
+ }
+ Goal: 99
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_BLESSING, AREA, playerattached()); sc_start SC_BLESSING, 30000, 1; ">
+ Items: {
+ Abrasive_Box_10: 1
+ }
+ }
+ Points: 30
+},
+{
+ Id: 200030
+ Name: "I really love it!"
+ Type: "ACH_STATUS_BY_JOBTYPE"
+ Objectives: {
+ *1: {
+ Description: "Achieve 99 base level as 1st classes"
+ Criteria: {
+ StatusType: "SP_BASELEVEL"
+ JobId: ["Job_Swordman", "Job_Mage", "Job_Archer", "Job_Acolyte", "Job_Merchant", "Job_Thief"]
+ }
+ Goal: 99
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_BLESSING, AREA, playerattached()); sc_start(SC_BLESSING, 30000, 1); ">
+ Items: {
+ Bubble_Gum_Box_10: 1
+ }
+ }
+ Points: 30
+},
+{
+ Id: 200031
+ Name: "Reborn in Valhalla!"
+ Type: "ACH_JOB_CHANGE"
+ Objectives: {
+ *1: {
+ Description: "Job change to transcendent Novice"
+ Criteria: {
+ JobId: "Job_Novice_High"
+ }
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Special_Gift_Box: 1
+ }
+ }
+ Points: 10
+},
+/*{
+ Id: 200032
+ Name: "Start of Another Adventure"
+ Type: "ACH_STATUS_BY_JOB"
+ Objectives: {
+ *1: {
+ Description: "Achieve Base Level 100"
+ Criteria: {
+ StatusType: "SP_BASELEVEL"
+ JobId: "" // Rebirth?
+ }
+ Goal: 100
+ }
+ }
+ Rewards: {
+ Items: {
+ ID23585: 1 (Non-Existent Item)
+ }
+ }
+ Points: 10
+},*/
+{
+ Id: 220000
+ Name: "Community begin"
+ Type: "ACH_CHATROOM_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Create a chatroom"
+ }
+ }
+ Points: 10
+},
+{
+ Id: 220001
+ Name: "A mouth only moment"
+ Type: "ACH_CHATROOM_CREATE_DEAD"
+ Objectives: {
+ *1: {
+ Description: "Create a chatroom when KO'ed"
+ }
+ }
+ Points: 10
+},
+{
+ Id: 220002
+ Name: "Admiring the chatter"
+ Type: "ACH_CHATROOM_MEMBERS"
+ Objectives: {
+ *1: {
+ Description: "Fill the chatroom with 20 people"
+ }
+ }
+ Points: 10
+},
+{
+ Id: 220003
+ Name: "My friend's friend~"
+ Type: "ACH_FRIEND_ADD"
+ Objectives: {
+ *1: {
+ Description: "Add 1 person as a friend"
+ }
+ }
+ Points: 10
+},
+{
+ Id: 220004
+ Name: "A competition of popularity"
+ Type: "ACH_FRIEND_ADD"
+ Objectives: {
+ *1: {
+ Description: "Add 10 person as a friend"
+ }
+ }
+ Points: 10
+},
+{
+ Id: 220005
+ Name: "Let's Party~"
+ Type: "ACH_PARTY_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Create a party"
+ }
+ }
+ Points: 10
+},
+{
+ Id: 220006
+ Name: "Married with who..?"
+ Type: "ACH_MARRY"
+ Objectives: {
+ *1: {
+ Description: "Succeed on marriage"
+ }
+ }
+ Rewards: {
+ TitleId: 1022
+ }
+ Points: 20
+},
+{
+ Id: 220007
+ Name: "Can you grow?"
+ Type: "ACH_ADOPT_PARENT"
+ Objectives: {
+ *1: {
+ Description: "Adopted by parents"
+ }
+ }
+ Rewards: {
+ TitleId: 1032
+ }
+ Points: 20
+},
+{
+ Id: 220008
+ Name: "Being a parent"
+ Type: "ACH_ADOPT_BABY"
+ Objectives: {
+ *1: {
+ Description: "Adopt a child"
+ }
+ }
+ Rewards: {
+ TitleId: 1033
+ }
+ Points: 20
+},
+{
+ Id: 220009
+ Name: "Activating the market economy (1)"
+ Type: "ACH_ZENY_SPEND_TOTAL"
+ Objectives: {
+ *1: {
+ Description: "Spend 10000 zeny on vending merchant"
+ Goal: 10000
+ }
+ }
+ Points: 10
+},
+{
+ Id: 220010
+ Name: "Activating the market economy (2)"
+ Type: "ACH_ZENY_SPEND_TOTAL"
+ Objectives: {
+ *1: {
+ Description: "Spend 100000 zeny on vending merchant"
+ Goal: 1000000
+ }
+ }
+ Points: 15
+},
+{
+ Id: 220011
+ Name: "Activating the market economy (3)"
+ Type: "ACH_ZENY_SPEND_TOTAL"
+ Objectives: {
+ *1: {
+ Description: "Spend 500000 zeny on vending merchant"
+ Goal: 5000000
+ }
+ }
+ Points: 20
+},
+{
+ Id: 220012
+ Name: "Activating the market economy (4)"
+ Type: "ACH_ZENY_SPEND_TOTAL"
+ Objectives: {
+ *1: {
+ Description: "Spend 1.000000 zeny on vending merchant"
+ Goal: 100000000
+ }
+ }
+ Points: 30
+},
+{
+ Id: 220013
+ Name: "Activating the market economy (5)"
+ Type: "ACH_ZENY_SPEND_TOTAL"
+ Objectives: {
+ *1: {
+ Description: "Spend 5.000000 zeny on vending merchant"
+ Goal: 500000000
+ }
+ }
+ Points: 50
+},
+{
+ Id: 220014
+ Name: "I can't quit from refining! (1)"
+ Type: "ACH_EQUIP_REFINE_SUCCESS_WLV"
+ Objectives: {
+ *1: {
+ Description: "Succeed on refining level 1 weapon to +7"
+ Criteria: {
+ ItemType: "IT_WEAPON"
+ WeaponLevel: 1
+ }
+ Goal: 7
+ }
+ }
+ Points: 10
+},
+{
+ Id: 220015
+ Name: "I can't quit from refining! (2)"
+ Type: "ACH_EQUIP_REFINE_SUCCESS_WLV"
+ Objectives: {
+ *1: {
+ Description: "Succeed on refining level 1 weapon to +12"
+ Criteria: {
+ ItemType: "IT_WEAPON"
+ WeaponLevel: 1
+ }
+ Goal: 12
+ }
+ }
+ Points: 15
+},
+{
+ Id: 220016
+ Name: "I can't quit from refining! (3)"
+ Type: "ACH_EQUIP_REFINE_SUCCESS_WLV"
+ Objectives: {
+ *1: {
+ Description: "Succeed on refining level 2 weapon to +7"
+ Criteria: {
+ ItemType: "IT_WEAPON"
+ WeaponLevel: 2
+ }
+ Goal: 7
+ }
+ }
+ Points: 10
+},
+{
+ Id: 220017
+ Name: "I can't quit from refining! (4)"
+ Type: "ACH_EQUIP_REFINE_SUCCESS_WLV"
+ Objectives: {
+ *1: {
+ Description: "Succeed on refining level 2 weapon to +12"
+ Criteria: {
+ ItemType: "IT_WEAPON"
+ WeaponLevel: 2
+ }
+ Goal: 12
+ }
+ }
+ Points: 15
+},
+{
+ Id: 220018
+ Name: "I can't quit from refining! (5)"
+ Type: "ACH_EQUIP_REFINE_SUCCESS_WLV"
+ Objectives: {
+ *1: {
+ Description: "Succeed on refining level 3 weapon to +7"
+ Criteria: {
+ ItemType: "IT_WEAPON"
+ WeaponLevel: 3
+ }
+ Goal: 7
+ }
+ }
+ Points: 15
+},
+{
+ Id: 220019
+ Name: "I can't quit from refining! (6)"
+ Type: "ACH_EQUIP_REFINE_SUCCESS_WLV"
+ Objectives: {
+ *1: {
+ Description: "Succeed on refining level 3 weapon to +12"
+ Criteria: {
+ ItemType: "IT_WEAPON"
+ WeaponLevel: 3
+ }
+ Goal: 12
+ }
+ }
+ Points: 20
+},
+{
+ Id: 220020
+ Name: "I can't quit from refining! (7)"
+ Type: "ACH_EQUIP_REFINE_SUCCESS_WLV"
+ Objectives: {
+ *1: {
+ Description: "Succeed on refining level 4 weapon to +7"
+ Criteria: {
+ ItemType: "IT_WEAPON"
+ WeaponLevel: 4
+ }
+ Goal: 7
+ }
+ }
+ Points: 20
+},
+{
+ Id: 220021
+ Name: "I can't quit from refining! (8)"
+ Type: "ACH_EQUIP_REFINE_SUCCESS_WLV"
+ Objectives: {
+ *1: {
+ Description: "Succeed on refining level 4 weapon to +12"
+ Criteria: {
+ ItemType: "IT_WEAPON"
+ WeaponLevel: 4
+ }
+ Goal: 12
+ }
+ }
+ Points: 30
+},
+{
+ Id: 220022
+ Name: "Human's greed has no ending.."
+ Type: "ACH_EQUIP_REFINE_FAILURE_TOTAL"
+ Objectives: {
+ *1: {
+ Description: "Experience the fail of refining"
+ Criteria: {
+ ItemType: ["IT_WEAPON", "IT_ARMOR"]
+ }
+ }
+ }
+ Points: 10
+},
+{
+ Id: 220023
+ Name: "I found it! (1)"
+ Type: "ACH_ITEM_GET_WORTH"
+ Objectives: {
+ *1: {
+ Description: "Obtain an item with worth of more than 100 zeny"
+ Goal: 100
+ }
+ }
+ Points: 10
+},
+{
+ Id: 220024
+ Name: "I found it! (2)"
+ Type: "ACH_ITEM_GET_WORTH"
+ Objectives: {
+ *1: {
+ Description: "Obtain an item with worth of more than 1000 zeny"
+ Goal: 1000
+ }
+ }
+ Points: 10
+},
+{
+ Id: 220025
+ Name: "I found it! (3)"
+ Type: "ACH_ITEM_GET_WORTH"
+ Objectives: {
+ *1: {
+ Description: "Obtain an item with worth of more than 5000 zeny"
+ Goal: 5000
+ }
+ }
+ Points: 15
+},
+{
+ Id: 220026
+ Name: "I found it! (4)"
+ Type: "ACH_ITEM_GET_WORTH"
+ Objectives: {
+ *1: {
+ Description: "Obtain an item with worth of more than 10000 zeny"
+ Goal: 10000
+ }
+ }
+ Points: 15
+},
+{
+ Id: 220027
+ Name: "I found it! (5)"
+ Type: "ACH_ITEM_GET_WORTH"
+ Objectives: {
+ *1: {
+ Description: "Obtain an item with worth of more than 50000 zeny"
+ Goal: 50000
+ }
+ }
+ Points: 20
+},
+{
+ Id: 220028
+ Name: "I found it! (6)"
+ Type: "ACH_ITEM_GET_WORTH"
+ Objectives: {
+ *1: {
+ Description: "Obtain an item with worth of more than 100000 zeny"
+ Goal: 100000
+ }
+ }
+ Points: 20
+},
+{
+ Id: 220029
+ Name: "I found it! (7)"
+ Type: "ACH_ITEM_GET_WORTH"
+ Objectives: {
+ *1: {
+ Description: "Obtain an item with worth of more than 150000 zeny"
+ Goal: 150000
+ }
+ }
+ Points: 30
+},
+{
+ Id: 220030
+ Name: "Rich King (1)"
+ Type: "ACH_ZENY_HOLD"
+ Objectives: {
+ *1: {
+ Description: "Hold more than 10000 zeny in pocket"
+ Goal: 10000
+ }
+ }
+ Points: 10
+},
+{
+ Id: 220031
+ Name: "Rich King (2)"
+ Type: "ACH_ZENY_HOLD"
+ Objectives: {
+ *1: {
+ Description: "Hold more than 100000 zeny in pocket"
+ Goal: 100000
+ }
+ }
+ Points: 15
+},
+{
+ Id: 220032
+ Name: "Rich King (3)"
+ Type: "ACH_ZENY_HOLD"
+ Objectives: {
+ *1: {
+ Description: "Hold more than 1000000 zeny in pocket"
+ Goal: 1000000
+ }
+ }
+ Points: 20
+},
+{
+ Id: 220033
+ Name: "Rich King (4)"
+ Type: "ACH_ZENY_HOLD"
+ Objectives: {
+ *1: {
+ Description: "Hold more than 10000000 zeny in pocket"
+ Goal: 10000000
+ }
+ }
+ Points: 25
+},
+{
+ Id: 220034
+ Name: "Rich King (5)"
+ Type: "ACH_ZENY_HOLD"
+ Objectives: {
+ *1: {
+ Description: "Hold more than 100000000 zeny in pocket"
+ Goal: 100000000
+ }
+ }
+ Points: 30
+},
+{
+ Id: 220035
+ Name: "Rich King (6)"
+ Type: "ACH_ZENY_HOLD"
+ Objectives: {
+ *1: {
+ Description: "Hold more than 1000000000 zeny in pocket"
+ Goal: 1000000000
+ }
+ }
+ Points: 40
+},
+{
+ Id: 230101
+ Name: "Poring - taming"
+ Type: "ACH_PET_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Succeed on Taming Poring"
+ Criteria: {
+ MobId: "PORING"
+ }
+ }
+ }
+ Points: 10
+},
+{
+ Id: 230102
+ Name: "Drops - taming"
+ Type: "ACH_PET_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Succeed on Taming Drops"
+ Criteria: {
+ MobId: "DROPS"
+ }
+ }
+ }
+ Points: 10
+},
+{
+ Id: 230103
+ Name: "Poporing - taming"
+ Type: "ACH_PET_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Succeed on Taming Poporing"
+ Criteria: {
+ MobId: "POPORING"
+ }
+ }
+ }
+ Points: 10
+},
+{
+ Id: 230104
+ Name: "Novice Poring - taming"
+ Type: "ACH_PET_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Succeed on Taming Novice Poring"
+ Criteria: {
+ MobId: "LITTLE_PORING"
+ }
+ }
+ }
+ Points: 10
+},
+{
+ Id: 230111
+ Name: "Chonchon - taming"
+ Type: "ACH_PET_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Succeed on Taming Chonchon"
+ Criteria: {
+ MobId: "CHONCHON"
+ }
+ }
+ }
+ Points: 10
+},
+{
+ Id: 230112
+ Name: "Steel Chonchon - taming"
+ Type: "ACH_PET_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Succeed on Taming Steel Chonchon"
+ Criteria: {
+ MobId: "STEEL_CHONCHON"
+ }
+ }
+ }
+ Points: 10
+},
+{
+ Id: 230113
+ Name: "Hunter Fly - taming"
+ Type: "ACH_PET_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Succeed on Taming Hunter Fly"
+ Criteria: {
+ MobId: "HUNTER_FLY"
+ }
+ }
+ }
+ Points: 10
+},
+{
+ Id: 230114
+ Name: "Rocker - taming"
+ Type: "ACH_PET_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Succeed on Taming Rocker"
+ Criteria: {
+ MobId: "ROCKER"
+ }
+ }
+ }
+ Points: 10
+},
+{
+ Id: 230115
+ Name: "Spore - taming"
+ Type: "ACH_PET_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Succeed on Taming Spore"
+ Criteria: {
+ MobId: "SPORE"
+ }
+ }
+ }
+ Points: 10
+},
+{
+ Id: 230116
+ Name: "Poison Spore - taming"
+ Type: "ACH_PET_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Succeed on Taming Poison Spore"
+ Criteria: {
+ MobId: "POISON_SPORE"
+ }
+ }
+ }
+ Points: 10
+},
+{
+ Id: 230121
+ Name: "Lunatic - taming"
+ Type: "ACH_PET_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Succeed on Taming Lunatic"
+ Criteria: {
+ MobId: "LUNATIC"
+ }
+ }
+ }
+ Points: 10
+},
+{
+ Id: 230122
+ Name: "Picky - taming"
+ Type: "ACH_PET_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Succeed on Taming Picky"
+ Criteria: {
+ MobId: "PICKY"
+ }
+ }
+ }
+ Points: 10
+},
+{
+ Id: 230123
+ Name: "Savage Bebe - taming"
+ Type: "ACH_PET_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Succeed on Taming Savage Bebe"
+ Criteria: {
+ MobId: "SAVAGE_BABE"
+ }
+ }
+ }
+ Points: 10
+},
+{
+ Id: 230124
+ Name: "Baby Desert Wolf - taming"
+ Type: "ACH_PET_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Succeed on Taming Baby Desert Wolf"
+ Criteria: {
+ MobId: "M_DESERT_WOLF_B"
+ }
+ }
+ }
+ Points: 10
+},
+{
+ Id: 230125
+ Name: "Smokie - taming"
+ Type: "ACH_PET_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Succeed on Taming Smokie"
+ Criteria: {
+ MobId: "SMOKIE"
+ }
+ }
+ }
+ Points: 10
+},
+{
+ Id: 230126
+ Name: "Yoyo - taming"
+ Type: "ACH_PET_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Succeed on Taming Yoyo"
+ Criteria: {
+ MobId: "YOYO"
+ }
+ }
+ }
+ Points: 10
+},
+{
+ Id: 230127
+ Name: "Peco Peco - taming"
+ Type: "ACH_PET_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Succeed on Taming Peco Peco"
+ Criteria: {
+ MobId: "PECOPECO"
+ }
+ }
+ }
+ Points: 10
+},
+{
+ Id: 230128
+ Name: "Petite - taming"
+ Type: "ACH_PET_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Succeed on Taming Petite"
+ Criteria: {
+ MobId: "PETIT"
+ }
+ }
+ }
+ Points: 10
+},
+{
+ Id: 230141
+ Name: "Munak - taming"
+ Type: "ACH_PET_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Succeed on Taming Munak"
+ Criteria: {
+ MobId: "MUNAK"
+ }
+ }
+ }
+ Points: 10
+},
+{
+ Id: 230142
+ Name: "Isis - taming"
+ Type: "ACH_PET_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Succeed on Taming Isis"
+ Criteria: {
+ MobId: "ISIS"
+ }
+ }
+ }
+ Points: 10
+},
+{
+ Id: 230143
+ Name: "Sohee - taming"
+ Type: "ACH_PET_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Succeed on Taming Sohee"
+ Criteria: {
+ MobId: "SOHEE"
+ }
+ }
+ }
+ Points: 10
+},
+{
+ Id: 230144
+ Name: "Zherlthsh - taming"
+ Type: "ACH_PET_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Succeed on Taming Zherlthsh"
+ Criteria: {
+ MobId: "ZHERLTHSH"
+ }
+ }
+ }
+ Points: 10
+},
+{
+ Id: 230145
+ Name: "Alice - taming"
+ Type: "ACH_PET_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Succeed on Taming Alice"
+ Criteria: {
+ MobId: "ALICE"
+ }
+ }
+ }
+ Points: 10
+},
+{
+ Id: 230146
+ Name: "Succubus - taming"
+ Type: "ACH_PET_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Succeed on Taming Succubus"
+ Criteria: {
+ MobId: "SUCCUBUS"
+ }
+ }
+ }
+ Points: 10
+},
+{
+ Id: 230147
+ Name: "Loli Ruri - taming"
+ Type: "ACH_PET_CREATE"
+ Objectives: {
+ *1: {
+ Description: "Succeed on Taming Loli Ruri"
+ Criteria: {
+ MobId: "LOLI_RURI"
+ }
+ }
+ }
+ Points: 10
+},
+{
+ Id: 230201
+ Name: "Exploring Poring's life (1)"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Hunt 10 Poring"
+ Criteria: {
+ MobId: "PORING"
+ }
+ Goal: 10
+ }
+ *2: {
+ Description: "Hunt 10 Novice Poring"
+ Criteria: {
+ MobId: "LITTLE_PORING"
+ }
+ Goal: 10
+ }
+ *3: {
+ Description: "Hunt 10 Drops"
+ Criteria: {
+ MobId: "DROPS"
+ }
+ Goal: 10
+ }
+ *4: {
+ Description: "Hunt 10 Poporing"
+ Criteria: {
+ MobId: "POPORING"
+ }
+ Goal: 10
+ }
+ *5: {
+ Description: "Hunt 10 Marin"
+ Criteria: {
+ MobId: "MARIN"
+ }
+ Goal: 10
+ }
+ }
+ Points: 10
+},
+{
+ Id: 230202
+ Name: "Exploring Poring's life (2)"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Hunt 1 Mastering"
+ Criteria: {
+ MobId: "MASTERING"
+ }
+ Goal: 1
+ }
+ *2: {
+ Description: "Hunt 1 Devilring"
+ Criteria: {
+ MobId: "DEVILING"
+ }
+ Goal: 1
+ }
+ *3: {
+ Description: "Hunt 1 Angelring"
+ Criteria: {
+ MobId: "ANGELING"
+ }
+ Goal: 1
+ }
+ *4: {
+ Description: "Hunt 1 Arch Angelring"
+ Criteria: {
+ MobId: "ARCHANGELING"
+ }
+ Goal: 1
+ }
+ *5: {
+ Description: "Hunt 1 Ghostring"
+ Criteria: {
+ MobId: "GHOSTRING"
+ }
+ Goal: 1
+ }
+ }
+ Points: 15
+},
+{
+ Id: 230203
+ Name: "Exploring Poring's life (3)"
+ Type: "ACH_KILL_MOB_CLASS"
+ Objectives: {
+ *1: {
+ Description: "Hunt 5 Metalring"
+ Criteria: {
+ MobId: "METALING"
+ }
+ Goal: 5
+ }
+ *2: {
+ Description: "Hunt 5 Heavy Metalring"
+ Criteria: {
+ MobId: "METALING"
+ }
+ Goal: 5
+ }
+ *3: {
+ Description: "Hunt 5 Magmaring"
+ Criteria: {
+ MobId: "MAGMARING"
+ }
+ Goal: 5
+ }
+ }
+ Points: 20
+},
+{
+ Id: 240000
+ Name: "Complete challenges after first introduction"
+ Type: "ACH_QUEST"
+ Objectives: {
+ *1: {
+ Description: "Complete challenges after first introduction"
+ }
+ }
+ Points: 10
+},
+{
+ Id: 240001
+ Name: "Achieve Level 1"
+ Type: "ACH_ACHIEVEMENT_RANK"
+ Objectives: {
+ *1: {
+ Description: "Achieving Rank 1"
+ Goal: 1
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 240002
+ Name: "Achieve Level 2"
+ Type: "ACH_ACHIEVEMENT_RANK"
+ Objectives: {
+ *1: {
+ Description: "Achieving Rank 2"
+ Goal: 2
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 240003
+ Name: "Achieve Level 3"
+ Type: "ACH_ACHIEVEMENT_RANK"
+ Objectives: {
+ *1: {
+ Description: "Achieving Rank 3"
+ Goal: 3
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 240004
+ Name: "Achieve Level 4"
+ Type: "ACH_ACHIEVEMENT_RANK"
+ Objectives: {
+ *1: {
+ Description: "Achieving Rank 4"
+ Goal: 4
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 240005
+ Name: "Achieve Level 5"
+ Type: "ACH_ACHIEVEMENT_RANK"
+ Objectives: {
+ *1: {
+ Description: "Achieving Rank 5"
+ Goal: 5
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 240006
+ Name: "Achieve Level 6"
+ Type: "ACH_ACHIEVEMENT_RANK"
+ Objectives: {
+ *1: {
+ Description: "Achieving Rank 6"
+ Goal: 6
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 240007
+ Name: "Achieve Level 7"
+ Type: "ACH_ACHIEVEMENT_RANK"
+ Objectives: {
+ *1: {
+ Description: "Achieving Rank 7"
+ Goal: 7
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 240008
+ Name: "Achieve Level 8"
+ Type: "ACH_ACHIEVEMENT_RANK"
+ Objectives: {
+ *1: {
+ Description: "Achieving Rank 8"
+ Goal: 8
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 240009
+ Name: "Achieve Level 9"
+ Type: "ACH_ACHIEVEMENT_RANK"
+ Objectives: {
+ *1: {
+ Description: "Achieving Rank 9"
+ Goal: 9
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 240010
+ Name: "Achieve Level 10"
+ Type: "ACH_ACHIEVEMENT_RANK"
+ Objectives: {
+ *1: {
+ Description: "Achieving Rank 10"
+ Goal: 10
+ }
+ }
+ Rewards: {
+ TitleId: 1023
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 240011
+ Name: "Achieve Level 11"
+ Type: "ACH_ACHIEVEMENT_RANK"
+ Objectives: {
+ *1: {
+ Description: "Achieving Rank 11"
+ Goal: 11
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 240012
+ Name: "Achieve Level 12"
+ Type: "ACH_ACHIEVEMENT_RANK"
+ Objectives: {
+ *1: {
+ Description: "Achieving Rank 12"
+ Goal: 12
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 240013
+ Name: "Achieve Level 13"
+ Type: "ACH_ACHIEVEMENT_RANK"
+ Objectives: {
+ *1: {
+ Description: "Achieving Rank 13"
+ Goal: 13
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 240014
+ Name: "Achieve Level 14"
+ Type: "ACH_ACHIEVEMENT_RANK"
+ Objectives: {
+ *1: {
+ Description: "Achieving Rank 14"
+ Goal: 14
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 240015
+ Name: "Achieve Level 15"
+ Type: "ACH_ACHIEVEMENT_RANK"
+ Objectives: {
+ *1: {
+ Description: "Achieving Rank 15"
+ Goal: 15
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 240016
+ Name: "Achieve Level 16"
+ Type: "ACH_ACHIEVEMENT_RANK"
+ Objectives: {
+ *1: {
+ Description: "Achieving Rank 16"
+ Goal: 16
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 240017
+ Name: "Achieve Level 17"
+ Type: "ACH_ACHIEVEMENT_RANK"
+ Objectives: {
+ *1: {
+ Description: "Achieving Rank 17"
+ Goal: 17
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 240018
+ Name: "Achieve Level 18"
+ Type: "ACH_ACHIEVEMENT_RANK"
+ Objectives: {
+ *1: {
+ Description: "Achieving Rank 18"
+ Goal: 18
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 240019
+ Name: "Achieve Level 19"
+ Type: "ACH_ACHIEVEMENT_RANK"
+ Objectives: {
+ *1: {
+ Description: "Achieving Rank 19"
+ Goal: 19
+ }
+ }
+ Rewards: {
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 10
+},
+{
+ Id: 240020
+ Name: "Achieve Level 20"
+ Type: "ACH_ACHIEVEMENT_RANK"
+ Objectives: {
+ *1: {
+ Description: "Achieving Rank 20"
+ Goal: 20
+ }
+ }
+ Rewards: {
+ TitleId: 1024
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ Items: {
+ Gift_Box: 1
+ }
+ }
+ Points: 10
+},
+/*****************************************************************
+ Postlude
+ Entries with criteria that must be read before itself.
+ *****************************************************************/
+{
+ Id: 230100
+ Name: "Poring is Love"
+ Type: "ACH_ACHIEVE"
+ Objectives: {
+ *1: {
+ Description: "Complete 'Poring - taming' challenge"
+ Criteria: {
+ Achieve: 230101
+ }
+ }
+ *2: {
+ Description: "Complete 'Drops - taming' challenge"
+ Criteria: {
+ Achieve: 230102
+ }
+ }
+ *3: {
+ Description: "Complete 'Poporing - taming' challenge"
+ Criteria: {
+ Achieve: 230103
+ }
+ }
+ *4: {
+ Description: "Complete 'Novice Poring - taming' challenge"
+ Criteria: {
+ Achieve: 230104
+ }
+ }
+ }
+ Rewards: {
+ TitleId: 1025
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ }
+ Points: 50
+},
+{
+ Id: 230110
+ Name: "Entomologist"
+ Type: "ACH_ACHIEVE"
+ Objectives: {
+ *1: {
+ Description: "Complete 'Chonchon - taming' challenge"
+ Criteria: {
+ Achieve: 230111
+ }
+ }
+ *2: {
+ Description: "Complete 'Steel Chonchon - taming' challenge"
+ Criteria: {
+ Achieve: 230112
+ }
+ }
+ *3: {
+ Description: "Complete 'Hunter Fly - taming' challenge"
+ Criteria: {
+ Achieve: 230113
+ }
+ }
+ *4: {
+ Description: "Complete 'Rocker - taming' challenge"
+ Criteria: {
+ Achieve: 230114
+ }
+ }
+ *5: {
+ Description: "Complete 'Spore - taming' challenge"
+ Criteria: {
+ Achieve: 230115
+ }
+ }
+ *6: {
+ Description: "Complete 'Poison Spore - taming' challenge"
+ Criteria: {
+ Achieve: 230116
+ }
+ }
+ }
+ Rewards: {
+ TitleId: 1026
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ }
+ Points: 50
+},
+{
+ Id: 230120
+ Name: "Animals are also our friend"
+ Type: "ACH_ACHIEVE"
+ Objectives: {
+ *1: {
+ Description: "Complete 'Lunatic - taming' challenge"
+ Criteria: {
+ Achieve: 230121
+ }
+ }
+ *2: {
+ Description: "Complete 'Picky - taming' challenge"
+ Criteria: {
+ Achieve: 230122
+ }
+ }
+ *3: {
+ Description: "Complete 'Savage Bebe - taming' challenge"
+ Criteria: {
+ Achieve: 230123
+ }
+ }
+ *4: {
+ Description: "Complete 'Baby Desert Wolf - taming' challenge"
+ Criteria: {
+ Achieve: 230124
+ }
+ }
+ *5: {
+ Description: "Complete 'Smokie - taming' challenge"
+ Criteria: {
+ Achieve: 230125
+ }
+ }
+ *6: {
+ Description: "Complete 'Yoyo - taming' challenge"
+ Criteria: {
+ Achieve: 230126
+ }
+ }
+ *7: {
+ Description: "Complete 'Peco Peco - taming' challenge"
+ Criteria: {
+ Achieve: 230127
+ }
+ }
+ *8: {
+ Description: "Complete 'Petite - taming' challenge"
+ Criteria: {
+ Achieve: 230128
+ }
+ }
+ }
+ Rewards: {
+ TitleId: 1027
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ }
+ Points: 50
+},
+{
+ Id: 230140
+ Name: "Monster Girls Unite!!"
+ Type: "ACH_ACHIEVE"
+ Objectives: {
+ *1: {
+ Description: "Complete 'Munak - taming' challenge"
+ Criteria: {
+ Achieve: 230141
+ }
+ }
+ *2: {
+ Description: "Complete 'Isis - taming' challenge"
+ Criteria: {
+ Achieve: 230142
+ }
+ }
+ *3: {
+ Description: "Complete 'Sohee - taming' challenge"
+ Criteria: {
+ Achieve: 230143
+ }
+ }
+ *4: {
+ Description: "Complete 'Zherlthsh - taming' challenge"
+ Criteria: {
+ Achieve: 230144
+ }
+ }
+ *5: {
+ Description: "Complete 'Alice - taming' challenge"
+ Criteria: {
+ Achieve: 230145
+ }
+ }
+ *6: {
+ Description: "Complete 'Succubus - taming' challenge"
+ Criteria: {
+ Achieve: 230146
+ }
+ }
+ *7: {
+ Description: "Complete 'Loli Ruri - taming' challenge"
+ Criteria: {
+ Achieve: 230147
+ }
+ }
+ }
+ Rewards: {
+ TitleId: 1029
+ Bonus: <" specialeffect(EF_INCAGILITY, AREA, playerattached()); sc_start SC_INC_AGI, 30000, 1; ">
+ }
+ Points: 50
+},
+{
+ Id: 230200
+ Name: "Poring seeker"
+ Type: "ACH_ACHIEVE"
+ Objectives: {
+ *1: {
+ Description: "Complete 'Exploring Poring's life (1)' challenge"
+ Criteria: {
+ Achieve: 230201
+ }
+ }
+ *2: {
+ Description: "Complete 'Exploring Poring's life (2)' challenge"
+ Criteria: {
+ Achieve: 230202
+ }
+ }
+ *3: {
+ Description: "Complete 'Exploring Poring's life (3)' challenge"
+ Criteria: {
+ Achieve: 230203
+ }
+ }
+ }
+ Points: 10
+},
+)
diff --git a/db/re/item_db.conf b/db/re/item_db.conf
index 21c11f3cd..093fc4868 100644
--- a/db/re/item_db.conf
+++ b/db/re/item_db.conf
@@ -74285,6 +74285,13 @@ item_db: (
Name: "Poring Badge"
},
{
+ Id: 6649
+ AegisName: "Broken_Horn"
+ Name: "Broken Horn"
+ Buy: 10
+ Weight: 10
+},
+{
Id: 6654
AegisName: "Needle_And_Thread"
Name: "Needle And Thread"
@@ -80092,6 +80099,12 @@ item_db: (
Weight: 10
},
{
+ Id: 7642
+ AegisName: "Bloody_Coin"
+ Name: "Bloody Coin"
+ Buy: 10
+},
+{
Id: 7646
AegisName: "RO_Luk_Bookmark"
Name: "RO Luk Bookmark"
@@ -92020,6 +92033,9 @@ item_db: (
nomail: true
noauction: true
}
+ Script: <"
+ autobonus("{ bonus(bCriticalRate, 30); }", 100, 1000);
+ ">
},
{
Id: 12515
@@ -95509,6 +95525,13 @@ item_db: (
Script: <" itemskill ECL_SEQUOIADUST,1; ">
},
{
+ Id: 12817
+ AegisName: "Old_Card_Album_"
+ Name: "Old Card Album"
+ Type: "IT_USABLE"
+ EquipLv: 80
+},
+{
Id: 12818
AegisName: "High_Weapon_Box_"
Name: "Advanced Weapons Box"
@@ -100402,6 +100425,46 @@ item_db: (
Subtype: "W_DAGGER"
},
{
+ Id: 13090
+ AegisName: "FaceWormQueen_Leg"
+ Name: "Faceworm Queen Leg"
+ Type: "IT_WEAPON"
+ Buy: 20
+ Weight: 500
+ Atk: 180
+ Matk: 120
+ Range: 1
+ Slots: 2
+ Job: {
+ Novice: true
+ Swordsman: true
+ Magician: true
+ Archer: true
+ Merchant: true
+ Thief: true
+ Knight: true
+ Wizard: true
+ Blacksmith: true
+ Hunter: true
+ Assassin: true
+ Crusader: true
+ Sage: true
+ Rogue: true
+ Alchemist: true
+ Bard: true
+ Soul_Linker: true
+ Ninja: true
+ }
+ Loc: "EQP_WEAPON"
+ WeaponLv: 4
+ EquipLv: 100
+ Subtype: "W_DAGGER"
+ Script: <"
+ bonus(bInt, 3);
+ autobonus("{ bonus3(bAutoSpell, NPC_EARTHQUAKE, 1, 200); }", 8, 5000, BF_NORMAL, "{ specialeffect(EF_POTION_BERSERK, AREA, playerattached()); montransform(FACEWORM_QUEEN, 5000); }");
+ ">
+},
+{
Id: 13092
AegisName: "RWC_Memory_Knife"
Name: "RWC Memory Knife"
@@ -124774,6 +124837,22 @@ item_db: (
">
},
{
+ Id: 15121
+ AegisName: "Robe_Of_Sarah"
+ Name: "Sarah Combat Robe"
+ Type: "IT_ARMOR"
+ Buy: 10
+ Weight: 800
+ Def: 35
+ Slots: 1
+ Loc: "EQP_ARMOR"
+ EquipLv: 145
+ Script: <"
+ //TODO: Confirm the real rate and additional MAtk
+ autobonus("{ bonus(bMatk, 20); }", 100, (10 + ((getrefine()) ? getrefine() * 8 : 0)) * 1000, BF_MAGIC);
+ ">
+},
+{
Id: 15123
AegisName: "Whikebain_Suit"
Name: "Whikebain Suit"
@@ -127368,6 +127447,16 @@ item_db: (
Script: <" packageitem(); ">
},
{
+ Id: 16483
+ AegisName: "Abrasive_Box_10"
+ Name: "Abrasive Box (10)"
+ Type: "IT_USABLE"
+ Buy: 20
+ Weight: 10
+ Script: <" getitem(E_Abrasive, 10); ">
+},
+
+{
Id: 16503
AegisName: "E_Insurance_Package"
Name: "E Insurance Package"
@@ -127376,6 +127465,15 @@ item_db: (
Script: <" getitem 12209,10; ">
},
{
+ Id: 16504
+ AegisName: "Bubble_Gum_Box_10"
+ Name: "Bubble Gum Box(10)"
+ Type: "IT_CASH"
+ Buy: 10
+ Weight: 10
+ Script: <" getitem(Bubble_Gum, 10); ">
+},
+{
Id: 16542
AegisName: "Xmas_Bless"
Name: "Xmas Bless"
@@ -147121,6 +147219,29 @@ item_db: (
Weight: 300
},
{
+ Id: 22534
+ AegisName: "Closedmind_Box"
+ Name: "Closed Mind Box"
+ Type: "IT_CASH"
+ Buy: 10
+ Weight: 1000
+ EquipLv: 1
+ Script: <"
+ // getgroupitem(IG_Sealed_Mind_Box);
+ ">
+},
+{
+ Id: 22537
+ AegisName: "PrizeOfHero"
+ Name: "Prize Of Hero"
+ Type: "IT_USABLE"
+ Weight: 100
+ EquipLv: 1
+ Script: <"
+ // getrandgroupitem(IG_PrizeOfHero, 1);
+ ">
+},
+{
Id: 22540
AegisName: "Runstone_Lux"
Name: "Lux Anima Rune"
@@ -147365,6 +147486,14 @@ item_db: (
">
},
{
+ Id: 22808
+ AegisName: "Special_Gift_Box"
+ Name: "Special Gift Box"
+ Type: "IT_USABLE"
+ Buy: 10
+ Weight: 100
+},
+{
Id: 22837
AegisName: "Integer_Time"
Name: "Integer Time"
@@ -147391,6 +147520,13 @@ item_db: (
Weight: 10
Script: <" getrandgroupitem 22838,1; ">
},
+{
+ Id: 22876
+ AegisName: "Old_Money_Pocket"
+ Name: "Old Money Pocket"
+ Type: "IT_USABLE"
+ Script: <" Zeny += rand(500, 550); ">
+},
//== Shadow Equipments =====================================
{
@@ -150327,6 +150463,37 @@ item_db: (
">
},
+//== New Cards
+
+{
+ Id: 27164
+ AegisName: "Faceworm_Queen_Card"
+ Name: "Faceworm Queen Card"
+ Type: "IT_CARD"
+ Buy: 20
+ Weight: 10
+ Loc: 64
+ Script: <"
+ bonus(bMaxHPrate, -10);
+ bonus(bCritical, 15 + getrefine());
+ bonus(bCritAtkRate, getrefine());
+ ">
+},
+{
+ Id: 27182
+ AegisName: "Captain_Felock_Card"
+ Name: "Captain Felock Card"
+ Type: "IT_CARD"
+ Buy: 20
+ Weight: 10
+ Loc: "EQP_WEAPON"
+ Script: <"
+ bonus(bAtk, 30);
+ bonus2(bSkillAtk, RL_AM_BLAST, getrefine() >= 10 ? 60 : 30);
+ bonus2(bSkillAtk, RL_HAMMER_OF_GOD, getrefine() >= 10 ? 60 : 30);
+ ">
+},
+
//== New Katars ============================================
{
Id: 28000
diff --git a/db/re/mob_db.conf b/db/re/mob_db.conf
index 188654cf8..e90b478e7 100644
--- a/db/re/mob_db.conf
+++ b/db/re/mob_db.conf
@@ -65595,13 +65595,215 @@ mob_db: (
//2526,E_BANDIT
//2527,ME_ANOPHELES
//2528,FACEWORM
-//2529,FACEWORM_QUEEN
+{
+ Id: 2529
+ SpriteName: "FACEWORM_QUEEN"
+ Name: "Faceworm Queen"
+ Lv: 155
+ Hp: 50000000
+ Sp: 1
+ Exp: 200000
+ JExp: 200000
+ AttackRange: 2
+ Attack: [4024, 1609]
+ Def: 100
+ Mdef: 60
+ Stats: {
+ Str: 200
+ Agi: 100
+ Vit: 200
+ Int: 200
+ Dex: 200
+ Luk: 100
+ }
+ ViewRange: 10
+ ChaseRange: 12
+ Size: "Size_Large"
+ Race: "RC_Insect"
+ Element: ("Ele_Poison", 4)
+ Mode: {
+ CanMove: true
+ Aggressive: true
+ CastSensorIdle: true
+ CanAttack: true
+ CastSensorChase: true
+ ChangeChase: true
+ ChangeTargetMelee: true
+ ChangeTargetChase: true
+ }
+ MoveSpeed: 200
+ AttackDelay: 768
+ AttackMotion: 540
+ DamageMotion: 480
+ MvpExp: 90909
+ MvpDrops: {
+ Old_Violet_Box: 2500
+ Magic_Card_Album: 2500
+ }
+ Drops: {
+ Yggdrasilberry: 1000
+ FaceWormQueen_Leg: 100
+ Broken_Horn: 5000
+ Faceworm_Queen_Card: 1
+ }
+},
//2530,FACEWORM_DARK
//2531,VENOM_BUG
//2532,FACEWORM_QUEEN_R
-//2533,FACEWORM_QUEEN_G
-//2534,FACEWORM_QUEEN_B
-//2535,FACEWORM_QUEEN_Y
+{
+ Id: 2533
+ SpriteName: "FACEWORM_QUEEN_G"
+ Name: "Faceworm Queen (Green)"
+ Lv: 155
+ Hp: 50000000
+ Sp: 1
+ Exp: 200000
+ JExp: 200000
+ AttackRange: 2
+ Attack: [5000, 2000]
+ Def: 500
+ Mdef: 60
+ Stats: {
+ Str: 200
+ Agi: 100
+ Vit: 400
+ Int: 200
+ Dex: 200
+ Luk: 100
+ }
+ ViewRange: 10
+ ChaseRange: 12
+ Size: "Size_Large"
+ Race: "RC_Insect"
+ Element: ("Ele_Earth", 1)
+ Mode: {
+ CanMove: true
+ Aggressive: true
+ CastSensorIdle: true
+ CanAttack: true
+ CastSensorChase: true
+ ChangeChase: true
+ ChangeTargetMelee: true
+ ChangeTargetChase: true
+ }
+ MoveSpeed: 200
+ AttackDelay: 768
+ AttackMotion: 540
+ DamageMotion: 480
+ MvpExp: 90909
+ MvpDrops: {
+ Old_Violet_Box: 2500
+ Magic_Card_Album: 2500
+ }
+ Drops: {
+ Broken_Horn: 5000
+ FaceWormQueen_Leg: 100
+ Great_Nature: 5000
+ }
+},
+{
+ Id: 2534
+ SpriteName: "FACEWORM_QUEEN_B"
+ Name: "Faceworm Queen (Blue)"
+ Lv: 155
+ Hp: 50000000
+ Sp: 1
+ Exp: 200000
+ JExp: 200000
+ AttackRange: 2
+ Attack: [5000, 2000]
+ Def: 100
+ Mdef: 400
+ Stats: {
+ Str: 200
+ Agi: 100
+ Vit: 200
+ Int: 400
+ Dex: 200
+ Luk: 100
+ }
+ ViewRange: 10
+ ChaseRange: 12
+ Size: "Size_Large"
+ Race: "RC_Insect"
+ Element: ("Ele_Water", 1)
+ Mode: {
+ CanMove: true
+ Aggressive: true
+ CastSensorIdle: true
+ CanAttack: true
+ CastSensorChase: true
+ ChangeChase: true
+ ChangeTargetMelee: true
+ ChangeTargetChase: true
+ }
+ MoveSpeed: 200
+ AttackDelay: 768
+ AttackMotion: 540
+ DamageMotion: 480
+ MvpExp: 90909
+ MvpDrops: {
+ Old_Violet_Box: 2500
+ Magic_Card_Album: 2500
+ }
+ Drops: {
+ Broken_Horn: 5000
+ FaceWormQueen_Leg: 100
+ Mistic_Frozen: 5000
+ }
+},
+{
+ Id: 2535
+ SpriteName: "FACEWORM_QUEEN_Y"
+ Name: "Faceworm Queen (Yellow)"
+ Lv: 155
+ Hp: 50000000
+ Sp: 1
+ Exp: 200000
+ JExp: 200000
+ AttackRange: 2
+ Attack: [5000, 2000]
+ Def: 100
+ Mdef: 60
+ Stats: {
+ Str: 200
+ Agi: 400
+ Vit: 200
+ Int: 200
+ Dex: 200
+ Luk: 100
+ }
+ ViewRange: 10
+ ChaseRange: 12
+ Size: "Size_Large"
+ Race: "RC_Insect"
+ Element: ("Ele_Wind", 1)
+ Mode: {
+ CanMove: true
+ Aggressive: true
+ CastSensorIdle: true
+ CanAttack: true
+ CastSensorChase: true
+ ChangeChase: true
+ ChangeTargetMelee: true
+ ChangeTargetChase: true
+ }
+ MoveSpeed: 200
+ AttackDelay: 768
+ AttackMotion: 540
+ DamageMotion: 480
+ MvpExp: 90909
+ MvpDrops: {
+ Old_Violet_Box: 2500
+ Magic_Card_Album: 2500
+ }
+ Drops: {
+ Broken_Horn: 5000
+ FaceWormQueen_Leg: 100
+ Rough_Wind: 5000
+ }
+},
+
//2536,HIDDEN_MOB3
//2537,HIDDEN_MOB4
//2538,E_KING_PORING
@@ -83446,7 +83648,62 @@ mob_db: (
//2993,XM_HYLOZOIST
//2994,XM_MARIONETTE
//2995,XM_TEDDY_BEAR
-//2996,XM_CELINE_KIMI
+{
+ Id: 2996
+ SpriteName: "XM_CELINE_KIMI"
+ Name: "Celine Kimi"
+ Lv: 160
+ Hp: 66666666
+ Sp: 1
+ Exp: 4444444
+ JExp: 4033332
+ AttackRange: 2
+ Attack: [5636, 8303]
+ Def: 479
+ Mdef: 444
+ Stats: {
+ Str: 144
+ Agi: 166
+ Vit: 44
+ Int: 444
+ Dex: 166
+ Luk: 166
+ }
+ ViewRange: 10
+ ChaseRange: 12
+ Size: "Size_Large"
+ Race: "RC_Undead"
+ Element: ("Ele_Ghost", 1)
+ Mode: {
+ CanMove: true
+ Aggressive: true
+ CastSensorIdle: true
+ CanAttack: true
+ CastSensorChase: true
+ ChangeChase: true
+ ChangeTargetMelee: true
+ ChangeTargetChase: true
+ }
+ MoveSpeed: 100
+ AttackDelay: 768
+ AttackMotion: 1056
+ DamageMotion: 480
+ MvpExp: 444444
+ MvpDrops: {
+ Old_Card_Album: 10000
+ Old_Violet_Box: 10000
+ Closedmind_Box: 10000
+ }
+ Drops: {
+ Closedmind_Box: 4000
+ Butterfly_Hairpin: 4000
+ Bloody_Coin: 4000
+ C_Red_Bonnet: 100
+ Old_Parasol: 100
+ Flower: 10000
+ }
+},
+
//2997,G_XM_CELINE_KIMI
//2998,EP14_MORS_EVENT
//2999,EP14_MORS_BOSSA
@@ -83479,7 +83736,50 @@ mob_db: (
//3026,FIREPIT
//3027,FULBUK
//3028,SONIA
-//3029,GRIM_REAPER_ANKOU
+{
+ Id: 3029
+ SpriteName: "GRIM_REAPER_ANKOU"
+ Name: "Grim Reaper Ankou"
+ Lv: 159
+ Hp: 50000000
+ Sp: 1553
+ Exp: 300000
+ JExp: 330000
+ AttackRange: 1
+ Attack: [1500, 2500]
+ Def: 200
+ Mdef: 70
+ Stats: {
+ Str: 200
+ Agi: 100
+ Vit: 200
+ Int: 200
+ Dex: 220
+ Luk: 100
+ }
+ ViewRange: 10
+ ChaseRange: 12
+ Size: "Size_Large"
+ Race: "RC_Undead"
+ Element: ("Ele_Undead", 4)
+ Mode: {
+ CanMove: true
+ Aggressive: true
+ CanAttack: true
+ }
+ MoveSpeed: 200
+ AttackDelay: 900
+ AttackMotion: 864
+ DamageMotion: 480
+ MvpExp: 0
+ Drops: {
+ Yggdrasilberry: 500
+ Old_Blue_Box: 200
+ Branch_Of_Dead_Tree: 200
+ PrizeOfHero: 10000
+ Fruit_Of_Mastela: 200
+ }
+},
//3030,STANDING_SOUL
//3031,MUTANT_NECROMANCER
//3032,MUTANT_GHOUL
@@ -83624,7 +83924,80 @@ mob_db: (
//3155,REPAIR_ROBOT
//3156,EXPLORATION_ROVER
//3166,M_E_DEVILING
-//
+{
+ Id: 3181
+ SpriteName: "E1_FELOCK"
+ Name: "Captain Ferlock"
+ Lv: 130
+ Hp: 3000000
+ Sp: 1
+ Exp: 3088
+ JExp: 333333
+ AttackRange: 10
+ ViewRange: 10
+ ChaseRange: 12
+ Size: "Size_Large"
+ Race: "RC_Dragon"
+ Element: ("Ele_Dark", 2)
+ Mode: {
+ CanMove: true
+ CanAttack: true
+ }
+ MoveSpeed: 170
+ AttackDelay: 1018
+ AttackMotion: 1008
+ DamageMotion: 300
+ MvpExp: 0
+ Drops: {
+ Felock_Armor: 100
+ Felock_Cape: 100
+ Felock_Boots: 100
+ Vit_Dish07: 3000
+ Str_Dish07: 3000
+ Agi_Dish07: 3000
+ Int_Dish07: 3000
+ Dex_Dish07: 3000
+ Captain_Felock_Card: 1
+ }
+},
+{
+ Id: 3190
+ SpriteName: "MM_SARAH"
+ Name: "Sarah"
+ Lv: 160
+ Hp: 100000000
+ Sp: 1
+ AttackRange: 12
+ Attack: [1090, 2755]
+ Def: 276
+ Mdef: 255
+ Stats: {
+ Str: 43
+ Agi: 161
+ Vit: 6
+ Int: 188
+ Dex: 225
+ Luk: 136
+ }
+ ViewRange: 10
+ ChaseRange: 12
+ Size: "Size_Medium"
+ Race: "RC_Human"
+ Element: ("Ele_Neutral", 1)
+ Mode: {
+ Aggressive: true
+ Boss: true
+ CanAttack: true
+ }
+ MoveSpeed: 2000
+ AttackDelay: 500
+ AttackMotion: 500
+ Drops: {
+ Robe_Of_Sarah: 1000
+ Sarah_Card: 1
+ }
+},
+
/*{
Id: 3201
SpriteName: "JT_LUCKYCASE"
diff --git a/doc/constants.md b/doc/constants.md
index 490d393f2..fd2be7fb8 100644
--- a/doc/constants.md
+++ b/doc/constants.md
@@ -3854,6 +3854,55 @@
- `HAT_EF_FSTONE`: 55
- `HAT_EF_MAGICCIRCLE`: 56
+### Achievement Types
+
+- `ACH_QUEST`: 0
+- `ACH_KILL_PC_TOTAL`: 1
+- `ACH_KILL_PC_JOB`: 2
+- `ACH_KILL_PC_JOBTYPE`: 3
+- `ACH_KILL_MOB_CLASS`: 4
+- `ACH_DAMAGE_PC_MAX`: 5
+- `ACH_DAMAGE_PC_TOTAL`: 6
+- `ACH_DAMAGE_PC_REC_MAX`: 7
+- `ACH_DAMAGE_PC_REC_TOTAL`: 8
+- `ACH_DAMAGE_MOB_MAX`: 9
+- `ACH_DAMAGE_MOB_TOTAL`: 10
+- `ACH_DAMAGE_MOB_REC_MAX`: 11
+- `ACH_DAMAGE_MOB_REC_TOTAL`: 12
+- `ACH_JOB_CHANGE`: 13
+- `ACH_STATUS`: 14
+- `ACH_STATUS_BY_JOB`: 15
+- `ACH_STATUS_BY_JOBTYPE`: 16
+- `ACH_CHATROOM_CREATE_DEAD`: 17
+- `ACH_CHATROOM_CREATE`: 18
+- `ACH_CHATROOM_MEMBERS`: 19
+- `ACH_FRIEND_ADD`: 20
+- `ACH_PARTY_CREATE`: 21
+- `ACH_PARTY_JOIN`: 22
+- `ACH_MARRY`: 23
+- `ACH_ADOPT_BABY`: 24
+- `ACH_ADOPT_PARENT`: 25
+- `ACH_ZENY_HOLD`: 26
+- `ACH_ZENY_GET_ONCE`: 27
+- `ACH_ZENY_GET_TOTAL`: 28
+- `ACH_ZENY_SPEND_ONCE`: 29
+- `ACH_ZENY_SPEND_TOTAL`: 30
+- `ACH_EQUIP_REFINE_SUCCESS`: 31
+- `ACH_EQUIP_REFINE_FAILURE`: 32
+- `ACH_EQUIP_REFINE_SUCCESS_TOTAL`: 33
+- `ACH_EQUIP_REFINE_FAILURE_TOTAL`: 34
+- `ACH_EQUIP_REFINE_SUCCESS_WLV`: 35
+- `ACH_EQUIP_REFINE_FAILURE_WLV`: 36
+- `ACH_EQUIP_REFINE_SUCCESS_ID`: 37
+- `ACH_EQUIP_REFINE_FAILURE_ID`: 38
+- `ACH_ITEM_GET_COUNT`: 39
+- `ACH_ITEM_GET_COUNT_ITEMTYPE`: 40
+- `ACH_ITEM_GET_WORTH`: 41
+- `ACH_ITEM_SELL_WORTH`: 42
+- `ACH_PET_CREATE`: 43
+- `ACH_ACHIEVE`: 44
+- `ACH_ACHIEVEMENT_RANK`: 45
+
## Hardcoded Constants (source)
@@ -7423,6 +7472,10 @@
- `NG_BAPHOMET`: 2483
- `G_NG_BAPHOMET_`: 2484
- `NG_CHIMERA`: 2485
+- `FACEWORM_QUEEN`: 2529
+- `FACEWORM_QUEEN_G`: 2533
+- `FACEWORM_QUEEN_B`: 2534
+- `FACEWORM_QUEEN_Y`: 2535
- `IRENE_ELDER`: 2542
- `PAYONSOLDIER`: 2543
- `PAYONSOLDIER2`: 2544
@@ -7790,7 +7843,11 @@
- `FATAL_DAYS`: 2958
- `TORTUROUS_REDEEMER`: 2959
- `E_TORTUROUS_REDEEMER`: 2961
+- `XM_CELINE_KIMI`: 2996
+- `GRIM_REAPER_ANKOU`: 3029
- `TIMEHOLDER`: 3074
+- `E1_FELOCK`: 3181
+- `MM_SARAH`: 3190
- `ORGANIC_JAKK`: 3202
- `INORGANIC_JAKK`: 3203
- `DARK_SOUL`: 3381
@@ -12303,6 +12360,7 @@
- `High_Purity_Energy_Xtal`: 6625
- `Blacksmith_Blessing`: 6635
- `Poring_Badge`: 6646
+- `Broken_Horn`: 6649
- `Needle_And_Thread`: 6654
- `Firm_Pumpkin`: 6655
- `Goast_Free_Charm`: 6656
@@ -12963,6 +13021,7 @@
- `Father_Giftbox`: 7637
- `Tw_Green_Box`: 7638
- `Tw_Red_Box`: 7639
+- `Bloody_Coin`: 7642
- `RO_Luk_Bookmark`: 7646
- `Taiwan_Luk_Coin`: 7647
- `Snake_Bookmark`: 7648
@@ -14337,6 +14396,7 @@
- `Peony_Mommy`: 12813
- `Slapping_Herb`: 12814
- `Yggdrasil_Dust`: 12815
+- `Old_Card_Album_`: 12817
- `High_Weapon_Box_`: 12818
- `Zherlthsh_Tck_Box_`: 12819
- `Mao_Guai_Scroll`: 12820
@@ -14552,6 +14612,7 @@
- `Octo_kitchen_Knife`: 13081
- `TE_Woe_Knife`: 13083
- `Goldsmithing_Dagger`: 13086
+- `FaceWormQueen_Leg`: 13090
- `RWC_Memory_Knife`: 13092
- `Thanos_Dagger`: 13093
- `Dagger_Of_Evil_Slayer`: 13094
@@ -15804,6 +15865,7 @@
- `Gray_Robe`: 15091
- `Airship_Armor`: 15116
- `Felock_Armor`: 15117
+- `Robe_Of_Sarah`: 15121
- `Whikebain_Suit`: 15123
- `Female_Poring_Balloon`: 15126
- `Female_Poring_Egg`: 15128
@@ -15948,7 +16010,9 @@
- `Red_Wing_Hat_Box`: 16461
- `FRed_Wing_Hat_Box`: 16462
- `My_Scroll2`: 16466
+- `Abrasive_Box_10`: 16483
- `E_Insurance_Package`: 16503
+- `Bubble_Gum_Box_10`: 16504
- `Xmas_Bless`: 16542
- `Snowman_Hat_Box`: 16543
- `FSnowman_Hat_Box`: 16544
@@ -17536,6 +17600,8 @@
- `Para_Team_Mark_`: 22508
- `Candy_Holder`: 22514
- `Key_Of_Twisted_Time`: 22515
+- `Closedmind_Box`: 22534
+- `PrizeOfHero`: 22537
- `Runstone_Lux`: 22540
- `HALLOWEEN_G_BOX`: 22669
- `DARK_INVITATION`: 22670
@@ -17558,8 +17624,10 @@
- `Bullet_Case_Stone`: 22748
- `Sanctified_Bullet_Case`: 22749
- `Buff_Gift_Set`: 22777
+- `Special_Gift_Box`: 22808
- `Integer_Time`: 22837
- `Something_Candy_Holder`: 22838
+- `Old_Money_Pocket`: 22876
- `T1_Shadow_Armor`: 24000
- `T1_Shadow_Weapon`: 24001
- `T1_Shadow_Shield`: 24002
@@ -17807,6 +17875,8 @@
- `S_Reload_Shield`: 24244
- `S_Reload_Armor`: 24245
- `Paradise_Foxtail_Staff_III`: 26101
+- `Faceworm_Queen_Card`: 27164
+- `Captain_Felock_Card`: 27182
- `Thanos_Katar`: 28000
- `Katar_Of_Evil_Slayer`: 28001
- `Half_BF_Katar2`: 28002
diff --git a/sql-files/item_db.sql b/sql-files/item_db.sql
index 7bd5a5012..da69f9fd3 100644
--- a/sql-files/item_db.sql
+++ b/sql-files/item_db.sql
@@ -6198,6 +6198,8 @@ REPLACE INTO `item_db` VALUES ('16257','Buddah_Scroll','Buddah Scroll','2','0','
REPLACE INTO `item_db` VALUES ('16304','Evil_Incarnation_Disable','Evil Incarnation','2','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','475',NULL,'0',NULL,'0',NULL,'0','packageitem();','','');
REPLACE INTO `item_db` VALUES ('16371','Tw_Aug_Scroll','Tw Aug Scroll','2','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','73',NULL,'0',NULL,'0',NULL,'0','packageitem();','','');
REPLACE INTO `item_db` VALUES ('16461','Red_Wing_Hat_Box','Red Wing Hat Box','18','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','73',NULL,'0',NULL,'0',NULL,'0','getitem 5690,1;','','');
+REPLACE INTO `item_db` VALUES ('16483','Abrasive_Box_10','Abrasive Box (10)','2','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','getitem(E_Abrasive, 10);','','');
+REPLACE INTO `item_db` VALUES ('16504','Bubble_Gum_Box_10','Bubble Gum Box(10)','18','0','10','5','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','getitem(Bubble_Gum, 10);','','');
REPLACE INTO `item_db` VALUES ('16555','Pr_Reset_Stone_Box','Pr Reset Stone Box','2','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','73',NULL,'0',NULL,'0',NULL,'0','packageitem();','','');
REPLACE INTO `item_db` VALUES ('16776','Universal_Catalog_Gold_Box10_','Universal Catalog Gold 10 Box','2','0','0','0','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','getitem 12581,10;','','');
REPLACE INTO `item_db` VALUES ('16777','Universal_Catalog_Gold_Box50','Universal Catalog Gold 50 Box','2','0','0','0','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','getitem 12581,50;','','');
@@ -6237,4 +6239,6 @@ REPLACE INTO `item_db` VALUES ('19506','T_Valkyrie_Feather_Band','T Valkyrie Fea
REPLACE INTO `item_db` VALUES ('19507','Fine_Sun','Clear Sun','5','0','0','0','0','0','0','0','0','0','18446744073709551615','63','2','1024','0','1',NULL,'0','0','654','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','','','');
REPLACE INTO `item_db` VALUES ('22540','Runstone_Lux','Lux Anima Rune','11','0','2','1','100','0','0','0','0','0','128','8','2','0','0','0',NULL,'0','1','0','0','0','0','60000','475',NULL,'0',NULL,'20','1','0','itemskill RK_LUXANIMA,1;','','');
REPLACE INTO `item_db` VALUES ('22777','Buff_Gift_Set','Buff Gift Set','2','0','20','10','100','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','499',NULL,'0',NULL,'0',NULL,'0','getitem 14534,5; getitem 12215,5; getitem 12216,5;','','');
+REPLACE INTO `item_db` VALUES ('22808','Special_Gift_Box','Special Gift Box','2','0','10','5','100','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','','','');
REPLACE INTO `item_db` VALUES ('22837','Integer_Time','Integer Time','2','0','0','0','0','0','0','0','0','0','18446744073709551615','63','2','0','0','50',NULL,'0','1','0','0','0','0','0','507',NULL,'0',NULL,'0',NULL,'0','TmpRouletteBronze += 1;','','');
+REPLACE INTO `item_db` VALUES ('22876','Old_Money_Pocket','Old Money Pocket','2','0','0','0','0','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','Zeny += rand(500, 550);','','');
diff --git a/sql-files/item_db_re.sql b/sql-files/item_db_re.sql
index 2d62a7a1e..118a4417b 100644
--- a/sql-files/item_db_re.sql
+++ b/sql-files/item_db_re.sql
@@ -4575,6 +4575,7 @@ REPLACE INTO `item_db` VALUES ('6624','Purified_Energy_Crystal','Purified Energy
REPLACE INTO `item_db` VALUES ('6625','High_Purity_Energy_Xtal','High Energy Crystal','3','0','0','0','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','467',NULL,'0',NULL,'0',NULL,'0','','','');
REPLACE INTO `item_db` VALUES ('6635','Blacksmith_Blessing','Blacksmith\'s Blessing','3','0','20','10','0','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','','','');
REPLACE INTO `item_db` VALUES ('6646','Poring_Badge','Poring Badge','3','0','0','0','0','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','','','');
+REPLACE INTO `item_db` VALUES ('6649','Broken_Horn','Broken Horn','3','0','10','5','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','','','');
REPLACE INTO `item_db` VALUES ('6654','Needle_And_Thread','Needle And Thread','3','0','0','0','0','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','499',NULL,'0',NULL,'0',NULL,'0','','','');
REPLACE INTO `item_db` VALUES ('6655','Firm_Pumpkin','Hard Pumpkin','3','0','0','0','0','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','499',NULL,'0',NULL,'0',NULL,'0','','','');
REPLACE INTO `item_db` VALUES ('6656','Goast_Free_Charm','Controlling Amulet','3','0','0','0','0','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','499',NULL,'0',NULL,'0',NULL,'0','','','');
@@ -5235,6 +5236,7 @@ REPLACE INTO `item_db` VALUES ('7636','Magic_Potion_Bottle','Magic Potion Bottle
REPLACE INTO `item_db` VALUES ('7637','Father_Giftbox','Father Gift Box','3','0','0','0','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','','','');
REPLACE INTO `item_db` VALUES ('7638','Tw_Green_Box','Green Box','3','0','0','0','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','','','');
REPLACE INTO `item_db` VALUES ('7639','Tw_Red_Box','Red Box','3','0','0','0','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','','','');
+REPLACE INTO `item_db` VALUES ('7642','Bloody_Coin','Bloody Coin','3','0','10','5','0','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','','','');
REPLACE INTO `item_db` VALUES ('7646','RO_Luk_Bookmark','RO Luk Bookmark','3','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','','','');
REPLACE INTO `item_db` VALUES ('7647','Taiwan_Luk_Coin','Taiwan Luk Coin','3','0','0','0','0','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','','','');
REPLACE INTO `item_db` VALUES ('7648','Snake_Bookmark','Snake Bookmark','3','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','','','');
@@ -6320,7 +6322,7 @@ REPLACE INTO `item_db` VALUES ('12510','E_WOB_Local','Blue Butterfly wings','2',
REPLACE INTO `item_db` VALUES ('12511','E_Siege_Teleport_Scroll','E Siege Teleport Scroll','2','0','0','0','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','','','');
REPLACE INTO `item_db` VALUES ('12512','E_Greed_Scroll','E Greed Scroll','2','0','0','0','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','','','');
REPLACE INTO `item_db` VALUES ('12513','E_Glass_Of_Illusion','E Glass Of Illusion','2','0','0','0','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','','','');
-REPLACE INTO `item_db` VALUES ('12514','E_Abrasive','E Abrasive','2','0','0','0','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','475',NULL,'0',NULL,'0',NULL,'0','','','');
+REPLACE INTO `item_db` VALUES ('12514','E_Abrasive','E Abrasive','2','0','0','0','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','475',NULL,'0',NULL,'0',NULL,'0','autobonus(\"{ bonus(bCriticalRate, 30); }\", 100, 1000);','','');
REPLACE INTO `item_db` VALUES ('12515','E_Med_Life_Potion','E Med Life Potion','2','0','0','0','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','','','');
REPLACE INTO `item_db` VALUES ('12516','E_Small_Life_Potion','E Small Life Potion','2','0','0','0','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','475',NULL,'0',NULL,'0',NULL,'0','','','');
REPLACE INTO `item_db` VALUES ('12517','E_Regeneration_Potion','E Regeneration Potion','2','0','0','0','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','','','');
@@ -6609,6 +6611,7 @@ REPLACE INTO `item_db` VALUES ('12812','Snow_Flip','Snow Flip','11','0','0','0',
REPLACE INTO `item_db` VALUES ('12813','Peony_Mommy','Peony Mamy','11','0','0','0','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','itemskill ECL_PEONYMAMY,1;','','');
REPLACE INTO `item_db` VALUES ('12814','Slapping_Herb','Sadagui','11','0','0','0','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','itemskill ECL_SADAGUI,1;','','');
REPLACE INTO `item_db` VALUES ('12815','Yggdrasil_Dust','Sequoia Dust','11','0','0','0','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','itemskill ECL_SEQUOIADUST,1;','','');
+REPLACE INTO `item_db` VALUES ('12817','Old_Card_Album_','Old Card Album','2','0','0','0','0','0','0','0','0','0','18446744073709551615','63','2','0','0','80',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','','','');
REPLACE INTO `item_db` VALUES ('12818','High_Weapon_Box_','Advanced Weapons Box','2','0','0','0','0','0','0','0','0','0','18446744073709551615','63','2','0','0','100',NULL,'0','1','0','0','0','0','0','507',NULL,'0',NULL,'0',NULL,'0','getitem Level_Up_Box,1;','','');
REPLACE INTO `item_db` VALUES ('12819','Zherlthsh_Tck_Box_','Zherlthsh Ticket Box','2','0','0','0','0','0','0','0','0','0','18446744073709551615','63','2','0','0','150',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','getitem Zherlthsh_Ticket,1;','','');
REPLACE INTO `item_db` VALUES ('12820','Mao_Guai_Scroll','Mao Guai Scroll','11','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','mercenary_create MER_CIVIL_SERVANT, 1800000;','','');
@@ -6824,6 +6827,7 @@ REPLACE INTO `item_db` VALUES ('13079','Metal_Dagger','Metal Dagger','4','1','20
REPLACE INTO `item_db` VALUES ('13081','Octo_kitchen_Knife','Discount knife Octopus','4','1','200000','100000','700','140','0','0','0','3','579821294','1','2','2','4','105',NULL,'1','0','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','','','');
REPLACE INTO `item_db` VALUES ('13083','TE_Woe_Knife','T Woe Knife','4','1','0','0','0','100','100','0','1','0','1049583343','1','2','2','3','40',NULL,'0','0','0','0','0','0','0','499',NULL,'0',NULL,'0',NULL,'0','bonus2 bAddRace,RC_Player,40; bonus2 bAddEff,Eff_Silence,1000;','','');
REPLACE INTO `item_db` VALUES ('13086','Goldsmithing_Dagger','Goldsmithing Dagger','4','1','20','10','500','35','25','0','1','0','41943142','56','2','2','1','0',NULL,'1','0','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','','','');
+REPLACE INTO `item_db` VALUES ('13090','FaceWormQueen_Leg','Faceworm Queen Leg','4','1','20','10','500','180','120','0','1','2','42950383','63','2','2','4','100',NULL,'1','0','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','bonus(bInt, 3); autobonus(\"{ bonus3(bAutoSpell, NPC_EARTHQUAKE, 1, 200); }\", 8, 5000, BF_NORMAL, \"{ specialeffect(EF_POTION_BERSERK, AREA, playerattached()); montransform(FACEWORM_QUEEN, 5000); }\");','','');
REPLACE INTO `item_db` VALUES ('13092','RWC_Memory_Knife','RWC Memory Knife','4','1','1000','500','650','50','0','0','1','1','41943157','1','2','2','3','0',NULL,'1','0','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','bonus bBaseAtk,20*(getrefine()/3); bonus bMatk,20*(getrefine()/3); if(getrefine()>=9) { .@val = 1; bonus4 bAutoSpell,BS_WEAPONPERFECT,1,20,0; } if (getrefine() >= 6) { .@rate = 5*(.@val+1); bonus2 bAddRace, RC_All, .@rate; bonus2 bMagicAddRace, RC_All, .@rate; }','','');
REPLACE INTO `item_db` VALUES ('13093','Thanos_Dagger','Thanatos Dagger','4','1','20','10','800','100','130','0','1','1','941290','56','2','2','4','120',NULL,'1','0','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','bonus bInt,6; bonus bVit,6; bonus bLuk,-6; bonus2 bSPDrainRate,10,5; bonus2 bHPDrainRate,10,5; bonus2 bHPLossRate,100,10000;','','heal -1000,0;');
REPLACE INTO `item_db` VALUES ('13094','Dagger_Of_Evil_Slayer','Evil Slayer Stabber Dagger','4','1','20','10','900','120','0','0','1','1','41943157','56','2','2','3','100',NULL,'1','0','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','bonus2 bAddRace,RC_Demon,10; bonus2 bAddRace,RC_Undead,10; if(getrefine()>=9) { bonus bAtkRate,5; } if(getrefine()>=12) { bonus bAtkRate,7; }','','');
@@ -8076,6 +8080,7 @@ REPLACE INTO `item_db` VALUES ('15090','Armor_Of_Gray','Gray Armor','5','0','0',
REPLACE INTO `item_db` VALUES ('15091','Gray_Robe','Gray Robe','5','0','0','0','1300','0','0','55','0','1','99092','56','2','16','0','120',NULL,'1','0','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','bonus2 bSubEle,Ele_Holy,10+(getrefine()/2);','','');
REPLACE INTO `item_db` VALUES ('15116','Airship_Armor','Armor Of Airship','5','0','20','10','700','0','0','100','0','0','18446744073709551615','63','2','16','0','125',NULL,'1','0','0','0','0','0','0','467',NULL,'0',NULL,'0',NULL,'0','bonus bMaxHP,1000; bonus bMaxSP,100; bonus bMdef,10; bonus bAllStats,1;','','');
REPLACE INTO `item_db` VALUES ('15117','Felock_Armor','Tarlock\'s Armor','5','0','20','10','750','0','0','70','0','0','18446744073709551615','63','2','16','0','125',NULL,'1','0','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','bonus bMaxHP,500; bonus bMaxSP,50; bonus bMdef,10; bonus bAllStats,1; if (getrefine()>=7) { bonus bMaxHP,500; bonus bMaxSP,50; } if (getrefine()>=9) { bonus bMaxHP,200; bonus bMaxSP,20; } if (getrefine()>=12) { bonus bMaxHP,300; bonus bMaxSP,30; }','','');
+REPLACE INTO `item_db` VALUES ('15121','Robe_Of_Sarah','Sarah Combat Robe','5','0','10','5','800','0','0','35','0','1','18446744073709551615','63','2','16','0','145',NULL,'1','0','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','//TODO: Confirm the real rate and additional MAtk autobonus(\"{ bonus(bMatk, 20); }\", 100, (10 + ((getrefine()) ? getrefine() * 8 : 0)) * 1000, BF_MAGIC);','','');
REPLACE INTO `item_db` VALUES ('15123','Whikebain_Suit','Whikebain Suit','5','0','10','5','9000','0','0','56','0','1','4096','56','2','16','0','105',NULL,'1','0','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','bonus3 bAutoSpell,DC_WINKCHARM,1,20; /* Custom - IDRO */ if(getrefine()>4) { bonus bCritAtkRate,4; } if(getrefine()>6) { bonus bCritAtkRate,6; }','','');
REPLACE INTO `item_db` VALUES ('15126','Female_Poring_Balloon','Private Doram Suits','5','0','20','10','700','0','0','80','0','1','0','63','2','16','0','100',NULL,'1','0','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','bonus bMaxHP, 500; bonus bMaxSP, 100; bonus bDex, getrefine() / 3; bonus bInt, getrefine() / 3;','','');
REPLACE INTO `item_db` VALUES ('15128','Female_Poring_Egg','Excellion Suit','5','0','20','10','1000','0','0','100','0','0','18446744073709551615','63','2','16','0','99',NULL,'1','0','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','bonus bVit,6; bonus bMaxHPrate,(getrefine()/3)*4; if(BaseLevel>130) { bonus bVit,4; }','','');
@@ -8220,7 +8225,9 @@ REPLACE INTO `item_db` VALUES ('16457','Tw_Nov_Scroll','Bough Scroll','2','0','2
REPLACE INTO `item_db` VALUES ('16461','Red_Wing_Hat_Box','Red Wing Hat Box','18','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','getitem 5690,1;','','');
REPLACE INTO `item_db` VALUES ('16462','FRed_Wing_Hat_Box','Red Wing Hat Box','18','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','getitem 5690,1;','','');
REPLACE INTO `item_db` VALUES ('16466','My_Scroll2','Egg Of Light Scroll','2','0','20','10','0','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','packageitem();','','');
+REPLACE INTO `item_db` VALUES ('16483','Abrasive_Box_10','Abrasive Box (10)','2','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','getitem(E_Abrasive, 10);','','');
REPLACE INTO `item_db` VALUES ('16503','E_Insurance_Package','E Insurance Package','18','0','20','10','0','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','getitem 12209,10;','','');
+REPLACE INTO `item_db` VALUES ('16504','Bubble_Gum_Box_10','Bubble Gum Box(10)','18','0','10','5','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','getitem(Bubble_Gum, 10);','','');
REPLACE INTO `item_db` VALUES ('16542','Xmas_Bless','Xmas Bless','2','0','20','10','0','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','','','');
REPLACE INTO `item_db` VALUES ('16543','Snowman_Hat_Box','Snowman Hat Box','18','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','475',NULL,'0',NULL,'0',NULL,'0','getitem 5738,1;','','');
REPLACE INTO `item_db` VALUES ('16544','FSnowman_Hat_Box','Snowman Hat Box','18','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','475',NULL,'0',NULL,'0',NULL,'0','getitem 5738,1;','','');
@@ -9808,6 +9815,8 @@ REPLACE INTO `item_db` VALUES ('22085','Elegant_Doram_Shoes','Elegant Doram Shoe
REPLACE INTO `item_db` VALUES ('22508','Para_Team_Mark_','Eden Group Mark','11','0','0','0','0','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','1200000','507',NULL,'0',NULL,'0',NULL,'0','warp \"moc_para01\", 171, 115;','','');
REPLACE INTO `item_db` VALUES ('22514','Candy_Holder','Candy Holder','11','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','','','');
REPLACE INTO `item_db` VALUES ('22515','Key_Of_Twisted_Time','Twisted Key of Time','3','0','10','5','300','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','','','');
+REPLACE INTO `item_db` VALUES ('22534','Closedmind_Box','Closed Mind Box','18','0','10','5','1000','0','0','0','0','0','18446744073709551615','63','2','0','0','1',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','','','');
+REPLACE INTO `item_db` VALUES ('22537','PrizeOfHero','Prize Of Hero','2','0','0','0','100','0','0','0','0','0','18446744073709551615','63','2','0','0','1',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','','','');
REPLACE INTO `item_db` VALUES ('22540','Runstone_Lux','Lux Anima Rune','11','0','2','1','100','0','0','0','0','0','128','56','2','0','0','0',NULL,'0','1','0','0','0','0','60000','475',NULL,'0',NULL,'20','1','0','itemskill RK_LUXANIMA, 1;','','');
REPLACE INTO `item_db` VALUES ('22669','HALLOWEEN_G_BOX','Halloween Box','2','0','0','0','20','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','getrandgroupitem 22669,1;','','');
REPLACE INTO `item_db` VALUES ('22670','DARK_INVITATION','Invitation of Darkness','2','0','10','5','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','.@temp = rand(1,3); if (.@temp == 1) { specialeffect(EF_DEVIL, AREA, playerattached()); warp \"niflheim\",193,186; } else if (.@temp == 2) { specialeffect(EF_DEVIL, AREA, playerattached()); warp \"niflheim\",106,254; } else { specialeffect(EF_DEVIL, AREA, playerattached()); warp \"niflheim\",347,255; }','','');
@@ -9830,8 +9839,10 @@ REPLACE INTO `item_db` VALUES ('22747','Bullet_Case_Electric','Dengeki Shot Cart
REPLACE INTO `item_db` VALUES ('22748','Bullet_Case_Stone','Hearthstone Shot Cartridge','2','0','2','1','250','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','getitem Magical_Stone_Bullet, 500;','','');
REPLACE INTO `item_db` VALUES ('22749','Sanctified_Bullet_Case','Purification Shot Cartridge','2','0','2','1','250','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','getitem Sanctified_Bullet, 500;','','');
REPLACE INTO `item_db` VALUES ('22777','Buff_Gift_Set','Buff Gift Set','2','0','20','10','100','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','475',NULL,'0',NULL,'0',NULL,'0','getitem 14534,5; getitem 12215,5; getitem 12216,5;','','');
+REPLACE INTO `item_db` VALUES ('22808','Special_Gift_Box','Special Gift Box','2','0','10','5','100','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','','','');
REPLACE INTO `item_db` VALUES ('22837','Integer_Time','Integer Time','2','0','0','0','0','0','0','0','0','0','18446744073709551615','63','2','0','0','50',NULL,'0','1','0','0','0','0','0','507',NULL,'0',NULL,'0',NULL,'0','TmpRouletteBronze += 1;','','');
REPLACE INTO `item_db` VALUES ('22838','Something_Candy_Holder','Pumpkin Candy Holder','2','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','getrandgroupitem 22838,1;','','');
+REPLACE INTO `item_db` VALUES ('22876','Old_Money_Pocket','Old Money Pocket','2','0','0','0','0','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','Zeny += rand(500, 550);','','');
REPLACE INTO `item_db` VALUES ('24000','T1_Shadow_Armor','T STR1 Armor Shadow','5','0','10','5','0','0','0','0','0','0','18446744073709551615','63','2','65536','0','0',NULL,'1','0','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','bonus bStr,1;','','');
REPLACE INTO `item_db` VALUES ('24001','T1_Shadow_Weapon','T DEX1 Weapon Shadow','5','0','10','5','0','0','0','0','0','0','18446744073709551615','63','2','131072','0','0',NULL,'1','0','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','bonus bDex,1;','','');
REPLACE INTO `item_db` VALUES ('24002','T1_Shadow_Shield','T LUK1 Shield Shadow','5','0','10','5','0','0','0','0','0','0','18446744073709551615','63','2','262144','0','0',NULL,'1','0','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','bonus bLuk,1;','','');
@@ -10079,6 +10090,8 @@ REPLACE INTO `item_db` VALUES ('24243','S_Reload_Shoes','Reload Shadow Shoes','5
REPLACE INTO `item_db` VALUES ('24244','S_Reload_Shield','Reload Shadow Shield','5','0','10','5','0','0','0','0','0','0','18446744073709551615','63','2','262144','0','0',NULL,'1','0','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','bonus bDelayrate,-1; if (getrefine()>=7) { bonus bDelayrate,-1; } if (getrefine()>=9) { bonus bDelayrate,-1; }','','');
REPLACE INTO `item_db` VALUES ('24245','S_Reload_Armor','Reload Shadow Armor','5','0','10','5','0','0','0','0','0','0','18446744073709551615','63','2','65536','0','0',NULL,'1','0','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','bonus bDelayrate,-1; if (getrefine()>=7) { bonus bDelayrate,-1; } if (getrefine()>=9) { bonus bDelayrate,-1; }','','');
REPLACE INTO `item_db` VALUES ('26101','Paradise_Foxtail_Staff_III','Eden Group Foxtail Staff III','4','10','20','10','0','150','195','0','1','0','0','7','2','2','3','60',NULL,'0','0','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','bonus bDex,5; bonus bInt,5; bonus bLongAtkRate,7;','','');
+REPLACE INTO `item_db` VALUES ('27164','Faceworm_Queen_Card','Faceworm Queen Card','6','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','64','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','bonus(bMaxHPrate, -10); bonus(bCritical, 15 + getrefine()); bonus(bCritAtkRate, getrefine());','','');
+REPLACE INTO `item_db` VALUES ('27182','Captain_Felock_Card','Captain Felock Card','6','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','2','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','bonus(bAtk, 30); bonus2(bSkillAtk, RL_AM_BLAST, getrefine() >= 10 ? 60 : 30); bonus2(bSkillAtk, RL_HAMMER_OF_GOD, getrefine() >= 10 ? 60 : 30);','','');
REPLACE INTO `item_db` VALUES ('28000','Thanos_Katar','Thanatos Katar','4','16','20','10','1800','220','80','0','1','1','4096','56','2','34','4','120',NULL,'1','0','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','bonus bInt,6; bonus bVit,6; bonus bLuk,-6; bonus2 bSPDrainRate,10,5; bonus2 bHPDrainRate,10,5; bonus2 bHPLossRate,100,10000;','','heal -1000,0;');
REPLACE INTO `item_db` VALUES ('28001','Katar_Of_Evil_Slayer','Evil Slayer Ripper Katar','4','16','20','10','1200','120','0','0','1','1','4096','56','2','34','3','100',NULL,'1','0','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','bonus2 bAddRace,RC_Demon,10; bonus2 bAddRace,RC_Undead,10; if(getrefine()>8) { bonus bAtkRate,5; } if(getrefine()>11) { bonus bAtkRate,7; }','','');
REPLACE INTO `item_db` VALUES ('28002','Half_BF_Katar2','Half BF Katar2','4','16','20','10','0','130','0','0','1','0','4096','63','2','34','3','80',NULL,'1','0','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','bonus bStr,1; bonus bDex,1; bonus bLuk,1; bonus2 bAddRace,RC_DemiPlayer,35; bonus bCritAtkRate,10; bonus bAspdRate,3; bonus bUnbreakableWeapon,0;','','');
diff --git a/sql-files/main.sql b/sql-files/main.sql
index d1c6364c6..d29f05a2e 100644
--- a/sql-files/main.sql
+++ b/sql-files/main.sql
@@ -118,6 +118,28 @@ CREATE TABLE IF NOT EXISTS `autotrade_merchants` (
) ENGINE=MyISAM;
--
+-- Table structure for table `char_achievements`
+--
+
+CREATE TABLE `char_achievements` (
+ `char_id` INT(11) UNSIGNED NOT NULL,
+ `ach_id` INT(11) UNSIGNED NOT NULL,
+ `completed_at` INT(10) UNSIGNED NOT NULL DEFAULT '0',
+ `rewarded_at` INT(10) UNSIGNED NOT NULL DEFAULT '0',
+ `obj_0` INT(10) UNSIGNED NOT NULL DEFAULT '0',
+ `obj_1` INT(10) UNSIGNED NOT NULL DEFAULT '0',
+ `obj_2` INT(10) UNSIGNED NOT NULL DEFAULT '0',
+ `obj_3` INT(10) UNSIGNED NOT NULL DEFAULT '0',
+ `obj_4` INT(10) UNSIGNED NOT NULL DEFAULT '0',
+ `obj_5` INT(10) UNSIGNED NOT NULL DEFAULT '0',
+ `obj_6` INT(10) UNSIGNED NOT NULL DEFAULT '0',
+ `obj_7` INT(10) UNSIGNED NOT NULL DEFAULT '0',
+ `obj_8` INT(10) UNSIGNED NOT NULL DEFAULT '0',
+ `obj_9` INT(10) UNSIGNED NOT NULL DEFAULT '0',
+ PRIMARY KEY (`char_id`, `ach_id`)
+) ENGINE=MyISAM;
+
+--
-- Table structure for table `cart_inventory`
--
@@ -221,6 +243,7 @@ CREATE TABLE IF NOT EXISTS `char` (
`hotkey_rowshift` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0',
`attendance_count` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0',
`attendance_timer` BIGINT(20) NULL DEFAULT '0',
+ `title_id` INT(11) UNSIGNED NOT NULL DEFAULT '0',
PRIMARY KEY (`char_id`),
UNIQUE KEY `name_key` (`name`),
KEY `account_id` (`account_id`),
@@ -894,6 +917,8 @@ INSERT IGNORE INTO `sql_updates` (`timestamp`) VALUES (1496588700); -- 2017-06-0
INSERT IGNORE INTO `sql_updates` (`timestamp`) VALUES (1509835214); -- 2017-11-04--10-39.sql
INSERT IGNORE INTO `sql_updates` (`timestamp`) VALUES (1519671456); -- 2018-02-26--15-57.sql
INSERT IGNORE INTO `sql_updates` (`timestamp`) VALUES (1520654809); -- 2018-03-10--04-06.sql
+INSERT IGNORE INTO `sql_updates` (`timestamp`) VALUES (1527964800); -- 2018-06-03--00-10.sql
+INSERT IGNORE INTO `sql_updates` (`timestamp`) VALUES (1528026381); -- 2018-06-03--17-16.sql
INSERT IGNORE INTO `sql_updates` (`timestamp`) VALUES (1528180320); -- 2018-06-05--12-02.sql
INSERT IGNORE INTO `sql_updates` (`timestamp`) VALUES (1532403228); -- 2018-07-24--03-23.sql
--
diff --git a/sql-files/mob_db_re.sql b/sql-files/mob_db_re.sql
index 35a2178de..c6ec23d1e 100644
--- a/sql-files/mob_db_re.sql
+++ b/sql-files/mob_db_re.sql
@@ -1433,6 +1433,10 @@ REPLACE INTO `mob_db` VALUES (2482,'G_MG_KHALITZBURG','Nightmare Khalitzburg','N
REPLACE INTO `mob_db` VALUES (2483,'NG_BAPHOMET','Nightmare Baphomet','Nightmare Baphomet',154,4008000,1,1308530,1002320,1,2794,1260,379,45,120,125,230,85,186,85,10,12,2,6,67,14261,100,768,768,576,198262,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
REPLACE INTO `mob_db` VALUES (2484,'G_NG_BAPHOMET_','Nightmare Baphomet Jr.','Nightmare Baphomet Jr.',141,49675,1,13085,10023,1,1302,558,175,62,52,60,90,40,52,25,10,12,0,6,27,13973,100,868,480,120,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
REPLACE INTO `mob_db` VALUES (2485,'NG_CHIMERA','Nightmare Chimera','Nightmare Chimera',140,528120,1,54260,46980,1,1887,823,159,20,101,76,110,176,182,170,10,12,2,2,63,14229,200,772,672,360,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
+REPLACE INTO `mob_db` VALUES (2529,'FACEWORM_QUEEN','Faceworm Queen','Faceworm Queen',155,50000000,1,200000,200000,2,4024,1609,100,60,200,100,200,200,200,100,10,12,2,4,85,13973,200,768,540,480,90909,617,2500,12246,2500,0,0,607,1000,13090,100,6649,5000,0,0,0,0,0,0,0,0,0,0,0,0,27164,1);
+REPLACE INTO `mob_db` VALUES (2533,'FACEWORM_QUEEN_G','Faceworm Queen (Green)','Faceworm Queen (Green)',155,50000000,1,200000,200000,2,5000,2000,500,60,200,100,400,200,200,100,10,12,2,4,22,13973,200,768,540,480,90909,617,2500,12246,2500,0,0,6649,5000,13090,100,997,5000,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
+REPLACE INTO `mob_db` VALUES (2534,'FACEWORM_QUEEN_B','Faceworm Queen (Blue)','Faceworm Queen (Blue)',155,50000000,1,200000,200000,2,5000,2000,100,400,200,100,200,400,200,100,10,12,2,4,21,13973,200,768,540,480,90909,617,2500,12246,2500,0,0,6649,5000,13090,100,995,5000,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
+REPLACE INTO `mob_db` VALUES (2535,'FACEWORM_QUEEN_Y','Faceworm Queen (Yellow)','Faceworm Queen (Yellow)',155,50000000,1,200000,200000,2,5000,2000,100,60,200,400,200,200,200,100,10,12,2,4,24,13973,200,768,540,480,90909,617,2500,12246,2500,0,0,6649,5000,13090,100,996,5000,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
REPLACE INTO `mob_db` VALUES (2542,'IRENE_ELDER','Irene Elder','Irene Elder',101,433110,1,11360,27032,1,1582,699,145,73,82,36,55,100,182,88,10,12,1,7,20,14261,170,398,384,288,0,0,0,0,0,0,0,12072,300,12082,300,12087,300,12077,300,12092,300,12097,300,7481,2,12129,1,0,0,0,0);
REPLACE INTO `mob_db` VALUES (2543,'PAYONSOLDIER','1st Payon Soldier','1st Payon Soldier',101,20099,1,1083,2688,1,545,51,66,36,20,46,35,35,64,30,10,12,1,7,20,12437,225,398,348,288,0,0,0,0,0,0,0,12054,500,12044,500,12059,500,12069,500,12049,500,12127,250,12064,500,7479,2,0,0,0,0);
REPLACE INTO `mob_db` VALUES (2544,'PAYONSOLDIER2','2nd Payon Soldier','2nd Payon Soldier',101,21099,1,1136,2703,1,697,51,66,36,20,46,25,35,64,30,10,12,1,7,20,12437,200,398,348,288,0,0,0,0,0,0,0,12071,500,12076,500,12091,500,12081,500,12096,500,12086,500,12128,150,7480,2,0,0,0,0);
@@ -1800,7 +1804,11 @@ REPLACE INTO `mob_db` VALUES (2957,'FORGOTTEN_NAME','Forgotten Name','Forgotten
REPLACE INTO `mob_db` VALUES (2958,'FATAL_DAYS','Fatal Days','Fatal Days',120,24240,1,2052,2026,2,1025,403,84,41,100,71,63,85,115,37,10,12,1,6,67,14469,170,720,384,480,0,0,0,0,0,0,0,1038,2500,1050,2500,6672,1500,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
REPLACE INTO `mob_db` VALUES (2959,'TORTUROUS_REDEEMER','Torturous Redeemer','Torturous Redeemer',120,103342,1,10599,8378,1,1253,500,144,28,133,69,72,55,165,44,10,12,1,7,62,14757,200,672,420,360,0,0,0,0,0,0,0,923,2000,6672,10000,6672,10000,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
REPLACE INTO `mob_db` VALUES (2961,'E_TORTUROUS_REDEEMER','Torturous Redeemer','Torturous Redeemer',120,103342,1,1,1,1,1,1,144,28,1,1,1,1,1,1,10,12,1,7,62,14757,200,672,420,360,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
+REPLACE INTO `mob_db` VALUES (2996,'XM_CELINE_KIMI','Celine Kimi','Celine Kimi',160,66666666,1,4444444,4033332,2,5636,8303,479,444,144,166,44,444,166,166,10,12,2,1,28,13973,100,1056,1056,480,444444,616,10000,617,10000,22534,10000,22534,4000,18549,4000,7642,4000,19701,100,13442,100,712,10000,0,0,0,0,0,0,0,0);
+REPLACE INTO `mob_db` VALUES (3029,'GRIM_REAPER_ANKOU','Grim Reaper Ankou','Grim Reaper Ankou',159,50000000,1553,300000,330000,1,1500,2500,200,70,200,100,200,200,220,100,10,12,2,1,89,133,200,900,864,480,0,0,0,0,0,0,0,607,500,603,200,604,200,22537,10000,522,200,0,0,0,0,0,0,0,0,0,0);
REPLACE INTO `mob_db` VALUES (3074,'TIMEHOLDER','Time Holder','Time Holder',170,25000000,1,2291250,1938750,1,5250,2100,288,265,224,152,251,257,402,77,10,12,2,6,80,14261,100,398,384,288,2291250,0,0,0,0,0,0,1095,3000,2121,10,7054,3000,22515,3000,18874,20,16024,5,15089,3,0,0,0,0,4625,1);
+REPLACE INTO `mob_db` VALUES (3181,'E1_FELOCK','Captain Ferlock','Captain Ferlock',130,3000000,1,3088,333333,10,0,0,0,0,0,0,0,0,0,0,10,12,2,9,47,129,170,1018,1008,300,0,0,0,0,0,0,0,15117,100,20744,100,22047,100,12082,3000,12072,3000,12087,3000,12077,3000,12092,3000,0,0,27182,1);
+REPLACE INTO `mob_db` VALUES (3190,'MM_SARAH','Sarah','Sarah',160,100000000,1,0,0,12,1090,2755,276,255,43,161,6,188,225,136,10,12,1,0,20,164,2000,500,500,0,0,0,0,0,0,0,0,15121,1000,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4610,1);
REPLACE INTO `mob_db` VALUES (3202,'ORGANIC_JAKK','Organic Pumpkin','Organic Pumpkin',10,40,1,20,13,1,100,0,160,99,1,1,1,1,999,1,1,1,0,3,21,97,200,398,199,0,0,0,0,0,0,0,0,6804,5000,6804,5000,6804,1000,2267,100,1062,1000,664,100,546,1000,12192,100,0,0,0,0);
REPLACE INTO `mob_db` VALUES (3203,'INORGANIC_JAKK','Inorganic Pumpkin','Inorganic Pumpkin',10,40,1,20,13,1,100,0,160,99,1,1,1,1,999,1,1,1,0,3,21,97,200,398,199,0,0,0,0,0,0,0,0,6805,5000,6805,5000,6805,1000,2267,100,1062,1000,664,100,546,1000,12192,100,0,0,0,0);
REPLACE INTO `mob_db` VALUES (3381,'DARK_SOUL','Dark Soul','Dark Soul',10,20,1,0,0,1,20,20,0,0,1,1,1,1,1,1,1,1,1,6,27,129,100,1960,960,504,0,0,0,0,0,0,0,12192,2000,6914,4000,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
diff --git a/sql-files/upgrades/2018-06-03--00-10.sql b/sql-files/upgrades/2018-06-03--00-10.sql
new file mode 100644
index 000000000..c7f6ac48d
--- /dev/null
+++ b/sql-files/upgrades/2018-06-03--00-10.sql
@@ -0,0 +1,40 @@
+#1527964800
+
+-- This file is part of Hercules.
+-- http://herc.ws - http://github.com/HerculesWS/Hercules
+--
+-- Copyright (C) 2018 Hercules Dev Team
+-- Copyright (C) Smokexyz
+--
+-- Hercules is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+CREATE TABLE `char_achievements` (
+ `char_id` INT(11) UNSIGNED NOT NULL,
+ `ach_id` INT(11) UNSIGNED NOT NULL,
+ `completed_at` INT(10) UNSIGNED NOT NULL DEFAULT '0',
+ `rewarded_at` INT(10) UNSIGNED NOT NULL DEFAULT '0',
+ `obj_0` INT(10) UNSIGNED NOT NULL DEFAULT '0',
+ `obj_1` INT(10) UNSIGNED NOT NULL DEFAULT '0',
+ `obj_2` INT(10) UNSIGNED NOT NULL DEFAULT '0',
+ `obj_3` INT(10) UNSIGNED NOT NULL DEFAULT '0',
+ `obj_4` INT(10) UNSIGNED NOT NULL DEFAULT '0',
+ `obj_5` INT(10) UNSIGNED NOT NULL DEFAULT '0',
+ `obj_6` INT(10) UNSIGNED NOT NULL DEFAULT '0',
+ `obj_7` INT(10) UNSIGNED NOT NULL DEFAULT '0',
+ `obj_8` INT(10) UNSIGNED NOT NULL DEFAULT '0',
+ `obj_9` INT(10) UNSIGNED NOT NULL DEFAULT '0',
+ PRIMARY KEY (`char_id`, `ach_id`)
+) ENGINE=MyISAM;
+
+INSERT INTO `sql_updates` (`timestamp`, `ignored`) VALUES (1527964800, 'No');
diff --git a/sql-files/upgrades/2018-06-03--17-16.sql b/sql-files/upgrades/2018-06-03--17-16.sql
new file mode 100644
index 000000000..e14ca62ca
--- /dev/null
+++ b/sql-files/upgrades/2018-06-03--17-16.sql
@@ -0,0 +1,24 @@
+#1528026381
+
+-- This file is part of Hercules.
+-- http://herc.ws - http://github.com/HerculesWS/Hercules
+--
+-- Copyright (C) 2018 Hercules Dev Team
+-- Copyright (C) Dastgir
+--
+-- Hercules is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+ALTER TABLE `char` ADD `title_id` INT(11) UNSIGNED NOT NULL DEFAULT '0';
+
+INSERT INTO `sql_updates` (`timestamp`, `ignored`) VALUES (1528026381, 'No');
diff --git a/sql-files/upgrades/2018-07-24--03-23.sql b/sql-files/upgrades/2018-07-24--03-23.sql
index 64e29996f..a8d2d8f77 100644
--- a/sql-files/upgrades/2018-07-24--03-23.sql
+++ b/sql-files/upgrades/2018-07-24--03-23.sql
@@ -18,5 +18,5 @@
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
-UPDATE `inventory` SET `identify` = 1, `attribute` = 1 WHERE `card0` = -256 and `identify` = 0
+UPDATE `inventory` SET `identify` = 1, `attribute` = 1 WHERE `card0` = -256 and `identify` = 0;
INSERT INTO `sql_updates` (`timestamp`) VALUES (1532403228);
diff --git a/sql-files/upgrades/index.txt b/sql-files/upgrades/index.txt
index c88ba25d4..705234d01 100644
--- a/sql-files/upgrades/index.txt
+++ b/sql-files/upgrades/index.txt
@@ -45,5 +45,7 @@
2017-11-04--10-39.sql
2018-02-26--15-57.sql
2018-03-10--04-06.sql
+2018-06-03--00-10.sql
+2018-06-03--17-16.sql
2018-06-05--12-02.sql
2018-07-24--03-23.sql
diff --git a/src/char/HPMchar.c b/src/char/HPMchar.c
index 9f075d909..db2c3702e 100644
--- a/src/char/HPMchar.c
+++ b/src/char/HPMchar.c
@@ -27,6 +27,7 @@
#include "char/char.h"
#include "char/geoip.h"
#include "char/inter.h"
+#include "char/int_achievement.h"
#include "char/int_auction.h"
#include "char/int_clan.h"
#include "char/int_elemental.h"
@@ -42,6 +43,7 @@
#include "char/loginif.h"
#include "char/mapif.h"
#include "char/pincode.h"
+
#include "common/HPMi.h"
#include "common/conf.h"
#include "common/console.h"
diff --git a/src/char/Makefile.in b/src/char/Makefile.in
index 49fc8ec92..95c8df813 100644
--- a/src/char/Makefile.in
+++ b/src/char/Makefile.in
@@ -40,12 +40,12 @@ MT19937AR_D = $(THIRDPARTY_D)/mt19937ar
MT19937AR_OBJ = $(MT19937AR_D)/mt19937ar.o
MT19937AR_H = $(MT19937AR_D)/mt19937ar.h
-CHAR_C = char.c HPMchar.c loginif.c mapif.c geoip.c inter.c int_auction.c int_clan.c int_elemental.c int_guild.c \
- int_homun.c int_mail.c int_mercenary.c int_party.c int_pet.c \
+CHAR_C = char.c HPMchar.c loginif.c mapif.c geoip.c inter.c int_achievement.c int_auction.c int_clan.c int_elemental.c \
+ int_guild.c int_homun.c int_mail.c int_mercenary.c int_party.c int_pet.c \
int_quest.c int_rodex.c int_storage.c pincode.c
CHAR_OBJ = $(addprefix obj_sql/, $(patsubst %.c,%.o,$(CHAR_C)))
-CHAR_H = char.h HPMchar.h loginif.h mapif.h geoip.h inter.h int_auction.h int_clan.h int_elemental.h int_guild.h \
- int_homun.h int_mail.h int_mercenary.h int_party.h int_pet.h \
+CHAR_H = char.h HPMchar.h loginif.h mapif.h geoip.h inter.h int_achievement.h int_auction.h int_clan.h int_elemental.h \
+ int_guild.h int_homun.h int_mail.h int_mercenary.h int_party.h int_pet.h \
int_quest.h int_rodex.h int_storage.h pincode.h
CHAR_PH =
diff --git a/src/char/char.c b/src/char/char.c
index 99198fa50..54f6ca7d1 100644
--- a/src/char/char.c
+++ b/src/char/char.c
@@ -37,6 +37,7 @@
#include "char/int_quest.h"
#include "char/int_rodex.h"
#include "char/int_storage.h"
+#include "char/int_achievement.h"
#include "char/inter.h"
#include "char/loginif.h"
#include "char/mapif.h"
@@ -112,6 +113,7 @@ char acc_reg_num_db[32] = "acc_reg_num_db";
char acc_reg_str_db[32] = "acc_reg_str_db";
char char_reg_str_db[32] = "char_reg_str_db";
char char_reg_num_db[32] = "char_reg_num_db";
+char char_achievement_db[256] = "char_achievements";
static struct char_interface char_s;
struct char_interface *chr;
@@ -291,12 +293,18 @@ static void char_set_char_offline(int char_id, int account_id)
}
else
{
- struct mmo_charstatus* cp = (struct mmo_charstatus*) idb_get(chr->char_db_,char_id);
+ struct mmo_charstatus *cp = (struct mmo_charstatus*) idb_get(chr->char_db_, char_id);
+ /* Character Achievements */
+ struct char_achievements *c_ach = (struct char_achievements *) idb_get(inter_achievement->char_achievements, char_id);
inter_guild->CharOffline(char_id, cp?cp->guild_id:-1);
- if (cp)
+ if (cp != NULL)
idb_remove(chr->char_db_,char_id);
+ if (c_ach != NULL) {
+ VECTOR_CLEAR(*c_ach);
+ idb_remove(inter_achievement->char_achievements, char_id);
+ }
if( SQL_ERROR == SQL->Query(inter->sql_handle, "UPDATE `%s` SET `online`='0' WHERE `char_id`='%d' LIMIT 1", char_db, char_id) )
Sql_ShowDebug(inter->sql_handle);
@@ -468,7 +476,7 @@ static int char_mmo_char_tosql(int char_id, struct mmo_charstatus *p)
(p->show_equip != cp->show_equip) || (p->allow_party != cp->allow_party) || (p->font != cp->font) ||
(p->uniqueitem_counter != cp->uniqueitem_counter) || (p->hotkey_rowshift != cp->hotkey_rowshift) ||
(p->clan_id != cp->clan_id) || (p->last_login != cp->last_login) || (p->attendance_count != cp->attendance_count) ||
- (p->attendance_timer != cp->attendance_timer)
+ (p->attendance_timer != cp->attendance_timer) || (p->title_id != cp->title_id)
) {
//Save status
unsigned int opt = 0;
@@ -486,7 +494,8 @@ static int char_mmo_char_tosql(int char_id, struct mmo_charstatus *p)
"`weapon`='%d',`shield`='%d',`head_top`='%d',`head_mid`='%d',`head_bottom`='%d',"
"`last_map`='%s',`last_x`='%d',`last_y`='%d',`save_map`='%s',`save_x`='%d',`save_y`='%d', `rename`='%d',"
"`delete_date`='%lu',`robe`='%d',`slotchange`='%d', `char_opt`='%u', `font`='%u', `uniqueitem_counter` ='%u',"
- "`hotkey_rowshift`='%d',`clan_id`='%d',`last_login`='%"PRId64"',`attendance_count`='%d',`attendance_timer`='%"PRId64"'"
+ "`hotkey_rowshift`='%d',`clan_id`='%d',`last_login`='%"PRId64"',`attendance_count`='%d',`attendance_timer`='%"PRId64"',"
+ "`title_id`='%d'"
" WHERE `account_id`='%d' AND `char_id` = '%d'",
char_db, p->base_level, p->job_level,
p->base_exp, p->job_exp, p->zeny,
@@ -499,6 +508,7 @@ static int char_mmo_char_tosql(int char_id, struct mmo_charstatus *p)
(unsigned long)p->delete_date, // FIXME: platform-dependent size
p->look.robe,p->slotchange,opt,p->font,p->uniqueitem_counter,
p->hotkey_rowshift,p->clan_id,p->last_login, p->attendance_count, p->attendance_timer,
+ p->title_id,
p->account_id, p->char_id) )
{
Sql_ShowDebug(inter->sql_handle);
@@ -1069,7 +1079,7 @@ static int char_mmo_chars_fromsql(struct char_session_data *sd, uint8 *buf)
"`str`,`agi`,`vit`,`int`,`dex`,`luk`,`max_hp`,`hp`,`max_sp`,`sp`,"
"`status_point`,`skill_point`,`option`,`karma`,`manner`,`hair`,`hair_color`,"
"`clothes_color`,`body`,`weapon`,`shield`,`head_top`,`head_mid`,`head_bottom`,`last_map`,`rename`,`delete_date`,"
- "`robe`,`slotchange`,`unban_time`,`sex`"
+ "`robe`,`slotchange`,`unban_time`,`sex`,`title_id`"
" FROM `%s` WHERE `account_id`='%d' AND `char_num` < '%d'", char_db, sd->account_id, MAX_CHARS)
|| SQL_ERROR == SQL->StmtExecute(stmt)
|| SQL_ERROR == SQL->StmtBindColumn(stmt, 0, SQLDT_INT, &p.char_id, sizeof p.char_id, NULL, NULL)
@@ -1112,6 +1122,7 @@ static int char_mmo_chars_fromsql(struct char_session_data *sd, uint8 *buf)
|| SQL_ERROR == SQL->StmtBindColumn(stmt, 37, SQLDT_USHORT, &p.slotchange, sizeof p.slotchange, NULL, NULL)
|| SQL_ERROR == SQL->StmtBindColumn(stmt, 38, SQLDT_TIME, &unban_time, sizeof unban_time, NULL, NULL)
|| SQL_ERROR == SQL->StmtBindColumn(stmt, 39, SQLDT_ENUM, &sex, sizeof sex, NULL, NULL)
+ || SQL_ERROR == SQL->StmtBindColumn(stmt, 40, SQLDT_INT, &p.title_id, sizeof p.title_id, NULL, NULL)
) {
SqlStmt_ShowDebug(stmt);
SQL->StmtFree(stmt);
@@ -1176,7 +1187,8 @@ static int char_mmo_char_fromsql(int char_id, struct mmo_charstatus *p, bool loa
"`status_point`,`skill_point`,`option`,`karma`,`manner`,`party_id`,`guild_id`,`pet_id`,`homun_id`,`elemental_id`,`hair`,"
"`hair_color`,`clothes_color`,`body`,`weapon`,`shield`,`head_top`,`head_mid`,`head_bottom`,`last_map`,`last_x`,`last_y`,"
"`save_map`,`save_x`,`save_y`,`partner_id`,`father`,`mother`,`child`,`fame`,`rename`,`delete_date`,`robe`,`slotchange`,"
- "`char_opt`,`font`,`uniqueitem_counter`,`sex`,`hotkey_rowshift`,`clan_id`,`last_login`, `attendance_count`, `attendance_timer`"
+ "`char_opt`,`font`,`uniqueitem_counter`,`sex`,`hotkey_rowshift`,`clan_id`,`last_login`, `attendance_count`, `attendance_timer`,"
+ "`title_id`"
" FROM `%s` WHERE `char_id`=? LIMIT 1", char_db)
|| SQL_ERROR == SQL->StmtBindParam(stmt, 0, SQLDT_INT, &char_id, sizeof char_id)
|| SQL_ERROR == SQL->StmtExecute(stmt)
@@ -1243,6 +1255,7 @@ static int char_mmo_char_fromsql(int char_id, struct mmo_charstatus *p, bool loa
|| SQL_ERROR == SQL->StmtBindColumn(stmt, 60, SQLDT_INT64, &p->last_login, sizeof p->last_login, NULL, NULL)
|| SQL_ERROR == SQL->StmtBindColumn(stmt, 61, SQLDT_SHORT, &p->attendance_count, sizeof p->attendance_count, NULL, NULL)
|| SQL_ERROR == SQL->StmtBindColumn(stmt, 62, SQLDT_INT64, &p->attendance_timer, sizeof p->attendance_timer, NULL, NULL)
+ || SQL_ERROR == SQL->StmtBindColumn(stmt, 63, SQLDT_INT, &p->title_id, sizeof p->title_id, NULL, NULL)
) {
SqlStmt_ShowDebug(stmt);
SQL->StmtFree(stmt);
@@ -5443,6 +5456,7 @@ static bool char_sql_config_read_pc(const char *filename, const struct config_t
libconfig->setting_lookup_mutable_string(setting, "hotkey_db", hotkey_db, sizeof(hotkey_db));
libconfig->setting_lookup_mutable_string(setting, "scdata_db", scdata_db, sizeof(scdata_db));
libconfig->setting_lookup_mutable_string(setting, "inventory_db", inventory_db, sizeof(inventory_db));
+ libconfig->setting_lookup_mutable_string(setting, "achievement_db", char_achievement_db, sizeof(char_achievement_db));
libconfig->setting_lookup_mutable_string(setting, "cart_db", cart_db, sizeof(cart_db));
libconfig->setting_lookup_mutable_string(setting, "charlog_db", charlog_db, sizeof(charlog_db));
libconfig->setting_lookup_mutable_string(setting, "storage_db", storage_db, sizeof(storage_db));
@@ -6319,6 +6333,7 @@ void char_load_defaults(void)
inter_quest_defaults();
inter_storage_defaults();
inter_rodex_defaults();
+ inter_achievement_defaults();
inter_defaults();
geoip_defaults();
}
diff --git a/src/char/char.h b/src/char/char.h
index 4d816583a..81cab1eaf 100644
--- a/src/char/char.h
+++ b/src/char/char.h
@@ -340,6 +340,7 @@ extern char acc_reg_num_db[32];
extern char acc_reg_str_db[32];
extern char char_reg_str_db[32];
extern char char_reg_num_db[32];
+extern char char_achievement_db[256];
extern int guild_exp_rate;
diff --git a/src/char/int_achievement.c b/src/char/int_achievement.c
new file mode 100644
index 000000000..14311ecf0
--- /dev/null
+++ b/src/char/int_achievement.c
@@ -0,0 +1,252 @@
+/**
+* This file is part of Hercules.
+* http://herc.ws - http://github.com/HerculesWS/Hercules
+*
+* Copyright (C) 2017 Hercules Dev Team
+* Copyright (C) Smokexyz
+*
+* Hercules is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#define HERCULES_CORE
+
+#include "int_achievement.h"
+
+#include "char/char.h"
+#include "char/inter.h"
+#include "char/mapif.h"
+
+#include "common/db.h"
+#include "common/memmgr.h"
+#include "common/mmo.h"
+#include "common/nullpo.h"
+#include "common/showmsg.h"
+#include "common/socket.h"
+#include "common/sql.h"
+#include "common/strlib.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+static struct inter_achievement_interface inter_achievement_s;
+struct inter_achievement_interface *inter_achievement;
+
+/**
+ * Saves changed achievements for a character.
+ * @param[in] char_id character identifier.
+ * @param[out] cp pointer to loaded achievements.
+ * @param[in] p pointer to map-sent character achievements.
+ * @return number of achievements saved.
+ */
+static int inter_achievement_tosql(int char_id, struct char_achievements *cp, const struct char_achievements *p)
+{
+ StringBuf buf;
+ int i = 0, rows = 0;
+
+ nullpo_ret(cp);
+ nullpo_ret(p);
+ Assert_ret(char_id > 0);
+
+ StrBuf->Init(&buf);
+ StrBuf->Printf(&buf, "REPLACE INTO `%s` (`char_id`, `ach_id`, `completed_at`, `rewarded_at`", char_achievement_db);
+ for (i = 0; i < MAX_ACHIEVEMENT_OBJECTIVES; i++)
+ StrBuf->Printf(&buf, ", `obj_%d`", i);
+ StrBuf->AppendStr(&buf, ") VALUES ");
+
+ for (i = 0; i < VECTOR_LENGTH(*p); i++) {
+ int j = 0;
+ bool save = false;
+ struct achievement *pa = &VECTOR_INDEX(*p, i), *cpa = NULL;
+
+ ARR_FIND(0, VECTOR_LENGTH(*cp), j, ((cpa = &VECTOR_INDEX(*cp, j)) && cpa->id == pa->id));
+
+ if (j == VECTOR_LENGTH(*cp))
+ save = true;
+ else if (memcmp(cpa, pa, sizeof(struct achievement)) != 0)
+ save = true;
+
+ if (save) {
+ StrBuf->Printf(&buf, "%s('%d', '%d', '%"PRId64"', '%"PRId64"'", rows ?", ":"", char_id, pa->id, (int64)pa->completed_at, (int64)pa->rewarded_at);
+ for (j = 0; j < MAX_ACHIEVEMENT_OBJECTIVES; j++)
+ StrBuf->Printf(&buf, ", '%d'", pa->objective[j]);
+ StrBuf->AppendStr(&buf, ")");
+ rows++;
+ }
+ }
+
+ if (rows > 0 && SQL_ERROR == SQL->QueryStr(inter->sql_handle, StrBuf->Value(&buf))) {
+ Sql_ShowDebug(inter->sql_handle);
+ StrBuf->Destroy(&buf); // Destroy the buffer.
+ return 0;
+ }
+ // Destroy the buffer.
+ StrBuf->Destroy(&buf);
+
+ if (rows) {
+ ShowInfo("achievements saved for char %d (total: %d, saved: %d)\n", char_id, VECTOR_LENGTH(*p), rows);
+
+ /* Sync with inter-db acheivements. */
+ VECTOR_CLEAR(*cp);
+ VECTOR_ENSURE(*cp, VECTOR_LENGTH(*p), 1);
+ VECTOR_PUSHARRAY(*cp, VECTOR_DATA(*p), VECTOR_LENGTH(*p));
+ }
+
+ return rows;
+}
+
+/**
+ * Retrieves all achievements of a character.
+ * @param[in] char_id character identifier.
+ * @param[out] cp pointer to character achievements structure.
+ * @return true on success, false on failure.
+ */
+static bool inter_achievement_fromsql(int char_id, struct char_achievements *cp)
+{
+ StringBuf buf;
+ char *data;
+ int i = 0, num_rows = 0;
+
+ nullpo_ret(cp);
+
+ Assert_ret(char_id > 0);
+
+ // char_achievements (`char_id`, `ach_id`, `completed_at`, `rewarded_at`, `obj_0`, `obj_2`, ...`obj_9`)
+ StrBuf->Init(&buf);
+ StrBuf->AppendStr(&buf, "SELECT `ach_id`, `completed_at`, `rewarded_at`");
+ for (i = 0; i < MAX_ACHIEVEMENT_OBJECTIVES; i++)
+ StrBuf->Printf(&buf, ", `obj_%d`", i);
+ StrBuf->Printf(&buf, " FROM `%s` WHERE `char_id` = '%d' ORDER BY `ach_id`", char_achievement_db, char_id);
+
+ if (SQL_ERROR == SQL->QueryStr(inter->sql_handle, StrBuf->Value(&buf))) {
+ Sql_ShowDebug(inter->sql_handle);
+ StrBuf->Destroy(&buf);
+ return false;
+ }
+
+ VECTOR_CLEAR(*cp);
+
+ if ((num_rows = (int) SQL->NumRows(inter->sql_handle)) != 0) {
+ int j = 0;
+
+ VECTOR_ENSURE(*cp, num_rows, 1);
+
+ for (i = 0; i < num_rows && SQL_SUCCESS == SQL->NextRow(inter->sql_handle); i++) {
+ struct achievement t_ach = { 0 };
+ SQL->GetData(inter->sql_handle, 0, &data, NULL); t_ach.id = atoi(data);
+ SQL->GetData(inter->sql_handle, 1, &data, NULL); t_ach.completed_at = atoi(data);
+ SQL->GetData(inter->sql_handle, 2, &data, NULL); t_ach.rewarded_at = atoi(data);
+ /* Objectives */
+ for (j = 0; j < MAX_ACHIEVEMENT_OBJECTIVES; j++) {
+ SQL->GetData(inter->sql_handle, j + 3, &data, NULL);
+ t_ach.objective[j] = atoi(data);
+ }
+ /* Add Entry */
+ VECTOR_PUSH(*cp, t_ach);
+ }
+ }
+
+ SQL->FreeResult(inter->sql_handle);
+
+ StrBuf->Destroy(&buf);
+
+ if (num_rows > 0)
+ ShowInfo("achievements loaded for char %d (total: %d)\n", char_id, num_rows);
+
+ return true;
+}
+
+/**
+ * Handles checking of map server packets and calls appropriate functions.
+ * @param fd socket descriptor.
+ * @return 0 on failure, 1 on succes.
+ */
+static int inter_achievement_parse_frommap(int fd)
+{
+ RFIFOHEAD(fd);
+
+ switch (RFIFOW(fd,0)) {
+ case 0x3012:
+ mapif->pLoadAchievements(fd);
+ break;
+ case 0x3013:
+ mapif->pSaveAchievements(fd);
+ break;
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+/**
+ * Initialization function
+ */
+static int inter_achievement_sql_init(void)
+{
+ // Initialize the loaded db storage.
+ // used as a comparand against map-server achievement data before saving.
+ inter_achievement->char_achievements = idb_alloc(DB_OPT_RELEASE_DATA);
+ return 1;
+}
+
+/**
+ * This function ensures idb's entry.
+ */
+static struct DBData inter_achievement_ensure_char_achievements(union DBKey key, va_list args)
+{
+ struct char_achievements *ca = NULL;
+
+ CREATE(ca, struct char_achievements, 1);
+ VECTOR_INIT(*ca);
+
+ return DB->ptr2data(ca);
+}
+
+/**
+ * Cleaning function called through db_destroy()
+ */
+static int inter_achievement_char_achievements_clear(union DBKey key, struct DBData *data, va_list args)
+{
+ struct char_achievements *ca = DB->data2ptr(data);
+
+ VECTOR_CLEAR(*ca);
+
+ return 0;
+}
+
+/**
+ * Finalization function.
+ */
+static void inter_achievement_sql_final(void)
+{
+ inter_achievement->char_achievements->destroy(inter_achievement->char_achievements, inter_achievement->char_achievements_clear);
+}
+
+/**
+ * Inter-achievement interface.
+ */
+void inter_achievement_defaults(void)
+{
+ inter_achievement = &inter_achievement_s;
+ /* */
+ inter_achievement->ensure_char_achievements = inter_achievement_ensure_char_achievements;
+ /* */
+ inter_achievement->sql_init = inter_achievement_sql_init;
+ inter_achievement->sql_final = inter_achievement_sql_final;
+ /* */
+ inter_achievement->tosql = inter_achievement_tosql;
+ inter_achievement->fromsql = inter_achievement_fromsql;
+ /* */
+ inter_achievement->parse_frommap = inter_achievement_parse_frommap;
+ inter_achievement->char_achievements_clear = inter_achievement_char_achievements_clear;
+}
diff --git a/src/char/int_achievement.h b/src/char/int_achievement.h
new file mode 100644
index 000000000..4a44a798d
--- /dev/null
+++ b/src/char/int_achievement.h
@@ -0,0 +1,53 @@
+/**
+* This file is part of Hercules.
+* http://herc.ws - http://github.com/HerculesWS/Hercules
+*
+* Copyright (C) 2017 Hercules Dev Team
+* Copyright (C) Smokexyz
+*
+* Hercules is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef CHAR_INT_ACHIEVEMENT_H
+#define CHAR_INT_ACHIEVEMENT_H
+
+#include "common/hercules.h"
+#include "common/db.h"
+
+struct achievement;
+struct char_achievements;
+
+/**
+ * inter_achievement Interface
+ */
+struct inter_achievement_interface {
+ struct DBMap *char_achievements;
+ /* */
+ int (*sql_init) (void);
+ void (*sql_final) (void);
+ /* */
+ int (*tosql) (int char_id, struct char_achievements *cp, const struct char_achievements *p);
+ bool (*fromsql) (int char_id, struct char_achievements *a);
+ /* */
+ struct DBData(*ensure_char_achievements) (union DBKey key, va_list args);
+ int (*char_achievements_clear) (union DBKey key, struct DBData *data, va_list args);
+ /* */
+ int (*parse_frommap) (int fd);
+};
+
+#ifdef HERCULES_CORE
+void inter_achievement_defaults(void);
+#endif // HERCULES_CORE
+
+HPShared struct inter_achievement_interface *inter_achievement;
+#endif /* CHAR_INT_ACHIEVEMENT_H */
diff --git a/src/char/inter.c b/src/char/inter.c
index 7269009a7..418c9b0a1 100644
--- a/src/char/inter.c
+++ b/src/char/inter.c
@@ -36,6 +36,7 @@
#include "char/int_quest.h"
#include "char/int_rodex.h"
#include "char/int_storage.h"
+#include "char/int_achievement.h"
#include "char/mapif.h"
#include "common/cbasetypes.h"
#include "common/conf.h"
@@ -70,7 +71,7 @@ int party_share_level = 10;
// recv. packet list
static int inter_recv_packet_length[] = {
-1,-1, 7,-1, -1,13,36, (2 + 4 + 4 + 4 + NAME_LENGTH), 0, 0, 0, 0, 0, 0, 0, 0, // 3000-
- 6,-1, 0, 0, 0, 0, 0, 0, 10,-1, 0, 0, 0, 0, 0, 0, // 3010- Account Storage [Smokexyz]
+ 6,-1, 6,-1, 0, 0, 0, 0, 10,-1, 0, 0, 0, 0, 0, 0, // 3010- Account Storage, Achievements [Smokexyz]
-1,10,-1,14, 14,19, 6,-1, 14,14, 0, 0, 0, 0, 0, 0, // 3020- Party
-1, 6,-1,-1, 55,19, 6,-1, 14,-1,-1,-1, 18,19,186,-1, // 3030-
-1, 9, 0, 0, 10,10, 0, 0, 7, 6,10,10, 10,-1, 0, 0, // 3040- Clan System(3044-3045)
@@ -974,6 +975,7 @@ static int inter_init_sql(const char *file)
inter_mail->sql_init();
inter_auction->sql_init();
inter_rodex->sql_init();
+ inter_achievement->sql_init();
geoip->init();
inter->msg_config_read("conf/messages.conf", false);
@@ -995,6 +997,7 @@ static void inter_final(void)
inter_mail->sql_final();
inter_auction->sql_final();
inter_rodex->sql_final();
+ inter_achievement->sql_final();
geoip->final(true);
inter->do_final_msg();
@@ -1133,6 +1136,7 @@ static int inter_parse_frommap(int fd)
|| inter_quest->parse_frommap(fd)
|| inter_rodex->parse_frommap(fd)
|| inter_clan->parse_frommap(fd)
+ || inter_achievement->parse_frommap(fd)
)
break;
else
diff --git a/src/char/mapif.c b/src/char/mapif.c
index 30f8c1178..dc5735550 100644
--- a/src/char/mapif.c
+++ b/src/char/mapif.c
@@ -24,6 +24,7 @@
#include "mapif.h"
#include "char/char.h"
+#include "char/int_achievement.h"
#include "char/int_auction.h"
#include "char/int_clan.h"
#include "char/int_guild.h"
@@ -2346,6 +2347,120 @@ static int mapif_parse_ClanMemberCount(int fd, int clan_id, int kick_interval)
return 0;
}
+// Achievement System
+/**
+ * Parse achievement load request from the map server
+ * @param[in] fd socket descriptor.
+ */
+static void mapif_parse_load_achievements(int fd)
+{
+ int char_id = 0;
+
+ /* Read received information from map-server. */
+ RFIFOHEAD(fd);
+ char_id = RFIFOL(fd, 2);
+
+ /* Load and send achievements to map */
+ mapif->achievement_load(fd, char_id);
+}
+
+/**
+ * Loads achievements and sends to the map server.
+ * @param[in] fd socket descriptor
+ * @param[in] char_id character Id.
+ */
+static void mapif_achievement_load(int fd, int char_id)
+{
+ struct char_achievements *cp = NULL;
+
+ /* Ensure data exists */
+ cp = idb_ensure(inter_achievement->char_achievements, char_id, inter_achievement->ensure_char_achievements);
+
+ /* Load storage for char-server. */
+ inter_achievement->fromsql(char_id, cp);
+
+ /* Send Achievements to map server. */
+ mapif->sAchievementsToMap(fd, char_id, cp);
+}
+
+/**
+ * Sends achievement data of a character to the map server.
+ * @packet[out] 0x3810 <packet_id>.W <payload_size>.W <char_id>.L <char_achievements[]>.P
+ * @param[in] fd socket descriptor.
+ * @param[in] char_id Character ID.
+ * @param[in] cp Pointer to character's achievement data vector.
+ */
+static void mapif_send_achievements_to_map(int fd, int char_id, const struct char_achievements *cp)
+{
+ int i = 0;
+ int data_size = 0;
+
+ nullpo_retv(cp);
+
+ data_size = sizeof(struct achievement) * VECTOR_LENGTH(*cp);
+
+STATIC_ASSERT((sizeof(struct achievement) * MAX_ACHIEVEMENT_DB + 8 <= UINT16_MAX),
+ "The achievements data can potentially be larger than the maximum packet size. This may cause errors at run-time.");
+
+ /* Send to the map server. */
+ WFIFOHEAD(fd, (8 + data_size));
+ WFIFOW(fd, 0) = 0x3810;
+ WFIFOW(fd, 2) = (8 + data_size);
+ WFIFOL(fd, 4) = char_id;
+ for (i = 0; i < VECTOR_LENGTH(*cp); i++)
+ memcpy(WFIFOP(fd, 8 + i * sizeof(struct achievement)), &VECTOR_INDEX(*cp, i), sizeof(struct achievement));
+ WFIFOSET(fd, 8 + data_size);
+}
+
+/**
+ * Handles achievement request and saves data from map server.
+ * @packet[in] 0x3013 <packet_size>.W <char_id>.L <char_achievement>.P
+ * @param[in] fd session socket descriptor.
+ */
+static void mapif_parse_save_achievements(int fd)
+{
+ int size = 0, char_id = 0, payload_count = 0, i = 0;
+ struct char_achievements p = { 0 };
+
+ RFIFOHEAD(fd);
+ size = RFIFOW(fd, 2);
+ char_id = RFIFOL(fd, 4);
+
+ payload_count = (size - 8) / sizeof(struct achievement);
+
+ VECTOR_INIT(p);
+ VECTOR_ENSURE(p, payload_count, 1);
+
+ for (i = 0; i < payload_count; i++) {
+ struct achievement ach = { 0 };
+ memcpy(&ach, RFIFOP(fd, 8 + i * sizeof(struct achievement)), sizeof(struct achievement));
+ VECTOR_PUSH(p, ach);
+ }
+
+ mapif->achievement_save(char_id, &p);
+
+ VECTOR_CLEAR(p);
+}
+
+/**
+ * Handles inter-server achievement db ensuring
+ * and saves current achievements to sql.
+ * @param[in] char_id character identifier.
+ * @param[out] p pointer to character achievements vector.
+ */
+static void mapif_achievement_save(int char_id, struct char_achievements *p)
+{
+ struct char_achievements *cp = NULL;
+
+ nullpo_retv(p);
+
+ /* Get loaded achievements. */
+ cp = idb_ensure(inter_achievement->char_achievements, char_id, inter_achievement->ensure_char_achievements);
+
+ if (VECTOR_LENGTH(*p)) /* Save current achievements. */
+ inter_achievement->tosql(char_id, cp, p);
+}
+
void mapif_defaults(void)
{
mapif = &mapif_s;
@@ -2361,6 +2476,11 @@ void mapif_defaults(void)
mapif->sendallwos = mapif_sendallwos;
mapif->send = mapif_send;
mapif->send_users_count = mapif_send_users_count;
+ mapif->pLoadAchievements = mapif_parse_load_achievements;
+ mapif->sAchievementsToMap = mapif_send_achievements_to_map;
+ mapif->pSaveAchievements = mapif_parse_save_achievements;
+ mapif->achievement_load = mapif_achievement_load;
+ mapif->achievement_save = mapif_achievement_save;
mapif->auction_message = mapif_auction_message;
mapif->auction_sendlist = mapif_auction_sendlist;
mapif->parse_auction_requestlist = mapif_parse_auction_requestlist;
diff --git a/src/char/mapif.h b/src/char/mapif.h
index d67ce1c79..bfdefe4ea 100644
--- a/src/char/mapif.h
+++ b/src/char/mapif.h
@@ -40,6 +40,11 @@ struct mapif_interface {
int (*sendallwos) (int sfd, unsigned char *buf, unsigned int len);
int (*send) (int fd, unsigned char *buf, unsigned int len);
void (*send_users_count) (int users);
+ void (*pLoadAchievements) (int fd);
+ void (*sAchievementsToMap) (int fd, int char_id, const struct char_achievements *p);
+ void (*pSaveAchievements) (int fd);
+ void (*achievement_load) (int fd, int char_id);
+ void (*achievement_save) (int char_id, struct char_achievements *p);
void (*auction_message) (int char_id, unsigned char result);
void (*auction_sendlist) (int fd, int char_id, short count, short pages, unsigned char *buf);
void (*parse_auction_requestlist) (int fd);
diff --git a/src/common/HPMDataCheck.h b/src/common/HPMDataCheck.h
index 7f96954bc..3784661f6 100644
--- a/src/common/HPMDataCheck.h
+++ b/src/common/HPMDataCheck.h
@@ -57,6 +57,11 @@ HPExport const struct s_HPMDataCheck HPMDataCheck[] = {
#else
#define CHAR_INTER_H
#endif // CHAR_INTER_H
+ #ifdef CHAR_INT_ACHIEVEMENT_H
+ { "inter_achievement_interface", sizeof(struct inter_achievement_interface), SERVER_TYPE_CHAR },
+ #else
+ #define CHAR_INT_ACHIEVEMENT_H
+ #endif // CHAR_INT_ACHIEVEMENT_H
#ifdef CHAR_INT_AUCTION_H
{ "inter_auction_interface", sizeof(struct inter_auction_interface), SERVER_TYPE_CHAR },
#else
@@ -199,7 +204,9 @@ HPExport const struct s_HPMDataCheck HPMDataCheck[] = {
#define COMMON_MEMMGR_H
#endif // COMMON_MEMMGR_H
#ifdef COMMON_MMO_H
+ { "achievement", sizeof(struct achievement), SERVER_TYPE_ALL },
{ "auction_data", sizeof(struct auction_data), SERVER_TYPE_ALL },
+ { "char_achievements", sizeof(struct char_achievements), SERVER_TYPE_ALL },
{ "clan", sizeof(struct clan), SERVER_TYPE_ALL },
{ "clan_buff", sizeof(struct clan_buff), SERVER_TYPE_ALL },
{ "clan_member", sizeof(struct clan_member), SERVER_TYPE_ALL },
@@ -371,6 +378,15 @@ HPExport const struct s_HPMDataCheck HPMDataCheck[] = {
#else
#define LOGIN_LOGIN_H
#endif // LOGIN_LOGIN_H
+ #ifdef MAP_ACHIEVEMENT_H
+ { "achievement_data", sizeof(struct achievement_data), SERVER_TYPE_MAP },
+ { "achievement_interface", sizeof(struct achievement_interface), SERVER_TYPE_MAP },
+ { "achievement_objective", sizeof(struct achievement_objective), SERVER_TYPE_MAP },
+ { "achievement_reward_item", sizeof(struct achievement_reward_item), SERVER_TYPE_MAP },
+ { "achievement_rewards", sizeof(struct achievement_rewards), SERVER_TYPE_MAP },
+ #else
+ #define MAP_ACHIEVEMENT_H
+ #endif // MAP_ACHIEVEMENT_H
#ifdef MAP_ATCOMMAND_H
{ "AliasInfo", sizeof(struct AliasInfo), SERVER_TYPE_MAP },
{ "AtCommandInfo", sizeof(struct AtCommandInfo), SERVER_TYPE_MAP },
@@ -690,9 +706,13 @@ HPExport const struct s_HPMDataCheck HPMDataCheck[] = {
{ "PACKET_ZC_USE_ITEM_ACK", sizeof(struct PACKET_ZC_USE_ITEM_ACK), SERVER_TYPE_MAP },
{ "PACKET_ZC_WRITE_MAIL_RESULT", sizeof(struct PACKET_ZC_WRITE_MAIL_RESULT), SERVER_TYPE_MAP },
{ "ZC_PROGRESS_ACTOR", sizeof(struct ZC_PROGRESS_ACTOR), SERVER_TYPE_MAP },
+ { "ach_list_info", sizeof(struct ach_list_info), SERVER_TYPE_MAP },
{ "mail_item", sizeof(struct mail_item), SERVER_TYPE_MAP },
{ "maillistinfo", sizeof(struct maillistinfo), SERVER_TYPE_MAP },
{ "packet_ZC_REFUSE_LOGIN", sizeof(struct packet_ZC_REFUSE_LOGIN), SERVER_TYPE_MAP },
+ { "packet_achievement_list", sizeof(struct packet_achievement_list), SERVER_TYPE_MAP },
+ { "packet_achievement_reward_ack", sizeof(struct packet_achievement_reward_ack), SERVER_TYPE_MAP },
+ { "packet_achievement_update", sizeof(struct packet_achievement_update), SERVER_TYPE_MAP },
{ "packet_additem", sizeof(struct packet_additem), SERVER_TYPE_MAP },
{ "packet_authok", sizeof(struct packet_authok), SERVER_TYPE_MAP },
{ "packet_banking_check", sizeof(struct packet_banking_check), SERVER_TYPE_MAP },
@@ -740,6 +760,8 @@ HPExport const struct s_HPMDataCheck HPMDataCheck[] = {
{ "packet_quest_list_info", sizeof(struct packet_quest_list_info), SERVER_TYPE_MAP },
{ "packet_quest_update_header", sizeof(struct packet_quest_update_header), SERVER_TYPE_MAP },
{ "packet_quest_update_hunt", sizeof(struct packet_quest_update_hunt), SERVER_TYPE_MAP },
+ { "packet_reqname_ack", sizeof(struct packet_reqname_ack), SERVER_TYPE_MAP },
+ { "packet_reqnameall_ack", sizeof(struct packet_reqnameall_ack), SERVER_TYPE_MAP },
{ "packet_roulette_close_ack", sizeof(struct packet_roulette_close_ack), SERVER_TYPE_MAP },
{ "packet_roulette_generate_ack", sizeof(struct packet_roulette_generate_ack), SERVER_TYPE_MAP },
{ "packet_roulette_info_ack", sizeof(struct packet_roulette_info_ack), SERVER_TYPE_MAP },
diff --git a/src/common/HPMSymbols.inc.h b/src/common/HPMSymbols.inc.h
index 70de5cdef..15acb1b06 100644
--- a/src/common/HPMSymbols.inc.h
+++ b/src/common/HPMSymbols.inc.h
@@ -32,6 +32,9 @@ struct HCache_interface *HCache;
#ifdef LOGIN_ACCOUNT_H /* account */
struct account_interface *account;
#endif // LOGIN_ACCOUNT_H
+#ifdef MAP_ACHIEVEMENT_H /* achievement */
+struct achievement_interface *achievement;
+#endif // MAP_ACHIEVEMENT_H
#ifdef MAP_ATCOMMAND_H /* atcommand */
struct atcommand_interface *atcommand;
#endif // MAP_ATCOMMAND_H
@@ -101,6 +104,9 @@ struct homunculus_interface *homun;
#ifdef MAP_INSTANCE_H /* instance */
struct instance_interface *instance;
#endif // MAP_INSTANCE_H
+#ifdef CHAR_INT_ACHIEVEMENT_H /* inter_achievement */
+struct inter_achievement_interface *inter_achievement;
+#endif // CHAR_INT_ACHIEVEMENT_H
#ifdef CHAR_INT_AUCTION_H /* inter_auction */
struct inter_auction_interface *inter_auction;
#endif // CHAR_INT_AUCTION_H
@@ -305,6 +311,10 @@ HPExport const char *HPM_shared_symbols(int server_type)
if ((server_type&(SERVER_TYPE_LOGIN)) != 0 && !HPM_SYMBOL("account", account))
return "account";
#endif // LOGIN_ACCOUNT_H
+#ifdef MAP_ACHIEVEMENT_H /* achievement */
+ if ((server_type&(SERVER_TYPE_MAP)) != 0 && !HPM_SYMBOL("achievement", achievement))
+ return "achievement";
+#endif // MAP_ACHIEVEMENT_H
#ifdef MAP_ATCOMMAND_H /* atcommand */
if ((server_type&(SERVER_TYPE_MAP)) != 0 && !HPM_SYMBOL("atcommand", atcommand))
return "atcommand";
@@ -397,6 +407,10 @@ HPExport const char *HPM_shared_symbols(int server_type)
if ((server_type&(SERVER_TYPE_MAP)) != 0 && !HPM_SYMBOL("instance", instance))
return "instance";
#endif // MAP_INSTANCE_H
+#ifdef CHAR_INT_ACHIEVEMENT_H /* inter_achievement */
+ if ((server_type&(SERVER_TYPE_CHAR)) != 0 && !HPM_SYMBOL("inter_achievement", inter_achievement))
+ return "inter_achievement";
+#endif // CHAR_INT_ACHIEVEMENT_H
#ifdef CHAR_INT_AUCTION_H /* inter_auction */
if ((server_type&(SERVER_TYPE_CHAR)) != 0 && !HPM_SYMBOL("inter_auction", inter_auction))
return "inter_auction";
diff --git a/src/common/mmo.h b/src/common/mmo.h
index 1b9562e9d..7e0d915eb 100644
--- a/src/common/mmo.h
+++ b/src/common/mmo.h
@@ -218,6 +218,16 @@
#define MAX_QUEST_OBJECTIVES 3 // Max quest objectives for a quest
#endif
+// Achievements [Smokexyz/Hercules]
+#ifndef MAX_ACHIEVEMENT_DB
+#define MAX_ACHIEVEMENT_DB 360 // Maximum number of achievements
+#define MAX_ACHIEVEMENT_OBJECTIVES 10 // Maximum number of achievement objectives
+STATIC_ASSERT(MAX_ACHIEVEMENT_OBJECTIVES <= 10, "This value is limited by the client and database layout and should only be increased if you know the consequences.");
+#define MAX_ACHIEVEMENT_RANKS 20 // Achievement Ranks
+STATIC_ASSERT(MAX_ACHIEVEMENT_RANKS <= 255, "This value is limited by the client and database layout and should only be increased if you know the consequences.");
+#define MAX_ACHIEVEMENT_ITEM_REWARDS 10 // Achievement Rewards
+#endif
+
// for produce
#define MIN_ATTRIBUTE 0
#define MAX_ATTRIBUTE 4
@@ -616,6 +626,14 @@ struct hotkey {
#endif
};
+struct achievement { // Achievements [Smokexyz/Hercules]
+ int id;
+ int objective[MAX_ACHIEVEMENT_OBJECTIVES];
+ time_t completed_at, rewarded_at;
+};
+
+VECTOR_STRUCT_DECL(char_achievements, struct achievement);
+
struct mmo_charstatus {
int char_id;
int account_id;
@@ -687,6 +705,8 @@ struct mmo_charstatus {
short attendance_count;
unsigned char hotkey_rowshift;
+
+ int32 title_id; // Achievement Title[Dastgir/Hercules]
};
typedef enum mail_status {
diff --git a/src/map/HPMmap.c b/src/map/HPMmap.c
index e4640d09d..091a53311 100644
--- a/src/map/HPMmap.c
+++ b/src/map/HPMmap.c
@@ -47,6 +47,7 @@
#include "common/sysinfo.h"
#include "common/timer.h"
#include "common/utils.h"
+#include "map/achievement.h"
#include "map/atcommand.h"
#include "map/battle.h"
#include "map/battleground.h"
diff --git a/src/map/Makefile.in b/src/map/Makefile.in
index 7c04a4f37..1bef380e1 100644
--- a/src/map/Makefile.in
+++ b/src/map/Makefile.in
@@ -40,14 +40,14 @@ MT19937AR_D = $(THIRDPARTY_D)/mt19937ar
MT19937AR_OBJ = $(MT19937AR_D)/mt19937ar.o
MT19937AR_H = $(MT19937AR_D)/mt19937ar.h
-MAP_C = atcommand.c battle.c battleground.c buyingstore.c channel.c chat.c \
+MAP_C = achievement.c atcommand.c battle.c battleground.c buyingstore.c channel.c chat.c \
chrif.c clan.c clif.c date.c duel.c elemental.c guild.c homunculus.c HPMmap.c \
instance.c intif.c irc-bot.c itemdb.c log.c mail.c map.c mapreg_sql.c \
mercenary.c mob.c npc.c npc_chat.c party.c path.c pc.c pc_groups.c \
pet.c quest.c rodex.c script.c searchstore.c skill.c status.c storage.c \
trade.c unit.c vending.c
MAP_OBJ = $(addprefix obj_sql/, $(patsubst %c,%o,$(MAP_C)))
-MAP_H = atcommand.h battle.h battleground.h buyingstore.h channel.h chat.h \
+MAP_H = achievement.h atcommand.h battle.h battleground.h buyingstore.h channel.h chat.h \
chrif.h clan.h clif.h date.h duel.h elemental.h guild.h homunculus.h HPMmap.h \
instance.h intif.h irc-bot.h itemdb.h log.h mail.h map.h mapreg.h \
mercenary.h messages.h messages_main.h messages_re.h messages_zero.h \
diff --git a/src/map/achievement.c b/src/map/achievement.c
new file mode 100644
index 000000000..0369b0fb5
--- /dev/null
+++ b/src/map/achievement.c
@@ -0,0 +1,1983 @@
+/**
+* This file is part of Hercules.
+* http://herc.ws - http://github.com/HerculesWS/Hercules
+*
+* Copyright (C) 2017 Hercules Dev Team
+* Copyright (C) Smokexyz
+* Copyright (C) Dastgir
+*
+* Hercules is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#define HERCULES_CORE
+
+#include "map/achievement.h"
+
+#include "map/itemdb.h"
+#include "map/mob.h"
+#include "map/party.h"
+#include "map/pc.h"
+#include "map/script.h"
+
+#include "common/conf.h"
+#include "common/db.h"
+#include "common/memmgr.h"
+#include "common/nullpo.h"
+#include "common/showmsg.h"
+#include "common/strlib.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static struct achievement_interface achievement_s;
+struct achievement_interface *achievement;
+
+/**
+ * Retrieve an achievement via it's ID.
+ * @param aid as the achievement ID.
+ * @return NULL or pointer to the achievement data.
+ */
+static const struct achievement_data *achievement_get(int aid)
+{
+ return (struct achievement_data *) idb_get(achievement->db, aid);
+}
+
+/**
+ * Searches the provided achievement data for an achievement,
+ * optionally creates a new one if no key exists.
+ * @param[in] sd a pointer to map_session_data.
+ * @param[in] aid ID of the achievement provided as key.
+ * @param[in] create new key creation flag.
+ * @return pointer to the session's achievement data.
+ */
+static struct achievement *achievement_ensure(struct map_session_data *sd, const struct achievement_data *ad)
+{
+ struct achievement *s_ad = NULL;
+ int i = 0;
+
+ nullpo_retr(NULL, sd);
+ nullpo_retr(NULL, ad);
+
+ /* Lookup for achievement entry */
+ ARR_FIND(0, VECTOR_LENGTH(sd->achievement), i, (s_ad = &VECTOR_INDEX(sd->achievement, i)) && s_ad->id == ad->id);
+
+ if (i == VECTOR_LENGTH(sd->achievement)) {
+ struct achievement ta = { 0 };
+ ta.id = ad->id;
+
+ VECTOR_ENSURE(sd->achievement, 1, 1);
+ VECTOR_PUSH(sd->achievement, ta);
+
+ s_ad = &VECTOR_LAST(sd->achievement);
+ }
+
+ return s_ad;
+}
+
+/**
+ * Calculates the achievement's totals via reference.
+ * @param[in] sd pointer to map_session_data
+ * @param[out] tota_points pointer to total points var
+ * @param[out] completed pointer to total var
+ * @param[out] rank pointer to completed var
+ * @param[out] curr_rank_points pointer to achievement rank var
+ */
+static void achievement_calculate_totals(const struct map_session_data *sd, int *total_points, int *completed, int *rank, int *curr_rank_points)
+{
+ const struct achievement *a = NULL;
+ const struct achievement_data *ad = NULL;
+ int tmp_curr_points = 0;
+ int tmp_total_points = 0;
+ int tmp_total_completed = 0;
+ int tmp_rank = 0;
+ int i = 0;
+
+ nullpo_retv(sd);
+
+ for (i = 0; i < VECTOR_LENGTH(sd->achievement); i++) {
+ a = &VECTOR_INDEX(sd->achievement, i);
+
+ if ((ad = achievement->get(a->id)) == NULL)
+ continue;
+
+ if (a->completed_at != 0) {
+ tmp_total_points += ad->points;
+ tmp_total_completed++;
+ }
+ }
+
+ if (tmp_total_points > 0) {
+ tmp_curr_points = tmp_total_points;
+ for (i = 0; i < MAX_ACHIEVEMENT_RANKS
+ && tmp_curr_points >= VECTOR_INDEX(achievement->rank_exp, i)
+ && i < VECTOR_LENGTH(achievement->rank_exp); i++) {
+ tmp_curr_points -= VECTOR_INDEX(achievement->rank_exp, i);
+ tmp_rank++;
+ }
+ }
+
+ if (total_points != NULL)
+ *total_points = tmp_total_points;
+
+ if (completed != NULL)
+ *completed = tmp_total_completed;
+
+ if (rank != NULL)
+ *rank = tmp_rank;
+
+ if (curr_rank_points != NULL)
+ *curr_rank_points = tmp_curr_points;
+}
+
+/**
+ * Checks whether all objectives of the achievement are completed.
+ * @param[in] sd as the map_session_data pointer
+ * @param[in] ad as the achievement_data pointer
+ * @return true if complete, false if not.
+ */
+static bool achievement_check_complete(struct map_session_data *sd, const struct achievement_data *ad)
+{
+ int i;
+ struct achievement *ach = NULL;
+
+ nullpo_retr(false, sd);
+ nullpo_retr(false, ad);
+
+ if ((ach = achievement->ensure(sd, ad)) == NULL)
+ return false;
+ for (i = 0; i < VECTOR_LENGTH(ad->objective); i++)
+ if (ach->objective[i] < VECTOR_INDEX(ad->objective, i).goal)
+ return false;
+
+ return true;
+}
+
+/**
+ * Compares the progress of an objective against it's goal.
+ * Increments the progress of the objective by the specified amount, towards the goal.
+ * @param sd [in] as a pointer to map_session_data
+ * @param ad [in] as a pointer to the achievement_data
+ * @param obj_idx [in] as the index of the objective.
+ * @param progress [in] as the progress of the objective to be added.
+ */
+static void achievement_progress_add(struct map_session_data *sd, const struct achievement_data *ad, unsigned int obj_idx, int progress)
+{
+ struct achievement *ach = NULL;
+
+ nullpo_retv(sd);
+ nullpo_retv(ad);
+
+ Assert_retv(progress != 0);
+ Assert_retv(obj_idx < VECTOR_LENGTH(ad->objective));
+
+ if ((ach = achievement->ensure(sd, ad)) == NULL)
+ return;
+
+ if (ach->completed_at)
+ return; // ignore the call if the achievement is completed.
+
+ // Check and increment the objective count.
+ if (!ach->objective[obj_idx] || ach->objective[obj_idx] < VECTOR_INDEX(ad->objective, obj_idx).goal) {
+ ach->objective[obj_idx] = min(progress + ach->objective[obj_idx], VECTOR_INDEX(ad->objective, obj_idx).goal);
+
+ // Check if the Achievement is complete.
+ if (achievement->check_complete(sd, ad)) {
+ achievement->validate_achieve(sd, ad->id);
+ ach->completed_at = time(NULL);
+ }
+
+ // update client.
+ clif->achievement_send_update(sd->fd, sd, ad);
+ }
+}
+
+/**
+ * Compare an absolute progress value against the goal of an objective.
+ * Does not add/increase progress.
+ * @param sd [in] pointer to map-server session data.
+ * @param ad [in] pointer to achievement data.
+ * @param obj_idx [in] index of the objective in question.
+ * @param progress progress of the objective in question.
+ */
+static void achievement_progress_set(struct map_session_data *sd, const struct achievement_data *ad, unsigned int obj_idx, int progress)
+{
+ struct achievement *ach = NULL;
+
+ nullpo_retv(sd);
+ nullpo_retv(ad);
+
+ Assert_retv(progress != 0);
+ Assert_retv(obj_idx < VECTOR_LENGTH(ad->objective));
+
+ if (progress >= VECTOR_INDEX(ad->objective, obj_idx).goal) {
+
+ if ((ach = achievement->ensure(sd, ad)) == NULL)
+ return;
+
+ if (ach->completed_at)
+ return;
+
+ ach->objective[obj_idx] = VECTOR_INDEX(ad->objective, obj_idx).goal;
+
+ if (achievement->check_complete(sd, ad)) {
+ achievement->validate_achieve(sd, ad->id);
+ ach->completed_at = time(NULL);
+ }
+
+ clif->achievement_send_update(sd->fd, sd, ad);
+ }
+}
+
+/**
+* Checks if the given criteria satisfies the achievement's objective.
+* @param objective [in] pointer to the achievement's objectives data.
+* @param criteria [in] pointer to the current session's criteria as a comparand.
+* @return true if all criteria are satisfied, else false.
+*/
+static bool achievement_check_criteria(const struct achievement_objective *objective, const struct achievement_objective *criteria)
+{
+ int i = 0, j = 0;
+
+ nullpo_retr(false, objective);
+ nullpo_retr(false, criteria);
+
+ /* Item Id */
+ if (objective->unique_type == CRITERIA_UNIQUE_ITEM_ID && objective->unique.itemid != criteria->unique.itemid)
+ return false;
+ /* Weapon Level */
+ else if (objective->unique_type == CRITERIA_UNIQUE_WEAPON_LV && objective->unique.weapon_lv != criteria->unique.weapon_lv)
+ return false;
+ /* Status Types */
+ else if (objective->unique_type == CRITERIA_UNIQUE_STATUS_TYPE && objective->unique.status_type != criteria->unique.status_type)
+ return false;
+ /* Achievement Id */
+ else if (objective->unique_type == CRITERIA_UNIQUE_ACHIEVE_ID && objective->unique.achieve_id != criteria->unique.achieve_id)
+ return false;
+
+ /* Monster Id */
+ if (objective->mobid > 0 && objective->mobid != criteria->mobid)
+ return false;
+
+ /* Item Type */
+ if (objective->item_type > 0 && (objective->item_type & (2 << criteria->item_type)) == 0)
+ return false;
+
+ /* Job Ids */
+ for (i = 0; i < VECTOR_LENGTH(objective->jobid); i++) {
+ ARR_FIND(0, VECTOR_LENGTH(criteria->jobid), j, VECTOR_INDEX(criteria->jobid, j) != VECTOR_INDEX(objective->jobid, i));
+ if (j < VECTOR_LENGTH(criteria->jobid))
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Validates an Achievement Objective of similar types.
+ * @param[in] sd as a pointer to the map session data.
+ * @param[in] type as the type of the achievement.
+ * @param[in] criteria as the criteria of the objective (mob id, job id etc.. 0 for no criteria).
+ * @param[in] progress as the current progress of the objective.
+ * @return total number of updated achievements on success, 0 on failure.
+ */
+static int achievement_validate_type(struct map_session_data *sd, enum achievement_types type, const struct achievement_objective *criteria, bool additive)
+{
+ int i = 0, total = 0;
+ struct achievement *ach = NULL;
+
+ nullpo_ret(sd);
+ nullpo_ret(criteria);
+
+ Assert_ret(criteria->goal != 0);
+
+ if (type == ACH_QUEST) {
+ ShowError("achievement_validate_type: ACH_QUEST is not handled by this function. (use achievement_validate())\n");
+ return 0;
+ } else if (type >= ACH_TYPE_MAX) {
+ ShowError("achievement_validate_type: Invalid Achievement Type %d! (min: %d, max: %d)\n", (int)type, (int)ACH_QUEST, (int)ACH_TYPE_MAX - 1);
+ return 0;
+ }
+
+ /* Loop through all achievements of the type, checking for possible matches. */
+ for (i = 0; i < VECTOR_LENGTH(achievement->category[type]); i++) {
+ int j = 0;
+ bool updated = false;
+ const struct achievement_data *ad = NULL;
+
+ if ((ad = achievement->get(VECTOR_INDEX(achievement->category[type], i))) == NULL)
+ continue;
+
+ for (j = 0; j < VECTOR_LENGTH(ad->objective); j++) {
+ // Check if objective criteria matches.
+ if (achievement->check_criteria(&VECTOR_INDEX(ad->objective, j), criteria) == false)
+ continue;
+ // Ensure availability of the achievement.
+ if ((ach = achievement->ensure(sd, ad)) == NULL)
+ return false;
+ // Criteria passed, check if not completed and update progress.
+ if ((ach->completed_at == 0 && ach->objective[j] < VECTOR_INDEX(ad->objective, j).goal)) {
+ if (additive == true)
+ achievement->progress_add(sd, ad, j, criteria->goal);
+ else
+ achievement->progress_set(sd, ad, j, criteria->goal);
+ updated = true;
+ }
+ }
+
+ if (updated == true)
+ total++;
+ }
+
+ return total;
+}
+
+/**
+ * Validates any achievement's specific objective index.
+ * @param[in] sd pointer to the session data.
+ * @param[in] aid ID of the achievement.
+ * @param[in] index index of the objective.
+ * @param[in] progress progress to be added towards the goal.
+ */
+static bool achievement_validate(struct map_session_data *sd, int aid, unsigned int obj_idx, int progress, bool additive)
+{
+ const struct achievement_data *ad = NULL;
+ struct achievement *ach = NULL;
+
+ nullpo_retr(false, sd);
+ Assert_retr(false, progress > 0);
+ Assert_retr(false, obj_idx < MAX_ACHIEVEMENT_OBJECTIVES);
+
+ if ((ad = achievement->get(aid)) == NULL) {
+ ShowError("achievement_validate: Invalid Achievement %d provided.", aid);
+ return false;
+ }
+
+ // Ensure availability of the achievement.
+ if ((ach = achievement->ensure(sd, ad)) == NULL)
+ return false;
+
+ // Check if not completed and update progress.
+ if ((!ach->completed_at && ach->objective[obj_idx] < VECTOR_INDEX(ad->objective, obj_idx).goal)) {
+ if (additive == true)
+ achievement->progress_add(sd, ad, obj_idx, progress);
+ else
+ achievement->progress_set(sd, ad, obj_idx, progress);
+ }
+
+ return true;
+}
+
+/**
+ * Validates monster kill type objectives.
+ * @type ACH_KILL_MOB_CLASS
+ * @param[in] sd pointer to session data.
+ * @param[in] mob_id (criteria) class of the monster checked for.
+ * @param[in] progress (goal) progress to be added.
+ * @see achievement_vaildate_type()
+ */
+static void achievement_validate_mob_kill(struct map_session_data *sd, int mob_id)
+{
+ struct achievement_objective criteria = { 0 };
+
+ nullpo_retv(sd);
+ Assert_retv(mob_id > 0 && mob->db(mob_id) != NULL);
+
+ if (sd->achievements_received == false)
+ return;
+
+ criteria.mobid = mob_id;
+ criteria.goal = 1;
+
+ achievement->validate_type(sd, ACH_KILL_MOB_CLASS, &criteria, true);
+}
+
+/**
+ * Validate monster damage type objectives.
+ * @types ACH_DAMAGE_MOB_REC_MAX
+ * ACH_DAMAGE_MOB_REC_TOTAL
+ * @param[in] sd pointer to session data.
+ * @param[in] damage amount of damage received/dealt.
+ * @param received received/dealt boolean switch.
+ */
+static void achievement_validate_mob_damage(struct map_session_data *sd, unsigned int damage, bool received)
+{
+ struct achievement_objective criteria = { 0 };
+
+ nullpo_retv(sd);
+ Assert_retv(damage > 0);
+
+ if (sd->achievements_received == false)
+ return;
+
+ criteria.goal = (int) damage;
+
+ if (received) {
+ achievement->validate_type(sd, ACH_DAMAGE_MOB_REC_MAX, &criteria, false);
+ achievement->validate_type(sd, ACH_DAMAGE_MOB_REC_TOTAL, &criteria, true);
+ } else {
+ achievement->validate_type(sd, ACH_DAMAGE_MOB_MAX, &criteria, false);
+ achievement->validate_type(sd, ACH_DAMAGE_MOB_TOTAL, &criteria, true);
+ }
+
+}
+
+/**
+ * Validate player kill (PVP) achievements.
+ * @types ACH_KILL_PC_TOTAL
+ * ACH_KILL_PC_JOB
+ * ACH_KILL_PC_JOBTYPE
+ * @param[in] sd pointer to killed player's session data.
+ * @param[in] dstsd pointer to killer's session data.
+ */
+static void achievement_validate_pc_kill(struct map_session_data *sd, struct map_session_data *dstsd)
+{
+ struct achievement_objective criteria = { 0 };
+
+ nullpo_retv(sd);
+ nullpo_retv(dstsd);
+
+ if (sd->achievements_received == false)
+ return;
+
+ criteria.goal = 1;
+
+ /* */
+ achievement->validate_type(sd, ACH_KILL_PC_TOTAL, &criteria, true);
+
+ /* */
+ VECTOR_INIT(criteria.jobid);
+ VECTOR_ENSURE(criteria.jobid, 1, 1);
+ VECTOR_PUSH(criteria.jobid, dstsd->status.class);
+
+ /* Job class */
+ achievement->validate_type(sd, ACH_KILL_PC_JOB, &criteria, true);
+ /* Job Type */
+ achievement->validate_type(sd, ACH_KILL_PC_JOBTYPE, &criteria, true);
+
+ VECTOR_CLEAR(criteria.jobid);
+}
+
+/**
+ * Validate player kill (PVP) achievements.
+ * @types ACH_DAMAGE_PC_MAX
+ * ACH_DAMAGE_PC_TOTAL
+ * ACH_DAMAGE_PC_REC_MAX
+ * ACH_DAMAGE_PC_REC_TOTAL
+ * @param[in] sd pointer to source player's session data.
+ * @param[in] dstsd pointer to target player's session data.
+ * @param[in] damage amount of damage dealt / received.
+ */
+static void achievement_validate_pc_damage(struct map_session_data *sd, struct map_session_data *dstsd, unsigned int damage)
+{
+ struct achievement_objective criteria = { 0 };
+
+ nullpo_retv(sd);
+
+ if (sd->achievements_received == false)
+ return;
+
+ if (damage == 0)
+ return;
+
+ criteria.goal = (int) damage;
+
+ /* */
+ achievement->validate_type(sd, ACH_DAMAGE_PC_MAX, &criteria, false);
+ achievement->validate_type(sd, ACH_DAMAGE_PC_TOTAL, &criteria, true);
+
+ /* */
+ achievement->validate_type(dstsd, ACH_DAMAGE_PC_REC_MAX, &criteria, false);
+ achievement->validate_type(dstsd, ACH_DAMAGE_PC_REC_TOTAL, &criteria, true);
+}
+
+/**
+ * Validates job change objectives.
+ * @type ACH_JOB_CHANGE
+ * @param[in] sd pointer to session data.
+ * @see achivement_validate_type()
+ */
+static void achievement_validate_jobchange(struct map_session_data *sd)
+{
+ struct achievement_objective criteria = { 0 };
+
+ nullpo_retv(sd);
+
+ if (sd->achievements_received == false)
+ return;
+
+ VECTOR_INIT(criteria.jobid);
+ VECTOR_ENSURE(criteria.jobid, 1, 1);
+ VECTOR_PUSH(criteria.jobid, sd->status.class);
+
+ criteria.goal = 1;
+
+ achievement->validate_type(sd, ACH_JOB_CHANGE, &criteria, false);
+
+ VECTOR_CLEAR(criteria.jobid);
+}
+
+/**
+ * Validates stat type objectives.
+ * @types ACH_STATUS
+ * ACH_STATUS_BY_JOB
+ * ACH_STATUS_BY_JOBTYPE
+ * @param[in] sd pointer to session data.
+ * @param[in] stat_type (criteria) status point type. (see status_point_types)
+ * @param[in] progress (goal) amount of absolute progress to check.
+ * @see achievement_validate_type()
+ */
+static void achievement_validate_stats(struct map_session_data *sd, enum status_point_types stat_type, int progress)
+{
+ struct achievement_objective criteria = { 0 };
+
+ nullpo_retv(sd);
+ Assert_retv(progress > 0);
+
+ if (sd->achievements_received == false)
+ return;
+
+ if (!achievement_valid_status_types(stat_type)) {
+ ShowError("achievement_validate_stats: Invalid status type %d given.\n", (int) stat_type);
+ return;
+ }
+
+ criteria.unique.status_type = stat_type;
+
+ criteria.goal = progress;
+
+ achievement->validate_type(sd, ACH_STATUS, &criteria, false);
+
+ VECTOR_INIT(criteria.jobid);
+ VECTOR_ENSURE(criteria.jobid, 1, 1);
+ VECTOR_PUSH(criteria.jobid, sd->status.class);
+
+ /* Stat and Job class */
+ achievement->validate_type(sd, ACH_STATUS_BY_JOB, &criteria, false);
+
+ /* Stat and Job Type */
+ achievement->validate_type(sd, ACH_STATUS_BY_JOBTYPE, &criteria, false);
+
+ VECTOR_CLEAR(criteria.jobid);
+}
+
+/**
+ * Validates chatroom creation type objectives.
+ * @types ACH_CHATROOM_CREATE
+ * ACH_CHATROOM_CREATE_DEAD
+ * @param[in] sd pointer to session data.
+ * @see achievement_validate_type()
+ */
+static void achievement_validate_chatroom_create(struct map_session_data *sd)
+{
+ struct achievement_objective criteria = { 0 };
+
+ nullpo_retv(sd);
+
+ if (sd->achievements_received == false)
+ return;
+
+ criteria.goal = 1;
+
+ if (pc_isdead(sd)) {
+ achievement->validate_type(sd, ACH_CHATROOM_CREATE_DEAD, &criteria, true);
+ return;
+ }
+
+ achievement->validate_type(sd, ACH_CHATROOM_CREATE, &criteria, true);
+}
+
+/**
+ * Validates chatroom member count type objectives.
+ * @type ACH_CHATROOM_MEMBERS
+ * @param[in] sd pointer to session data.
+ * @param[in] progress (goal) amount of progress to be added.
+ * @see achievement_validate_type()
+ */
+static void achievement_validate_chatroom_members(struct map_session_data *sd, int progress)
+{
+ struct achievement_objective criteria = { 0 };
+
+ nullpo_retv(sd);
+
+ if (sd->achievements_received == false)
+ return;
+
+ Assert_retv(progress > 0);
+
+ criteria.goal = progress;
+
+ achievement->validate_type(sd, ACH_CHATROOM_MEMBERS, &criteria, false);
+}
+
+/**
+ * Validates friend add type objectives.
+ * @type ACH_FRIEND_ADD
+ * @param[in] sd pointer to session data.
+ * @see achievement_validate_type()
+ */
+static void achievement_validate_friend_add(struct map_session_data *sd)
+{
+ struct achievement_objective criteria = { 0 };
+
+ nullpo_retv(sd);
+
+ if (sd->achievements_received == false)
+ return;
+
+ criteria.goal = 1;
+
+ achievement->validate_type(sd, ACH_FRIEND_ADD, &criteria, true);
+}
+
+/**
+ * Validates party creation type objectives.
+ * @type ACH_PARTY_CREATE
+ * @param[in] sd pointer to session data.
+ * @see achievement_validate_type()
+ */
+static void achievement_validate_party_create(struct map_session_data *sd)
+{
+ struct achievement_objective criteria = { 0 };
+
+ nullpo_retv(sd);
+
+ if (sd->achievements_received == false)
+ return;
+
+ criteria.goal = 1;
+ achievement->validate_type(sd, ACH_PARTY_CREATE, &criteria, true);
+}
+
+/**
+ * Validates marriage type objectives.
+ * @type ACH_MARRY
+ * @param[in] sd pointer to session data.
+ * @see achievement_validate_type()
+ */
+static void achievement_validate_marry(struct map_session_data *sd)
+{
+ struct achievement_objective criteria = { 0 };
+
+ nullpo_retv(sd);
+
+ if (sd->achievements_received == false)
+ return;
+
+ criteria.goal = 1;
+
+ achievement->validate_type(sd, ACH_MARRY, &criteria, true);
+}
+
+/**
+ * Validates adoption type objectives.
+ * @types ACH_ADOPT_PARENT
+ * ACH_ADOPT_BABY
+ * @param[in] sd pointer to session data.
+ * @param[in] parent (type) boolean value to indicate if parent (true) or baby (false).
+ * @see achievement_validate_type()
+ */
+static void achievement_validate_adopt(struct map_session_data *sd, bool parent)
+{
+ struct achievement_objective criteria = { 0 };
+
+ nullpo_retv(sd);
+
+ if (sd->achievements_received == false)
+ return;
+
+ criteria.goal = 1;
+
+ if (parent)
+ achievement->validate_type(sd, ACH_ADOPT_PARENT, &criteria, true);
+ else
+ achievement->validate_type(sd, ACH_ADOPT_BABY, &criteria, true);
+}
+
+/**
+ * Validates zeny type objectives.
+ * @types ACH_ZENY_HOLD
+ * ACH_ZENY_GET_ONCE
+ * ACH_ZENY_GET_TOTAL
+ * ACH_ZENY_SPEND_ONCE
+ * ACH_ZENY_SPEND_TOTAL
+ * @param[in] sd pointer to session data.
+ * @param[in] amount (goal) amount of zeny earned or spent.
+ * @see achievement_validate_type()
+ */
+static void achievement_validate_zeny(struct map_session_data *sd, int amount)
+{
+ struct achievement_objective criteria = { 0 };
+
+ nullpo_retv(sd);
+
+ if (sd->achievements_received == false)
+ return;
+
+ Assert_retv(amount != 0);
+
+ if (amount > 0) {
+ criteria.goal = sd->status.zeny;
+ achievement->validate_type(sd, ACH_ZENY_HOLD, &criteria, false);
+ criteria.goal = amount;
+ achievement->validate_type(sd, ACH_ZENY_GET_ONCE, &criteria, false);
+ achievement->validate_type(sd, ACH_ZENY_GET_TOTAL, &criteria, true);
+ } else {
+ criteria.goal = amount;
+ achievement->validate_type(sd, ACH_ZENY_SPEND_ONCE, &criteria, false);
+ achievement->validate_type(sd, ACH_ZENY_SPEND_TOTAL, &criteria, true);
+ }
+}
+
+/**
+ * Validates equipment refinement type objectives.
+ * @types ACH_EQUIP_REFINE_SUCCESS
+ * ACH_EQUIP_REFINE_FAILURE
+ * ACH_EQUIP_REFINE_SUCCESS_TOTAL
+ * ACH_EQUIP_REFINE_FAILURE_TOTAL
+ * ACH_EQUIP_REFINE_SUCCESS_WLV
+ * ACH_EQUIP_REFINE_FAILURE_WLV
+ * ACH_EQUIP_REFINE_SUCCESS_ID
+ * ACH_EQUIP_REFINE_FAILURE_ID
+ * @param[in] sd pointer to session data.
+ * @param[in] idx Inventory index of the item.
+ * @param[in] success (type) boolean switch for failure / success.
+ * @see achievement_validate_type()
+ */
+static void achievement_validate_refine(struct map_session_data *sd, unsigned int idx, bool success)
+{
+ struct achievement_objective criteria = { 0 };
+ struct item_data *id = NULL;
+
+ nullpo_retv(sd);
+ Assert_retv(idx < MAX_INVENTORY);
+
+ id = itemdb->exists(sd->status.inventory[idx].nameid);
+
+ if (sd->achievements_received == false)
+ return;
+
+ Assert_retv(idx < MAX_INVENTORY);
+ Assert_retv(id != NULL);
+
+ criteria.goal = sd->status.inventory[idx].refine;
+
+ /* Universal */
+ achievement->validate_type(sd,
+ success ? ACH_EQUIP_REFINE_SUCCESS : ACH_EQUIP_REFINE_FAILURE,
+ &criteria, false);
+
+ /* Total */
+ criteria.goal = 1;
+ achievement->validate_type(sd,
+ success ? ACH_EQUIP_REFINE_SUCCESS_TOTAL : ACH_EQUIP_REFINE_FAILURE_TOTAL,
+ &criteria, true);
+
+ /* By Weapon Level */
+ if (id->type == IT_WEAPON) {
+ criteria.item_type = id->type;
+ criteria.unique.weapon_lv = id->wlv;
+ criteria.goal = sd->status.inventory[idx].refine;
+ achievement->validate_type(sd,
+ success ? ACH_EQUIP_REFINE_SUCCESS_WLV : ACH_EQUIP_REFINE_FAILURE_WLV,
+ &criteria, false);
+ criteria.item_type = 0;
+ criteria.unique.weapon_lv = 0; // cleanup
+ }
+
+ /* By NameId */
+ criteria.unique.itemid = id->nameid;
+ criteria.goal = sd->status.inventory[idx].refine;
+ achievement->validate_type(sd,
+ success ? ACH_EQUIP_REFINE_SUCCESS_ID : ACH_EQUIP_REFINE_FAILURE_ID,
+ &criteria, false);
+ criteria.unique.itemid = 0; // cleanup
+}
+
+/**
+ * Validates item received type objectives.
+ * @types ACH_ITEM_GET_COUNT
+ * ACH_ITEM_GET_WORTH
+ * ACH_ITEM_GET_COUNT_ITEMTYPE
+ * @param[in] sd pointer to session data.
+ * @param[in] nameid (criteria) ID of the item.
+ * @param[in] amount (goal) amount of the item collected.
+ */
+static void achievement_validate_item_get(struct map_session_data *sd, int nameid, int amount)
+{
+ struct item_data *it = itemdb->exists(nameid);
+ struct achievement_objective criteria = { 0 };
+
+ nullpo_retv(sd);
+
+ if (sd->achievements_received == false)
+ return;
+
+ Assert_retv(amount > 0);
+ nullpo_retv(it);
+
+ criteria.unique.itemid = it->nameid;
+ criteria.goal = amount;
+ achievement->validate_type(sd, ACH_ITEM_GET_COUNT, &criteria, false);
+ criteria.unique.itemid = 0; // cleanup
+
+ /* Item Buy Value*/
+ criteria.goal = max(it->value_buy, 1);
+ achievement->validate_type(sd, ACH_ITEM_GET_WORTH, &criteria, false);
+
+ /* Item Type */
+ criteria.item_type = it->type;
+ criteria.goal = 1;
+ achievement->validate_type(sd, ACH_ITEM_GET_COUNT_ITEMTYPE, &criteria, false);
+ criteria.item_type = 0; // cleanup
+}
+
+/**
+ * Validates item sold type objectives.
+ * @type ACH_ITEM_SELL_WORTH
+ * @param[in] sd pointer to session data.
+ * @param[in] nameid Item Id in question.
+ * @param[in] amount amount of item in question.
+ */
+static void achievement_validate_item_sell(struct map_session_data *sd, int nameid, int amount)
+{
+ struct item_data *it = itemdb->exists(nameid);
+ struct achievement_objective criteria = { 0 };
+
+ nullpo_retv(sd);
+
+ if (sd->achievements_received == false)
+ return;
+
+ Assert_retv(amount > 0);
+ nullpo_retv(it);
+
+ criteria.unique.itemid = it->nameid;
+
+ criteria.goal = max(it->value_sell, 1);
+
+ achievement->validate_type(sd, ACH_ITEM_SELL_WORTH, &criteria, false);
+}
+
+/**
+ * Validates achievement type objectives.
+ * @type ACH_ACHIEVE
+ * @param[in] sd pointer to session data.
+ * @param[in] achid (criteria) achievement id.
+ */
+static void achievement_validate_achieve(struct map_session_data *sd, int achid)
+{
+ const struct achievement_data *ad = achievement->get(achid);
+ struct achievement_objective criteria = { 0 };
+
+ nullpo_retv(sd);
+ nullpo_retv(ad);
+
+ if (sd->achievements_received == false)
+ return;
+
+ Assert_retv(achid > 0);
+
+ criteria.unique.achieve_id = ad->id;
+
+ criteria.goal = 1;
+
+ achievement->validate_type(sd, ACH_ACHIEVE, &criteria, false);
+}
+
+/**
+ * Validates taming type objectives.
+ * @type ACH_PET_CREATE
+ * @param[in] sd pointer to session data.
+ * @param[in] class (criteria) class of the monster tamed.
+ */
+static void achievement_validate_taming(struct map_session_data *sd, int class)
+{
+ struct achievement_objective criteria = { 0 };
+
+ nullpo_retv(sd);
+
+ if (sd->achievements_received == false)
+ return;
+
+ Assert_retv(class > 0);
+ Assert_retv(mob->db(class) != mob->dummy);
+
+ criteria.mobid = class;
+ criteria.goal = 1;
+
+ achievement->validate_type(sd, ACH_PET_CREATE, &criteria, true);
+}
+
+/**
+ * Validated achievement rank type objectives.
+ * @type ACH_ACHIEVEMENT_RANK
+ * @param[in] sd pointer to session data.
+ * @param[in] rank (goal) rank of earned.
+ */
+static void achievement_validate_achievement_rank(struct map_session_data *sd, int rank)
+{
+ struct achievement_objective criteria = { 0 };
+
+ nullpo_retv(sd);
+
+ if (sd->achievements_received == false)
+ return;
+
+ Assert_retv(rank >= 0 && rank <= VECTOR_LENGTH(achievement->rank_exp));
+
+ criteria.goal = 1;
+
+ achievement->validate_type(sd, ACH_ACHIEVEMENT_RANK, &criteria, false);
+}
+
+/**
+ * Verifies if an achievement type requires a criteria field.
+ * @param[in] type achievement type in question.
+ * @return true if required, false if not.
+ */
+static bool achievement_type_requires_criteria(enum achievement_types type)
+{
+ if (type == ACH_KILL_PC_JOB
+ || type == ACH_KILL_PC_JOBTYPE
+ || type == ACH_KILL_MOB_CLASS
+ || type == ACH_JOB_CHANGE
+ || type == ACH_STATUS
+ || type == ACH_STATUS_BY_JOB
+ || type == ACH_STATUS_BY_JOBTYPE
+ || type == ACH_EQUIP_REFINE_SUCCESS_WLV
+ || type == ACH_EQUIP_REFINE_FAILURE_WLV
+ || type == ACH_EQUIP_REFINE_SUCCESS_ID
+ || type == ACH_EQUIP_REFINE_FAILURE_ID
+ || type == ACH_ITEM_GET_COUNT
+ || type == ACH_PET_CREATE
+ || type == ACH_ACHIEVE)
+ return true;
+
+ return false;
+}
+
+/**
+ * Stores all the title ID that has been earned by player
+ * @param[in] sd pointer to session data.
+ */
+static void achievement_init_titles(struct map_session_data *sd)
+{
+ int i;
+ nullpo_retv(sd);
+
+ VECTOR_INIT(sd->title_ids);
+ /* Browse through the session's achievement list and gather their values. */
+ for (i = 0; i < VECTOR_LENGTH(sd->achievement); i++) {
+ struct achievement *a = &VECTOR_INDEX(sd->achievement, i);
+ const struct achievement_data *ad = NULL;
+
+ /* Sanity check for nonull pointers. */
+ if (a == NULL || (ad = achievement->get(a->id)) == NULL)
+ continue;
+
+ if (a->completed_at > 0 && a->rewarded_at > 0 && ad->rewards.title_id > 0) {
+ VECTOR_ENSURE(sd->title_ids, 1, 1);
+ VECTOR_PUSH(sd->title_ids, ad->rewards.title_id);
+ }
+ }
+}
+
+/**
+ * Validates whether player has earned the title.
+ * @param[in] sd pointer to session data.
+ * @param[in] title_id Title ID
+ * @return true, if title has been earned, else false
+ */
+static bool achievement_check_title(struct map_session_data *sd, int title_id) {
+ int i;
+
+ nullpo_retr(false, sd);
+
+ if (title_id == 0)
+ return true;
+
+ for (i = 0; i < VECTOR_LENGTH(sd->title_ids); i++) {
+ if (VECTOR_INDEX(sd->title_ids, i) == title_id) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/**
+ * Achievement rewards are given to player
+ * @param sd session data
+ * @param ad achievement data
+ */
+static void achievement_get_rewards(struct map_session_data *sd, const struct achievement_data *ad) {
+ int i = 0;
+ struct achievement *ach = NULL;
+
+ nullpo_retv(sd);
+ nullpo_retv(ad);
+
+ if ((ach = achievement->ensure(sd, ad)) == NULL)
+ return;
+
+ /* Buff */
+ if (ad->rewards.bonus != NULL)
+ script->run(ad->rewards.bonus, 0, sd->bl.id, 0);
+
+ /* Give Items */
+ for (i = 0; i < VECTOR_LENGTH(ad->rewards.item); i++) {
+ struct item it = { 0 };
+ int total = 0;
+
+ it.nameid = VECTOR_INDEX(ad->rewards.item, i).id;
+ total = VECTOR_INDEX(ad->rewards.item, i).amount;
+
+ it.identify = 1;
+
+ //Check if it's stackable.
+ if (!itemdb->isstackable(it.nameid)) {
+ int j = 0;
+ for (j = 0; j < total; ++j)
+ pc->additem(sd, &it, (it.amount = 1), LOG_TYPE_SCRIPT);
+ } else {
+ pc->additem(sd, &it, (it.amount = total), LOG_TYPE_SCRIPT);
+ }
+ }
+
+ ach->rewarded_at = time(NULL);
+
+ if (ad->rewards.title_id > 0) { // Add Title
+ VECTOR_ENSURE(sd->title_ids, 1, 1);
+ VECTOR_PUSH(sd->title_ids, ad->rewards.title_id);
+ clif->achievement_send_list(sd->fd, sd);
+ } else {
+ clif->achievement_reward_ack(sd->fd, sd, ad);
+ clif->achievement_send_update(sd->fd, sd, ad); // send update.
+ }
+}
+
+/**
+ * Parses the Achievement Ranks.
+ * @read db/achievement_rank_db.conf
+ */
+static void achievement_readdb_ranks(void)
+{
+ const char *filename = "db/achievement_rank_db.conf";
+ struct config_t ar_conf = { 0 };
+ struct config_setting_t *ardb = NULL, *conf = NULL;
+ int entry = 0;
+
+ if (!libconfig->load_file(&ar_conf, filename))
+ return; // report error.
+
+ if (!(ardb = libconfig->setting_get_member(ar_conf.root, "achievement_rank_db"))) {
+ ShowError("achievement_readdb_ranks: Could not process contents of file '%s', skipping...\n", filename);
+ libconfig->destroy(&ar_conf);
+ return;
+ }
+
+ while (entry < libconfig->setting_length(ardb) && entry < MAX_ACHIEVEMENT_RANKS) {
+ char rank[8];
+
+ if (!(conf = libconfig->setting_get_elem(ardb, entry))) {
+ ShowError("achievement_readdb_ranks: Could not read value for entry %d, skipping...\n", entry+1);
+ continue;
+ }
+
+ entry++; // Rank counter;
+
+ sprintf(rank, "Rank%d", entry);
+
+ if (strcmp(rank, config_setting_name(conf)) == 0) {
+ int exp = 0;
+
+ if ((exp = libconfig->setting_get_int(conf)) <= 0) {
+ ShowError("achievement_readdb_ranks: Invalid value provided for %s in '%s'.\n", rank, filename);
+ continue;
+ }
+
+ VECTOR_ENSURE(achievement->rank_exp, 1, 1);
+ VECTOR_PUSH(achievement->rank_exp, exp);
+ } else {
+ ShowWarning("achievement_readdb_ranks: Ranks are not in order! Ignoring all ranks after Rank %d...\n", entry);
+ break; // break if elements are not in order or rank doesn't exist.
+ }
+ }
+
+ if (libconfig->setting_length(ardb) > MAX_ACHIEVEMENT_RANKS)
+ ShowWarning("achievement_rankdb_ranks: Maximum number of achievement ranks exceeded. Skipping all after entry %d...\n", entry);
+
+ libconfig->destroy(&ar_conf);
+
+ if (!entry) {
+ ShowError("achievement_readdb_ranks: No ranks provided in '%s'!\n", filename);
+ return;
+ }
+
+ ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", entry, filename);
+}
+
+/**
+ * Validates Mob Id criteria of an objective while parsing an achievement entry.
+ * @param[in] t pointer to the config setting.
+ * @param[out] obj pointer to the achievement objective entry being parsed.
+ * @param[in] type Type of the achievement being parsed.
+ * @param[in] entry_id Id of the entry being parsed.
+ * @param[in] obj_idx Index of the objective entry being parsed.
+ * @return false on failure, true on success
+ */
+static bool achievement_readdb_validate_criteria_mobid(const struct config_setting_t *t, struct achievement_objective *obj, enum achievement_types type, int entry_id, int obj_idx)
+{
+ int val = 0;
+ const char *string = NULL;
+
+ nullpo_retr(false, t);
+ nullpo_retr(false, obj);
+
+ if (libconfig->setting_lookup_int(t, "MobId", &val)) {
+ if (mob->db_checkid(val) == 0) {
+ ShowError("achievement_readdb_validate_criteria_mobid: Non-existant monster with ID %id provided (Achievement: %d, Objective: %d). Skipping...\n", val, entry_id, obj_idx);
+ return false;
+ }
+
+ obj->mobid = val;
+ } else if (libconfig->setting_lookup_string(t, "MobId", &string)) {
+ if (!script->get_constant(string, &val)) {
+ ShowError("achievement_readdb_validate_criteria_mobid: Non-existant constant %s provided (Achievement: %d, Objective: %d). Skipping...\n", string, entry_id, obj_idx);
+ return false;
+ }
+
+ obj->mobid = val;
+ } else if (achievement_criteria_mobid(type)) {
+ ShowError("achievement_readdb_validate_criteria_mobid: Achievement type of ID %d requires MobId as objective criteria, setting not provided. Skipping...\n", entry_id);
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Validates Job Id criteria of an objective while parsing an achievement entry.
+ * @param[in] t pointer to the config setting.
+ * @param[out] obj pointer to the achievement objective entry being parsed.
+ * @param[in] type Type of the achievement being parsed.
+ * @param[in] entry_id Id of the entry being parsed.
+ * @param[in] obj_idx Index of the objective entry being parsed.
+ * @return false on failure, true on success.
+ */
+static bool achievement_readdb_validate_criteria_jobid(const struct config_setting_t *t, struct achievement_objective *obj, enum achievement_types type, int entry_id, int obj_idx)
+{
+ int job_id = 0;
+ const char *string = NULL;
+ struct config_setting_t *tt = NULL;
+
+ nullpo_retr(false, t);
+ nullpo_retr(false, obj);
+
+ // initialize the buffered objective jobid vector.
+ VECTOR_INIT(obj->jobid);
+
+ if (libconfig->setting_lookup_int(t, "JobId", &job_id)) {
+ if (pc->jobid2mapid(job_id) == -1) {
+ ShowError("achievement_readdb_validate_criteria_jobid: Invalid JobId %d provided (Achievement: %d, Objective: %d). Skipping...\n", job_id, entry_id, obj_idx);
+ return false;
+ }
+
+ VECTOR_ENSURE(obj->jobid, 1, 1);
+ VECTOR_PUSH(obj->jobid, job_id);
+ } else if (libconfig->setting_lookup_string(t, "JobId", &string)) {
+ if (script->get_constant(string, &job_id) == false) {
+ ShowError("achievement_readdb_validate_criteria_jobid: Invalid JobId %d provided (Achievement: %d, Objective: %d). Skipping...\n", job_id, entry_id, obj_idx);
+ return false;
+ }
+
+ VECTOR_ENSURE(obj->jobid, 1, 1);
+ VECTOR_PUSH(obj->jobid, job_id);
+ } else if ((tt = libconfig->setting_get_member(t, "JobId")) && config_setting_is_array(tt)) {
+ int j = 0;
+
+ while (j < libconfig->setting_length(tt)) {
+ if ((job_id = libconfig->setting_get_int_elem(tt, j)) == 0) {
+ if ((string = libconfig->setting_get_string_elem(tt, j)) != NULL && script->get_constant(string, &job_id) == false) {
+ ShowError("achievement_readdb_validate_criteria_jobid: Invalid JobId provided at index %d (Achievement: %d, Objective: %d). Skipping...\n", j, entry_id, obj_idx);
+ continue;
+ }
+ }
+
+ /* Ensure size and allocation */
+ VECTOR_ENSURE(obj->jobid, 1, 1);
+ /* push buffer */
+ VECTOR_PUSH(obj->jobid, job_id);
+ j++;
+ }
+ } else if (achievement_criteria_jobid(type)) {
+ ShowError("achievement_readdb_validate_criteria_jobid: Achievement type of ID %d requires a JobId field in the objective criteria, setting not provided. Skipping...\n", entry_id);
+ return false;
+ }
+
+ return true;
+
+}
+
+/**
+ * Validates Item Id criteria of an objective while parsing an achievement entry.
+ * @param[in] t pointer to the config setting.
+ * @param[out] obj pointer to the achievement objective entry being parsed.
+ * @param[in] type Type of the achievement being parsed.
+ * @param[in] entry_id Id of the entry being parsed.
+ * @param[in] obj_idx Index of the objective entry being parsed.
+ * @return false on failure, true on success.
+ */
+static bool achievement_readdb_validate_criteria_itemid(const struct config_setting_t *t, struct achievement_objective *obj, enum achievement_types type, int entry_id, int obj_idx)
+{
+ int val = 0;
+ const char *string = NULL;
+
+ nullpo_retr(false, t);
+ nullpo_retr(false, obj);
+
+
+ if (libconfig->setting_lookup_int(t, "ItemId", &val)) {
+ if (itemdb->exists(val) == NULL) {
+ ShowError("achievement_readdb_validate_criteria_itemid: Invalid ItemID %d provided (Achievement: %d, Objective: %d). Skipping...\n", val, entry_id, obj_idx);
+ return false;
+ } else if (obj->unique_type != CRITERIA_UNIQUE_NONE) {
+ ShowError("achievement_readdb_validate_criteria_itemid: Unique criteria has already been set to type %d. (Achievement: %d, Objective: %d). Skipping...\n", (int) obj->unique_type, entry_id, obj_idx);
+ return false;
+ }
+
+ obj->unique.itemid = val;
+ obj->unique_type = CRITERIA_UNIQUE_ITEM_ID;
+ } else if (libconfig->setting_lookup_string(t, "ItemId", &string)) {
+ if (script->get_constant(string, &val) == false) {
+ ShowError("achievement_readdb_validate_criteria_itemid: Invalid ItemID %d provided (Achievement: %d, Objective: %d). Skipping...\n", val, entry_id, obj_idx);
+ return false;
+ } else if (obj->unique_type != CRITERIA_UNIQUE_NONE) {
+ ShowError("achievement_readdb_validate_criteria_itemid: Unique criteria has already been set to type %d. (Achievement: %d, Objective: %d). Skipping...\n", (int) obj->unique_type, entry_id, obj_idx);
+ return false;
+ }
+
+ obj->unique.itemid = val;
+ obj->unique_type = CRITERIA_UNIQUE_ITEM_ID;
+ } else if (achievement_criteria_itemid(type)) {
+ ShowError("achievement_readdb_validate_criteria_itemid: Criteria requires a ItemId field (Achievement: %d, Objective: %d). Skipping...\n", entry_id, obj_idx);
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Validates Status Type criteria of an objective while parsing an achievement entry.
+ * @param[in] t pointer to the config setting.
+ * @param[out] obj pointer to the achievement objective entry being parsed.
+ * @param[in] type Type of the achievement being parsed.
+ * @param[in] entry_id Id of the entry being parsed.
+ * @param[in] obj_idx Index of the objective entry being parsed.
+ * @return false on failure, true on success.
+ */
+static bool achievement_readdb_validate_criteria_statustype(const struct config_setting_t *t, struct achievement_objective *obj, enum achievement_types type, int entry_id, int obj_idx)
+{
+ int val = 0;
+ const char *string = NULL;
+
+ nullpo_retr(false, t);
+ nullpo_retr(false, obj);
+
+ if (libconfig->setting_lookup_int(t, "StatusType", &val)) {
+ if (!achievement_valid_status_types(val)) {
+ ShowError("achievement_readdb_validate_criteria_statustype: Invalid StatusType %d provided (Achievement: %d, Objective: %d). Skipping...\n", val, entry_id, obj_idx);
+ return false;
+ } else if (obj->unique_type != CRITERIA_UNIQUE_NONE) {
+ ShowError("achievement_readdb_validate_criteria_statustype: Unique criteria has already been set to type %d. (Achievement: %d, Objective: %d). Skipping...\n", (int) obj->unique_type, entry_id, obj_idx);
+ return false;
+ }
+
+ obj->unique.status_type = (enum status_point_types) val;
+ obj->unique_type = CRITERIA_UNIQUE_STATUS_TYPE;
+ } else if (libconfig->setting_lookup_string(t, "StatusType", &string)) {
+ if (strcmp(string, "SP_STR") == 0) val = SP_STR;
+ else if (strcmp(string, "SP_AGI") == 0) val = SP_AGI;
+ else if (strcmp(string, "SP_VIT") == 0) val = SP_VIT;
+ else if (strcmp(string, "SP_INT") == 0) val = SP_INT;
+ else if (strcmp(string, "SP_DEX") == 0) val = SP_DEX;
+ else if (strcmp(string, "SP_LUK") == 0) val = SP_LUK;
+ else if (strcmp(string, "SP_BASELEVEL") == 0) val = SP_BASELEVEL;
+ else if (strcmp(string, "SP_JOBLEVEL") == 0) val = SP_JOBLEVEL;
+ else val = SP_NONE;
+
+ if (!achievement_valid_status_types(val)) {
+ ShowError("achievement_readdb_validate_criteria_statustype: Invalid StatusType %s provided (Achievement: %d, Objective: %d). Skipping...\n", string, entry_id, obj_idx);
+ return false;
+ } else if (obj->unique_type != CRITERIA_UNIQUE_NONE) {
+ ShowError("achievement_readdb_validate_criteria_statustype: Unique criteria has already been set to type %d. (Achievement: %d, Objective: %d). Skipping...\n", (int) obj->unique_type, entry_id, obj_idx);
+ return false;
+ }
+
+ obj->unique.status_type = (enum status_point_types) val;
+ obj->unique_type = CRITERIA_UNIQUE_STATUS_TYPE;
+ } else if (achievement_criteria_stattype(type)) {
+ ShowError("achievement_readdb_validate_criteria_statustype: Criteria requires a StatusType field (Achievement: %d, Objective: %d). Skipping...\n", entry_id, obj_idx);
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Validates Item Type criteria of an objective while parsing an achievement entry.
+ * @param[in] t pointer to the config setting.
+ * @param[out] obj pointer to the achievement objective entry being parsed.
+ * @param[in] type Type of the achievement being parsed.
+ * @param[in] entry_id Id of the entry being parsed.
+ * @param[in] obj_idx Index of the objective entry being parsed.
+ * @return false on failure, true on success.
+ */
+static bool achievement_readdb_validate_criteria_itemtype(const struct config_setting_t *t, struct achievement_objective *obj, enum achievement_types type, int entry_id, int obj_idx)
+{
+ int val = 0;
+ const char *string = NULL;
+ struct config_setting_t *tt = NULL;
+
+ nullpo_retr(false, t);
+ nullpo_retr(false, obj);
+
+ if (libconfig->setting_lookup_int(t, "ItemType", &val)) {
+ if (val < IT_HEALING || val > IT_MAX) {
+ ShowError("achievement_readdb_validate_criteria_itemtype: Invalid ItemType %d provided (Achievement: %d, Objective: %d). Skipping...\n", val, entry_id, obj_idx);
+ return false;
+ }
+
+ if (val == IT_MAX) {
+ obj->item_type |= (2 << val) - 1;
+ } else {
+ obj->item_type |= (2 << val);
+ }
+
+ } else if (libconfig->setting_lookup_string(t, "ItemType", &string)) {
+ if (!script->get_constant(string, &val) || val < IT_HEALING || val > IT_MAX) {
+ ShowError("achievement_readdb_validate_criteria_itemtype: Invalid ItemType %d provided (Achievement: %d, Objective: %d). Skipping...\n", val, entry_id, obj_idx);
+ return false;
+ }
+
+ if (val == IT_MAX) {
+ obj->item_type |= (2 << val) - 1;
+ } else {
+ obj->item_type |= (2 << val);
+ }
+ } else if ((tt = libconfig->setting_get_member(t, "ItemType")) && config_setting_is_array(tt)) {
+ int j = 0;
+ uint32 it_type = 0;
+
+ while (j < libconfig->setting_length(tt)) {
+ if ((val = libconfig->setting_get_int_elem(tt, j))) {
+ if (val < IT_HEALING || val >= IT_MAX) {
+ ShowError("achievement_readdb_validate_criteria_itemtype: Invalid ItemType %d provided (Achievement: %d, Objective: %d). Skipping...\n", val, entry_id, obj_idx);
+ continue;
+ }
+ if (val == IT_MAX) {
+ obj->item_type |= (2 << val) - 1;
+ } else {
+ obj->item_type |= (2 << val);
+ }
+ } else if ((string = libconfig->setting_get_string_elem(tt, j))) {
+ if (!script->get_constant(string, &val)) {
+ ShowError("achievement_readdb_validate_criteria_itemtype: Invalid ItemType %s provided (Achievement: %d, Objective: %d). Skipping...\n", string, entry_id, obj_idx);
+ continue;
+ }
+
+ if (val == IT_MAX) {
+ obj->item_type |= (2 << val) - 1;
+ } else {
+ obj->item_type |= (2 << val);
+ }
+ }
+ j++;
+ }
+
+ obj->item_type = it_type;
+ } else if (achievement_criteria_itemtype(type)) {
+ ShowError("achievement_readdb_validate_criteria_itemtype: Criteria requires a ItemType field (Achievement: %d, Objective: %d). Skipping...\n", entry_id, obj_idx);
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Validates Weapon Level criteria of an objective while parsing an achievement entry.
+ * @param[in] t pointer to the config setting.
+ * @param[out] obj pointer to the achievement objective entry being parsed.
+ * @param[in] type Type of the achievement being parsed.
+ * @param[in] entry_id Id of the entry being parsed.
+ * @param[in] obj_idx Index of the objective entry being parsed.
+ * @return false on failure, true on success.
+ */
+static bool achievement_readdb_validate_criteria_weaponlv(const struct config_setting_t *t, struct achievement_objective *obj, enum achievement_types type, int entry_id, int obj_idx)
+{
+ int val = 0;
+
+ nullpo_retr(false, t);
+ nullpo_retr(false, obj);
+
+ if (libconfig->setting_lookup_int(t, "WeaponLevel", &val)) {
+ if (val < 1 || val > 4) {
+ ShowError("achievement_readdb_validate_criteria_weaponlv: Invalid WeaponLevel %d provided (Achievement: %d, Objective: %d). Skipping...\n", val, entry_id, obj_idx);
+ return false;
+ } else if (obj->unique_type != CRITERIA_UNIQUE_NONE) {
+ ShowError("achievement_readdb_validate_criteria_weaponlv: Unique criteria has already been set to type %d. (Achievement: %d, Objective: %d). Skipping...\n", (int) obj->unique_type, entry_id, obj_idx);
+ return false;
+ }
+
+ obj->unique.weapon_lv = val;
+ obj->unique_type = CRITERIA_UNIQUE_WEAPON_LV;
+ } else if (achievement_criteria_weaponlv(type)) {
+ ShowError("achievement_readdb_validate_criteria_weaponlv: Criteria requires a WeaponType field. (Achievement: %d, Objective: %d). Skipping...\n", entry_id, obj_idx);
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Validates achievement Id criteria of an objective while parsing an achievement entry.
+ * @param[in] t pointer to the config setting.
+ * @param[out] obj pointer to the achievement objective entry being parsed.
+ * @param[in] type Type of the achievement being parsed.
+ * @param[in] entry_id Id of the entry being parsed.
+ * @param[in] obj_idx Index of the objective entry being parsed.
+ * @return false on failure, true on success.
+ */
+static bool achievement_readdb_validate_criteria_achievement(const struct config_setting_t *t, struct achievement_objective *obj, enum achievement_types type, int entry_id, int obj_idx)
+{
+ int val = 0;
+
+ nullpo_retr(false, t);
+ nullpo_retr(false, obj);
+
+ if (libconfig->setting_lookup_int(t, "Achieve", &val)) {
+ if (achievement->get(val) == NULL) {
+ ShowError("achievement_readdb_validate_criteria_achievement: Invalid Achievement %d provided as objective (Achievement %d, Objective %d). Skipping...\n", val, entry_id, obj_idx);
+ return false;
+ } else if (obj->unique_type != CRITERIA_UNIQUE_NONE) {
+ ShowError("achievement_readdb_validate_criteria_achievement: Unique criteria has already been set to type %d. (Achievement: %d, Objective: %d). Skipping...\n", (int) obj->unique_type, entry_id, obj_idx);
+ return false;
+ }
+
+ obj->unique.achieve_id = val;
+ obj->unique_type = CRITERIA_UNIQUE_ACHIEVE_ID;
+ } else if (type == ACH_ACHIEVE) {
+ ShowError("achievement_readdb_validate_criteria_achievement: Achievement type of ID %d requires an Achieve field in the objective criteria, setting not provided. Skipping...\n", entry_id);
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Read a single objective entry of an achievement.
+ * @param[in] conf config pointer.
+ * @param[in] index Index of the objective being in the objective list being parsed.
+ * @param[out] entry pointer to the achievement db entry being parsed.
+ * @return false on failure, true on success.
+ */
+static bool achievement_readdb_objective_sub(const struct config_setting_t *conf, int index, struct achievement_data *entry)
+{
+ struct config_setting_t *tt = NULL;
+ char objnum[12];
+
+ nullpo_retr(false, conf);
+ nullpo_retr(false, entry);
+
+ sprintf(objnum, "*%d", index); // Search Objective 1..MAX
+ if ((tt = libconfig->setting_get_member(conf, objnum)) && config_setting_is_group(tt)) {
+ struct achievement_objective obj = { 0 };
+ struct config_setting_t *c = NULL;
+
+ /* Description */
+ if (libconfig->setting_lookup_mutable_string(tt, "Description", obj.description, OBJECTIVE_DESCRIPTION_LENGTH) == 0) {
+ ShowError("achievement_readdb_objective_sub: Objective %d has no description for Achievement %d, skipping...\n", index, entry->id);
+ return false;
+ }
+
+ /* Criteria */
+ if ((c = libconfig->setting_get_member(tt, "Criteria")) && config_setting_is_group(tt)) {
+ /* MobId */
+ if (achievement->readdb_validate_criteria_mobid(c, &obj, entry->type, entry->id, index) == false)
+ return false;
+
+ /* ItemId */
+ if (achievement->readdb_validate_criteria_itemid(c, &obj, entry->type, entry->id, index) == false)
+ return false;
+
+ /* StatusType */
+ if (achievement->readdb_validate_criteria_statustype(c, &obj, entry->type, entry->id, index) == false)
+ return false;
+
+ /* ItemType */
+ if (achievement->readdb_validate_criteria_itemtype(c, &obj, entry->type, entry->id, index) == false)
+ return false;
+
+ /* WeaponLevel */
+ if (achievement->readdb_validate_criteria_weaponlv(c, &obj, entry->type, entry->id, index) == false)
+ return false;
+
+ /* Achievement */
+ if (achievement->readdb_validate_criteria_achievement(c, &obj, entry->type, entry->id, index) == false)
+ return false;
+
+ /**
+ * Vectors are read last to avoid memory leaks if either of the above break, in cases where they are stacked with other criteria.
+ * Note to future editors - be sure to cleanup previous vectors before breaks.
+ */
+ /* JobId */
+ if (achievement->readdb_validate_criteria_jobid(c, &obj, entry->type, entry->id, index) == false)
+ return false;
+ } else if (achievement->type_requires_criteria(entry->type)) {
+ ShowError("achievement_readdb_objective_sub: No criteria field added (Achievement: %d, Objective: %d)! Skipping...\n", entry->id, index);
+ return false;
+ }
+
+ /* Goal */
+ if (libconfig->setting_lookup_int(tt, "Goal", &obj.goal) <= 0)
+ obj.goal = 1; // 1 count by default.
+
+ /* Ensure size and allocation */
+ VECTOR_ENSURE(entry->objective, 1, 1);
+
+ /* Push buffer */
+ VECTOR_PUSH(entry->objective, obj);
+ } else { // Break if not in order, to comply with the client's objective order.
+ ShowWarning("achievement_readdb_objective_sub: Objectives for Achievement %d are not in order (starting from *%d). Remaining objectives will be skipped.\n", entry->id, index);
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Parses achievement objective entries of the current achievement db entry being parsed.
+ * @param[in] conf config pointer.
+ * @param[out] entry pointer to the achievement db entry being parsed.
+ * @return false on failure, true on success.
+ */
+static bool achievement_readdb_objectives(const struct config_setting_t *conf, struct achievement_data *entry)
+{
+ struct config_setting_t *t = NULL;
+
+ nullpo_retr(false, conf);
+ nullpo_retr(false, entry);
+
+ if ((t = libconfig->setting_get_member(conf, "Objectives")) && config_setting_is_group(t)) {
+ int i = 0;
+ // Initialize the buffer objective vector.
+ VECTOR_INIT(entry->objective);
+
+ for (i = 0; i < libconfig->setting_length(t) && i < MAX_ACHIEVEMENT_OBJECTIVES; i++)
+ if (achievement_readdb_objective_sub(t, i + 1, entry) == false)
+ break;
+
+ // Assess total objectives.
+ if (libconfig->setting_length(t) > MAX_ACHIEVEMENT_OBJECTIVES)
+ ShowWarning("achievement_readdb_objectives: Exceeded maximum number of objectives (%d) for Achievement %d. Remaining objectives will be skipped.\n", MAX_ACHIEVEMENT_OBJECTIVES, entry->id);
+ if (i == 0) {
+ ShowError("achievement_readdb_objectives: No Objectives provided for Achievement %d, skipping...\n", entry->id);
+ return false;
+ }
+ } else {
+ ShowError("achievement_readdb_objectives: No Objectives provided for Achievement %d, skipping...\n", entry->id);
+ return false;
+ } // end of "Objectives"
+
+ return true;
+}
+
+/**
+ * Validates a single reward item in the reward item list of an achievement.
+ * @param[in] t pointer to the config setting.
+ * @param[in] index Index of the item in the reward list.
+ * @param[out] entry pointer to the achievement entry being parsed.
+ * @return false on failure, true on success.
+ */
+static bool achievement_readdb_validate_reward_item_sub(const struct config_setting_t *t, int index, struct achievement_data *entry)
+{
+ struct config_setting_t *it = NULL;
+ struct achievement_reward_item item = { 0 };
+ const char *name = NULL;
+ int amount = 0;
+ int val = 0;
+
+ nullpo_retr(false, t);
+ nullpo_retr(false, entry);
+
+ if ((it = libconfig->setting_get_elem(t, index)) == NULL)
+ return false;
+
+ name = config_setting_name(it);
+ amount = libconfig->setting_get_int(it);
+
+ if (name[0] == 'I' && name[1] == 'D' && itemdb->exists(atoi(name+2))) {
+ val = atoi(name);
+ } else if (!script->get_constant(name, &val)) {
+ ShowWarning("achievement_readdb_validate_reward_item_sub: Non existant Item %s provided as a reward in Achievement %d, skipping...\n", name, entry->id);
+ return false;
+ }
+
+ if (amount <= 0) {
+ ShowWarning("achievement_readdb_validate_reward_item_sub: No amount provided for Item %s as a reward in Achievement %d, skipping...\n", name, entry->id);
+ return false;
+ }
+
+ /* Ensure size and allocation */
+ VECTOR_ENSURE(entry->rewards.item, 1, 1);
+
+ item.id = val;
+ item.amount = amount;
+
+ /* push buffer */
+ VECTOR_PUSH(entry->rewards.item, item);
+
+ return true;
+}
+
+/**
+ * Validates the reward items when parsing an achievement db entry.
+ * @param[in] t pointer to the config setting.
+ * @param[out] entry pointer to the achievement entry being parsed.
+ */
+static void achievement_readdb_validate_reward_items(const struct config_setting_t *t, struct achievement_data *entry)
+{
+ struct config_setting_t *tt = NULL;
+ int i = 0;
+
+ nullpo_retv(t);
+ nullpo_retv(entry);
+
+ if ((tt = libconfig->setting_get_member(t, "Items")) && config_setting_is_group(t)) {
+ for (i = 0; i < libconfig->setting_length(tt) && i < MAX_ACHIEVEMENT_ITEM_REWARDS; i++)
+ if (achievement->readdb_validate_reward_item_sub(tt, i, entry) == false)
+ continue;
+
+ if (libconfig->setting_length(tt) > MAX_ACHIEVEMENT_ITEM_REWARDS)
+ ShowError("achievement_readdb_validate_reward_items: Maximum amount of item rewards (%d) exceeded for Achievement %d. Remaining items will be skipped.\n", MAX_ACHIEVEMENT_ITEM_REWARDS, entry->id);
+ }
+}
+
+/**
+ * Validates the reward Bonus script when parsing an achievement db entry.
+ * @param[in] t pointer to the config setting.
+ * @param[out] entry pointer to the achievement entry being parsed.
+ * @param[in] source pointer to the source file name.
+ */
+static void achievement_readdb_validate_reward_bonus(const struct config_setting_t *t, struct achievement_data *entry, const char *source)
+{
+ const char *string = NULL;
+
+ nullpo_retv(source);
+ nullpo_retv(t);
+ nullpo_retv(entry);
+
+ if (libconfig->setting_lookup_string(t, "Bonus", &string))
+ entry->rewards.bonus = string ? script->parse(string, source, 0, SCRIPT_IGNORE_EXTERNAL_BRACKETS, NULL) : NULL;
+}
+
+/**
+ * Validates the reward Title Id when parsing an achievement entry.
+ * @param[in] t pointer to the config setting.
+ * @param[out] entry pointer to the entry.
+ */
+static void achievement_readdb_validate_reward_titleid(const struct config_setting_t *t, struct achievement_data *entry)
+{
+ nullpo_retv(t);
+ nullpo_retv(entry);
+
+ libconfig->setting_lookup_int(t, "TitleId", &entry->rewards.title_id);
+}
+
+/**
+ * Validates the reward Bonus script when parsing an achievement db entry.
+ * @param[in] conf pointer to the config setting.
+ * @param[out] entry pointer to the achievement entry being parsed.
+ * @param[in] source pointer to the source file name.
+ */
+static bool achievement_readdb_rewards(const struct config_setting_t *conf, struct achievement_data *entry, const char *source)
+{
+ struct config_setting_t *t = NULL;
+
+ nullpo_retr(false, conf);
+ nullpo_retr(false, entry);
+ nullpo_retr(false, source);
+
+ VECTOR_INIT(entry->rewards.item);
+
+ if ((t = libconfig->setting_get_member(conf, "Rewards")) && config_setting_is_group(t)) {
+ /* Items */
+ achievement->readdb_validate_reward_items(t, entry);
+
+ /* Buff/Bonus Script Code */
+ achievement->readdb_validate_reward_bonus(t, entry, source);
+
+ /* Title Id */
+ // @TODO Check Title ID against title DB!
+ achievement->readdb_validate_reward_titleid(t, entry);
+
+ }
+
+ return true;
+}
+
+/**
+ * Validates the reward Bonus script when parsing an achievement db entry.
+ * @param[in] conf pointer to the config setting.
+ * @param[out] entry pointer to the achievement entry being parsed.
+ * @param[in] source pointer to the source file name.
+ */
+static void achievement_readdb_additional_fields(const struct config_setting_t *conf, struct achievement_data *entry, const char *source)
+{
+ // plugins do their own thing.
+}
+
+/**
+ * Parses the Achievement DB.
+ * @read achievement_db.conf
+ */
+static void achievement_readb(void)
+{
+ const char *filename = "db/"DBPATH"achievement_db.conf";
+ struct config_t ach_conf = { 0 };
+ struct config_setting_t *achdb = NULL, *conf = NULL;
+ int entry = 0, count = 0;
+ VECTOR_DECL(int) duplicate;
+
+ if (!libconfig->load_file(&ach_conf, filename))
+ return; // report error.
+
+ if (!(achdb = libconfig->setting_get_member(ach_conf.root, "achievement_db"))) {
+ ShowError("achievement_readdb: Could not process contents of file '%s', skipping...\n", filename);
+ libconfig->destroy(&ach_conf);
+ return;
+ }
+
+ VECTOR_INIT(duplicate);
+
+ while ((conf = libconfig->setting_get_elem(achdb, entry++))) {
+ const char *string = NULL;
+ int val = 0, i = 0;
+ struct achievement_data t_ad = { 0 }, *p_ad = NULL;
+
+ /* Achievement ID */
+ if (libconfig->setting_lookup_int(conf, "Id", &t_ad.id) == 0) {
+ ShowError("achievement_readdb: Id field for entry %d is not provided! Skipping...\n", entry);
+ continue;
+ } else if (t_ad.id <= 0 || t_ad.id > INT32_MAX) {
+ ShowError("achievement_readdb: Invalid Id %d for entry %d. Skipping...\n", t_ad.id, entry);
+ continue;
+ }
+
+ ARR_FIND(0, VECTOR_LENGTH(duplicate), i, VECTOR_INDEX(duplicate, i) == t_ad.id);
+ if (i != VECTOR_LENGTH(duplicate)) {
+ ShowError("achievement_readdb: Duplicate Id %d for entry %d. Skipping...\n", t_ad.id, entry);
+ continue;
+ }
+
+ /* Achievement Name */
+ if (libconfig->setting_lookup_mutable_string(conf, "Name", t_ad.name, ACHIEVEMENT_NAME_LENGTH) == 0) {
+ ShowError("achievement_readdb: Name field not provided for Achievement %d!\n", t_ad.id);
+ continue;
+ }
+
+ /* Achievement Type*/
+ if (libconfig->setting_lookup_string(conf, "Type", &string) == 0) {
+ ShowError("achievement_readdb: Type field not provided for Achievement %d! Skipping...\n", t_ad.id);
+ continue;
+ } else if (!script->get_constant(string, &val)) {
+ ShowError("achievement_readdb: Invalid constant %s provided as type for Achievement %d! Skipping...\n", string, t_ad.id);
+ continue;
+ }
+
+ t_ad.type = (enum achievement_types) val;
+
+ /* Objectives */
+ achievement->readdb_objectives(conf, &t_ad);
+
+ /* Rewards */
+ achievement->readdb_rewards(conf, &t_ad, filename);
+
+ /* Achievement Points */
+ libconfig->setting_lookup_int(conf, "Points", &t_ad.points);
+
+ /* Additional Fields */
+ achievement->readdb_additional_fields(conf, &t_ad, filename);
+
+ /* Allocate memory for data. */
+ CREATE(p_ad, struct achievement_data, 1);
+ *p_ad = t_ad;
+
+ /* Place in the database. */
+ idb_put(achievement->db, p_ad->id, p_ad);
+
+ /* Put achievement key in categories. */
+ VECTOR_ENSURE(achievement->category[p_ad->type], 1, 1);
+ VECTOR_PUSH(achievement->category[p_ad->type], p_ad->id);
+
+ /* Qualify for duplicate Id checks */
+ VECTOR_ENSURE(duplicate, 1, 1);
+ VECTOR_PUSH(duplicate, t_ad.id);
+
+ count++;
+ } // end of achievement_db parsing.
+
+ /* Destroy the buffer */
+ libconfig->destroy(&ach_conf);
+
+ VECTOR_CLEAR(duplicate);
+
+ ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, filename);
+}
+
+/**
+ * On server initiation.
+ * @param[in] minimal ignores alocating/reading databases.
+ */
+static void do_init_achievement(bool minimal)
+{
+ int i = 0;
+
+ if (minimal)
+ return;
+
+ /* DB Initialization */
+ achievement->db = idb_alloc(DB_OPT_RELEASE_DATA);
+
+ for (i = 0; i < ACH_TYPE_MAX; i++)
+ VECTOR_INIT(achievement->category[i]);
+
+ VECTOR_INIT(achievement->rank_exp);
+
+ /* Read LibConfig Files */
+ achievement->readdb();
+ achievement->readdb_ranks();
+}
+
+/**
+ * Cleaning function called through achievement->db->destroy()
+ */
+static int achievement_db_finalize(union DBKey key, struct DBData *data, va_list args)
+{
+ int i = 0;
+ struct achievement_data *ad = DB->data2ptr(data);
+
+ for(i = 0; i < VECTOR_LENGTH(ad->objective); i++)
+ VECTOR_CLEAR(VECTOR_INDEX(ad->objective, i).jobid);
+
+ VECTOR_CLEAR(ad->objective);
+ VECTOR_CLEAR(ad->rewards.item);
+
+ // Free the script
+ if (ad->rewards.bonus != NULL) {
+ script->free_code(ad->rewards.bonus);
+ ad->rewards.bonus = NULL;
+ }
+
+ return 0;
+}
+
+/**
+ * On server finalizing.
+ */
+static void do_final_achievement(void)
+{
+ int i = 0;
+
+ achievement->db->destroy(achievement->db, achievement->db_finalize);
+
+ for (i = 0; i < ACH_TYPE_MAX; i++)
+ VECTOR_CLEAR(achievement->category[i]);
+
+ VECTOR_CLEAR(achievement->rank_exp);
+}
+
+/**
+ * Achievement Interface
+ */
+void achievement_defaults(void)
+{
+ achievement = &achievement_s;
+ /* */
+ achievement->init = do_init_achievement;
+ achievement->final = do_final_achievement;
+ /* */
+ achievement->db_finalize = achievement_db_finalize;
+ /* */
+ achievement->readdb = achievement_readb;
+ /* */
+ achievement->readdb_objectives_sub = achievement_readdb_objective_sub;
+ achievement->readdb_objectives = achievement_readdb_objectives;
+ /* */
+ achievement->readdb_validate_criteria_mobid = achievement_readdb_validate_criteria_mobid;
+ achievement->readdb_validate_criteria_jobid = achievement_readdb_validate_criteria_jobid;
+ achievement->readdb_validate_criteria_itemid = achievement_readdb_validate_criteria_itemid;
+ achievement->readdb_validate_criteria_statustype = achievement_readdb_validate_criteria_statustype;
+ achievement->readdb_validate_criteria_itemtype = achievement_readdb_validate_criteria_itemtype;
+ achievement->readdb_validate_criteria_weaponlv = achievement_readdb_validate_criteria_weaponlv;
+ achievement->readdb_validate_criteria_achievement = achievement_readdb_validate_criteria_achievement;
+ /* */
+ achievement->readdb_rewards = achievement_readdb_rewards;
+ achievement->readdb_validate_reward_items = achievement_readdb_validate_reward_items;
+ achievement->readdb_validate_reward_item_sub = achievement_readdb_validate_reward_item_sub;
+ achievement->readdb_validate_reward_bonus = achievement_readdb_validate_reward_bonus;
+ achievement->readdb_validate_reward_titleid = achievement_readdb_validate_reward_titleid;
+ /* */
+ achievement->readdb_additional_fields = achievement_readdb_additional_fields;
+ /* */
+ achievement->readdb_ranks = achievement_readdb_ranks;
+ /* */
+ achievement->get = achievement_get;
+ achievement->ensure = achievement_ensure;
+ /* */
+ achievement->calculate_totals = achievement_calculate_totals;
+ achievement->check_complete = achievement_check_complete;
+ achievement->progress_add = achievement_progress_add;
+ achievement->progress_set = achievement_progress_set;
+ achievement->check_criteria = achievement_check_criteria;
+ /* */
+ achievement->validate = achievement_validate;
+ achievement->validate_type = achievement_validate_type;
+ /* */
+ achievement->validate_mob_kill = achievement_validate_mob_kill;
+ achievement->validate_mob_damage = achievement_validate_mob_damage;
+ achievement->validate_pc_kill = achievement_validate_pc_kill;
+ achievement->validate_pc_damage = achievement_validate_pc_damage;
+ achievement->validate_jobchange = achievement_validate_jobchange;
+ achievement->validate_stats = achievement_validate_stats;
+ achievement->validate_chatroom_create = achievement_validate_chatroom_create;
+ achievement->validate_chatroom_members = achievement_validate_chatroom_members;
+ achievement->validate_friend_add = achievement_validate_friend_add;
+ achievement->validate_party_create = achievement_validate_party_create;
+ achievement->validate_marry = achievement_validate_marry;
+ achievement->validate_adopt = achievement_validate_adopt;
+ achievement->validate_zeny = achievement_validate_zeny;
+ achievement->validate_refine = achievement_validate_refine;
+ achievement->validate_item_get = achievement_validate_item_get;
+ achievement->validate_item_sell = achievement_validate_item_sell;
+ achievement->validate_achieve = achievement_validate_achieve;
+ achievement->validate_taming = achievement_validate_taming;
+ achievement->validate_achievement_rank = achievement_validate_achievement_rank;
+ /* */
+ achievement->type_requires_criteria = achievement_type_requires_criteria;
+ /* */
+ achievement->init_titles = achievement_init_titles;
+ achievement->check_title = achievement_check_title;
+ achievement->get_rewards = achievement_get_rewards;
+}
diff --git a/src/map/achievement.h b/src/map/achievement.h
new file mode 100644
index 000000000..beba120a2
--- /dev/null
+++ b/src/map/achievement.h
@@ -0,0 +1,289 @@
+/**
+* This file is part of Hercules.
+* http://herc.ws - http://github.com/HerculesWS/Hercules
+*
+* Copyright (C) 2018 Hercules Dev Team
+* Copyright (C) Smokexyz
+*
+* Hercules is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef MAP_ACHIEVEMENT_H
+#define MAP_ACHIEVEMENT_H
+
+#include "common/hercules.h"
+#include "common/db.h"
+#include "map/map.h" // enum status_point_types
+
+#define ACHIEVEMENT_NAME_LENGTH 50
+#define OBJECTIVE_DESCRIPTION_LENGTH 100
+
+struct achievement;
+struct map_session_data;
+struct char_achievements;
+
+/**
+ * Achievement Types
+ */
+enum achievement_types {
+ // Quest
+ ACH_QUEST, // achievement and objective specific
+ // PC Kills
+ ACH_KILL_PC_TOTAL,
+ ACH_KILL_PC_JOB,
+ ACH_KILL_PC_JOBTYPE,
+ // Mob Kills
+ ACH_KILL_MOB_CLASS,
+ // PC Damage
+ ACH_DAMAGE_PC_MAX,
+ ACH_DAMAGE_PC_TOTAL,
+ ACH_DAMAGE_PC_REC_MAX,
+ ACH_DAMAGE_PC_REC_TOTAL,
+ // Mob Damage
+ ACH_DAMAGE_MOB_MAX,
+ ACH_DAMAGE_MOB_TOTAL,
+ ACH_DAMAGE_MOB_REC_MAX,
+ ACH_DAMAGE_MOB_REC_TOTAL,
+ // Job
+ ACH_JOB_CHANGE,
+ // Status
+ ACH_STATUS,
+ ACH_STATUS_BY_JOB,
+ ACH_STATUS_BY_JOBTYPE,
+ // Chatroom
+ ACH_CHATROOM_CREATE_DEAD,
+ ACH_CHATROOM_CREATE,
+ ACH_CHATROOM_MEMBERS,
+ // Friend
+ ACH_FRIEND_ADD,
+ // Party
+ ACH_PARTY_CREATE,
+ ACH_PARTY_JOIN,
+ // Marriage
+ ACH_MARRY,
+ // Adoption
+ ACH_ADOPT_BABY,
+ ACH_ADOPT_PARENT,
+ // Zeny
+ ACH_ZENY_HOLD,
+ ACH_ZENY_GET_ONCE,
+ ACH_ZENY_GET_TOTAL,
+ ACH_ZENY_SPEND_ONCE,
+ ACH_ZENY_SPEND_TOTAL,
+ // Equipment
+ ACH_EQUIP_REFINE_SUCCESS,
+ ACH_EQUIP_REFINE_FAILURE,
+ ACH_EQUIP_REFINE_SUCCESS_TOTAL,
+ ACH_EQUIP_REFINE_FAILURE_TOTAL,
+ ACH_EQUIP_REFINE_SUCCESS_WLV,
+ ACH_EQUIP_REFINE_FAILURE_WLV,
+ ACH_EQUIP_REFINE_SUCCESS_ID,
+ ACH_EQUIP_REFINE_FAILURE_ID,
+ // Items
+ ACH_ITEM_GET_COUNT,
+ ACH_ITEM_GET_COUNT_ITEMTYPE,
+ ACH_ITEM_GET_WORTH,
+ ACH_ITEM_SELL_WORTH,
+ // Monsters
+ ACH_PET_CREATE,
+ // Achievement
+ ACH_ACHIEVE,
+ ACH_ACHIEVEMENT_RANK,
+ ACH_TYPE_MAX
+};
+
+enum unique_criteria_types {
+ CRITERIA_UNIQUE_NONE,
+ CRITERIA_UNIQUE_ACHIEVE_ID,
+ CRITERIA_UNIQUE_ITEM_ID,
+ CRITERIA_UNIQUE_STATUS_TYPE,
+ CRITERIA_UNIQUE_WEAPON_LV
+};
+
+/**
+ * Achievement Objective Structure
+ *
+ * @see achievement_type_requires_criteria()
+ * @see achievement_criteria_mobid()
+ * @see achievement_criteria_jobid()
+ * @see achievement_criteria_itemid()
+ * @see achievement_criteria_stattype()
+ * @see achievement_criteria_itemtype()
+ * @see achievement_criteria_weaponlv()
+ */
+struct achievement_objective {
+ int goal;
+ char description[OBJECTIVE_DESCRIPTION_LENGTH];
+ /**
+ * Those criteria that do not make sense if stacked together.
+ * union identifier is set in unique_type. (@see unique_criteria_type)
+ */
+ union {
+ int achieve_id;
+ int itemid;
+ enum status_point_types status_type;
+ int weapon_lv;
+ } unique;
+ enum unique_criteria_types unique_type;
+ /* */
+ uint32 item_type;
+ int mobid;
+ VECTOR_DECL(int) jobid;
+};
+
+struct achievement_reward_item {
+ int id, amount;
+};
+
+struct achievement_rewards {
+ int title_id;
+ struct script_code *bonus;
+ VECTOR_DECL(struct achievement_reward_item) item;
+};
+
+/**
+ * Achievement Data Structure
+ */
+struct achievement_data {
+ int id;
+ char name[ACHIEVEMENT_NAME_LENGTH];
+ enum achievement_types type;
+ int points;
+ VECTOR_DECL(struct achievement_objective) objective;
+ struct achievement_rewards rewards;
+};
+
+// Achievements types that use Mob ID as criteria.
+#define achievement_criteria_mobid(t) ( \
+ (t) == ACH_KILL_MOB_CLASS \
+ || (t) == ACH_PET_CREATE )
+
+// Achievements types that use JobID vector as criteria.
+#define achievement_criteria_jobid(t) ( \
+ (t) == ACH_KILL_PC_JOB \
+ || (t) == ACH_KILL_PC_JOBTYPE \
+ || (t) == ACH_JOB_CHANGE \
+ || (t) == ACH_STATUS_BY_JOB \
+ || (t) == ACH_STATUS_BY_JOBTYPE )
+
+// Achievements types that use Item ID as criteria.
+#define achievement_criteria_itemid(t) ( \
+ (t) == ACH_ITEM_GET_COUNT \
+ || (t) == ACH_EQUIP_REFINE_SUCCESS_ID \
+ || (t) == ACH_EQUIP_REFINE_FAILURE_ID )
+
+// Achievements types that use status type parameter as criteria.
+#define achievement_criteria_stattype(t) ( \
+ (t) == ACH_STATUS \
+ || (t) == ACH_STATUS_BY_JOB \
+ || (t) == ACH_STATUS_BY_JOBTYPE )
+
+// Achievements types that use item type mask as criteria.
+#define achievement_criteria_itemtype(t) ( \
+ (t) == ACH_ITEM_GET_COUNT_ITEMTYPE )
+
+// Achievements types that use weapon level as criteria.
+#define achievement_criteria_weaponlv(t) ( \
+ (t) == ACH_EQUIP_REFINE_SUCCESS_WLV \
+ || (t) == ACH_EQUIP_REFINE_FAILURE_WLV )
+
+// Valid status types for objective criteria.
+#define achievement_valid_status_types(s) ( \
+ (s) == SP_STR \
+ || (s) == SP_AGI \
+ || (s) == SP_VIT \
+ || (s) == SP_INT \
+ || (s) == SP_DEX \
+ || (s) == SP_LUK \
+ || (s) == SP_BASELEVEL || (s) == SP_JOBLEVEL )
+
+struct achievement_interface {
+ struct DBMap *db; // int id -> struct achievement_data *
+ /* */
+ VECTOR_DECL(int) rank_exp; // Achievement Rank Exp Requirements
+ VECTOR_DECL(int) category[ACH_TYPE_MAX]; /* A collection of Ids per type for faster processing. */
+ /* */
+ void (*init) (bool minimal);
+ void (*final) (void);
+ /* */
+ int (*db_finalize) (union DBKey key, struct DBData *data, va_list args);
+ /* */
+ void (*readdb)(void);
+ /* */
+ bool (*readdb_objectives_sub) (const struct config_setting_t *conf, int index, struct achievement_data *entry);
+ bool (*readdb_objectives) (const struct config_setting_t *conf, struct achievement_data *entry);
+ /* */
+ bool (*readdb_validate_criteria_mobid) (const struct config_setting_t *t, struct achievement_objective *obj, enum achievement_types type, int entry_id, int obj_idx);
+ bool (*readdb_validate_criteria_jobid) (const struct config_setting_t *t, struct achievement_objective *obj, enum achievement_types type, int entry_id, int obj_idx);
+ bool (*readdb_validate_criteria_itemid) (const struct config_setting_t *t, struct achievement_objective *obj, enum achievement_types type, int entry_id, int obj_idx);
+ bool (*readdb_validate_criteria_statustype) (const struct config_setting_t *t, struct achievement_objective *obj, enum achievement_types type, int entry_id, int obj_idx);
+ bool (*readdb_validate_criteria_itemtype) (const struct config_setting_t *t, struct achievement_objective *obj, enum achievement_types type, int entry_id, int obj_idx);
+ bool (*readdb_validate_criteria_weaponlv) (const struct config_setting_t *t, struct achievement_objective *obj, enum achievement_types type, int entry_id, int obj_idx);
+ bool (*readdb_validate_criteria_achievement) (const struct config_setting_t *t, struct achievement_objective *obj, enum achievement_types type, int entry_id, int obj_idx);
+ /* */
+ bool (*readdb_rewards) (const struct config_setting_t *conf, struct achievement_data *entry, const char *source);
+ void (*readdb_validate_reward_items) (const struct config_setting_t *t, struct achievement_data *entry);
+ bool (*readdb_validate_reward_item_sub) (const struct config_setting_t *t, int element, struct achievement_data *entry);
+ void (*readdb_validate_reward_bonus) (const struct config_setting_t *t, struct achievement_data *entry, const char *source);
+ void (*readdb_validate_reward_titleid) (const struct config_setting_t *t, struct achievement_data *entry);
+ /* */
+ void (*readdb_additional_fields) (const struct config_setting_t *conf, struct achievement_data *entry, const char *source);
+ /* */
+ void (*readdb_ranks) (void);
+ /* */
+ const struct achievement_data *(*get) (int aid);
+ struct achievement *(*ensure) (struct map_session_data *sd, const struct achievement_data *ad);
+ /* */
+ void (*calculate_totals) (const struct map_session_data *sd, int *points, int *completed, int *rank, int *curr_rank_points);
+ bool (*check_complete) (struct map_session_data *sd, const struct achievement_data *ad);
+ void (*progress_add) (struct map_session_data *sd, const struct achievement_data *ad, unsigned int obj_idx, int progress);
+ void (*progress_set) (struct map_session_data *sd, const struct achievement_data *ad, unsigned int obj_idx, int progress);
+ bool (*check_criteria) (const struct achievement_objective *objective, const struct achievement_objective *criteria);
+ /* */
+ bool (*validate) (struct map_session_data *sd, int aid, unsigned int obj_idx, int progress, bool additive);
+ int (*validate_type) (struct map_session_data *sd, enum achievement_types type, const struct achievement_objective *criteria, bool additive);
+ /* */
+ void (*validate_mob_kill) (struct map_session_data *sd, int mob_id);
+ void (*validate_mob_damage) (struct map_session_data *sd, unsigned int damage, bool received);
+ void (*validate_pc_kill) (struct map_session_data *sd, struct map_session_data *dstsd);
+ void (*validate_pc_damage) (struct map_session_data *sd, struct map_session_data *dstsd, unsigned int damage);
+ void (*validate_jobchange) (struct map_session_data *sd);
+ void (*validate_stats) (struct map_session_data *sd, enum status_point_types stat_type, int progress);
+ void (*validate_chatroom_create) (struct map_session_data *sd);
+ void (*validate_chatroom_members) (struct map_session_data *sd, int progress);
+ void (*validate_friend_add) (struct map_session_data *sd);
+ void (*validate_party_create) (struct map_session_data *sd);
+ void (*validate_marry) (struct map_session_data *sd);
+ void (*validate_adopt) (struct map_session_data *sd, bool parent);
+ void (*validate_zeny) (struct map_session_data *sd, int amount);
+ void (*validate_refine) (struct map_session_data *sd, unsigned int idx, bool success);
+ void (*validate_item_get) (struct map_session_data *sd, int nameid, int amount);
+ void (*validate_item_sell) (struct map_session_data *sd, int nameid, int amount);
+ void (*validate_achieve) (struct map_session_data *sd, int achid);
+ void (*validate_taming) (struct map_session_data *sd, int class);
+ void (*validate_achievement_rank) (struct map_session_data *sd, int rank);
+ /* */
+ bool (*type_requires_criteria) (enum achievement_types type);
+ /* */
+ void (*init_titles) (struct map_session_data *sd);
+ bool (*check_title) (struct map_session_data *sd, int title_id);
+ void (*get_rewards) (struct map_session_data *sd, const struct achievement_data *ad);
+};
+
+#ifdef HERCULES_CORE
+void achievement_defaults(void);
+#endif // HERCULES_CORE
+
+HPShared struct achievement_interface *achievement;
+
+#endif // MAP_ACHIEVEMENT_H
diff --git a/src/map/atcommand.c b/src/map/atcommand.c
index 3ec709b57..52bf64e87 100644
--- a/src/map/atcommand.c
+++ b/src/map/atcommand.c
@@ -55,6 +55,7 @@
#include "map/storage.h"
#include "map/trade.h"
#include "map/unit.h"
+#include "map/achievement.h"
#include "common/cbasetypes.h"
#include "common/conf.h"
#include "common/core.h"
@@ -1421,6 +1422,10 @@ ACMD(baselevelup)
clif->updatestatus(sd, SP_BASEEXP);
clif->updatestatus(sd, SP_NEXTBASEEXP);
pc->baselevelchanged(sd);
+
+ // achievements
+ achievement->validate_stats(sd, SP_BASELEVEL, sd->status.base_level);
+
if(sd->status.party_id)
party->send_levelup(sd);
@@ -2526,6 +2531,7 @@ ACMD(param)
clif->updatestatus(sd, SP_USTR + i);
status_calc_pc(sd, SCO_FORCE);
clif->message(fd, msg_fd(fd,42)); // Stat changed.
+ achievement->validate_stats(sd, SP_STR + i, new_value); // Achievements [Smokexyz/Hercules]
} else {
if (value < 0)
clif->message(fd, msg_fd(fd,41)); // Unable to decrease the number/value.
diff --git a/src/map/chat.c b/src/map/chat.c
index 9852131be..d9b642219 100644
--- a/src/map/chat.c
+++ b/src/map/chat.c
@@ -29,6 +29,7 @@
#include "map/npc.h" // npc_event_do()
#include "map/pc.h"
#include "map/skill.h" // ext_skill_unit_onplace()
+#include "map/achievement.h"
#include "common/cbasetypes.h"
#include "common/memmgr.h"
#include "common/mmo.h"
@@ -126,6 +127,7 @@ static bool chat_createpcchat(struct map_session_data *sd, const char *title, co
pc_stop_attack(sd);
clif->createchat(sd,0); // 0 = success
clif->dispchat(cd,0);
+ achievement->validate_chatroom_create(sd); // Achievements [Smokexyz/Hercules]
return true;
}
clif->createchat(sd,1); // 1 = Room limit exceeded
@@ -181,6 +183,9 @@ static bool chat_joinchat(struct map_session_data *sd, int chatid, const char *p
cd->usersd[cd->users] = sd;
cd->users++;
+ if (cd->owner->type == BL_PC)
+ achievement->validate_chatroom_members(BL_UCAST(BL_PC, cd->owner), cd->users);
+
pc_setchatid(sd,cd->bl.id);
clif->joinchatok(sd, cd); //To the person who newly joined the list of all
diff --git a/src/map/chrif.c b/src/map/chrif.c
index cd24c5fea..609c856c6 100644
--- a/src/map/chrif.c
+++ b/src/map/chrif.c
@@ -336,6 +336,8 @@ static bool chrif_save(struct map_session_data *sd, int flag)
elemental->save(sd->ed);
if( sd->save_quest )
intif->quest_save(sd);
+ if (VECTOR_LENGTH(sd->achievement) > 0)
+ intif->achievements_save(sd);
if (sd->storage.received == true && sd->storage.save == true)
intif->send_account_storage(sd);
diff --git a/src/map/clif.c b/src/map/clif.c
index 82507a84a..80cd44aaf 100644
--- a/src/map/clif.c
+++ b/src/map/clif.c
@@ -56,13 +56,14 @@
#include "map/trade.h"
#include "map/unit.h"
#include "map/vending.h"
+#include "map/achievement.h"
#include "common/HPM.h"
#include "common/cbasetypes.h"
#include "common/conf.h"
#include "common/ers.h"
#include "common/grfio.h"
#include "common/memmgr.h"
-#include "common/mmo.h" // NEW_CARTS
+#include "common/mmo.h" // NEW_CARTS, char_achievements
#include "common/nullpo.h"
#include "common/random.h"
#include "common/showmsg.h"
@@ -8816,17 +8817,18 @@ static void clif_refresh(struct map_session_data *sd)
/// Updates the object's (bl) name on client.
/// 0095 <id>.L <char name>.24B (ZC_ACK_REQNAME)
/// 0195 <id>.L <char name>.24B <party name>.24B <guild name>.24B <position name>.24B (ZC_ACK_REQNAMEALL)
+/// 0A30 <id>.L <char name>.24B <party name>.24B <guild name>.24B <position name>.24B <title id>.L (ZC_ACK_REQNAMEALL2)
static void clif_charnameack(int fd, struct block_list *bl)
{
- unsigned char buf[103];
- int cmd = 0x95;
+ struct packet_reqnameall_ack packet = { 0 };
+ int len = sizeof(struct packet_reqnameall_ack);
nullpo_retv(bl);
- WBUFW(buf,0) = cmd;
- WBUFL(buf,2) = bl->id;
+ packet.packet_id = reqName;
+ packet.gid = bl->id;
- switch( bl->type ) {
+ switch(bl->type) {
case BL_PC:
{
const struct map_session_data *ssd = BL_UCCAST(BL_PC, bl);
@@ -8834,17 +8836,28 @@ static void clif_charnameack(int fd, struct block_list *bl)
const struct guild *g = NULL;
int ps = -1;
+ if (ssd->fakename[0] != '\0' || ssd->status.guild_id > 0 || ssd->status.party_id > 0 || ssd->status.title_id > 0) {
+ packet.packet_id = reqNameAllType;
+ }
+
//Requesting your own "shadow" name. [Skotlex]
- if (ssd->fd == fd && ssd->disguise != -1)
- WBUFL(buf,2) = -bl->id;
+ if (ssd->fd == fd && ssd->disguise != -1) {
+ packet.gid = -bl->id;
+ }
if (ssd->fakename[0] != '\0') {
- WBUFW(buf, 0) = cmd = 0x195;
- memcpy(WBUFP(buf,6), ssd->fakename, NAME_LENGTH);
- WBUFB(buf,30) = WBUFB(buf,54) = WBUFB(buf,78) = 0;
+ memcpy(packet.name, ssd->fakename, NAME_LENGTH);
break;
}
- memcpy(WBUFP(buf,6), ssd->status.name, NAME_LENGTH);
+
+#if PACKETVER >= 20150503
+ // Title System [Dastgir/Hercules]
+ if (ssd->status.title_id > 0) {
+ packet.title_id = ssd->status.title_id;
+ }
+#endif
+
+ memcpy(packet.name, ssd->status.name, NAME_LENGTH);
if (ssd->status.party_id != 0) {
p = party->search(ssd->status.party_id);
@@ -8866,47 +8879,41 @@ static void clif_charnameack(int fd, struct block_list *bl)
if (p == NULL && g == NULL)
break;
- WBUFW(buf, 0) = cmd = 0x195;
- if (p != NULL)
- memcpy(WBUFP(buf,30), p->party.name, NAME_LENGTH);
- else
- WBUFB(buf,30) = 0;
+ if (p != NULL) {
+ memcpy(packet.party_name, p->party.name, NAME_LENGTH);
+ }
if (g != NULL && ps >= 0 && ps < MAX_GUILDPOSITION) {
- memcpy(WBUFP(buf,54), g->name,NAME_LENGTH);
- memcpy(WBUFP(buf,78), g->position[ps].name, NAME_LENGTH);
- } else { //Assume no guild.
- WBUFB(buf,54) = 0;
- WBUFB(buf,78) = 0;
+ memcpy(packet.guild_name, g->name,NAME_LENGTH);
+ memcpy(packet.position_name, g->position[ps].name, NAME_LENGTH);
}
}
break;
//[blackhole89]
case BL_HOM:
- memcpy(WBUFP(buf,6), BL_UCCAST(BL_HOM, bl)->homunculus.name, NAME_LENGTH);
+ memcpy(packet.name, BL_UCCAST(BL_HOM, bl)->homunculus.name, NAME_LENGTH);
break;
case BL_MER:
- memcpy(WBUFP(buf,6), BL_UCCAST(BL_MER, bl)->db->name, NAME_LENGTH);
+ memcpy(packet.name, BL_UCCAST(BL_MER, bl)->db->name, NAME_LENGTH);
break;
case BL_PET:
- memcpy(WBUFP(buf,6), BL_UCCAST(BL_PET, bl)->pet.name, NAME_LENGTH);
+ memcpy(packet.name, BL_UCCAST(BL_PET, bl)->pet.name, NAME_LENGTH);
break;
case BL_NPC:
- memcpy(WBUFP(buf,6), BL_UCCAST(BL_NPC, bl)->name, NAME_LENGTH);
+ memcpy(packet.name, BL_UCCAST(BL_NPC, bl)->name, NAME_LENGTH);
break;
case BL_MOB:
{
const struct mob_data *md = BL_UCCAST(BL_MOB, bl);
- memcpy(WBUFP(buf,6), md->name, NAME_LENGTH);
+ memcpy(packet.name, md->name, NAME_LENGTH);
if (md->guardian_data && md->guardian_data->g) {
- WBUFW(buf, 0) = cmd = 0x195;
- WBUFB(buf,30) = 0;
- memcpy(WBUFP(buf,54), md->guardian_data->g->name, NAME_LENGTH);
- memcpy(WBUFP(buf,78), md->guardian_data->castle->castle_name, NAME_LENGTH);
+ packet.packet_id = reqNameAllType;
+ memcpy(packet.guild_name, md->guardian_data->g->name, NAME_LENGTH);
+ memcpy(packet.position_name, md->guardian_data->castle->castle_name, NAME_LENGTH);
} else if (battle_config.show_mob_info) {
char mobhp[50], *str_p = mobhp;
- WBUFW(buf, 0) = cmd = 0x195;
+ packet.packet_id = reqNameAllType;
if (battle_config.show_mob_info&4)
str_p += sprintf(str_p, "Lv. %d | ", md->level);
if (battle_config.show_mob_info&1)
@@ -8917,34 +8924,39 @@ static void clif_charnameack(int fd, struct block_list *bl)
//can parse it. [Skotlex]
if (str_p != mobhp) {
*(str_p-3) = '\0'; //Remove trailing space + pipe.
- memcpy(WBUFP(buf,30), mobhp, NAME_LENGTH);
- WBUFB(buf,54) = 0;
- WBUFB(buf,78) = 0;
+ memcpy(packet.party_name, mobhp, NAME_LENGTH);
}
}
}
break;
case BL_CHAT:
#if 0 //FIXME: Clients DO request this... what should be done about it? The chat's title may not fit... [Skotlex]
- memcpy(WBUFP(buf,6), BL_UCCAST(BL_CHAT, bl)->title, NAME_LENGTH);
+ memcpy(packet.name, BL_UCCAST(BL_CHAT, bl)->title, NAME_LENGTH);
break;
#endif
return;
case BL_ELEM:
- memcpy(WBUFP(buf,6), BL_UCCAST(BL_ELEM, bl)->db->name, NAME_LENGTH);
+ memcpy(packet.name, BL_UCCAST(BL_ELEM, bl)->db->name, NAME_LENGTH);
break;
default:
ShowError("clif_charnameack: bad type %u(%d)\n", bl->type, bl->id);
return;
}
+ if (packet.packet_id == reqName) {
+ len = sizeof(struct packet_reqname_ack);
+ }
+ // if no recipient specified just update nearby clients
// if no recipient specified just update nearby clients
if (fd == 0) {
- clif->send(buf, packet_len(cmd), bl, AREA);
+ clif->send(&packet, len, bl, AREA);
} else {
- WFIFOHEAD(fd, packet_len(cmd));
- memcpy(WFIFOP(fd, 0), buf, packet_len(cmd));
- WFIFOSET(fd, packet_len(cmd));
+ struct map_session_data *sd = sockt->session_is_valid(fd) ? sockt->session[fd]->session_data : NULL;
+ if (sd != NULL) {
+ clif->send(&packet, len, &sd->bl, SELF);
+ } else {
+ clif->send(&packet, len, bl, SELF);
+ }
}
}
@@ -8952,54 +8964,52 @@ static void clif_charnameack(int fd, struct block_list *bl)
//Needed because when you send a 0x95 packet, the client will not remove the cached party/guild info that is not sent.
static void clif_charnameupdate(struct map_session_data *ssd)
{
- unsigned char buf[103];
- int cmd = 0x195, ps = -1;
+ int ps = -1;
struct party_data *p = NULL;
struct guild *g = NULL;
+ struct packet_reqnameall_ack packet = { 0 };
nullpo_retv(ssd);
- if( ssd->fakename[0] )
+ if (ssd->fakename[0])
return; //No need to update as the party/guild was not displayed anyway.
- WBUFW(buf,0) = cmd;
- WBUFL(buf,2) = ssd->bl.id;
+ packet.packet_id = reqNameAllType;
+ packet.gid = ssd->bl.id;
- memcpy(WBUFP(buf,6), ssd->status.name, NAME_LENGTH);
+ memcpy(packet.name, ssd->status.name, NAME_LENGTH);
if (!battle_config.display_party_name) {
if (ssd->status.party_id > 0 && ssd->status.guild_id > 0 && (g = ssd->guild) != NULL)
p = party->search(ssd->status.party_id);
- }else{
+ } else {
if (ssd->status.party_id > 0)
p = party->search(ssd->status.party_id);
}
- if( ssd->status.guild_id > 0 && (g = ssd->guild) != NULL )
- {
+ if (ssd->status.guild_id > 0 && (g = ssd->guild) != NULL) {
int i;
ARR_FIND(0, g->max_member, i, g->member[i].account_id == ssd->status.account_id && g->member[i].char_id == ssd->status.char_id);
if( i < g->max_member ) ps = g->member[i].position;
}
- if( p )
- memcpy(WBUFP(buf,30), p->party.name, NAME_LENGTH);
- else
- WBUFB(buf,30) = 0;
+ if (p != NULL)
+ memcpy(packet.party_name, p->party.name, NAME_LENGTH);
- if( g && ps >= 0 && ps < MAX_GUILDPOSITION )
- {
- memcpy(WBUFP(buf,54), g->name,NAME_LENGTH);
- memcpy(WBUFP(buf,78), g->position[ps].name, NAME_LENGTH);
+ if (g != NULL && ps >= 0 && ps < MAX_GUILDPOSITION) {
+ memcpy(packet.guild_name, g->name,NAME_LENGTH);
+ memcpy(packet.position_name, g->position[ps].name, NAME_LENGTH);
}
- else
- {
- WBUFB(buf,54) = 0;
- WBUFB(buf,78) = 0;
+
+#if PACKETVER >= 20150503
+ // Achievement System [Dastgir/Hercules]
+ if (ssd->status.title_id > 0) {
+ packet.title_id = ssd->status.title_id;
}
+#endif
// Update nearby clients
- clif->send(buf, packet_len(cmd), &ssd->bl, AREA);
+ clif->send(&packet, sizeof(packet), &ssd->bl, AREA);
}
/// Taekwon Jump (TK_HIGHJUMP) effect (ZC_HIGHJUMP).
@@ -14787,6 +14797,7 @@ static void clif_parse_FriendsListReply(int fd, struct map_session_data *sd)
f_sd->status.friends[i].char_id = sd->status.char_id;
memcpy(f_sd->status.friends[i].name, sd->status.name, NAME_LENGTH);
clif->friendslist_reqack(f_sd, sd, 0);
+ achievement->validate_friend_add(f_sd); // Achievements [Smokexyz/Hercules]
if (battle_config.friend_auto_add) {
// Also add f_sd to sd's friendlist.
@@ -14805,6 +14816,7 @@ static void clif_parse_FriendsListReply(int fd, struct map_session_data *sd)
sd->status.friends[i].char_id = f_sd->status.char_id;
memcpy(sd->status.friends[i].name, f_sd->status.name, NAME_LENGTH);
clif->friendslist_reqack(sd, f_sd, 0);
+ achievement->validate_friend_add(sd); // Achievements [Smokexyz/Hercules]
}
}
}
@@ -20224,6 +20236,216 @@ static unsigned short clif_parse_cmd_optional(int fd, struct map_session_data *s
return cmd;
}
+/**
+ * Send all of a session's achievement information to client.
+ * Called only once on login/char-loading. (PACKET_ZC_ALL_ACH_LIST)
+ * @packet [out] 0x0A23 <ID>.W <Length>.W <ach_count>.L <total_points>.L <rank>.W <current_rank_points>.L <next_rank_points>.L <struct ach_list_info *[]>.P
+ * @param fd socket descriptor
+ * @param sd pointer to map_session_data
+ */
+static void clif_achievement_send_list(int fd, struct map_session_data *sd)
+{
+#if PACKETVER >= 20141016
+ int i = 0, count = 0, curr_exp_tmp = 0;
+ struct packet_achievement_list p = { 0 };
+
+ nullpo_retv(sd);
+
+ /* Browse through the session's achievement list and gather their values. */
+ for (i = 0; i < VECTOR_LENGTH(sd->achievement); i++) {
+ int j = 0;
+ struct achievement *a = &VECTOR_INDEX(sd->achievement, i);
+ const struct achievement_data *ad = NULL;
+
+ /* Sanity check for nonull pointers. */
+ if (a == NULL || (ad = achievement->get(a->id)) == NULL)
+ continue;
+
+ p.ach[count].ach_id = a->id;
+
+ for (j = 0; j < VECTOR_LENGTH(ad->objective); j++)
+ p.ach[count].objective[j] = a->objective[j];
+
+ if (a->completed_at) {
+ p.ach[count].completed = 1;
+ p.ach[count].completed_at = (uint32) a->completed_at;
+ p.ach[count].reward = a->rewarded_at ? 1 : 0;
+ p.total_points += ad->points;
+ }
+
+ count++;
+ }
+
+ p.packet_id = achievementListType;
+ p.packet_len = sizeof(struct ach_list_info) * count + 22;
+ p.total_achievements = count;
+ /* Determine Achievement Rank and current exp */
+ curr_exp_tmp = p.total_points;
+ for (i = 0; curr_exp_tmp && i < MAX_ACHIEVEMENT_RANKS && i < VECTOR_LENGTH(achievement->rank_exp); i++) {
+ if (curr_exp_tmp >= VECTOR_INDEX(achievement->rank_exp, i)) {
+ curr_exp_tmp -= VECTOR_INDEX(achievement->rank_exp, i);
+ p.rank++;
+
+ // Validate achievement rank type achievements.
+ achievement->validate_achievement_rank(sd, p.rank);
+ }
+ }
+ /* Determine Achievement Rank Exp */
+ p.current_rank_points = curr_exp_tmp;
+ p.next_rank_points = VECTOR_INDEX(achievement->rank_exp, p.rank);
+ /* Send payload */
+ clif->send(&p, p.packet_len, &sd->bl, SELF);
+#endif // PACKETVER >= 20141016
+}
+
+/**
+ * Sends achievement information for a single achievement.
+ * Called on objective progress updates/completion. (PACKET_ZC_ACH_UPDATE)
+ * @packet [out] 0x0A24 <ID>.W <total_points>.L <rank>.W <current_rank_points>.L <next_rank_points>.L <struct ach_list_info *>.P
+ * @param fd socket descriptor
+ * @param sd pointer to struct map_session_data
+ * @param ad const pointer to struct achievement_data from the achievement db.
+ */
+static void clif_achievement_send_update(int fd, struct map_session_data *sd, const struct achievement_data *ad)
+{
+#if PACKETVER >= 20141016
+ struct packet_achievement_update p = { 0 };
+ struct achievement *a = NULL;
+ int i = 0, points = 0, rank = 0, curr_rank_points = 0;
+
+ nullpo_retv(sd);
+ nullpo_retv(ad);
+
+ /* Get Session Achievement Data */
+ if ((a = achievement->ensure(sd, ad)) == NULL)
+ return;
+
+ /* Get total points, current rank and current rank points from the session. */
+ achievement->calculate_totals(sd, &points, NULL, &rank, &curr_rank_points);
+
+ p.packet_id = achievementUpdateType;
+
+ /* Determine Total Achievement Points */
+ p.total_points = points;
+
+ /* Determine Achievement Rank */
+ p.rank = rank;
+
+ /* Determine Achievement Rank Exp */
+ p.current_rank_points = curr_rank_points;
+ p.next_rank_points = VECTOR_INDEX(achievement->rank_exp, p.rank);
+
+ p.ach.ach_id = ad->id;
+ p.ach.completed = (uint8) achievement->check_complete(sd, ad);
+
+ for (i = 0; i < VECTOR_LENGTH(ad->objective); i++)
+ p.ach.objective[i] = a->objective[i];
+
+ p.ach.completed_at = (uint32) a->completed_at;
+
+ p.ach.reward = a->rewarded_at ? 1 : 0;
+
+ clif->send(&p, packet_len(achievementUpdateType), &sd->bl, SELF);
+
+ /* Validate rank-related achievements */
+ achievement->validate_achievement_rank(sd, rank);
+
+#endif // PACKETVER >= 20141016
+}
+
+/**
+ * Parses achievement reward packet from session.
+ * @packet [in] 0x0A25 <ach_id>.L
+ * @param fd socket descriptor.
+ * @param sd ptr to session data.
+ */
+static void clif_parse_achievement_get_reward(int fd, struct map_session_data *sd) __attribute__((nonnull(2)));
+static void clif_parse_achievement_get_reward(int fd, struct map_session_data *sd)
+{
+#if PACKETVER >= 20141016
+ int ach_id = RFIFOL(fd, 2);
+ const struct achievement_data *ad = NULL;
+ struct achievement *ach = NULL;
+
+ if (ach_id <= 0 || (ad = achievement->get(ach_id)) == NULL)
+ return;
+
+ if ((ach = achievement->ensure(sd, ad)) == NULL)
+ return;
+
+ if (achievement->check_complete(sd, ad) && ach->completed_at && ach->rewarded_at == 0) {
+ achievement->get_rewards(sd, ad);
+ }
+#endif // PACKETVER >= 20141016
+}
+
+/**
+ * Sends achievement reward collection acknowledgement to the client.
+ * @packet [out] 0x0A26 <packet_id>.W <received
+ */
+static void clif_achievement_reward_ack(int fd, struct map_session_data *sd, const struct achievement_data *ad)
+{
+#if PACKETVER >= 20141016
+ struct packet_achievement_reward_ack p = { 0 };
+
+ nullpo_retv(sd);
+ nullpo_retv(ad);
+
+ p.packet_id = achievementRewardAckType;
+ p.received = 1;
+ p.ach_id = ad->id;
+
+ clif->send(&p, packet_len(achievementRewardAckType), &sd->bl, SELF);
+#endif // PACKETVER >= 20141016
+}
+
+/**
+ * Sends achievement reward collection acknowledgement to the client.
+ * @packet[in] 0x0A2E <packet_id>.W <title_id>.L
+ */
+static void clif_parse_change_title(int fd, struct map_session_data *sd) __attribute__((nonnull(2)));
+static void clif_parse_change_title(int fd, struct map_session_data *sd)
+{
+ int title_id = RFIFOL(fd, 2);
+
+ if (title_id == sd->status.title_id) { // Same Title
+ return;
+ } else if (title_id < 0) {
+ title_id = 0;
+ }
+
+ clif->change_title_ack(fd, sd, title_id);
+}
+
+/**
+ * [clif_change_title_ack description]
+ * @packet [out] 0x0A2F <packet_id>.W <Result>.B <title_id>.L
+ */
+static void clif_change_title_ack(int fd, struct map_session_data *sd, int title_id)
+{
+#if PACKETVER >= 20141016
+ unsigned char failed = 0;
+
+ if (!achievement->check_title(sd, title_id)) {
+ clif->message(fd, "Title is not yet earned.");
+ failed = 1;
+ }
+
+ sd->status.title_id = title_id;
+
+ WFIFOHEAD(fd, packet_len(0xa2f));
+ WFIFOW(fd, 0) = 0xa2f;
+ WFIFOB(fd, 2) = failed;
+ WFIFOL(fd, 3) = sd->status.title_id;
+ WFIFOSET(fd, packet_len(0xa2f));
+
+ // Update names
+ clif->charnameack(fd, &sd->bl);
+ clif->charnameack(0, &sd->bl);
+#endif
+}
+// End of Achievement System
+
/*==========================================
* RoDEX
*------------------------------------------*/
@@ -22166,6 +22388,14 @@ void clif_defaults(void)
clif->isdisguised = clif_isdisguised;
clif->navigate_to = clif_navigate_to;
clif->bl_type = clif_bl_type;
+ /* Achievement System */
+ clif->achievement_send_list = clif_achievement_send_list;
+ clif->achievement_send_update = clif_achievement_send_update;
+ clif->pAchievementGetReward = clif_parse_achievement_get_reward;
+ clif->achievement_reward_ack = clif_achievement_reward_ack;
+ /* Title */
+ clif->change_title_ack = clif_change_title_ack;
+ clif->pChangeTitle = clif_parse_change_title;
/*------------------------
*- Parse Incoming Packet
@@ -22413,6 +22643,7 @@ void clif_defaults(void)
clif->pHotkeyRowShift = clif_parse_HotkeyRowShift;
clif->dressroom_open = clif_dressroom_open;
clif->pOneClick_ItemIdentify = clif_parse_OneClick_ItemIdentify;
+ /* Achievements [Smokexyz/Hercules] */
clif->get_bl_name = clif_get_bl_name;
/* RODEX */
clif->pRodexOpenWriteMail = clif_parse_rodex_open_write_mail;
diff --git a/src/map/clif.h b/src/map/clif.h
index 0077566b5..8cff8a21e 100644
--- a/src/map/clif.h
+++ b/src/map/clif.h
@@ -54,6 +54,7 @@ struct skill_cd;
struct skill_unit;
struct unit_data;
struct view_data;
+struct achievement_data; // map/achievement.h
enum clif_messages;
enum rodex_add_item;
@@ -1197,6 +1198,13 @@ struct clif_interface {
bool (*isdisguised) (struct block_list* bl);
void (*navigate_to) (struct map_session_data *sd, const char* mapname, uint16 x, uint16 y, uint8 flag, bool hideWindow, uint16 mob_id);
unsigned char (*bl_type) (struct block_list *bl);
+ /* Achievement System */
+ void (*achievement_send_list) (int fd, struct map_session_data *sd);
+ void (*achievement_send_update) (int fd, struct map_session_data *sd, const struct achievement_data *ad);
+ void (*pAchievementGetReward) (int fd, struct map_session_data *sd);
+ void (*achievement_reward_ack) (int fd, struct map_session_data *sd, const struct achievement_data *ad);
+ void (*change_title_ack) (int fd, struct map_session_data *sd, int title_id);
+ void (*pChangeTitle) (int fd, struct map_session_data *sd);
/*------------------------
*- Parse Incoming Packet
*------------------------*/
diff --git a/src/map/intif.c b/src/map/intif.c
index 393058a8a..5fafc0913 100644
--- a/src/map/intif.c
+++ b/src/map/intif.c
@@ -41,6 +41,8 @@
#include "map/quest.h"
#include "map/rodex.h"
#include "map/storage.h"
+#include "map/achievement.h"
+
#include "common/memmgr.h"
#include "common/nullpo.h"
#include "common/showmsg.h"
@@ -1730,6 +1732,99 @@ static void intif_parse_DeleteHomunculusOk(int fd)
ShowError("Homunculus data delete failure\n");
}
+/***************************************
+ * ACHIEVEMENT SYSTEM FUNCTIONS
+ ***************************************/
+/**
+ * Sends a request to the inter-server to load
+ * and send a character's achievement data.
+ * @packet [out] 0x3012 <char_id>.L
+ * @param sd pointer to map_session_data.
+ */
+static void intif_achievements_request(struct map_session_data *sd)
+{
+ nullpo_retv(sd);
+
+ if (intif->CheckForCharServer())
+ return;
+
+ WFIFOHEAD(inter_fd, 6);
+ WFIFOW(inter_fd, 0) = 0x3012;
+ WFIFOL(inter_fd, 2) = sd->status.char_id;
+ WFIFOSET(inter_fd, 6);
+}
+
+/**
+ * Handles reception of achievement data for a character from the inter-server.
+ * @packet [in] 0x3810 <packet_len>.W <char_id>.L <char_achievements[]>.P
+ * @param fd socket descriptor.
+ */
+static void intif_parse_achievements_load(int fd)
+{
+ int size = RFIFOW(fd, 2);
+ int char_id = RFIFOL(fd, 4);
+ int payload_count = (size - 8) / sizeof(struct achievement);
+ struct map_session_data *sd = map->charid2sd(char_id);
+ int i = 0;
+
+ if (sd == NULL) {
+ ShowError("intif_parse_achievements_load: Parse request for achievements received but character is offline!\n");
+ return;
+ }
+
+ if (VECTOR_LENGTH(sd->achievement) > 0) {
+ ShowError("intif_parse_achievements_load: Achievements already loaded! Possible multiple calls from the inter-server received.\n");
+ return;
+ }
+
+ VECTOR_ENSURE(sd->achievement, payload_count, 1);
+
+ for (i = 0; i < payload_count; i++) {
+ struct achievement t_ach = { 0 };
+
+ memcpy(&t_ach, RFIFOP(fd, 8 + i * sizeof(struct achievement)), sizeof(struct achievement));
+
+ if (achievement->get(t_ach.id) == NULL) {
+ ShowError("intif_parse_achievements_load: Invalid Achievement %d received from character %d. Ignoring...\n", t_ach.id, char_id);
+ continue;
+ }
+
+ VECTOR_PUSH(sd->achievement, t_ach);
+ }
+
+ achievement->init_titles(sd);
+ clif->achievement_send_list(fd, sd);
+ sd->achievements_received = true;
+}
+
+/**
+ * Send character's achievement data to the inter-server.
+ * @packet 0x3013 <packet_len>.W <char_id>.L <achievements[]>.P
+ * @param sd pointer to map session data.
+ */
+static void intif_achievements_save(struct map_session_data *sd)
+{
+ int packet_len = 0, payload_size = 0, i = 0;
+
+ nullpo_retv(sd);
+ /* check for character server. */
+ if (intif->CheckForCharServer())
+ return;
+ /* Return if no data. */
+ if (!(payload_size = VECTOR_LENGTH(sd->achievement) * sizeof(struct achievement)))
+ return;
+
+ packet_len = payload_size + 8;
+
+ WFIFOHEAD(inter_fd, packet_len);
+ WFIFOW(inter_fd, 0) = 0x3013;
+ WFIFOW(inter_fd, 2) = packet_len;
+ WFIFOL(inter_fd, 4) = sd->status.char_id;
+ for (i = 0; i < VECTOR_LENGTH(sd->achievement); i++)
+ memcpy(WFIFOP(inter_fd, 8 + i * sizeof(struct achievement)), &VECTOR_INDEX(sd->achievement, i), sizeof(struct achievement));
+ WFIFOSET(inter_fd, packet_len);
+}
+
/**************************************
* QUESTLOG SYSTEM FUNCTIONS *
**************************************/
@@ -2799,6 +2894,7 @@ static int intif_parse(int fd)
case 0x3806: intif->pChangeNameOk(fd); break;
case 0x3807: intif->pMessageToFD(fd); break;
case 0x3808: intif->pAccountStorageSaveAck(fd); break;
+ case 0x3810: intif->pAchievementsLoad(fd); break;
case 0x3818: intif->pLoadGuildStorage(fd); break;
case 0x3819: intif->pSaveGuildStorage(fd); break;
case 0x3820: intif->pPartyCreated(fd); break;
@@ -2896,7 +2992,7 @@ void intif_defaults(void)
{
const int packet_len_table [INTIF_PACKET_LEN_TABLE_SIZE] = {
-1,-1,27,-1, -1,-1,37,-1, 7, 0, 0, 0, 0, 0, 0, 0, //0x3800-0x380f
- 0, 0, 0, 0, 0, 0, 0, 0, -1,11, 0, 0, 0, 0, 0, 0, //0x3810
+ -1, 0, 0, 0, 0, 0, 0, 0, -1,11, 0, 0, 0, 0, 0, 0, //0x3810 Achievements [Smokexyz/Hercules]
39,-1,15,15, 14,19, 7,-1, 0, 0, 0, 0, 0, 0, 0, 0, //0x3820
10,-1,15, 0, 79,23, 7,-1, 0,-1,-1,-1, 14,67,186,-1, //0x3830
-1, 0, 0,14, 0, 0, 0, 0, -1,74,-1,11, 11,-1, 0, 0, //0x3840
@@ -3001,6 +3097,9 @@ void intif_defaults(void)
intif->CheckForCharServer = CheckForCharServer;
/* */
intif->itembound_req = intif_itembound_req;
+ /* Achievement System */
+ intif->achievements_request = intif_achievements_request;
+ intif->achievements_save = intif_achievements_save;
/* parse functions */
intif->pWisMessage = intif_parse_WisMessage;
intif->pWisEnd = intif_parse_WisEnd;
@@ -3073,4 +3172,6 @@ void intif_defaults(void)
intif->pRodexCheckName = intif_parse_RodexCheckName;
/* Clan System */
intif->pRecvClanMemberAction = intif_parse_RecvClanMemberAction;
+ /* Achievement System */
+ intif->pAchievementsLoad = intif_parse_achievements_load;
}
diff --git a/src/map/intif.h b/src/map/intif.h
index c75b93201..1e98d11f8 100644
--- a/src/map/intif.h
+++ b/src/map/intif.h
@@ -145,6 +145,9 @@ struct intif_interface {
void (*request_accinfo) (int u_fd, int aid, int group_lv, char* query);
/* */
int (*CheckForCharServer) (void);
+ /* Achievement System [Smokexyz/Hercules] */
+ void(*achievements_request) (struct map_session_data *sd);
+ void(*achievements_save) (struct map_session_data *sd);
/* */
void (*pWisMessage) (int fd);
void (*pWisEnd) (int fd);
@@ -217,6 +220,8 @@ struct intif_interface {
void(*pRodexCheckName) (int fd);
/* Clan System */
void (*pRecvClanMemberAction) (int fd);
+ /* Achievements */
+ void (*pAchievementsLoad) (int fd);
};
#ifdef HERCULES_CORE
diff --git a/src/map/map.c b/src/map/map.c
index 0124a3035..ce8f4cdf5 100644
--- a/src/map/map.c
+++ b/src/map/map.c
@@ -59,6 +59,7 @@
#include "map/rodex.h"
#include "map/trade.h"
#include "map/unit.h"
+#include "map/achievement.h"
#include "common/HPM.h"
#include "common/cbasetypes.h"
#include "common/conf.h"
@@ -6134,6 +6135,7 @@ int do_final(void)
map->list_final();
vending->final();
rodex->final();
+ achievement->final();
HPM_map_do_final();
@@ -6338,6 +6340,7 @@ static void map_load_defaults(void)
pet_defaults();
path_defaults();
quest_defaults();
+ achievement_defaults();
npc_chat_defaults();
rodex_defaults();
}
@@ -6653,6 +6656,7 @@ int do_init(int argc, char *argv[])
mercenary->init(minimal);
elemental->init(minimal);
quest->init(minimal);
+ achievement->init(minimal);
npc->init(minimal);
unit->init(minimal);
bg->init(minimal);
diff --git a/src/map/map.h b/src/map/map.h
index 04525b4d5..207fef2ce 100644
--- a/src/map/map.h
+++ b/src/map/map.h
@@ -66,6 +66,16 @@ enum E_MAPSERVER_ST {
#define block_free_max 1048576
#define BL_LIST_MAX 1048576
+// The following system marks a different job ID system used by the map server,
+// which makes a lot more sense than the normal one. [Skotlex]
+// These marks the "level" of the job.
+#define JOBL_2_1 0x0100
+#define JOBL_2_2 0x0200
+#define JOBL_2 0x0300 // JOBL_2_1 | JOBL_2_2
+#define JOBL_UPPER 0x1000
+#define JOBL_BABY 0x2000
+#define JOBL_THIRD 0x4000
+
// For filtering and quick checking.
#define MAPID_BASEMASK 0x00ff
#define MAPID_UPPERMASK 0x0fff
@@ -537,6 +547,7 @@ struct flooritem_data {
};
enum status_point_types { //we better clean up this enum and change it name [Hemagx]
+ SP_NONE = -1,
SP_SPEED,SP_BASEEXP,SP_JOBEXP,SP_KARMA,SP_MANNER,SP_HP,SP_MAXHP,SP_SP, // 0-7
SP_MAXSP,SP_STATUSPOINT,SP_0a,SP_BASELEVEL,SP_SKILLPOINT,SP_STR,SP_AGI,SP_VIT, // 8-15
SP_INT,SP_DEX,SP_LUK,SP_CLASS,SP_ZENY,SP_SEX,SP_NEXTBASEEXP,SP_NEXTJOBEXP, // 16-23
diff --git a/src/map/mob.c b/src/map/mob.c
index 0dbff9211..27039490c 100644
--- a/src/map/mob.c
+++ b/src/map/mob.c
@@ -44,6 +44,7 @@
#include "map/script.h"
#include "map/skill.h"
#include "map/status.h"
+#include "map/achievement.h"
#include "common/HPM.h"
#include "common/cbasetypes.h"
#include "common/conf.h"
@@ -2188,6 +2189,10 @@ static void mob_damage(struct mob_data *md, struct block_list *src, int damage)
if (src)
mob->log_damage(md, src, damage);
md->dmgtick = timer->gettick();
+
+ // Achievements [Smokexyz/Hercules]
+ if (src != NULL && src->type == BL_PC)
+ achievement->validate_mob_damage(BL_UCAST(BL_PC, src), damage, false);
}
if (battle_config.show_mob_info&3)
@@ -2420,6 +2425,8 @@ static int mob_dead(struct mob_data *md, struct block_list *src, int type)
}
if(zeny) // zeny from mobs [Valaris]
pc->getzeny(tmpsd[i], zeny, LOG_TYPE_PICKDROP_MONSTER, NULL);
+
+ achievement->validate_mob_kill(tmpsd[i], md->db->mob_id); // Achievements [Smokexyz/Hercules]
}
}
diff --git a/src/map/npc.c b/src/map/npc.c
index 383558eaf..3a00b38ea 100644
--- a/src/map/npc.c
+++ b/src/map/npc.c
@@ -40,6 +40,7 @@
#include "map/skill.h"
#include "map/status.h"
#include "map/unit.h"
+#include "map/achievement.h"
#include "common/HPM.h"
#include "common/cbasetypes.h"
#include "common/db.h"
@@ -2272,6 +2273,9 @@ static int npc_selllist(struct map_session_data *sd, struct itemlist *item_list)
}
pc->delitem(sd, idx, entry->amount, 0, DELITEM_SOLD, LOG_TYPE_NPC);
+
+ // Achievements [Smokexyz/Hercules]
+ achievement->validate_item_sell(sd, sd->status.inventory[idx].nameid, entry->amount);
}
if (z + sd->status.zeny > MAX_ZENY && nd->master_nd == NULL)
diff --git a/src/map/packets.h b/src/map/packets.h
index 8ef011d08..61bf625cf 100644
--- a/src/map/packets.h
+++ b/src/map/packets.h
@@ -3209,7 +3209,7 @@ packet(0x96e,-1,clif->ackmergeitems);
packet(0x0a22,3); // ZC_RECV_ROULETTE_ITEM
packet(0x0a23,-1); // ZC_ALL_ACH_LIST
packet(0x0a24,35); // ZC_ACH_UPDATE
- packet(0x0a25,6,clif->pDull/*,XXX*/); // CZ_REQ_ACH_REWARD
+ packet(0x0a25,6,clif->pAchievementGetReward, 2); // CZ_REQ_ACH_REWARD
packet(0x0a26,7); // ZC_REQ_ACH_REWARD_ACK
// changed packet sizes
packet(0x0a18,14); // ZC_ACCEPT_ENTER3
@@ -3266,7 +3266,7 @@ packet(0x96e,-1,clif->ackmergeitems);
// 2014-09-03aRagexeRE
#if PACKETVER >= 20140903
// new packets
- packet(0x0a2e,6,clif->pDull/*,XXX*/); // CZ_REQ_CHANGE_TITLE
+ packet(0x0a2e,6,clif->pChangeTitle); // CZ_REQ_CHANGE_TITLE
packet(0x0a2f,7); // ZC_ACK_CHANGE_TITLE
// changed packet sizes
#endif
diff --git a/src/map/packets_struct.h b/src/map/packets_struct.h
index e8207d29c..5f6443ef3 100644
--- a/src/map/packets_struct.h
+++ b/src/map/packets_struct.h
@@ -302,6 +302,11 @@ enum packet_headers {
rouletteinfoackType = 0xa1c,
roulettgenerateackType = 0xa20,
roulettercvitemackType = 0xa22,
+#if PACKETVER >= 20141016
+ achievementListType = 0xa23,
+ achievementUpdateType = 0xa24,
+ achievementRewardAckType = 0xa26,
+#endif // PACKETVER >= 20141016
#if PACKETVER >= 20150513 // [4144] 0x09f8 handling in client from 2014-10-29aRagexe and 2014-03-26cRagexeRE
questListType = 0x9f8, ///< ZC_ALL_QUEST_LIST3
#elif PACKETVER >= 20141022
@@ -401,6 +406,12 @@ enum packet_headers {
#else
hominfoType = 0x22e,
#endif
+ reqName = 0x95,
+#if PACKETVER >= 20150503 // Confirm this?
+ reqNameAllType = 0xA30,
+#else
+ reqNameAllType = 0x195,
+#endif
};
#if !defined(sun) && (!defined(__NETBSD__) || __NetBSD_Version__ >= 600000000) // NetBSD 5 and Solaris don't like pragma pack but accept the packed attribute
@@ -2589,6 +2600,61 @@ struct PACKET_ZC_SEARCH_STORE_INFO_ACK {
struct PACKET_ZC_SEARCH_STORE_INFO_ACK_sub items[];
} __attribute__((packed));
+/* Achievement System */
+struct ach_list_info {
+ uint32 ach_id;
+ uint8 completed;
+ uint32 objective[MAX_ACHIEVEMENT_OBJECTIVES];
+ uint32 completed_at;
+ uint8 reward;
+} __attribute__((packed));
+
+struct packet_achievement_list {
+ uint16 packet_id;
+ uint16 packet_len;
+ uint32 total_achievements;
+ uint32 total_points;
+ uint16 rank;
+ uint32 current_rank_points;
+ uint32 next_rank_points;
+ struct ach_list_info ach[MAX_ACHIEVEMENT_DB];
+} __attribute__((packed));
+
+struct packet_achievement_update {
+ uint16 packet_id;
+ uint32 total_points;
+ uint16 rank;
+ uint32 current_rank_points;
+ uint32 next_rank_points;
+ struct ach_list_info ach;
+} __attribute__((packed));
+
+struct packet_achievement_reward_ack {
+ uint16 packet_id;
+ uint8 received;
+ uint32 ach_id;
+} __attribute__((packed));
+
+// Name Packet ZC_ACK_REQNAME
+struct packet_reqname_ack {
+ uint16 packet_id;
+ int32 gid;
+ char name[NAME_LENGTH];
+} __attribute__((packed));
+
+// ZC_ACK_REQNAMEALL / ZC_ACK_REQNAMEALL2
+struct packet_reqnameall_ack {
+ uint16 packet_id;
+ int32 gid;
+ char name[NAME_LENGTH];
+ char party_name[NAME_LENGTH];
+ char guild_name[NAME_LENGTH];
+ char position_name[NAME_LENGTH];
+#if PACKETVER >= 20150503 // Confirm this?
+ int32 title_id; // Achievement Title
+#endif
+} __attribute__((packed));
+
#if !defined(sun) && (!defined(__NETBSD__) || __NetBSD_Version__ >= 600000000) // NetBSD 5 and Solaris don't like pragma pack but accept the packed attribute
#pragma pack(pop)
#endif // not NetBSD < 6 / Solaris
diff --git a/src/map/party.c b/src/map/party.c
index 9024b1c19..e4fb18c23 100644
--- a/src/map/party.c
+++ b/src/map/party.c
@@ -36,6 +36,7 @@
#include "map/pc.h"
#include "map/skill.h"
#include "map/status.h"
+#include "map/achievement.h"
#include "common/HPM.h"
#include "common/cbasetypes.h"
#include "common/memmgr.h"
@@ -189,6 +190,9 @@ static int party_create(struct map_session_data *sd, const char *name, int item,
party->fill_member(&leader, sd, 1);
intif->create_party(&leader,name,item,item2);
+
+ achievement->validate_party_create(sd); //Achievements (Smokexyz)
+
return 0;
}
diff --git a/src/map/pc.c b/src/map/pc.c
index d8a1c0b0e..01bae5e14 100644
--- a/src/map/pc.c
+++ b/src/map/pc.c
@@ -55,6 +55,7 @@
#include "map/skill.h"
#include "map/status.h" // struct status_data
#include "map/storage.h"
+#include "map/achievement.h"
#include "common/cbasetypes.h"
#include "common/conf.h"
#include "common/core.h" // get_svn_revision()
@@ -1053,6 +1054,11 @@ static bool pc_adoption(struct map_session_data *p1_sd, struct map_session_data
pc->skill(p1_sd, WE_CALLBABY, 1, SKILL_GRANT_PERMANENT);
pc->skill(p2_sd, WE_CALLBABY, 1, SKILL_GRANT_PERMANENT);
+ // Achievements [Smokexyz/Hercules]
+ achievement->validate_adopt(p1_sd, true); // Parent 1
+ achievement->validate_adopt(p2_sd, true); // Parent 2
+ achievement->validate_adopt(b_sd, false); // Baby
+
return true;
}
@@ -1325,6 +1331,7 @@ static bool pc_authok(struct map_session_data *sd, int login_id2, time_t expirat
sd->bg_queue.type = 0;
VECTOR_INIT(sd->script_queues);
+ VECTOR_INIT(sd->achievement); // Achievements [Smokexyz/Hercules]
VECTOR_INIT(sd->storage.item); // initialize storage item vector.
VECTOR_INIT(sd->hatEffectId);
@@ -1384,6 +1391,7 @@ static bool pc_authok(struct map_session_data *sd, int login_id2, time_t expirat
" Group '"CL_WHITE"%d"CL_RESET"').\n",
sd->status.name, sd->status.account_id, sd->status.char_id,
CONVIP(ip), sd->group_id);
+
// Send friends list
clif->friendslist_send(sd);
@@ -1464,7 +1472,6 @@ static int pc_reg_received(struct map_session_data *sd)
nullpo_ret(sd);
sd->vars_ok = true;
-
sd->change_level_2nd = pc_readglobalreg(sd,script->add_str("jobchange_level"));
sd->change_level_3rd = pc_readglobalreg(sd,script->add_str("jobchange_level_3rd"));
sd->die_counter = pc_readglobalreg(sd,script->add_str("PC_DIE_COUNTER"));
@@ -1587,6 +1594,9 @@ static int pc_reg_received(struct map_session_data *sd)
if( npc->motd ) /* [Ind/Hercules] */
script->run(npc->motd->u.scr.script, 0, sd->bl.id, npc->fake_nd->bl.id);
+ // Achievements [Smokexyz/Hercules]
+ intif->achievements_request(sd);
+
return 1;
}
@@ -4494,6 +4504,8 @@ static int pc_payzeny(struct map_session_data *sd, int zeny, enum e_log_pick_typ
sd->status.zeny -= zeny;
clif->updatestatus(sd,SP_ZENY);
+ achievement->validate_zeny(sd, -zeny); // Achievements [Smokexyz/Hercules]
+
if(!tsd) tsd = sd;
logs->zeny(sd, type, tsd, -zeny);
if( zeny > 0 && sd->state.showzeny ) {
@@ -4630,6 +4642,8 @@ static int pc_getzeny(struct map_session_data *sd, int zeny, enum e_log_pick_typ
sd->status.zeny += zeny;
clif->updatestatus(sd,SP_ZENY);
+ achievement->validate_zeny(sd, zeny); // Achievements [Smokexyz/Hercules]
+
if(!tsd) tsd = sd;
logs->zeny(sd, type, tsd, zeny);
if( zeny > 0 && sd->state.showzeny ) {
@@ -4754,6 +4768,7 @@ static int pc_additem(struct map_session_data *sd, struct item *item_data, int a
sd->status.inventory[i].amount = amount;
sd->inventory_data[i] = data;
clif->additem(sd,i,amount,0);
+
}
if( ( !itemdb->isstackable2(data) || data->flag.force_serial || data->type == IT_CASH) && !item_data->unique_id )
@@ -4761,6 +4776,8 @@ static int pc_additem(struct map_session_data *sd, struct item *item_data, int a
logs->pick_pc(sd, log_type, amount, &sd->status.inventory[i],sd->inventory_data[i]);
+ achievement->validate_item_get(sd, sd->status.inventory[i].nameid, sd->status.inventory[i].amount); // Achievements [Smokexyz/Hercules]
+
sd->weight += w;
clif->updatestatus(sd,SP_WEIGHT);
//Auto-equip
@@ -6873,11 +6890,15 @@ static int pc_checkbaselevelup(struct map_session_data *sd)
clif->misceffect(&sd->bl,0);
npc->script_event(sd, NPCE_BASELVUP); //LORDALFA - LVLUPEVENT
- if(sd->status.party_id)
+ if (sd->status.party_id)
party->send_levelup(sd);
pc->baselevelchanged(sd);
+
quest->questinfo_refresh(sd);
+
+ achievement->validate_stats(sd, SP_BASELEVEL, sd->status.base_level);
+
return 1;
}
@@ -6940,7 +6961,11 @@ static int pc_checkjoblevelup(struct map_session_data *sd)
clif->status_change(&sd->bl,SI_DEVIL1, 1, 0, 0, 0, 1); //Permanent blind effect from SG_DEVIL.
npc->script_event(sd, NPCE_JOBLVUP);
+
quest->questinfo_refresh(sd);
+
+ achievement->validate_stats(sd, SP_BASELEVEL, sd->status.job_level);
+
return 1;
}
@@ -7237,6 +7262,8 @@ static int pc_setstat(struct map_session_data *sd, int type, int val)
return -1;
}
+ achievement->validate_stats(sd, type, val); // Achievements [Smokexyz/Hercules]
+
return val;
}
@@ -7968,6 +7995,14 @@ static void pc_damage(struct map_session_data *sd, struct block_list *src, unsig
if (battle_config.prevent_logout_trigger & PLT_DAMAGE)
sd->canlog_tick = timer->gettick();
+
+ // Achievements [Smokexyz/Hercules]
+ if (src != NULL) {
+ if (src->type == BL_PC)
+ achievement->validate_pc_damage(BL_UCAST(BL_PC, src), sd, hp);
+ else if (src->type == BL_MOB)
+ achievement->validate_mob_damage(sd, hp, true);
+ }
}
/*==========================================
@@ -8118,6 +8153,8 @@ static int pc_dead(struct map_session_data *sd, struct block_list *src)
pc->setparam(ssd, SP_KILLEDRID, sd->bl.id);
npc->script_event(ssd, NPCE_KILLPC);
+ achievement->validate_pc_kill(ssd, sd); // Achievements [Smokexyz/Hercules]
+
if (battle_config.pk_mode&2) {
ssd->status.manner -= 5;
if(ssd->status.manner < 0)
@@ -9036,6 +9073,8 @@ static int pc_jobchange(struct map_session_data *sd, int class, int upper)
}
quest->questinfo_refresh(sd);
+ achievement->validate_jobchange(sd); // Achievements [Smokexyz/Hercules]
+
return 0;
}
@@ -10676,6 +10715,11 @@ static int pc_marriage(struct map_session_data *sd, struct map_session_data *dst
return -1;
sd->status.partner_id = dstsd->status.char_id;
dstsd->status.partner_id = sd->status.char_id;
+
+ // Achievements [Smokexyz/Hercules]
+ achievement->validate_marry(sd);
+ achievement->validate_marry(dstsd);
+
return 0;
}
diff --git a/src/map/pc.h b/src/map/pc.h
index 0781fe801..17a9b8200 100644
--- a/src/map/pc.h
+++ b/src/map/pc.h
@@ -37,7 +37,7 @@
#include "common/db.h"
#include "common/ers.h" // struct eri
#include "common/hercules.h"
-#include "common/mmo.h" // JOB_*, MAX_FAME_LIST, struct fame_list, struct mmo_charstatus, NEW_CARTS
+#include "common/mmo.h" // JOB_*, MAX_FAME_LIST, struct fame_list, struct mmo_charstatus, NEW_CARTS, struct s_achievement
/**
* Defines
@@ -631,6 +631,12 @@ END_ZEROED_BLOCK;
unsigned sitstand : 1;
unsigned commands : 1;
} block_action;
+
+ /* Achievement System */
+ struct char_achievements achievement;
+ bool achievements_received;
+ // Title
+ VECTOR_DECL(int) title_ids;
};
#define EQP_WEAPON EQP_HAND_R
diff --git a/src/map/pet.c b/src/map/pet.c
index d1d8a5a33..cfb3e8253 100644
--- a/src/map/pet.c
+++ b/src/map/pet.c
@@ -23,6 +23,7 @@
#include "config/core.h" // DBPATH
#include "pet.h"
+#include "map/achievement.h"
#include "map/atcommand.h" // msg_txt()
#include "map/battle.h"
#include "map/chrif.h"
@@ -582,8 +583,8 @@ static int pet_catch_process2(struct map_session_data *sd, int target_id)
pet_catch_rate = (pet->db[i].capture + (sd->status.base_level - md->level)*30 + sd->battle_status.luk*20)*(200 - get_percentage(md->status.hp, md->status.max_hp))/100;
if(pet_catch_rate < 1) pet_catch_rate = 1;
- if(battle_config.pet_catch_rate != 100)
- pet_catch_rate = (pet_catch_rate*battle_config.pet_catch_rate)/100;
+ if(battle->bc->pet_catch_rate != 100)
+ pet_catch_rate = (pet_catch_rate*battle->bc->pet_catch_rate)/100;
if(rnd()%10000 < pet_catch_rate)
{
@@ -592,6 +593,8 @@ static int pet_catch_process2(struct map_session_data *sd, int target_id)
clif->pet_roulette(sd,1);
intif->create_pet(sd->status.account_id,sd->status.char_id,pet->db[i].class_,mob->db(pet->db[i].class_)->lv,
pet->db[i].EggID,0,pet->db[i].intimate,100,0,1,pet->db[i].jname);
+
+ achievement->validate_taming(sd, pet->db[i].class_);
}
else
{
diff --git a/src/map/script.c b/src/map/script.c
index 24d03bbe2..e38aae562 100644
--- a/src/map/script.c
+++ b/src/map/script.c
@@ -57,6 +57,7 @@
#include "map/status.h"
#include "map/storage.h"
#include "map/unit.h"
+#include "map/achievement.h"
#include "common/cbasetypes.h"
#include "common/conf.h"
#include "common/db.h"
@@ -9582,6 +9583,11 @@ static BUILDIN(successrefitem)
clif->additem(sd,i,1,0);
pc->equipitem(sd,i,ep);
clif->misceffect(&sd->bl,3);
+
+ achievement->validate_refine(sd, i, true); // Achievements [Smokexyz/Hercules]
+
+ /* The following check is exclusive to characters (possibly only whitesmiths)
+ * that create equipments and refine them to level 10. */
if(sd->status.inventory[i].refine == 10 &&
sd->status.inventory[i].card[0] == CARD0_FORGE &&
sd->status.char_id == (int)MakeDWord(sd->status.inventory[i].card[2],sd->status.inventory[i].card[3])
@@ -9619,6 +9625,9 @@ static BUILDIN(failedrefitem)
if (num > 0 && num <= ARRAYLENGTH(script->equip))
i=pc->checkequip(sd,script->equip[num-1]);
if(i >= 0) {
+ // Call before changing refine to 0.
+ achievement->validate_refine(sd, i, false);
+
sd->status.inventory[i].refine = 0;
pc->unequipitem(sd, i, PCUNEQUIPITEM_RECALC|PCUNEQUIPITEM_FORCE); //recalculate bonus
clif->refine(sd->fd,1,i,sd->status.inventory[i].refine); //notify client of failure
@@ -9666,6 +9675,9 @@ static BUILDIN(downrefitem)
clif->additem(sd,i,1,0);
pc->equipitem(sd,i,ep);
+
+ achievement->validate_refine(sd, i, false); // Achievements [Smokexyz/Hercules]
+
clif->misceffect(&sd->bl,2);
}
@@ -21254,6 +21266,78 @@ static BUILDIN(showevent)
}
/*==========================================
+ * Achievement System [Smokexyz/Hercules]
+ *-----------------------------------------*/
+/**
+ * Validates an objective index for the given achievement.
+ * Can be used for any achievement type.
+ * @command achievement_progress(<ach_id>,<obj_idx>,<progress>,<incremental?>{,<char_id>});
+ * @param aid - achievement ID
+ * @param obj_idx - achievement objective index.
+ * @param progress - objective progress towards goal.
+ * @Param incremental - (boolean) true to add the progress towards the goal,
+ * false to use the progress only as a comparand.
+ * @param account_id - (optional) character ID to perform on.
+ * @return true on success, false on failure.
+ * @push 1 on success, 0 on failure.
+ */
+static BUILDIN(achievement_progress)
+{
+ struct map_session_data *sd = script->rid2sd(st);
+ int aid = script_getnum(st, 2);
+ int obj_idx = script_getnum(st, 3);
+ int progress = script_getnum(st, 4);
+ int incremental = script_getnum(st, 5);
+ int account_id = script_hasdata(st, 6) ? script_getnum(st, 6) : 0;
+ const struct achievement_data *ad = NULL;
+
+ if ((ad = achievement->get(aid)) == NULL) {
+ ShowError("buildin_achievement_progress: Invalid achievement ID %d received.\n", aid);
+ script_pushint(st, 0);
+ return false;
+ }
+
+ if (obj_idx <= 0 || obj_idx > VECTOR_LENGTH(ad->objective)) {
+ ShowError("buildin_achievement_progress: Invalid objective index %d received. (min: %d, max: %d)\n", obj_idx, 0, VECTOR_LENGTH(ad->objective));
+ script_pushint(st, 0);
+ return false;
+ }
+
+ obj_idx--; // convert to array index.
+
+ if (progress <= 0 || progress > VECTOR_INDEX(ad->objective, obj_idx).goal) {
+ ShowError("buildin_achievement_progress: Progress exceeds goal limit for achievement id %d.\n", aid);
+ script_pushint(st, 0);
+ return false;
+ }
+
+ if (incremental < 0 || incremental > 1) {
+ ShowError("buildin_achievement_progress: Argument 4 expects boolean (0/1). provided value: %d\n", incremental);
+ script_pushint(st, 0);
+ return false;
+ }
+
+ if (script_hasdata(st, 6)) {
+ if (account_id <= 0) {
+ ShowError("buildin_achievement_progress: Invalid Account id %d provided.\n", account_id);
+ script_pushint(st, 0);
+ return false;
+ } else if ((sd = map->id2sd(account_id)) == NULL) {
+ ShowError("buildin_achievement_progress: Account with id %d was not found.\n", account_id);
+ script_pushint(st, 0);
+ return false;
+ }
+ }
+
+ if (achievement->validate(sd, aid, obj_idx, progress, incremental ? true : false))
+ script_pushint(st, progress);
+ else
+ script_pushint(st, 0);
+
+ return true;
+}
+
+/*==========================================
* BattleGround System
*------------------------------------------*/
static BUILDIN(waitingroom2bg)
@@ -25132,6 +25216,8 @@ static void script_parse_builtin(void)
BUILDIN_DEF(agitstart2,""),
BUILDIN_DEF(agitend2,""),
BUILDIN_DEF(agitcheck2,""),
+ // Achievements [Smokexyz/Hercules]
+ BUILDIN_DEF(achievement_progress, "iiii?"),
// BattleGround
BUILDIN_DEF(waitingroom2bg,"siiss?"),
BUILDIN_DEF(waitingroom2bg_single,"isiis"),
diff --git a/src/map/unit.c b/src/map/unit.c
index 2fd8d6efb..9174bdccd 100644
--- a/src/map/unit.c
+++ b/src/map/unit.c
@@ -2765,8 +2765,10 @@ static int unit_free(struct block_list *bl, clr_type clrtype)
sd->instance = NULL;
}
VECTOR_CLEAR(sd->script_queues);
+ VECTOR_CLEAR(sd->achievement); // Achievement [Smokexyz/Hercules]
VECTOR_CLEAR(sd->storage.item);
VECTOR_CLEAR(sd->hatEffectId);
+ VECTOR_CLEAR(sd->title_ids); // Title [Dastgir/Hercules]
sd->storage.received = false;
if( sd->quest_log != NULL ) {
aFree(sd->quest_log);
diff --git a/src/plugins/HPMHooking.c b/src/plugins/HPMHooking.c
index ca64aca6a..b477cb5c3 100644
--- a/src/plugins/HPMHooking.c
+++ b/src/plugins/HPMHooking.c
@@ -48,6 +48,7 @@ PRAGMA_GCC5(GCC diagnostic ignored "-Wdiscarded-qualifiers")
#define HPM_SOURCES_INCLUDE "HPMHooking/HPMHooking_char.sources.inc"
#include "char/char.h"
#include "char/geoip.h"
+#include "char/int_achievement.h"
#include "char/int_auction.h"
#include "char/int_clan.h"
#include "char/int_elemental.h"
@@ -71,6 +72,7 @@ PRAGMA_GCC5(GCC diagnostic ignored "-Wdiscarded-qualifiers")
#define HPM_HOOKS_INCLUDE "HPMHooking/HPMHooking_map.Hooks.inc"
#define HPM_POINTS_INCLUDE "HPMHooking/HPMHooking_map.HookingPoints.inc"
#define HPM_SOURCES_INCLUDE "HPMHooking/HPMHooking_map.sources.inc"
+#include "map/achievement.h"
#include "map/atcommand.h"
#include "map/battle.h"
#include "map/battleground.h"
diff --git a/src/plugins/HPMHooking/HPMHooking.Defs.inc b/src/plugins/HPMHooking/HPMHooking.Defs.inc
index 7f1145146..e3fbb178e 100644
--- a/src/plugins/HPMHooking/HPMHooking.Defs.inc
+++ b/src/plugins/HPMHooking/HPMHooking.Defs.inc
@@ -73,6 +73,112 @@ typedef bool (*HPMHOOK_post_account_db_sql_iter_next) (bool retVal___, AccountDB
typedef bool (*HPMHOOK_pre_account_db_read_inter) (AccountDB_SQL **db, const char **filename, bool *imported);
typedef bool (*HPMHOOK_post_account_db_read_inter) (bool retVal___, AccountDB_SQL *db, const char *filename, bool imported);
#endif // LOGIN_ACCOUNT_H
+#ifdef MAP_ACHIEVEMENT_H /* achievement */
+typedef void (*HPMHOOK_pre_achievement_init) (bool *minimal);
+typedef void (*HPMHOOK_post_achievement_init) (bool minimal);
+typedef void (*HPMHOOK_pre_achievement_final) (void);
+typedef void (*HPMHOOK_post_achievement_final) (void);
+typedef int (*HPMHOOK_pre_achievement_db_finalize) (union DBKey *key, struct DBData **data, va_list args);
+typedef int (*HPMHOOK_post_achievement_db_finalize) (int retVal___, union DBKey key, struct DBData *data, va_list args);
+typedef void (*HPMHOOK_pre_achievement_readdb) (void);
+typedef void (*HPMHOOK_post_achievement_readdb) (void);
+typedef bool (*HPMHOOK_pre_achievement_readdb_objectives_sub) (const struct config_setting_t **conf, int *index, struct achievement_data **entry);
+typedef bool (*HPMHOOK_post_achievement_readdb_objectives_sub) (bool retVal___, const struct config_setting_t *conf, int index, struct achievement_data *entry);
+typedef bool (*HPMHOOK_pre_achievement_readdb_objectives) (const struct config_setting_t **conf, struct achievement_data **entry);
+typedef bool (*HPMHOOK_post_achievement_readdb_objectives) (bool retVal___, const struct config_setting_t *conf, struct achievement_data *entry);
+typedef bool (*HPMHOOK_pre_achievement_readdb_validate_criteria_mobid) (const struct config_setting_t **t, struct achievement_objective **obj, enum achievement_types *type, int *entry_id, int *obj_idx);
+typedef bool (*HPMHOOK_post_achievement_readdb_validate_criteria_mobid) (bool retVal___, const struct config_setting_t *t, struct achievement_objective *obj, enum achievement_types type, int entry_id, int obj_idx);
+typedef bool (*HPMHOOK_pre_achievement_readdb_validate_criteria_jobid) (const struct config_setting_t **t, struct achievement_objective **obj, enum achievement_types *type, int *entry_id, int *obj_idx);
+typedef bool (*HPMHOOK_post_achievement_readdb_validate_criteria_jobid) (bool retVal___, const struct config_setting_t *t, struct achievement_objective *obj, enum achievement_types type, int entry_id, int obj_idx);
+typedef bool (*HPMHOOK_pre_achievement_readdb_validate_criteria_itemid) (const struct config_setting_t **t, struct achievement_objective **obj, enum achievement_types *type, int *entry_id, int *obj_idx);
+typedef bool (*HPMHOOK_post_achievement_readdb_validate_criteria_itemid) (bool retVal___, const struct config_setting_t *t, struct achievement_objective *obj, enum achievement_types type, int entry_id, int obj_idx);
+typedef bool (*HPMHOOK_pre_achievement_readdb_validate_criteria_statustype) (const struct config_setting_t **t, struct achievement_objective **obj, enum achievement_types *type, int *entry_id, int *obj_idx);
+typedef bool (*HPMHOOK_post_achievement_readdb_validate_criteria_statustype) (bool retVal___, const struct config_setting_t *t, struct achievement_objective *obj, enum achievement_types type, int entry_id, int obj_idx);
+typedef bool (*HPMHOOK_pre_achievement_readdb_validate_criteria_itemtype) (const struct config_setting_t **t, struct achievement_objective **obj, enum achievement_types *type, int *entry_id, int *obj_idx);
+typedef bool (*HPMHOOK_post_achievement_readdb_validate_criteria_itemtype) (bool retVal___, const struct config_setting_t *t, struct achievement_objective *obj, enum achievement_types type, int entry_id, int obj_idx);
+typedef bool (*HPMHOOK_pre_achievement_readdb_validate_criteria_weaponlv) (const struct config_setting_t **t, struct achievement_objective **obj, enum achievement_types *type, int *entry_id, int *obj_idx);
+typedef bool (*HPMHOOK_post_achievement_readdb_validate_criteria_weaponlv) (bool retVal___, const struct config_setting_t *t, struct achievement_objective *obj, enum achievement_types type, int entry_id, int obj_idx);
+typedef bool (*HPMHOOK_pre_achievement_readdb_validate_criteria_achievement) (const struct config_setting_t **t, struct achievement_objective **obj, enum achievement_types *type, int *entry_id, int *obj_idx);
+typedef bool (*HPMHOOK_post_achievement_readdb_validate_criteria_achievement) (bool retVal___, const struct config_setting_t *t, struct achievement_objective *obj, enum achievement_types type, int entry_id, int obj_idx);
+typedef bool (*HPMHOOK_pre_achievement_readdb_rewards) (const struct config_setting_t **conf, struct achievement_data **entry, const char **source);
+typedef bool (*HPMHOOK_post_achievement_readdb_rewards) (bool retVal___, const struct config_setting_t *conf, struct achievement_data *entry, const char *source);
+typedef void (*HPMHOOK_pre_achievement_readdb_validate_reward_items) (const struct config_setting_t **t, struct achievement_data **entry);
+typedef void (*HPMHOOK_post_achievement_readdb_validate_reward_items) (const struct config_setting_t *t, struct achievement_data *entry);
+typedef bool (*HPMHOOK_pre_achievement_readdb_validate_reward_item_sub) (const struct config_setting_t **t, int *element, struct achievement_data **entry);
+typedef bool (*HPMHOOK_post_achievement_readdb_validate_reward_item_sub) (bool retVal___, const struct config_setting_t *t, int element, struct achievement_data *entry);
+typedef void (*HPMHOOK_pre_achievement_readdb_validate_reward_bonus) (const struct config_setting_t **t, struct achievement_data **entry, const char **source);
+typedef void (*HPMHOOK_post_achievement_readdb_validate_reward_bonus) (const struct config_setting_t *t, struct achievement_data *entry, const char *source);
+typedef void (*HPMHOOK_pre_achievement_readdb_validate_reward_titleid) (const struct config_setting_t **t, struct achievement_data **entry);
+typedef void (*HPMHOOK_post_achievement_readdb_validate_reward_titleid) (const struct config_setting_t *t, struct achievement_data *entry);
+typedef void (*HPMHOOK_pre_achievement_readdb_additional_fields) (const struct config_setting_t **conf, struct achievement_data **entry, const char **source);
+typedef void (*HPMHOOK_post_achievement_readdb_additional_fields) (const struct config_setting_t *conf, struct achievement_data *entry, const char *source);
+typedef void (*HPMHOOK_pre_achievement_readdb_ranks) (void);
+typedef void (*HPMHOOK_post_achievement_readdb_ranks) (void);
+typedef const struct achievement_data* (*HPMHOOK_pre_achievement_get) (int *aid);
+typedef const struct achievement_data* (*HPMHOOK_post_achievement_get) (const struct achievement_data* retVal___, int aid);
+typedef struct achievement* (*HPMHOOK_pre_achievement_ensure) (struct map_session_data **sd, const struct achievement_data **ad);
+typedef struct achievement* (*HPMHOOK_post_achievement_ensure) (struct achievement* retVal___, struct map_session_data *sd, const struct achievement_data *ad);
+typedef void (*HPMHOOK_pre_achievement_calculate_totals) (const struct map_session_data **sd, int **points, int **completed, int **rank, int **curr_rank_points);
+typedef void (*HPMHOOK_post_achievement_calculate_totals) (const struct map_session_data *sd, int *points, int *completed, int *rank, int *curr_rank_points);
+typedef bool (*HPMHOOK_pre_achievement_check_complete) (struct map_session_data **sd, const struct achievement_data **ad);
+typedef bool (*HPMHOOK_post_achievement_check_complete) (bool retVal___, struct map_session_data *sd, const struct achievement_data *ad);
+typedef void (*HPMHOOK_pre_achievement_progress_add) (struct map_session_data **sd, const struct achievement_data **ad, unsigned int *obj_idx, int *progress);
+typedef void (*HPMHOOK_post_achievement_progress_add) (struct map_session_data *sd, const struct achievement_data *ad, unsigned int obj_idx, int progress);
+typedef void (*HPMHOOK_pre_achievement_progress_set) (struct map_session_data **sd, const struct achievement_data **ad, unsigned int *obj_idx, int *progress);
+typedef void (*HPMHOOK_post_achievement_progress_set) (struct map_session_data *sd, const struct achievement_data *ad, unsigned int obj_idx, int progress);
+typedef bool (*HPMHOOK_pre_achievement_check_criteria) (const struct achievement_objective **objective, const struct achievement_objective **criteria);
+typedef bool (*HPMHOOK_post_achievement_check_criteria) (bool retVal___, const struct achievement_objective *objective, const struct achievement_objective *criteria);
+typedef bool (*HPMHOOK_pre_achievement_validate) (struct map_session_data **sd, int *aid, unsigned int *obj_idx, int *progress, bool *additive);
+typedef bool (*HPMHOOK_post_achievement_validate) (bool retVal___, struct map_session_data *sd, int aid, unsigned int obj_idx, int progress, bool additive);
+typedef int (*HPMHOOK_pre_achievement_validate_type) (struct map_session_data **sd, enum achievement_types *type, const struct achievement_objective **criteria, bool *additive);
+typedef int (*HPMHOOK_post_achievement_validate_type) (int retVal___, struct map_session_data *sd, enum achievement_types type, const struct achievement_objective *criteria, bool additive);
+typedef void (*HPMHOOK_pre_achievement_validate_mob_kill) (struct map_session_data **sd, int *mob_id);
+typedef void (*HPMHOOK_post_achievement_validate_mob_kill) (struct map_session_data *sd, int mob_id);
+typedef void (*HPMHOOK_pre_achievement_validate_mob_damage) (struct map_session_data **sd, unsigned int *damage, bool *received);
+typedef void (*HPMHOOK_post_achievement_validate_mob_damage) (struct map_session_data *sd, unsigned int damage, bool received);
+typedef void (*HPMHOOK_pre_achievement_validate_pc_kill) (struct map_session_data **sd, struct map_session_data **dstsd);
+typedef void (*HPMHOOK_post_achievement_validate_pc_kill) (struct map_session_data *sd, struct map_session_data *dstsd);
+typedef void (*HPMHOOK_pre_achievement_validate_pc_damage) (struct map_session_data **sd, struct map_session_data **dstsd, unsigned int *damage);
+typedef void (*HPMHOOK_post_achievement_validate_pc_damage) (struct map_session_data *sd, struct map_session_data *dstsd, unsigned int damage);
+typedef void (*HPMHOOK_pre_achievement_validate_jobchange) (struct map_session_data **sd);
+typedef void (*HPMHOOK_post_achievement_validate_jobchange) (struct map_session_data *sd);
+typedef void (*HPMHOOK_pre_achievement_validate_stats) (struct map_session_data **sd, enum status_point_types *stat_type, int *progress);
+typedef void (*HPMHOOK_post_achievement_validate_stats) (struct map_session_data *sd, enum status_point_types stat_type, int progress);
+typedef void (*HPMHOOK_pre_achievement_validate_chatroom_create) (struct map_session_data **sd);
+typedef void (*HPMHOOK_post_achievement_validate_chatroom_create) (struct map_session_data *sd);
+typedef void (*HPMHOOK_pre_achievement_validate_chatroom_members) (struct map_session_data **sd, int *progress);
+typedef void (*HPMHOOK_post_achievement_validate_chatroom_members) (struct map_session_data *sd, int progress);
+typedef void (*HPMHOOK_pre_achievement_validate_friend_add) (struct map_session_data **sd);
+typedef void (*HPMHOOK_post_achievement_validate_friend_add) (struct map_session_data *sd);
+typedef void (*HPMHOOK_pre_achievement_validate_party_create) (struct map_session_data **sd);
+typedef void (*HPMHOOK_post_achievement_validate_party_create) (struct map_session_data *sd);
+typedef void (*HPMHOOK_pre_achievement_validate_marry) (struct map_session_data **sd);
+typedef void (*HPMHOOK_post_achievement_validate_marry) (struct map_session_data *sd);
+typedef void (*HPMHOOK_pre_achievement_validate_adopt) (struct map_session_data **sd, bool *parent);
+typedef void (*HPMHOOK_post_achievement_validate_adopt) (struct map_session_data *sd, bool parent);
+typedef void (*HPMHOOK_pre_achievement_validate_zeny) (struct map_session_data **sd, int *amount);
+typedef void (*HPMHOOK_post_achievement_validate_zeny) (struct map_session_data *sd, int amount);
+typedef void (*HPMHOOK_pre_achievement_validate_refine) (struct map_session_data **sd, unsigned int *idx, bool *success);
+typedef void (*HPMHOOK_post_achievement_validate_refine) (struct map_session_data *sd, unsigned int idx, bool success);
+typedef void (*HPMHOOK_pre_achievement_validate_item_get) (struct map_session_data **sd, int *nameid, int *amount);
+typedef void (*HPMHOOK_post_achievement_validate_item_get) (struct map_session_data *sd, int nameid, int amount);
+typedef void (*HPMHOOK_pre_achievement_validate_item_sell) (struct map_session_data **sd, int *nameid, int *amount);
+typedef void (*HPMHOOK_post_achievement_validate_item_sell) (struct map_session_data *sd, int nameid, int amount);
+typedef void (*HPMHOOK_pre_achievement_validate_achieve) (struct map_session_data **sd, int *achid);
+typedef void (*HPMHOOK_post_achievement_validate_achieve) (struct map_session_data *sd, int achid);
+typedef void (*HPMHOOK_pre_achievement_validate_taming) (struct map_session_data **sd, int *class);
+typedef void (*HPMHOOK_post_achievement_validate_taming) (struct map_session_data *sd, int class);
+typedef void (*HPMHOOK_pre_achievement_validate_achievement_rank) (struct map_session_data **sd, int *rank);
+typedef void (*HPMHOOK_post_achievement_validate_achievement_rank) (struct map_session_data *sd, int rank);
+typedef bool (*HPMHOOK_pre_achievement_type_requires_criteria) (enum achievement_types *type);
+typedef bool (*HPMHOOK_post_achievement_type_requires_criteria) (bool retVal___, enum achievement_types type);
+typedef void (*HPMHOOK_pre_achievement_init_titles) (struct map_session_data **sd);
+typedef void (*HPMHOOK_post_achievement_init_titles) (struct map_session_data *sd);
+typedef bool (*HPMHOOK_pre_achievement_check_title) (struct map_session_data **sd, int *title_id);
+typedef bool (*HPMHOOK_post_achievement_check_title) (bool retVal___, struct map_session_data *sd, int title_id);
+typedef void (*HPMHOOK_pre_achievement_get_rewards) (struct map_session_data **sd, const struct achievement_data **ad);
+typedef void (*HPMHOOK_post_achievement_get_rewards) (struct map_session_data *sd, const struct achievement_data *ad);
+#endif // MAP_ACHIEVEMENT_H
#ifdef MAP_ATCOMMAND_H /* atcommand */
typedef void (*HPMHOOK_pre_atcommand_init) (bool *minimal);
typedef void (*HPMHOOK_post_atcommand_init) (bool minimal);
@@ -1884,6 +1990,18 @@ typedef void (*HPMHOOK_pre_clif_navigate_to) (struct map_session_data **sd, cons
typedef void (*HPMHOOK_post_clif_navigate_to) (struct map_session_data *sd, const char *mapname, uint16 x, uint16 y, uint8 flag, bool hideWindow, uint16 mob_id);
typedef unsigned char (*HPMHOOK_pre_clif_bl_type) (struct block_list **bl);
typedef unsigned char (*HPMHOOK_post_clif_bl_type) (unsigned char retVal___, struct block_list *bl);
+typedef void (*HPMHOOK_pre_clif_achievement_send_list) (int *fd, struct map_session_data **sd);
+typedef void (*HPMHOOK_post_clif_achievement_send_list) (int fd, struct map_session_data *sd);
+typedef void (*HPMHOOK_pre_clif_achievement_send_update) (int *fd, struct map_session_data **sd, const struct achievement_data **ad);
+typedef void (*HPMHOOK_post_clif_achievement_send_update) (int fd, struct map_session_data *sd, const struct achievement_data *ad);
+typedef void (*HPMHOOK_pre_clif_pAchievementGetReward) (int *fd, struct map_session_data **sd);
+typedef void (*HPMHOOK_post_clif_pAchievementGetReward) (int fd, struct map_session_data *sd);
+typedef void (*HPMHOOK_pre_clif_achievement_reward_ack) (int *fd, struct map_session_data **sd, const struct achievement_data **ad);
+typedef void (*HPMHOOK_post_clif_achievement_reward_ack) (int fd, struct map_session_data *sd, const struct achievement_data *ad);
+typedef void (*HPMHOOK_pre_clif_change_title_ack) (int *fd, struct map_session_data **sd, int *title_id);
+typedef void (*HPMHOOK_post_clif_change_title_ack) (int fd, struct map_session_data *sd, int title_id);
+typedef void (*HPMHOOK_pre_clif_pChangeTitle) (int *fd, struct map_session_data **sd);
+typedef void (*HPMHOOK_post_clif_pChangeTitle) (int fd, struct map_session_data *sd);
typedef void (*HPMHOOK_pre_clif_pWantToConnection) (int *fd, struct map_session_data **sd);
typedef void (*HPMHOOK_post_clif_pWantToConnection) (int fd, struct map_session_data *sd);
typedef void (*HPMHOOK_pre_clif_pLoadEndAck) (int *fd, struct map_session_data **sd);
@@ -2993,6 +3111,22 @@ typedef bool (*HPMHOOK_post_instance_valid) (bool retVal___, int instance_id);
typedef int (*HPMHOOK_pre_instance_destroy_timer) (int *tid, int64 *tick, int *id, intptr_t *data);
typedef int (*HPMHOOK_post_instance_destroy_timer) (int retVal___, int tid, int64 tick, int id, intptr_t data);
#endif // MAP_INSTANCE_H
+#ifdef CHAR_INT_ACHIEVEMENT_H /* inter_achievement */
+typedef int (*HPMHOOK_pre_inter_achievement_sql_init) (void);
+typedef int (*HPMHOOK_post_inter_achievement_sql_init) (int retVal___);
+typedef void (*HPMHOOK_pre_inter_achievement_sql_final) (void);
+typedef void (*HPMHOOK_post_inter_achievement_sql_final) (void);
+typedef int (*HPMHOOK_pre_inter_achievement_tosql) (int *char_id, struct char_achievements **cp, const struct char_achievements **p);
+typedef int (*HPMHOOK_post_inter_achievement_tosql) (int retVal___, int char_id, struct char_achievements *cp, const struct char_achievements *p);
+typedef bool (*HPMHOOK_pre_inter_achievement_fromsql) (int *char_id, struct char_achievements **a);
+typedef bool (*HPMHOOK_post_inter_achievement_fromsql) (bool retVal___, int char_id, struct char_achievements *a);
+typedef struct DBData (*HPMHOOK_pre_inter_achievement_ensure_char_achievements) (union DBKey *key, va_list args);
+typedef struct DBData (*HPMHOOK_post_inter_achievement_ensure_char_achievements) (struct DBData retVal___, union DBKey key, va_list args);
+typedef int (*HPMHOOK_pre_inter_achievement_char_achievements_clear) (union DBKey *key, struct DBData **data, va_list args);
+typedef int (*HPMHOOK_post_inter_achievement_char_achievements_clear) (int retVal___, union DBKey key, struct DBData *data, va_list args);
+typedef int (*HPMHOOK_pre_inter_achievement_parse_frommap) (int *fd);
+typedef int (*HPMHOOK_post_inter_achievement_parse_frommap) (int retVal___, int fd);
+#endif // CHAR_INT_ACHIEVEMENT_H
#ifdef CHAR_INT_AUCTION_H /* inter_auction */
typedef int (*HPMHOOK_pre_inter_auction_count) (int *char_id, bool *buy);
typedef int (*HPMHOOK_post_inter_auction_count) (int retVal___, int char_id, bool buy);
@@ -3496,6 +3630,10 @@ typedef void (*HPMHOOK_pre_intif_request_accinfo) (int *u_fd, int *aid, int *gro
typedef void (*HPMHOOK_post_intif_request_accinfo) (int u_fd, int aid, int group_lv, char *query);
typedef int (*HPMHOOK_pre_intif_CheckForCharServer) (void);
typedef int (*HPMHOOK_post_intif_CheckForCharServer) (int retVal___);
+typedef void (*HPMHOOK_pre_intif_achievements_request) (struct map_session_data **sd);
+typedef void (*HPMHOOK_post_intif_achievements_request) (struct map_session_data *sd);
+typedef void (*HPMHOOK_pre_intif_achievements_save) (struct map_session_data **sd);
+typedef void (*HPMHOOK_post_intif_achievements_save) (struct map_session_data *sd);
typedef void (*HPMHOOK_pre_intif_pWisMessage) (int *fd);
typedef void (*HPMHOOK_post_intif_pWisMessage) (int fd);
typedef void (*HPMHOOK_pre_intif_pWisEnd) (int *fd);
@@ -3634,6 +3772,8 @@ typedef void (*HPMHOOK_pre_intif_pRodexCheckName) (int *fd);
typedef void (*HPMHOOK_post_intif_pRodexCheckName) (int fd);
typedef void (*HPMHOOK_pre_intif_pRecvClanMemberAction) (int *fd);
typedef void (*HPMHOOK_post_intif_pRecvClanMemberAction) (int fd);
+typedef void (*HPMHOOK_pre_intif_pAchievementsLoad) (int *fd);
+typedef void (*HPMHOOK_post_intif_pAchievementsLoad) (int fd);
#endif // MAP_INTIF_H
#ifdef LOGIN_IPBAN_H /* ipban */
typedef void (*HPMHOOK_pre_ipban_init) (void);
@@ -4556,6 +4696,16 @@ typedef int (*HPMHOOK_pre_mapif_send) (int *fd, unsigned char **buf, unsigned in
typedef int (*HPMHOOK_post_mapif_send) (int retVal___, int fd, unsigned char *buf, unsigned int len);
typedef void (*HPMHOOK_pre_mapif_send_users_count) (int *users);
typedef void (*HPMHOOK_post_mapif_send_users_count) (int users);
+typedef void (*HPMHOOK_pre_mapif_pLoadAchievements) (int *fd);
+typedef void (*HPMHOOK_post_mapif_pLoadAchievements) (int fd);
+typedef void (*HPMHOOK_pre_mapif_sAchievementsToMap) (int *fd, int *char_id, const struct char_achievements **p);
+typedef void (*HPMHOOK_post_mapif_sAchievementsToMap) (int fd, int char_id, const struct char_achievements *p);
+typedef void (*HPMHOOK_pre_mapif_pSaveAchievements) (int *fd);
+typedef void (*HPMHOOK_post_mapif_pSaveAchievements) (int fd);
+typedef void (*HPMHOOK_pre_mapif_achievement_load) (int *fd, int *char_id);
+typedef void (*HPMHOOK_post_mapif_achievement_load) (int fd, int char_id);
+typedef void (*HPMHOOK_pre_mapif_achievement_save) (int *char_id, struct char_achievements **p);
+typedef void (*HPMHOOK_post_mapif_achievement_save) (int char_id, struct char_achievements *p);
typedef void (*HPMHOOK_pre_mapif_auction_message) (int *char_id, unsigned char *result);
typedef void (*HPMHOOK_post_mapif_auction_message) (int char_id, unsigned char result);
typedef void (*HPMHOOK_pre_mapif_auction_sendlist) (int *fd, int *char_id, short *count, short *pages, unsigned char **buf);
diff --git a/src/plugins/HPMHooking/HPMHooking_char.HPMHooksCore.inc b/src/plugins/HPMHooking/HPMHooking_char.HPMHooksCore.inc
index d77174ef5..2b0291453 100644
--- a/src/plugins/HPMHooking/HPMHooking_char.HPMHooksCore.inc
+++ b/src/plugins/HPMHooking/HPMHooking_char.HPMHooksCore.inc
@@ -448,6 +448,20 @@ struct {
struct HPMHookPoint *HP_geoip_final_post;
struct HPMHookPoint *HP_geoip_init_pre;
struct HPMHookPoint *HP_geoip_init_post;
+ struct HPMHookPoint *HP_inter_achievement_sql_init_pre;
+ struct HPMHookPoint *HP_inter_achievement_sql_init_post;
+ struct HPMHookPoint *HP_inter_achievement_sql_final_pre;
+ struct HPMHookPoint *HP_inter_achievement_sql_final_post;
+ struct HPMHookPoint *HP_inter_achievement_tosql_pre;
+ struct HPMHookPoint *HP_inter_achievement_tosql_post;
+ struct HPMHookPoint *HP_inter_achievement_fromsql_pre;
+ struct HPMHookPoint *HP_inter_achievement_fromsql_post;
+ struct HPMHookPoint *HP_inter_achievement_ensure_char_achievements_pre;
+ struct HPMHookPoint *HP_inter_achievement_ensure_char_achievements_post;
+ struct HPMHookPoint *HP_inter_achievement_char_achievements_clear_pre;
+ struct HPMHookPoint *HP_inter_achievement_char_achievements_clear_post;
+ struct HPMHookPoint *HP_inter_achievement_parse_frommap_pre;
+ struct HPMHookPoint *HP_inter_achievement_parse_frommap_post;
struct HPMHookPoint *HP_inter_auction_count_pre;
struct HPMHookPoint *HP_inter_auction_count_post;
struct HPMHookPoint *HP_inter_auction_save_pre;
@@ -952,6 +966,16 @@ struct {
struct HPMHookPoint *HP_mapif_send_post;
struct HPMHookPoint *HP_mapif_send_users_count_pre;
struct HPMHookPoint *HP_mapif_send_users_count_post;
+ struct HPMHookPoint *HP_mapif_pLoadAchievements_pre;
+ struct HPMHookPoint *HP_mapif_pLoadAchievements_post;
+ struct HPMHookPoint *HP_mapif_sAchievementsToMap_pre;
+ struct HPMHookPoint *HP_mapif_sAchievementsToMap_post;
+ struct HPMHookPoint *HP_mapif_pSaveAchievements_pre;
+ struct HPMHookPoint *HP_mapif_pSaveAchievements_post;
+ struct HPMHookPoint *HP_mapif_achievement_load_pre;
+ struct HPMHookPoint *HP_mapif_achievement_load_post;
+ struct HPMHookPoint *HP_mapif_achievement_save_pre;
+ struct HPMHookPoint *HP_mapif_achievement_save_post;
struct HPMHookPoint *HP_mapif_auction_message_pre;
struct HPMHookPoint *HP_mapif_auction_message_post;
struct HPMHookPoint *HP_mapif_auction_sendlist_pre;
@@ -2047,6 +2071,20 @@ struct {
int HP_geoip_final_post;
int HP_geoip_init_pre;
int HP_geoip_init_post;
+ int HP_inter_achievement_sql_init_pre;
+ int HP_inter_achievement_sql_init_post;
+ int HP_inter_achievement_sql_final_pre;
+ int HP_inter_achievement_sql_final_post;
+ int HP_inter_achievement_tosql_pre;
+ int HP_inter_achievement_tosql_post;
+ int HP_inter_achievement_fromsql_pre;
+ int HP_inter_achievement_fromsql_post;
+ int HP_inter_achievement_ensure_char_achievements_pre;
+ int HP_inter_achievement_ensure_char_achievements_post;
+ int HP_inter_achievement_char_achievements_clear_pre;
+ int HP_inter_achievement_char_achievements_clear_post;
+ int HP_inter_achievement_parse_frommap_pre;
+ int HP_inter_achievement_parse_frommap_post;
int HP_inter_auction_count_pre;
int HP_inter_auction_count_post;
int HP_inter_auction_save_pre;
@@ -2551,6 +2589,16 @@ struct {
int HP_mapif_send_post;
int HP_mapif_send_users_count_pre;
int HP_mapif_send_users_count_post;
+ int HP_mapif_pLoadAchievements_pre;
+ int HP_mapif_pLoadAchievements_post;
+ int HP_mapif_sAchievementsToMap_pre;
+ int HP_mapif_sAchievementsToMap_post;
+ int HP_mapif_pSaveAchievements_pre;
+ int HP_mapif_pSaveAchievements_post;
+ int HP_mapif_achievement_load_pre;
+ int HP_mapif_achievement_load_post;
+ int HP_mapif_achievement_save_pre;
+ int HP_mapif_achievement_save_post;
int HP_mapif_auction_message_pre;
int HP_mapif_auction_message_post;
int HP_mapif_auction_sendlist_pre;
@@ -3232,6 +3280,7 @@ struct {
struct db_interface DB;
struct des_interface des;
struct geoip_interface geoip;
+ struct inter_achievement_interface inter_achievement;
struct inter_auction_interface inter_auction;
struct inter_clan_interface inter_clan;
struct inter_elemental_interface inter_elemental;
diff --git a/src/plugins/HPMHooking/HPMHooking_char.HookingPoints.inc b/src/plugins/HPMHooking/HPMHooking_char.HookingPoints.inc
index d91cc43c8..cb6ae1bb8 100644
--- a/src/plugins/HPMHooking/HPMHooking_char.HookingPoints.inc
+++ b/src/plugins/HPMHooking/HPMHooking_char.HookingPoints.inc
@@ -245,6 +245,14 @@ struct HookingPointData HookingPoints[] = {
{ HP_POP(geoip->getcountry, HP_geoip_getcountry) },
{ HP_POP(geoip->final, HP_geoip_final) },
{ HP_POP(geoip->init, HP_geoip_init) },
+/* inter_achievement_interface */
+ { HP_POP(inter_achievement->sql_init, HP_inter_achievement_sql_init) },
+ { HP_POP(inter_achievement->sql_final, HP_inter_achievement_sql_final) },
+ { HP_POP(inter_achievement->tosql, HP_inter_achievement_tosql) },
+ { HP_POP(inter_achievement->fromsql, HP_inter_achievement_fromsql) },
+ { HP_POP(inter_achievement->ensure_char_achievements, HP_inter_achievement_ensure_char_achievements) },
+ { HP_POP(inter_achievement->char_achievements_clear, HP_inter_achievement_char_achievements_clear) },
+ { HP_POP(inter_achievement->parse_frommap, HP_inter_achievement_parse_frommap) },
/* inter_auction_interface */
{ HP_POP(inter_auction->count, HP_inter_auction_count) },
{ HP_POP(inter_auction->save, HP_inter_auction_save) },
@@ -513,6 +521,11 @@ struct HookingPointData HookingPoints[] = {
{ HP_POP(mapif->sendallwos, HP_mapif_sendallwos) },
{ HP_POP(mapif->send, HP_mapif_send) },
{ HP_POP(mapif->send_users_count, HP_mapif_send_users_count) },
+ { HP_POP(mapif->pLoadAchievements, HP_mapif_pLoadAchievements) },
+ { HP_POP(mapif->sAchievementsToMap, HP_mapif_sAchievementsToMap) },
+ { HP_POP(mapif->pSaveAchievements, HP_mapif_pSaveAchievements) },
+ { HP_POP(mapif->achievement_load, HP_mapif_achievement_load) },
+ { HP_POP(mapif->achievement_save, HP_mapif_achievement_save) },
{ HP_POP(mapif->auction_message, HP_mapif_auction_message) },
{ HP_POP(mapif->auction_sendlist, HP_mapif_auction_sendlist) },
{ HP_POP(mapif->parse_auction_requestlist, HP_mapif_parse_auction_requestlist) },
@@ -865,4 +878,4 @@ struct HookingPointData HookingPoints[] = {
{ HP_POP(timer->final, HP_timer_final) },
};
-int HookingPointsLenMax = 42;
+int HookingPointsLenMax = 43;
diff --git a/src/plugins/HPMHooking/HPMHooking_char.Hooks.inc b/src/plugins/HPMHooking/HPMHooking_char.Hooks.inc
index 831c9da63..767c7d24e 100644
--- a/src/plugins/HPMHooking/HPMHooking_char.Hooks.inc
+++ b/src/plugins/HPMHooking/HPMHooking_char.Hooks.inc
@@ -5640,6 +5640,207 @@ void HP_geoip_init(void) {
}
return;
}
+/* inter_achievement_interface */
+int HP_inter_achievement_sql_init(void) {
+ int hIndex = 0;
+ int retVal___ = 0;
+ if (HPMHooks.count.HP_inter_achievement_sql_init_pre > 0) {
+ int (*preHookFunc) (void);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_inter_achievement_sql_init_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_inter_achievement_sql_init_pre[hIndex].func;
+ retVal___ = preHookFunc();
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return retVal___;
+ }
+ }
+ {
+ retVal___ = HPMHooks.source.inter_achievement.sql_init();
+ }
+ if (HPMHooks.count.HP_inter_achievement_sql_init_post > 0) {
+ int (*postHookFunc) (int retVal___);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_inter_achievement_sql_init_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_inter_achievement_sql_init_post[hIndex].func;
+ retVal___ = postHookFunc(retVal___);
+ }
+ }
+ return retVal___;
+}
+void HP_inter_achievement_sql_final(void) {
+ int hIndex = 0;
+ if (HPMHooks.count.HP_inter_achievement_sql_final_pre > 0) {
+ void (*preHookFunc) (void);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_inter_achievement_sql_final_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_inter_achievement_sql_final_pre[hIndex].func;
+ preHookFunc();
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.inter_achievement.sql_final();
+ }
+ if (HPMHooks.count.HP_inter_achievement_sql_final_post > 0) {
+ void (*postHookFunc) (void);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_inter_achievement_sql_final_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_inter_achievement_sql_final_post[hIndex].func;
+ postHookFunc();
+ }
+ }
+ return;
+}
+int HP_inter_achievement_tosql(int char_id, struct char_achievements *cp, const struct char_achievements *p) {
+ int hIndex = 0;
+ int retVal___ = 0;
+ if (HPMHooks.count.HP_inter_achievement_tosql_pre > 0) {
+ int (*preHookFunc) (int *char_id, struct char_achievements **cp, const struct char_achievements **p);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_inter_achievement_tosql_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_inter_achievement_tosql_pre[hIndex].func;
+ retVal___ = preHookFunc(&char_id, &cp, &p);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return retVal___;
+ }
+ }
+ {
+ retVal___ = HPMHooks.source.inter_achievement.tosql(char_id, cp, p);
+ }
+ if (HPMHooks.count.HP_inter_achievement_tosql_post > 0) {
+ int (*postHookFunc) (int retVal___, int char_id, struct char_achievements *cp, const struct char_achievements *p);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_inter_achievement_tosql_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_inter_achievement_tosql_post[hIndex].func;
+ retVal___ = postHookFunc(retVal___, char_id, cp, p);
+ }
+ }
+ return retVal___;
+}
+bool HP_inter_achievement_fromsql(int char_id, struct char_achievements *a) {
+ int hIndex = 0;
+ bool retVal___ = false;
+ if (HPMHooks.count.HP_inter_achievement_fromsql_pre > 0) {
+ bool (*preHookFunc) (int *char_id, struct char_achievements **a);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_inter_achievement_fromsql_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_inter_achievement_fromsql_pre[hIndex].func;
+ retVal___ = preHookFunc(&char_id, &a);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return retVal___;
+ }
+ }
+ {
+ retVal___ = HPMHooks.source.inter_achievement.fromsql(char_id, a);
+ }
+ if (HPMHooks.count.HP_inter_achievement_fromsql_post > 0) {
+ bool (*postHookFunc) (bool retVal___, int char_id, struct char_achievements *a);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_inter_achievement_fromsql_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_inter_achievement_fromsql_post[hIndex].func;
+ retVal___ = postHookFunc(retVal___, char_id, a);
+ }
+ }
+ return retVal___;
+}
+struct DBData HP_inter_achievement_ensure_char_achievements(union DBKey key, va_list args) {
+ int hIndex = 0;
+ struct DBData retVal___ = { 0 };
+ if (HPMHooks.count.HP_inter_achievement_ensure_char_achievements_pre > 0) {
+ struct DBData (*preHookFunc) (union DBKey *key, va_list args);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_inter_achievement_ensure_char_achievements_pre; hIndex++) {
+ va_list args___copy; va_copy(args___copy, args);
+ preHookFunc = HPMHooks.list.HP_inter_achievement_ensure_char_achievements_pre[hIndex].func;
+ retVal___ = preHookFunc(&key, args___copy);
+ va_end(args___copy);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return retVal___;
+ }
+ }
+ {
+ va_list args___copy; va_copy(args___copy, args);
+ retVal___ = HPMHooks.source.inter_achievement.ensure_char_achievements(key, args___copy);
+ va_end(args___copy);
+ }
+ if (HPMHooks.count.HP_inter_achievement_ensure_char_achievements_post > 0) {
+ struct DBData (*postHookFunc) (struct DBData retVal___, union DBKey key, va_list args);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_inter_achievement_ensure_char_achievements_post; hIndex++) {
+ va_list args___copy; va_copy(args___copy, args);
+ postHookFunc = HPMHooks.list.HP_inter_achievement_ensure_char_achievements_post[hIndex].func;
+ retVal___ = postHookFunc(retVal___, key, args___copy);
+ va_end(args___copy);
+ }
+ }
+ return retVal___;
+}
+int HP_inter_achievement_char_achievements_clear(union DBKey key, struct DBData *data, va_list args) {
+ int hIndex = 0;
+ int retVal___ = 0;
+ if (HPMHooks.count.HP_inter_achievement_char_achievements_clear_pre > 0) {
+ int (*preHookFunc) (union DBKey *key, struct DBData **data, va_list args);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_inter_achievement_char_achievements_clear_pre; hIndex++) {
+ va_list args___copy; va_copy(args___copy, args);
+ preHookFunc = HPMHooks.list.HP_inter_achievement_char_achievements_clear_pre[hIndex].func;
+ retVal___ = preHookFunc(&key, &data, args___copy);
+ va_end(args___copy);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return retVal___;
+ }
+ }
+ {
+ va_list args___copy; va_copy(args___copy, args);
+ retVal___ = HPMHooks.source.inter_achievement.char_achievements_clear(key, data, args___copy);
+ va_end(args___copy);
+ }
+ if (HPMHooks.count.HP_inter_achievement_char_achievements_clear_post > 0) {
+ int (*postHookFunc) (int retVal___, union DBKey key, struct DBData *data, va_list args);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_inter_achievement_char_achievements_clear_post; hIndex++) {
+ va_list args___copy; va_copy(args___copy, args);
+ postHookFunc = HPMHooks.list.HP_inter_achievement_char_achievements_clear_post[hIndex].func;
+ retVal___ = postHookFunc(retVal___, key, data, args___copy);
+ va_end(args___copy);
+ }
+ }
+ return retVal___;
+}
+int HP_inter_achievement_parse_frommap(int fd) {
+ int hIndex = 0;
+ int retVal___ = 0;
+ if (HPMHooks.count.HP_inter_achievement_parse_frommap_pre > 0) {
+ int (*preHookFunc) (int *fd);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_inter_achievement_parse_frommap_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_inter_achievement_parse_frommap_pre[hIndex].func;
+ retVal___ = preHookFunc(&fd);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return retVal___;
+ }
+ }
+ {
+ retVal___ = HPMHooks.source.inter_achievement.parse_frommap(fd);
+ }
+ if (HPMHooks.count.HP_inter_achievement_parse_frommap_post > 0) {
+ int (*postHookFunc) (int retVal___, int fd);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_inter_achievement_parse_frommap_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_inter_achievement_parse_frommap_post[hIndex].func;
+ retVal___ = postHookFunc(retVal___, fd);
+ }
+ }
+ return retVal___;
+}
/* inter_auction_interface */
int HP_inter_auction_count(int char_id, bool buy) {
int hIndex = 0;
@@ -12430,6 +12631,136 @@ void HP_mapif_send_users_count(int users) {
}
return;
}
+void HP_mapif_pLoadAchievements(int fd) {
+ int hIndex = 0;
+ if (HPMHooks.count.HP_mapif_pLoadAchievements_pre > 0) {
+ void (*preHookFunc) (int *fd);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_mapif_pLoadAchievements_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_mapif_pLoadAchievements_pre[hIndex].func;
+ preHookFunc(&fd);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.mapif.pLoadAchievements(fd);
+ }
+ if (HPMHooks.count.HP_mapif_pLoadAchievements_post > 0) {
+ void (*postHookFunc) (int fd);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_mapif_pLoadAchievements_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_mapif_pLoadAchievements_post[hIndex].func;
+ postHookFunc(fd);
+ }
+ }
+ return;
+}
+void HP_mapif_sAchievementsToMap(int fd, int char_id, const struct char_achievements *p) {
+ int hIndex = 0;
+ if (HPMHooks.count.HP_mapif_sAchievementsToMap_pre > 0) {
+ void (*preHookFunc) (int *fd, int *char_id, const struct char_achievements **p);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_mapif_sAchievementsToMap_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_mapif_sAchievementsToMap_pre[hIndex].func;
+ preHookFunc(&fd, &char_id, &p);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.mapif.sAchievementsToMap(fd, char_id, p);
+ }
+ if (HPMHooks.count.HP_mapif_sAchievementsToMap_post > 0) {
+ void (*postHookFunc) (int fd, int char_id, const struct char_achievements *p);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_mapif_sAchievementsToMap_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_mapif_sAchievementsToMap_post[hIndex].func;
+ postHookFunc(fd, char_id, p);
+ }
+ }
+ return;
+}
+void HP_mapif_pSaveAchievements(int fd) {
+ int hIndex = 0;
+ if (HPMHooks.count.HP_mapif_pSaveAchievements_pre > 0) {
+ void (*preHookFunc) (int *fd);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_mapif_pSaveAchievements_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_mapif_pSaveAchievements_pre[hIndex].func;
+ preHookFunc(&fd);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.mapif.pSaveAchievements(fd);
+ }
+ if (HPMHooks.count.HP_mapif_pSaveAchievements_post > 0) {
+ void (*postHookFunc) (int fd);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_mapif_pSaveAchievements_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_mapif_pSaveAchievements_post[hIndex].func;
+ postHookFunc(fd);
+ }
+ }
+ return;
+}
+void HP_mapif_achievement_load(int fd, int char_id) {
+ int hIndex = 0;
+ if (HPMHooks.count.HP_mapif_achievement_load_pre > 0) {
+ void (*preHookFunc) (int *fd, int *char_id);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_mapif_achievement_load_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_mapif_achievement_load_pre[hIndex].func;
+ preHookFunc(&fd, &char_id);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.mapif.achievement_load(fd, char_id);
+ }
+ if (HPMHooks.count.HP_mapif_achievement_load_post > 0) {
+ void (*postHookFunc) (int fd, int char_id);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_mapif_achievement_load_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_mapif_achievement_load_post[hIndex].func;
+ postHookFunc(fd, char_id);
+ }
+ }
+ return;
+}
+void HP_mapif_achievement_save(int char_id, struct char_achievements *p) {
+ int hIndex = 0;
+ if (HPMHooks.count.HP_mapif_achievement_save_pre > 0) {
+ void (*preHookFunc) (int *char_id, struct char_achievements **p);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_mapif_achievement_save_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_mapif_achievement_save_pre[hIndex].func;
+ preHookFunc(&char_id, &p);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.mapif.achievement_save(char_id, p);
+ }
+ if (HPMHooks.count.HP_mapif_achievement_save_post > 0) {
+ void (*postHookFunc) (int char_id, struct char_achievements *p);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_mapif_achievement_save_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_mapif_achievement_save_post[hIndex].func;
+ postHookFunc(char_id, p);
+ }
+ }
+ return;
+}
void HP_mapif_auction_message(int char_id, unsigned char result) {
int hIndex = 0;
if (HPMHooks.count.HP_mapif_auction_message_pre > 0) {
diff --git a/src/plugins/HPMHooking/HPMHooking_char.sources.inc b/src/plugins/HPMHooking/HPMHooking_char.sources.inc
index 9ba9e129e..0d69cd755 100644
--- a/src/plugins/HPMHooking/HPMHooking_char.sources.inc
+++ b/src/plugins/HPMHooking/HPMHooking_char.sources.inc
@@ -33,6 +33,7 @@ HPMHooks.source.core = *core;
HPMHooks.source.DB = *DB;
HPMHooks.source.des = *des;
HPMHooks.source.geoip = *geoip;
+HPMHooks.source.inter_achievement = *inter_achievement;
HPMHooks.source.inter_auction = *inter_auction;
HPMHooks.source.inter_clan = *inter_clan;
HPMHooks.source.inter_elemental = *inter_elemental;
diff --git a/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc b/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc
index 6ab215bfc..fadab9ea7 100644
--- a/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc
+++ b/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc
@@ -32,6 +32,110 @@ struct {
struct HPMHookPoint *HP_HCache_check_post;
struct HPMHookPoint *HP_HCache_open_pre;
struct HPMHookPoint *HP_HCache_open_post;
+ struct HPMHookPoint *HP_achievement_init_pre;
+ struct HPMHookPoint *HP_achievement_init_post;
+ struct HPMHookPoint *HP_achievement_final_pre;
+ struct HPMHookPoint *HP_achievement_final_post;
+ struct HPMHookPoint *HP_achievement_db_finalize_pre;
+ struct HPMHookPoint *HP_achievement_db_finalize_post;
+ struct HPMHookPoint *HP_achievement_readdb_pre;
+ struct HPMHookPoint *HP_achievement_readdb_post;
+ struct HPMHookPoint *HP_achievement_readdb_objectives_sub_pre;
+ struct HPMHookPoint *HP_achievement_readdb_objectives_sub_post;
+ struct HPMHookPoint *HP_achievement_readdb_objectives_pre;
+ struct HPMHookPoint *HP_achievement_readdb_objectives_post;
+ struct HPMHookPoint *HP_achievement_readdb_validate_criteria_mobid_pre;
+ struct HPMHookPoint *HP_achievement_readdb_validate_criteria_mobid_post;
+ struct HPMHookPoint *HP_achievement_readdb_validate_criteria_jobid_pre;
+ struct HPMHookPoint *HP_achievement_readdb_validate_criteria_jobid_post;
+ struct HPMHookPoint *HP_achievement_readdb_validate_criteria_itemid_pre;
+ struct HPMHookPoint *HP_achievement_readdb_validate_criteria_itemid_post;
+ struct HPMHookPoint *HP_achievement_readdb_validate_criteria_statustype_pre;
+ struct HPMHookPoint *HP_achievement_readdb_validate_criteria_statustype_post;
+ struct HPMHookPoint *HP_achievement_readdb_validate_criteria_itemtype_pre;
+ struct HPMHookPoint *HP_achievement_readdb_validate_criteria_itemtype_post;
+ struct HPMHookPoint *HP_achievement_readdb_validate_criteria_weaponlv_pre;
+ struct HPMHookPoint *HP_achievement_readdb_validate_criteria_weaponlv_post;
+ struct HPMHookPoint *HP_achievement_readdb_validate_criteria_achievement_pre;
+ struct HPMHookPoint *HP_achievement_readdb_validate_criteria_achievement_post;
+ struct HPMHookPoint *HP_achievement_readdb_rewards_pre;
+ struct HPMHookPoint *HP_achievement_readdb_rewards_post;
+ struct HPMHookPoint *HP_achievement_readdb_validate_reward_items_pre;
+ struct HPMHookPoint *HP_achievement_readdb_validate_reward_items_post;
+ struct HPMHookPoint *HP_achievement_readdb_validate_reward_item_sub_pre;
+ struct HPMHookPoint *HP_achievement_readdb_validate_reward_item_sub_post;
+ struct HPMHookPoint *HP_achievement_readdb_validate_reward_bonus_pre;
+ struct HPMHookPoint *HP_achievement_readdb_validate_reward_bonus_post;
+ struct HPMHookPoint *HP_achievement_readdb_validate_reward_titleid_pre;
+ struct HPMHookPoint *HP_achievement_readdb_validate_reward_titleid_post;
+ struct HPMHookPoint *HP_achievement_readdb_additional_fields_pre;
+ struct HPMHookPoint *HP_achievement_readdb_additional_fields_post;
+ struct HPMHookPoint *HP_achievement_readdb_ranks_pre;
+ struct HPMHookPoint *HP_achievement_readdb_ranks_post;
+ struct HPMHookPoint *HP_achievement_get_pre;
+ struct HPMHookPoint *HP_achievement_get_post;
+ struct HPMHookPoint *HP_achievement_ensure_pre;
+ struct HPMHookPoint *HP_achievement_ensure_post;
+ struct HPMHookPoint *HP_achievement_calculate_totals_pre;
+ struct HPMHookPoint *HP_achievement_calculate_totals_post;
+ struct HPMHookPoint *HP_achievement_check_complete_pre;
+ struct HPMHookPoint *HP_achievement_check_complete_post;
+ struct HPMHookPoint *HP_achievement_progress_add_pre;
+ struct HPMHookPoint *HP_achievement_progress_add_post;
+ struct HPMHookPoint *HP_achievement_progress_set_pre;
+ struct HPMHookPoint *HP_achievement_progress_set_post;
+ struct HPMHookPoint *HP_achievement_check_criteria_pre;
+ struct HPMHookPoint *HP_achievement_check_criteria_post;
+ struct HPMHookPoint *HP_achievement_validate_pre;
+ struct HPMHookPoint *HP_achievement_validate_post;
+ struct HPMHookPoint *HP_achievement_validate_type_pre;
+ struct HPMHookPoint *HP_achievement_validate_type_post;
+ struct HPMHookPoint *HP_achievement_validate_mob_kill_pre;
+ struct HPMHookPoint *HP_achievement_validate_mob_kill_post;
+ struct HPMHookPoint *HP_achievement_validate_mob_damage_pre;
+ struct HPMHookPoint *HP_achievement_validate_mob_damage_post;
+ struct HPMHookPoint *HP_achievement_validate_pc_kill_pre;
+ struct HPMHookPoint *HP_achievement_validate_pc_kill_post;
+ struct HPMHookPoint *HP_achievement_validate_pc_damage_pre;
+ struct HPMHookPoint *HP_achievement_validate_pc_damage_post;
+ struct HPMHookPoint *HP_achievement_validate_jobchange_pre;
+ struct HPMHookPoint *HP_achievement_validate_jobchange_post;
+ struct HPMHookPoint *HP_achievement_validate_stats_pre;
+ struct HPMHookPoint *HP_achievement_validate_stats_post;
+ struct HPMHookPoint *HP_achievement_validate_chatroom_create_pre;
+ struct HPMHookPoint *HP_achievement_validate_chatroom_create_post;
+ struct HPMHookPoint *HP_achievement_validate_chatroom_members_pre;
+ struct HPMHookPoint *HP_achievement_validate_chatroom_members_post;
+ struct HPMHookPoint *HP_achievement_validate_friend_add_pre;
+ struct HPMHookPoint *HP_achievement_validate_friend_add_post;
+ struct HPMHookPoint *HP_achievement_validate_party_create_pre;
+ struct HPMHookPoint *HP_achievement_validate_party_create_post;
+ struct HPMHookPoint *HP_achievement_validate_marry_pre;
+ struct HPMHookPoint *HP_achievement_validate_marry_post;
+ struct HPMHookPoint *HP_achievement_validate_adopt_pre;
+ struct HPMHookPoint *HP_achievement_validate_adopt_post;
+ struct HPMHookPoint *HP_achievement_validate_zeny_pre;
+ struct HPMHookPoint *HP_achievement_validate_zeny_post;
+ struct HPMHookPoint *HP_achievement_validate_refine_pre;
+ struct HPMHookPoint *HP_achievement_validate_refine_post;
+ struct HPMHookPoint *HP_achievement_validate_item_get_pre;
+ struct HPMHookPoint *HP_achievement_validate_item_get_post;
+ struct HPMHookPoint *HP_achievement_validate_item_sell_pre;
+ struct HPMHookPoint *HP_achievement_validate_item_sell_post;
+ struct HPMHookPoint *HP_achievement_validate_achieve_pre;
+ struct HPMHookPoint *HP_achievement_validate_achieve_post;
+ struct HPMHookPoint *HP_achievement_validate_taming_pre;
+ struct HPMHookPoint *HP_achievement_validate_taming_post;
+ struct HPMHookPoint *HP_achievement_validate_achievement_rank_pre;
+ struct HPMHookPoint *HP_achievement_validate_achievement_rank_post;
+ struct HPMHookPoint *HP_achievement_type_requires_criteria_pre;
+ struct HPMHookPoint *HP_achievement_type_requires_criteria_post;
+ struct HPMHookPoint *HP_achievement_init_titles_pre;
+ struct HPMHookPoint *HP_achievement_init_titles_post;
+ struct HPMHookPoint *HP_achievement_check_title_pre;
+ struct HPMHookPoint *HP_achievement_check_title_post;
+ struct HPMHookPoint *HP_achievement_get_rewards_pre;
+ struct HPMHookPoint *HP_achievement_get_rewards_post;
struct HPMHookPoint *HP_atcommand_init_pre;
struct HPMHookPoint *HP_atcommand_init_post;
struct HPMHookPoint *HP_atcommand_final_pre;
@@ -1478,6 +1582,18 @@ struct {
struct HPMHookPoint *HP_clif_navigate_to_post;
struct HPMHookPoint *HP_clif_bl_type_pre;
struct HPMHookPoint *HP_clif_bl_type_post;
+ struct HPMHookPoint *HP_clif_achievement_send_list_pre;
+ struct HPMHookPoint *HP_clif_achievement_send_list_post;
+ struct HPMHookPoint *HP_clif_achievement_send_update_pre;
+ struct HPMHookPoint *HP_clif_achievement_send_update_post;
+ struct HPMHookPoint *HP_clif_pAchievementGetReward_pre;
+ struct HPMHookPoint *HP_clif_pAchievementGetReward_post;
+ struct HPMHookPoint *HP_clif_achievement_reward_ack_pre;
+ struct HPMHookPoint *HP_clif_achievement_reward_ack_post;
+ struct HPMHookPoint *HP_clif_change_title_ack_pre;
+ struct HPMHookPoint *HP_clif_change_title_ack_post;
+ struct HPMHookPoint *HP_clif_pChangeTitle_pre;
+ struct HPMHookPoint *HP_clif_pChangeTitle_post;
struct HPMHookPoint *HP_clif_pWantToConnection_pre;
struct HPMHookPoint *HP_clif_pWantToConnection_post;
struct HPMHookPoint *HP_clif_pLoadEndAck_pre;
@@ -2710,6 +2826,10 @@ struct {
struct HPMHookPoint *HP_intif_request_accinfo_post;
struct HPMHookPoint *HP_intif_CheckForCharServer_pre;
struct HPMHookPoint *HP_intif_CheckForCharServer_post;
+ struct HPMHookPoint *HP_intif_achievements_request_pre;
+ struct HPMHookPoint *HP_intif_achievements_request_post;
+ struct HPMHookPoint *HP_intif_achievements_save_pre;
+ struct HPMHookPoint *HP_intif_achievements_save_post;
struct HPMHookPoint *HP_intif_pWisMessage_pre;
struct HPMHookPoint *HP_intif_pWisMessage_post;
struct HPMHookPoint *HP_intif_pWisEnd_pre;
@@ -2848,6 +2968,8 @@ struct {
struct HPMHookPoint *HP_intif_pRodexCheckName_post;
struct HPMHookPoint *HP_intif_pRecvClanMemberAction_pre;
struct HPMHookPoint *HP_intif_pRecvClanMemberAction_post;
+ struct HPMHookPoint *HP_intif_pAchievementsLoad_pre;
+ struct HPMHookPoint *HP_intif_pAchievementsLoad_post;
struct HPMHookPoint *HP_ircbot_init_pre;
struct HPMHookPoint *HP_ircbot_init_post;
struct HPMHookPoint *HP_ircbot_final_pre;
@@ -6455,6 +6577,110 @@ struct {
int HP_HCache_check_post;
int HP_HCache_open_pre;
int HP_HCache_open_post;
+ int HP_achievement_init_pre;
+ int HP_achievement_init_post;
+ int HP_achievement_final_pre;
+ int HP_achievement_final_post;
+ int HP_achievement_db_finalize_pre;
+ int HP_achievement_db_finalize_post;
+ int HP_achievement_readdb_pre;
+ int HP_achievement_readdb_post;
+ int HP_achievement_readdb_objectives_sub_pre;
+ int HP_achievement_readdb_objectives_sub_post;
+ int HP_achievement_readdb_objectives_pre;
+ int HP_achievement_readdb_objectives_post;
+ int HP_achievement_readdb_validate_criteria_mobid_pre;
+ int HP_achievement_readdb_validate_criteria_mobid_post;
+ int HP_achievement_readdb_validate_criteria_jobid_pre;
+ int HP_achievement_readdb_validate_criteria_jobid_post;
+ int HP_achievement_readdb_validate_criteria_itemid_pre;
+ int HP_achievement_readdb_validate_criteria_itemid_post;
+ int HP_achievement_readdb_validate_criteria_statustype_pre;
+ int HP_achievement_readdb_validate_criteria_statustype_post;
+ int HP_achievement_readdb_validate_criteria_itemtype_pre;
+ int HP_achievement_readdb_validate_criteria_itemtype_post;
+ int HP_achievement_readdb_validate_criteria_weaponlv_pre;
+ int HP_achievement_readdb_validate_criteria_weaponlv_post;
+ int HP_achievement_readdb_validate_criteria_achievement_pre;
+ int HP_achievement_readdb_validate_criteria_achievement_post;
+ int HP_achievement_readdb_rewards_pre;
+ int HP_achievement_readdb_rewards_post;
+ int HP_achievement_readdb_validate_reward_items_pre;
+ int HP_achievement_readdb_validate_reward_items_post;
+ int HP_achievement_readdb_validate_reward_item_sub_pre;
+ int HP_achievement_readdb_validate_reward_item_sub_post;
+ int HP_achievement_readdb_validate_reward_bonus_pre;
+ int HP_achievement_readdb_validate_reward_bonus_post;
+ int HP_achievement_readdb_validate_reward_titleid_pre;
+ int HP_achievement_readdb_validate_reward_titleid_post;
+ int HP_achievement_readdb_additional_fields_pre;
+ int HP_achievement_readdb_additional_fields_post;
+ int HP_achievement_readdb_ranks_pre;
+ int HP_achievement_readdb_ranks_post;
+ int HP_achievement_get_pre;
+ int HP_achievement_get_post;
+ int HP_achievement_ensure_pre;
+ int HP_achievement_ensure_post;
+ int HP_achievement_calculate_totals_pre;
+ int HP_achievement_calculate_totals_post;
+ int HP_achievement_check_complete_pre;
+ int HP_achievement_check_complete_post;
+ int HP_achievement_progress_add_pre;
+ int HP_achievement_progress_add_post;
+ int HP_achievement_progress_set_pre;
+ int HP_achievement_progress_set_post;
+ int HP_achievement_check_criteria_pre;
+ int HP_achievement_check_criteria_post;
+ int HP_achievement_validate_pre;
+ int HP_achievement_validate_post;
+ int HP_achievement_validate_type_pre;
+ int HP_achievement_validate_type_post;
+ int HP_achievement_validate_mob_kill_pre;
+ int HP_achievement_validate_mob_kill_post;
+ int HP_achievement_validate_mob_damage_pre;
+ int HP_achievement_validate_mob_damage_post;
+ int HP_achievement_validate_pc_kill_pre;
+ int HP_achievement_validate_pc_kill_post;
+ int HP_achievement_validate_pc_damage_pre;
+ int HP_achievement_validate_pc_damage_post;
+ int HP_achievement_validate_jobchange_pre;
+ int HP_achievement_validate_jobchange_post;
+ int HP_achievement_validate_stats_pre;
+ int HP_achievement_validate_stats_post;
+ int HP_achievement_validate_chatroom_create_pre;
+ int HP_achievement_validate_chatroom_create_post;
+ int HP_achievement_validate_chatroom_members_pre;
+ int HP_achievement_validate_chatroom_members_post;
+ int HP_achievement_validate_friend_add_pre;
+ int HP_achievement_validate_friend_add_post;
+ int HP_achievement_validate_party_create_pre;
+ int HP_achievement_validate_party_create_post;
+ int HP_achievement_validate_marry_pre;
+ int HP_achievement_validate_marry_post;
+ int HP_achievement_validate_adopt_pre;
+ int HP_achievement_validate_adopt_post;
+ int HP_achievement_validate_zeny_pre;
+ int HP_achievement_validate_zeny_post;
+ int HP_achievement_validate_refine_pre;
+ int HP_achievement_validate_refine_post;
+ int HP_achievement_validate_item_get_pre;
+ int HP_achievement_validate_item_get_post;
+ int HP_achievement_validate_item_sell_pre;
+ int HP_achievement_validate_item_sell_post;
+ int HP_achievement_validate_achieve_pre;
+ int HP_achievement_validate_achieve_post;
+ int HP_achievement_validate_taming_pre;
+ int HP_achievement_validate_taming_post;
+ int HP_achievement_validate_achievement_rank_pre;
+ int HP_achievement_validate_achievement_rank_post;
+ int HP_achievement_type_requires_criteria_pre;
+ int HP_achievement_type_requires_criteria_post;
+ int HP_achievement_init_titles_pre;
+ int HP_achievement_init_titles_post;
+ int HP_achievement_check_title_pre;
+ int HP_achievement_check_title_post;
+ int HP_achievement_get_rewards_pre;
+ int HP_achievement_get_rewards_post;
int HP_atcommand_init_pre;
int HP_atcommand_init_post;
int HP_atcommand_final_pre;
@@ -7901,6 +8127,18 @@ struct {
int HP_clif_navigate_to_post;
int HP_clif_bl_type_pre;
int HP_clif_bl_type_post;
+ int HP_clif_achievement_send_list_pre;
+ int HP_clif_achievement_send_list_post;
+ int HP_clif_achievement_send_update_pre;
+ int HP_clif_achievement_send_update_post;
+ int HP_clif_pAchievementGetReward_pre;
+ int HP_clif_pAchievementGetReward_post;
+ int HP_clif_achievement_reward_ack_pre;
+ int HP_clif_achievement_reward_ack_post;
+ int HP_clif_change_title_ack_pre;
+ int HP_clif_change_title_ack_post;
+ int HP_clif_pChangeTitle_pre;
+ int HP_clif_pChangeTitle_post;
int HP_clif_pWantToConnection_pre;
int HP_clif_pWantToConnection_post;
int HP_clif_pLoadEndAck_pre;
@@ -9133,6 +9371,10 @@ struct {
int HP_intif_request_accinfo_post;
int HP_intif_CheckForCharServer_pre;
int HP_intif_CheckForCharServer_post;
+ int HP_intif_achievements_request_pre;
+ int HP_intif_achievements_request_post;
+ int HP_intif_achievements_save_pre;
+ int HP_intif_achievements_save_post;
int HP_intif_pWisMessage_pre;
int HP_intif_pWisMessage_post;
int HP_intif_pWisEnd_pre;
@@ -9271,6 +9513,8 @@ struct {
int HP_intif_pRodexCheckName_post;
int HP_intif_pRecvClanMemberAction_pre;
int HP_intif_pRecvClanMemberAction_post;
+ int HP_intif_pAchievementsLoad_pre;
+ int HP_intif_pAchievementsLoad_post;
int HP_ircbot_init_pre;
int HP_ircbot_init_post;
int HP_ircbot_final_pre;
@@ -12873,6 +13117,7 @@ struct {
struct {
struct HCache_interface HCache;
+ struct achievement_interface achievement;
struct atcommand_interface atcommand;
struct battle_interface battle;
struct battleground_interface bg;
diff --git a/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc b/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc
index 43c9c8e6d..57728fbc4 100644
--- a/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc
+++ b/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc
@@ -30,6 +30,59 @@ struct HookingPointData HookingPoints[] = {
{ HP_POP(HCache->init, HP_HCache_init) },
{ HP_POP(HCache->check, HP_HCache_check) },
{ HP_POP(HCache->open, HP_HCache_open) },
+/* achievement_interface */
+ { HP_POP(achievement->init, HP_achievement_init) },
+ { HP_POP(achievement->final, HP_achievement_final) },
+ { HP_POP(achievement->db_finalize, HP_achievement_db_finalize) },
+ { HP_POP(achievement->readdb, HP_achievement_readdb) },
+ { HP_POP(achievement->readdb_objectives_sub, HP_achievement_readdb_objectives_sub) },
+ { HP_POP(achievement->readdb_objectives, HP_achievement_readdb_objectives) },
+ { HP_POP(achievement->readdb_validate_criteria_mobid, HP_achievement_readdb_validate_criteria_mobid) },
+ { HP_POP(achievement->readdb_validate_criteria_jobid, HP_achievement_readdb_validate_criteria_jobid) },
+ { HP_POP(achievement->readdb_validate_criteria_itemid, HP_achievement_readdb_validate_criteria_itemid) },
+ { HP_POP(achievement->readdb_validate_criteria_statustype, HP_achievement_readdb_validate_criteria_statustype) },
+ { HP_POP(achievement->readdb_validate_criteria_itemtype, HP_achievement_readdb_validate_criteria_itemtype) },
+ { HP_POP(achievement->readdb_validate_criteria_weaponlv, HP_achievement_readdb_validate_criteria_weaponlv) },
+ { HP_POP(achievement->readdb_validate_criteria_achievement, HP_achievement_readdb_validate_criteria_achievement) },
+ { HP_POP(achievement->readdb_rewards, HP_achievement_readdb_rewards) },
+ { HP_POP(achievement->readdb_validate_reward_items, HP_achievement_readdb_validate_reward_items) },
+ { HP_POP(achievement->readdb_validate_reward_item_sub, HP_achievement_readdb_validate_reward_item_sub) },
+ { HP_POP(achievement->readdb_validate_reward_bonus, HP_achievement_readdb_validate_reward_bonus) },
+ { HP_POP(achievement->readdb_validate_reward_titleid, HP_achievement_readdb_validate_reward_titleid) },
+ { HP_POP(achievement->readdb_additional_fields, HP_achievement_readdb_additional_fields) },
+ { HP_POP(achievement->readdb_ranks, HP_achievement_readdb_ranks) },
+ { HP_POP(achievement->get, HP_achievement_get) },
+ { HP_POP(achievement->ensure, HP_achievement_ensure) },
+ { HP_POP(achievement->calculate_totals, HP_achievement_calculate_totals) },
+ { HP_POP(achievement->check_complete, HP_achievement_check_complete) },
+ { HP_POP(achievement->progress_add, HP_achievement_progress_add) },
+ { HP_POP(achievement->progress_set, HP_achievement_progress_set) },
+ { HP_POP(achievement->check_criteria, HP_achievement_check_criteria) },
+ { HP_POP(achievement->validate, HP_achievement_validate) },
+ { HP_POP(achievement->validate_type, HP_achievement_validate_type) },
+ { HP_POP(achievement->validate_mob_kill, HP_achievement_validate_mob_kill) },
+ { HP_POP(achievement->validate_mob_damage, HP_achievement_validate_mob_damage) },
+ { HP_POP(achievement->validate_pc_kill, HP_achievement_validate_pc_kill) },
+ { HP_POP(achievement->validate_pc_damage, HP_achievement_validate_pc_damage) },
+ { HP_POP(achievement->validate_jobchange, HP_achievement_validate_jobchange) },
+ { HP_POP(achievement->validate_stats, HP_achievement_validate_stats) },
+ { HP_POP(achievement->validate_chatroom_create, HP_achievement_validate_chatroom_create) },
+ { HP_POP(achievement->validate_chatroom_members, HP_achievement_validate_chatroom_members) },
+ { HP_POP(achievement->validate_friend_add, HP_achievement_validate_friend_add) },
+ { HP_POP(achievement->validate_party_create, HP_achievement_validate_party_create) },
+ { HP_POP(achievement->validate_marry, HP_achievement_validate_marry) },
+ { HP_POP(achievement->validate_adopt, HP_achievement_validate_adopt) },
+ { HP_POP(achievement->validate_zeny, HP_achievement_validate_zeny) },
+ { HP_POP(achievement->validate_refine, HP_achievement_validate_refine) },
+ { HP_POP(achievement->validate_item_get, HP_achievement_validate_item_get) },
+ { HP_POP(achievement->validate_item_sell, HP_achievement_validate_item_sell) },
+ { HP_POP(achievement->validate_achieve, HP_achievement_validate_achieve) },
+ { HP_POP(achievement->validate_taming, HP_achievement_validate_taming) },
+ { HP_POP(achievement->validate_achievement_rank, HP_achievement_validate_achievement_rank) },
+ { HP_POP(achievement->type_requires_criteria, HP_achievement_type_requires_criteria) },
+ { HP_POP(achievement->init_titles, HP_achievement_init_titles) },
+ { HP_POP(achievement->check_title, HP_achievement_check_title) },
+ { HP_POP(achievement->get_rewards, HP_achievement_get_rewards) },
/* atcommand_interface */
{ HP_POP(atcommand->init, HP_atcommand_init) },
{ HP_POP(atcommand->final, HP_atcommand_final) },
@@ -762,6 +815,12 @@ struct HookingPointData HookingPoints[] = {
{ HP_POP(clif->isdisguised, HP_clif_isdisguised) },
{ HP_POP(clif->navigate_to, HP_clif_navigate_to) },
{ HP_POP(clif->bl_type, HP_clif_bl_type) },
+ { HP_POP(clif->achievement_send_list, HP_clif_achievement_send_list) },
+ { HP_POP(clif->achievement_send_update, HP_clif_achievement_send_update) },
+ { HP_POP(clif->pAchievementGetReward, HP_clif_pAchievementGetReward) },
+ { HP_POP(clif->achievement_reward_ack, HP_clif_achievement_reward_ack) },
+ { HP_POP(clif->change_title_ack, HP_clif_change_title_ack) },
+ { HP_POP(clif->pChangeTitle, HP_clif_pChangeTitle) },
{ HP_POP(clif->pWantToConnection, HP_clif_pWantToConnection) },
{ HP_POP(clif->pLoadEndAck, HP_clif_pLoadEndAck) },
{ HP_POP(clif->pTickSend, HP_clif_pTickSend) },
@@ -1391,6 +1450,8 @@ struct HookingPointData HookingPoints[] = {
{ HP_POP(intif->clan_membercount, HP_intif_clan_membercount) },
{ HP_POP(intif->request_accinfo, HP_intif_request_accinfo) },
{ HP_POP(intif->CheckForCharServer, HP_intif_CheckForCharServer) },
+ { HP_POP(intif->achievements_request, HP_intif_achievements_request) },
+ { HP_POP(intif->achievements_save, HP_intif_achievements_save) },
{ HP_POP(intif->pWisMessage, HP_intif_pWisMessage) },
{ HP_POP(intif->pWisEnd, HP_intif_pWisEnd) },
{ HP_POP(intif->pWisToGM_sub, HP_intif_pWisToGM_sub) },
@@ -1460,6 +1521,7 @@ struct HookingPointData HookingPoints[] = {
{ HP_POP(intif->pRodexSendMail, HP_intif_pRodexSendMail) },
{ HP_POP(intif->pRodexCheckName, HP_intif_pRodexCheckName) },
{ HP_POP(intif->pRecvClanMemberAction, HP_intif_pRecvClanMemberAction) },
+ { HP_POP(intif->pAchievementsLoad, HP_intif_pAchievementsLoad) },
/* irc_bot_interface */
{ HP_POP(ircbot->init, HP_ircbot_init) },
{ HP_POP(ircbot->final, HP_ircbot_final) },
diff --git a/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc b/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc
index ca35225c6..e224a10bc 100644
--- a/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc
+++ b/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc
@@ -106,6 +106,1385 @@ FILE* HP_HCache_open(const char *file, const char *opt) {
}
return retVal___;
}
+/* achievement_interface */
+void HP_achievement_init(bool minimal) {
+ int hIndex = 0;
+ if (HPMHooks.count.HP_achievement_init_pre > 0) {
+ void (*preHookFunc) (bool *minimal);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_init_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_achievement_init_pre[hIndex].func;
+ preHookFunc(&minimal);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.achievement.init(minimal);
+ }
+ if (HPMHooks.count.HP_achievement_init_post > 0) {
+ void (*postHookFunc) (bool minimal);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_init_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_achievement_init_post[hIndex].func;
+ postHookFunc(minimal);
+ }
+ }
+ return;
+}
+void HP_achievement_final(void) {
+ int hIndex = 0;
+ if (HPMHooks.count.HP_achievement_final_pre > 0) {
+ void (*preHookFunc) (void);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_final_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_achievement_final_pre[hIndex].func;
+ preHookFunc();
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.achievement.final();
+ }
+ if (HPMHooks.count.HP_achievement_final_post > 0) {
+ void (*postHookFunc) (void);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_final_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_achievement_final_post[hIndex].func;
+ postHookFunc();
+ }
+ }
+ return;
+}
+int HP_achievement_db_finalize(union DBKey key, struct DBData *data, va_list args) {
+ int hIndex = 0;
+ int retVal___ = 0;
+ if (HPMHooks.count.HP_achievement_db_finalize_pre > 0) {
+ int (*preHookFunc) (union DBKey *key, struct DBData **data, va_list args);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_db_finalize_pre; hIndex++) {
+ va_list args___copy; va_copy(args___copy, args);
+ preHookFunc = HPMHooks.list.HP_achievement_db_finalize_pre[hIndex].func;
+ retVal___ = preHookFunc(&key, &data, args___copy);
+ va_end(args___copy);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return retVal___;
+ }
+ }
+ {
+ va_list args___copy; va_copy(args___copy, args);
+ retVal___ = HPMHooks.source.achievement.db_finalize(key, data, args___copy);
+ va_end(args___copy);
+ }
+ if (HPMHooks.count.HP_achievement_db_finalize_post > 0) {
+ int (*postHookFunc) (int retVal___, union DBKey key, struct DBData *data, va_list args);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_db_finalize_post; hIndex++) {
+ va_list args___copy; va_copy(args___copy, args);
+ postHookFunc = HPMHooks.list.HP_achievement_db_finalize_post[hIndex].func;
+ retVal___ = postHookFunc(retVal___, key, data, args___copy);
+ va_end(args___copy);
+ }
+ }
+ return retVal___;
+}
+void HP_achievement_readdb(void) {
+ int hIndex = 0;
+ if (HPMHooks.count.HP_achievement_readdb_pre > 0) {
+ void (*preHookFunc) (void);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_readdb_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_achievement_readdb_pre[hIndex].func;
+ preHookFunc();
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.achievement.readdb();
+ }
+ if (HPMHooks.count.HP_achievement_readdb_post > 0) {
+ void (*postHookFunc) (void);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_readdb_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_achievement_readdb_post[hIndex].func;
+ postHookFunc();
+ }
+ }
+ return;
+}
+bool HP_achievement_readdb_objectives_sub(const struct config_setting_t *conf, int index, struct achievement_data *entry) {
+ int hIndex = 0;
+ bool retVal___ = false;
+ if (HPMHooks.count.HP_achievement_readdb_objectives_sub_pre > 0) {
+ bool (*preHookFunc) (const struct config_setting_t **conf, int *index, struct achievement_data **entry);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_readdb_objectives_sub_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_achievement_readdb_objectives_sub_pre[hIndex].func;
+ retVal___ = preHookFunc(&conf, &index, &entry);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return retVal___;
+ }
+ }
+ {
+ retVal___ = HPMHooks.source.achievement.readdb_objectives_sub(conf, index, entry);
+ }
+ if (HPMHooks.count.HP_achievement_readdb_objectives_sub_post > 0) {
+ bool (*postHookFunc) (bool retVal___, const struct config_setting_t *conf, int index, struct achievement_data *entry);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_readdb_objectives_sub_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_achievement_readdb_objectives_sub_post[hIndex].func;
+ retVal___ = postHookFunc(retVal___, conf, index, entry);
+ }
+ }
+ return retVal___;
+}
+bool HP_achievement_readdb_objectives(const struct config_setting_t *conf, struct achievement_data *entry) {
+ int hIndex = 0;
+ bool retVal___ = false;
+ if (HPMHooks.count.HP_achievement_readdb_objectives_pre > 0) {
+ bool (*preHookFunc) (const struct config_setting_t **conf, struct achievement_data **entry);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_readdb_objectives_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_achievement_readdb_objectives_pre[hIndex].func;
+ retVal___ = preHookFunc(&conf, &entry);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return retVal___;
+ }
+ }
+ {
+ retVal___ = HPMHooks.source.achievement.readdb_objectives(conf, entry);
+ }
+ if (HPMHooks.count.HP_achievement_readdb_objectives_post > 0) {
+ bool (*postHookFunc) (bool retVal___, const struct config_setting_t *conf, struct achievement_data *entry);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_readdb_objectives_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_achievement_readdb_objectives_post[hIndex].func;
+ retVal___ = postHookFunc(retVal___, conf, entry);
+ }
+ }
+ return retVal___;
+}
+bool HP_achievement_readdb_validate_criteria_mobid(const struct config_setting_t *t, struct achievement_objective *obj, enum achievement_types type, int entry_id, int obj_idx) {
+ int hIndex = 0;
+ bool retVal___ = false;
+ if (HPMHooks.count.HP_achievement_readdb_validate_criteria_mobid_pre > 0) {
+ bool (*preHookFunc) (const struct config_setting_t **t, struct achievement_objective **obj, enum achievement_types *type, int *entry_id, int *obj_idx);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_readdb_validate_criteria_mobid_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_achievement_readdb_validate_criteria_mobid_pre[hIndex].func;
+ retVal___ = preHookFunc(&t, &obj, &type, &entry_id, &obj_idx);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return retVal___;
+ }
+ }
+ {
+ retVal___ = HPMHooks.source.achievement.readdb_validate_criteria_mobid(t, obj, type, entry_id, obj_idx);
+ }
+ if (HPMHooks.count.HP_achievement_readdb_validate_criteria_mobid_post > 0) {
+ bool (*postHookFunc) (bool retVal___, const struct config_setting_t *t, struct achievement_objective *obj, enum achievement_types type, int entry_id, int obj_idx);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_readdb_validate_criteria_mobid_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_achievement_readdb_validate_criteria_mobid_post[hIndex].func;
+ retVal___ = postHookFunc(retVal___, t, obj, type, entry_id, obj_idx);
+ }
+ }
+ return retVal___;
+}
+bool HP_achievement_readdb_validate_criteria_jobid(const struct config_setting_t *t, struct achievement_objective *obj, enum achievement_types type, int entry_id, int obj_idx) {
+ int hIndex = 0;
+ bool retVal___ = false;
+ if (HPMHooks.count.HP_achievement_readdb_validate_criteria_jobid_pre > 0) {
+ bool (*preHookFunc) (const struct config_setting_t **t, struct achievement_objective **obj, enum achievement_types *type, int *entry_id, int *obj_idx);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_readdb_validate_criteria_jobid_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_achievement_readdb_validate_criteria_jobid_pre[hIndex].func;
+ retVal___ = preHookFunc(&t, &obj, &type, &entry_id, &obj_idx);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return retVal___;
+ }
+ }
+ {
+ retVal___ = HPMHooks.source.achievement.readdb_validate_criteria_jobid(t, obj, type, entry_id, obj_idx);
+ }
+ if (HPMHooks.count.HP_achievement_readdb_validate_criteria_jobid_post > 0) {
+ bool (*postHookFunc) (bool retVal___, const struct config_setting_t *t, struct achievement_objective *obj, enum achievement_types type, int entry_id, int obj_idx);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_readdb_validate_criteria_jobid_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_achievement_readdb_validate_criteria_jobid_post[hIndex].func;
+ retVal___ = postHookFunc(retVal___, t, obj, type, entry_id, obj_idx);
+ }
+ }
+ return retVal___;
+}
+bool HP_achievement_readdb_validate_criteria_itemid(const struct config_setting_t *t, struct achievement_objective *obj, enum achievement_types type, int entry_id, int obj_idx) {
+ int hIndex = 0;
+ bool retVal___ = false;
+ if (HPMHooks.count.HP_achievement_readdb_validate_criteria_itemid_pre > 0) {
+ bool (*preHookFunc) (const struct config_setting_t **t, struct achievement_objective **obj, enum achievement_types *type, int *entry_id, int *obj_idx);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_readdb_validate_criteria_itemid_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_achievement_readdb_validate_criteria_itemid_pre[hIndex].func;
+ retVal___ = preHookFunc(&t, &obj, &type, &entry_id, &obj_idx);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return retVal___;
+ }
+ }
+ {
+ retVal___ = HPMHooks.source.achievement.readdb_validate_criteria_itemid(t, obj, type, entry_id, obj_idx);
+ }
+ if (HPMHooks.count.HP_achievement_readdb_validate_criteria_itemid_post > 0) {
+ bool (*postHookFunc) (bool retVal___, const struct config_setting_t *t, struct achievement_objective *obj, enum achievement_types type, int entry_id, int obj_idx);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_readdb_validate_criteria_itemid_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_achievement_readdb_validate_criteria_itemid_post[hIndex].func;
+ retVal___ = postHookFunc(retVal___, t, obj, type, entry_id, obj_idx);
+ }
+ }
+ return retVal___;
+}
+bool HP_achievement_readdb_validate_criteria_statustype(const struct config_setting_t *t, struct achievement_objective *obj, enum achievement_types type, int entry_id, int obj_idx) {
+ int hIndex = 0;
+ bool retVal___ = false;
+ if (HPMHooks.count.HP_achievement_readdb_validate_criteria_statustype_pre > 0) {
+ bool (*preHookFunc) (const struct config_setting_t **t, struct achievement_objective **obj, enum achievement_types *type, int *entry_id, int *obj_idx);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_readdb_validate_criteria_statustype_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_achievement_readdb_validate_criteria_statustype_pre[hIndex].func;
+ retVal___ = preHookFunc(&t, &obj, &type, &entry_id, &obj_idx);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return retVal___;
+ }
+ }
+ {
+ retVal___ = HPMHooks.source.achievement.readdb_validate_criteria_statustype(t, obj, type, entry_id, obj_idx);
+ }
+ if (HPMHooks.count.HP_achievement_readdb_validate_criteria_statustype_post > 0) {
+ bool (*postHookFunc) (bool retVal___, const struct config_setting_t *t, struct achievement_objective *obj, enum achievement_types type, int entry_id, int obj_idx);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_readdb_validate_criteria_statustype_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_achievement_readdb_validate_criteria_statustype_post[hIndex].func;
+ retVal___ = postHookFunc(retVal___, t, obj, type, entry_id, obj_idx);
+ }
+ }
+ return retVal___;
+}
+bool HP_achievement_readdb_validate_criteria_itemtype(const struct config_setting_t *t, struct achievement_objective *obj, enum achievement_types type, int entry_id, int obj_idx) {
+ int hIndex = 0;
+ bool retVal___ = false;
+ if (HPMHooks.count.HP_achievement_readdb_validate_criteria_itemtype_pre > 0) {
+ bool (*preHookFunc) (const struct config_setting_t **t, struct achievement_objective **obj, enum achievement_types *type, int *entry_id, int *obj_idx);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_readdb_validate_criteria_itemtype_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_achievement_readdb_validate_criteria_itemtype_pre[hIndex].func;
+ retVal___ = preHookFunc(&t, &obj, &type, &entry_id, &obj_idx);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return retVal___;
+ }
+ }
+ {
+ retVal___ = HPMHooks.source.achievement.readdb_validate_criteria_itemtype(t, obj, type, entry_id, obj_idx);
+ }
+ if (HPMHooks.count.HP_achievement_readdb_validate_criteria_itemtype_post > 0) {
+ bool (*postHookFunc) (bool retVal___, const struct config_setting_t *t, struct achievement_objective *obj, enum achievement_types type, int entry_id, int obj_idx);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_readdb_validate_criteria_itemtype_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_achievement_readdb_validate_criteria_itemtype_post[hIndex].func;
+ retVal___ = postHookFunc(retVal___, t, obj, type, entry_id, obj_idx);
+ }
+ }
+ return retVal___;
+}
+bool HP_achievement_readdb_validate_criteria_weaponlv(const struct config_setting_t *t, struct achievement_objective *obj, enum achievement_types type, int entry_id, int obj_idx) {
+ int hIndex = 0;
+ bool retVal___ = false;
+ if (HPMHooks.count.HP_achievement_readdb_validate_criteria_weaponlv_pre > 0) {
+ bool (*preHookFunc) (const struct config_setting_t **t, struct achievement_objective **obj, enum achievement_types *type, int *entry_id, int *obj_idx);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_readdb_validate_criteria_weaponlv_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_achievement_readdb_validate_criteria_weaponlv_pre[hIndex].func;
+ retVal___ = preHookFunc(&t, &obj, &type, &entry_id, &obj_idx);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return retVal___;
+ }
+ }
+ {
+ retVal___ = HPMHooks.source.achievement.readdb_validate_criteria_weaponlv(t, obj, type, entry_id, obj_idx);
+ }
+ if (HPMHooks.count.HP_achievement_readdb_validate_criteria_weaponlv_post > 0) {
+ bool (*postHookFunc) (bool retVal___, const struct config_setting_t *t, struct achievement_objective *obj, enum achievement_types type, int entry_id, int obj_idx);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_readdb_validate_criteria_weaponlv_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_achievement_readdb_validate_criteria_weaponlv_post[hIndex].func;
+ retVal___ = postHookFunc(retVal___, t, obj, type, entry_id, obj_idx);
+ }
+ }
+ return retVal___;
+}
+bool HP_achievement_readdb_validate_criteria_achievement(const struct config_setting_t *t, struct achievement_objective *obj, enum achievement_types type, int entry_id, int obj_idx) {
+ int hIndex = 0;
+ bool retVal___ = false;
+ if (HPMHooks.count.HP_achievement_readdb_validate_criteria_achievement_pre > 0) {
+ bool (*preHookFunc) (const struct config_setting_t **t, struct achievement_objective **obj, enum achievement_types *type, int *entry_id, int *obj_idx);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_readdb_validate_criteria_achievement_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_achievement_readdb_validate_criteria_achievement_pre[hIndex].func;
+ retVal___ = preHookFunc(&t, &obj, &type, &entry_id, &obj_idx);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return retVal___;
+ }
+ }
+ {
+ retVal___ = HPMHooks.source.achievement.readdb_validate_criteria_achievement(t, obj, type, entry_id, obj_idx);
+ }
+ if (HPMHooks.count.HP_achievement_readdb_validate_criteria_achievement_post > 0) {
+ bool (*postHookFunc) (bool retVal___, const struct config_setting_t *t, struct achievement_objective *obj, enum achievement_types type, int entry_id, int obj_idx);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_readdb_validate_criteria_achievement_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_achievement_readdb_validate_criteria_achievement_post[hIndex].func;
+ retVal___ = postHookFunc(retVal___, t, obj, type, entry_id, obj_idx);
+ }
+ }
+ return retVal___;
+}
+bool HP_achievement_readdb_rewards(const struct config_setting_t *conf, struct achievement_data *entry, const char *source) {
+ int hIndex = 0;
+ bool retVal___ = false;
+ if (HPMHooks.count.HP_achievement_readdb_rewards_pre > 0) {
+ bool (*preHookFunc) (const struct config_setting_t **conf, struct achievement_data **entry, const char **source);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_readdb_rewards_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_achievement_readdb_rewards_pre[hIndex].func;
+ retVal___ = preHookFunc(&conf, &entry, &source);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return retVal___;
+ }
+ }
+ {
+ retVal___ = HPMHooks.source.achievement.readdb_rewards(conf, entry, source);
+ }
+ if (HPMHooks.count.HP_achievement_readdb_rewards_post > 0) {
+ bool (*postHookFunc) (bool retVal___, const struct config_setting_t *conf, struct achievement_data *entry, const char *source);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_readdb_rewards_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_achievement_readdb_rewards_post[hIndex].func;
+ retVal___ = postHookFunc(retVal___, conf, entry, source);
+ }
+ }
+ return retVal___;
+}
+void HP_achievement_readdb_validate_reward_items(const struct config_setting_t *t, struct achievement_data *entry) {
+ int hIndex = 0;
+ if (HPMHooks.count.HP_achievement_readdb_validate_reward_items_pre > 0) {
+ void (*preHookFunc) (const struct config_setting_t **t, struct achievement_data **entry);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_readdb_validate_reward_items_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_achievement_readdb_validate_reward_items_pre[hIndex].func;
+ preHookFunc(&t, &entry);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.achievement.readdb_validate_reward_items(t, entry);
+ }
+ if (HPMHooks.count.HP_achievement_readdb_validate_reward_items_post > 0) {
+ void (*postHookFunc) (const struct config_setting_t *t, struct achievement_data *entry);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_readdb_validate_reward_items_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_achievement_readdb_validate_reward_items_post[hIndex].func;
+ postHookFunc(t, entry);
+ }
+ }
+ return;
+}
+bool HP_achievement_readdb_validate_reward_item_sub(const struct config_setting_t *t, int element, struct achievement_data *entry) {
+ int hIndex = 0;
+ bool retVal___ = false;
+ if (HPMHooks.count.HP_achievement_readdb_validate_reward_item_sub_pre > 0) {
+ bool (*preHookFunc) (const struct config_setting_t **t, int *element, struct achievement_data **entry);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_readdb_validate_reward_item_sub_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_achievement_readdb_validate_reward_item_sub_pre[hIndex].func;
+ retVal___ = preHookFunc(&t, &element, &entry);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return retVal___;
+ }
+ }
+ {
+ retVal___ = HPMHooks.source.achievement.readdb_validate_reward_item_sub(t, element, entry);
+ }
+ if (HPMHooks.count.HP_achievement_readdb_validate_reward_item_sub_post > 0) {
+ bool (*postHookFunc) (bool retVal___, const struct config_setting_t *t, int element, struct achievement_data *entry);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_readdb_validate_reward_item_sub_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_achievement_readdb_validate_reward_item_sub_post[hIndex].func;
+ retVal___ = postHookFunc(retVal___, t, element, entry);
+ }
+ }
+ return retVal___;
+}
+void HP_achievement_readdb_validate_reward_bonus(const struct config_setting_t *t, struct achievement_data *entry, const char *source) {
+ int hIndex = 0;
+ if (HPMHooks.count.HP_achievement_readdb_validate_reward_bonus_pre > 0) {
+ void (*preHookFunc) (const struct config_setting_t **t, struct achievement_data **entry, const char **source);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_readdb_validate_reward_bonus_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_achievement_readdb_validate_reward_bonus_pre[hIndex].func;
+ preHookFunc(&t, &entry, &source);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.achievement.readdb_validate_reward_bonus(t, entry, source);
+ }
+ if (HPMHooks.count.HP_achievement_readdb_validate_reward_bonus_post > 0) {
+ void (*postHookFunc) (const struct config_setting_t *t, struct achievement_data *entry, const char *source);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_readdb_validate_reward_bonus_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_achievement_readdb_validate_reward_bonus_post[hIndex].func;
+ postHookFunc(t, entry, source);
+ }
+ }
+ return;
+}
+void HP_achievement_readdb_validate_reward_titleid(const struct config_setting_t *t, struct achievement_data *entry) {
+ int hIndex = 0;
+ if (HPMHooks.count.HP_achievement_readdb_validate_reward_titleid_pre > 0) {
+ void (*preHookFunc) (const struct config_setting_t **t, struct achievement_data **entry);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_readdb_validate_reward_titleid_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_achievement_readdb_validate_reward_titleid_pre[hIndex].func;
+ preHookFunc(&t, &entry);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.achievement.readdb_validate_reward_titleid(t, entry);
+ }
+ if (HPMHooks.count.HP_achievement_readdb_validate_reward_titleid_post > 0) {
+ void (*postHookFunc) (const struct config_setting_t *t, struct achievement_data *entry);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_readdb_validate_reward_titleid_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_achievement_readdb_validate_reward_titleid_post[hIndex].func;
+ postHookFunc(t, entry);
+ }
+ }
+ return;
+}
+void HP_achievement_readdb_additional_fields(const struct config_setting_t *conf, struct achievement_data *entry, const char *source) {
+ int hIndex = 0;
+ if (HPMHooks.count.HP_achievement_readdb_additional_fields_pre > 0) {
+ void (*preHookFunc) (const struct config_setting_t **conf, struct achievement_data **entry, const char **source);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_readdb_additional_fields_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_achievement_readdb_additional_fields_pre[hIndex].func;
+ preHookFunc(&conf, &entry, &source);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.achievement.readdb_additional_fields(conf, entry, source);
+ }
+ if (HPMHooks.count.HP_achievement_readdb_additional_fields_post > 0) {
+ void (*postHookFunc) (const struct config_setting_t *conf, struct achievement_data *entry, const char *source);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_readdb_additional_fields_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_achievement_readdb_additional_fields_post[hIndex].func;
+ postHookFunc(conf, entry, source);
+ }
+ }
+ return;
+}
+void HP_achievement_readdb_ranks(void) {
+ int hIndex = 0;
+ if (HPMHooks.count.HP_achievement_readdb_ranks_pre > 0) {
+ void (*preHookFunc) (void);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_readdb_ranks_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_achievement_readdb_ranks_pre[hIndex].func;
+ preHookFunc();
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.achievement.readdb_ranks();
+ }
+ if (HPMHooks.count.HP_achievement_readdb_ranks_post > 0) {
+ void (*postHookFunc) (void);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_readdb_ranks_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_achievement_readdb_ranks_post[hIndex].func;
+ postHookFunc();
+ }
+ }
+ return;
+}
+const struct achievement_data* HP_achievement_get(int aid) {
+ int hIndex = 0;
+ const struct achievement_data* retVal___ = NULL;
+ if (HPMHooks.count.HP_achievement_get_pre > 0) {
+ const struct achievement_data* (*preHookFunc) (int *aid);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_get_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_achievement_get_pre[hIndex].func;
+ retVal___ = preHookFunc(&aid);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return retVal___;
+ }
+ }
+ {
+ retVal___ = HPMHooks.source.achievement.get(aid);
+ }
+ if (HPMHooks.count.HP_achievement_get_post > 0) {
+ const struct achievement_data* (*postHookFunc) (const struct achievement_data* retVal___, int aid);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_get_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_achievement_get_post[hIndex].func;
+ retVal___ = postHookFunc(retVal___, aid);
+ }
+ }
+ return retVal___;
+}
+struct achievement* HP_achievement_ensure(struct map_session_data *sd, const struct achievement_data *ad) {
+ int hIndex = 0;
+ struct achievement* retVal___ = NULL;
+ if (HPMHooks.count.HP_achievement_ensure_pre > 0) {
+ struct achievement* (*preHookFunc) (struct map_session_data **sd, const struct achievement_data **ad);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_ensure_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_achievement_ensure_pre[hIndex].func;
+ retVal___ = preHookFunc(&sd, &ad);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return retVal___;
+ }
+ }
+ {
+ retVal___ = HPMHooks.source.achievement.ensure(sd, ad);
+ }
+ if (HPMHooks.count.HP_achievement_ensure_post > 0) {
+ struct achievement* (*postHookFunc) (struct achievement* retVal___, struct map_session_data *sd, const struct achievement_data *ad);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_ensure_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_achievement_ensure_post[hIndex].func;
+ retVal___ = postHookFunc(retVal___, sd, ad);
+ }
+ }
+ return retVal___;
+}
+void HP_achievement_calculate_totals(const struct map_session_data *sd, int *points, int *completed, int *rank, int *curr_rank_points) {
+ int hIndex = 0;
+ if (HPMHooks.count.HP_achievement_calculate_totals_pre > 0) {
+ void (*preHookFunc) (const struct map_session_data **sd, int **points, int **completed, int **rank, int **curr_rank_points);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_calculate_totals_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_achievement_calculate_totals_pre[hIndex].func;
+ preHookFunc(&sd, &points, &completed, &rank, &curr_rank_points);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.achievement.calculate_totals(sd, points, completed, rank, curr_rank_points);
+ }
+ if (HPMHooks.count.HP_achievement_calculate_totals_post > 0) {
+ void (*postHookFunc) (const struct map_session_data *sd, int *points, int *completed, int *rank, int *curr_rank_points);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_calculate_totals_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_achievement_calculate_totals_post[hIndex].func;
+ postHookFunc(sd, points, completed, rank, curr_rank_points);
+ }
+ }
+ return;
+}
+bool HP_achievement_check_complete(struct map_session_data *sd, const struct achievement_data *ad) {
+ int hIndex = 0;
+ bool retVal___ = false;
+ if (HPMHooks.count.HP_achievement_check_complete_pre > 0) {
+ bool (*preHookFunc) (struct map_session_data **sd, const struct achievement_data **ad);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_check_complete_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_achievement_check_complete_pre[hIndex].func;
+ retVal___ = preHookFunc(&sd, &ad);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return retVal___;
+ }
+ }
+ {
+ retVal___ = HPMHooks.source.achievement.check_complete(sd, ad);
+ }
+ if (HPMHooks.count.HP_achievement_check_complete_post > 0) {
+ bool (*postHookFunc) (bool retVal___, struct map_session_data *sd, const struct achievement_data *ad);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_check_complete_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_achievement_check_complete_post[hIndex].func;
+ retVal___ = postHookFunc(retVal___, sd, ad);
+ }
+ }
+ return retVal___;
+}
+void HP_achievement_progress_add(struct map_session_data *sd, const struct achievement_data *ad, unsigned int obj_idx, int progress) {
+ int hIndex = 0;
+ if (HPMHooks.count.HP_achievement_progress_add_pre > 0) {
+ void (*preHookFunc) (struct map_session_data **sd, const struct achievement_data **ad, unsigned int *obj_idx, int *progress);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_progress_add_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_achievement_progress_add_pre[hIndex].func;
+ preHookFunc(&sd, &ad, &obj_idx, &progress);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.achievement.progress_add(sd, ad, obj_idx, progress);
+ }
+ if (HPMHooks.count.HP_achievement_progress_add_post > 0) {
+ void (*postHookFunc) (struct map_session_data *sd, const struct achievement_data *ad, unsigned int obj_idx, int progress);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_progress_add_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_achievement_progress_add_post[hIndex].func;
+ postHookFunc(sd, ad, obj_idx, progress);
+ }
+ }
+ return;
+}
+void HP_achievement_progress_set(struct map_session_data *sd, const struct achievement_data *ad, unsigned int obj_idx, int progress) {
+ int hIndex = 0;
+ if (HPMHooks.count.HP_achievement_progress_set_pre > 0) {
+ void (*preHookFunc) (struct map_session_data **sd, const struct achievement_data **ad, unsigned int *obj_idx, int *progress);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_progress_set_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_achievement_progress_set_pre[hIndex].func;
+ preHookFunc(&sd, &ad, &obj_idx, &progress);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.achievement.progress_set(sd, ad, obj_idx, progress);
+ }
+ if (HPMHooks.count.HP_achievement_progress_set_post > 0) {
+ void (*postHookFunc) (struct map_session_data *sd, const struct achievement_data *ad, unsigned int obj_idx, int progress);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_progress_set_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_achievement_progress_set_post[hIndex].func;
+ postHookFunc(sd, ad, obj_idx, progress);
+ }
+ }
+ return;
+}
+bool HP_achievement_check_criteria(const struct achievement_objective *objective, const struct achievement_objective *criteria) {
+ int hIndex = 0;
+ bool retVal___ = false;
+ if (HPMHooks.count.HP_achievement_check_criteria_pre > 0) {
+ bool (*preHookFunc) (const struct achievement_objective **objective, const struct achievement_objective **criteria);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_check_criteria_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_achievement_check_criteria_pre[hIndex].func;
+ retVal___ = preHookFunc(&objective, &criteria);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return retVal___;
+ }
+ }
+ {
+ retVal___ = HPMHooks.source.achievement.check_criteria(objective, criteria);
+ }
+ if (HPMHooks.count.HP_achievement_check_criteria_post > 0) {
+ bool (*postHookFunc) (bool retVal___, const struct achievement_objective *objective, const struct achievement_objective *criteria);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_check_criteria_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_achievement_check_criteria_post[hIndex].func;
+ retVal___ = postHookFunc(retVal___, objective, criteria);
+ }
+ }
+ return retVal___;
+}
+bool HP_achievement_validate(struct map_session_data *sd, int aid, unsigned int obj_idx, int progress, bool additive) {
+ int hIndex = 0;
+ bool retVal___ = false;
+ if (HPMHooks.count.HP_achievement_validate_pre > 0) {
+ bool (*preHookFunc) (struct map_session_data **sd, int *aid, unsigned int *obj_idx, int *progress, bool *additive);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_validate_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_achievement_validate_pre[hIndex].func;
+ retVal___ = preHookFunc(&sd, &aid, &obj_idx, &progress, &additive);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return retVal___;
+ }
+ }
+ {
+ retVal___ = HPMHooks.source.achievement.validate(sd, aid, obj_idx, progress, additive);
+ }
+ if (HPMHooks.count.HP_achievement_validate_post > 0) {
+ bool (*postHookFunc) (bool retVal___, struct map_session_data *sd, int aid, unsigned int obj_idx, int progress, bool additive);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_validate_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_achievement_validate_post[hIndex].func;
+ retVal___ = postHookFunc(retVal___, sd, aid, obj_idx, progress, additive);
+ }
+ }
+ return retVal___;
+}
+int HP_achievement_validate_type(struct map_session_data *sd, enum achievement_types type, const struct achievement_objective *criteria, bool additive) {
+ int hIndex = 0;
+ int retVal___ = 0;
+ if (HPMHooks.count.HP_achievement_validate_type_pre > 0) {
+ int (*preHookFunc) (struct map_session_data **sd, enum achievement_types *type, const struct achievement_objective **criteria, bool *additive);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_validate_type_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_achievement_validate_type_pre[hIndex].func;
+ retVal___ = preHookFunc(&sd, &type, &criteria, &additive);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return retVal___;
+ }
+ }
+ {
+ retVal___ = HPMHooks.source.achievement.validate_type(sd, type, criteria, additive);
+ }
+ if (HPMHooks.count.HP_achievement_validate_type_post > 0) {
+ int (*postHookFunc) (int retVal___, struct map_session_data *sd, enum achievement_types type, const struct achievement_objective *criteria, bool additive);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_validate_type_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_achievement_validate_type_post[hIndex].func;
+ retVal___ = postHookFunc(retVal___, sd, type, criteria, additive);
+ }
+ }
+ return retVal___;
+}
+void HP_achievement_validate_mob_kill(struct map_session_data *sd, int mob_id) {
+ int hIndex = 0;
+ if (HPMHooks.count.HP_achievement_validate_mob_kill_pre > 0) {
+ void (*preHookFunc) (struct map_session_data **sd, int *mob_id);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_validate_mob_kill_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_achievement_validate_mob_kill_pre[hIndex].func;
+ preHookFunc(&sd, &mob_id);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.achievement.validate_mob_kill(sd, mob_id);
+ }
+ if (HPMHooks.count.HP_achievement_validate_mob_kill_post > 0) {
+ void (*postHookFunc) (struct map_session_data *sd, int mob_id);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_validate_mob_kill_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_achievement_validate_mob_kill_post[hIndex].func;
+ postHookFunc(sd, mob_id);
+ }
+ }
+ return;
+}
+void HP_achievement_validate_mob_damage(struct map_session_data *sd, unsigned int damage, bool received) {
+ int hIndex = 0;
+ if (HPMHooks.count.HP_achievement_validate_mob_damage_pre > 0) {
+ void (*preHookFunc) (struct map_session_data **sd, unsigned int *damage, bool *received);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_validate_mob_damage_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_achievement_validate_mob_damage_pre[hIndex].func;
+ preHookFunc(&sd, &damage, &received);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.achievement.validate_mob_damage(sd, damage, received);
+ }
+ if (HPMHooks.count.HP_achievement_validate_mob_damage_post > 0) {
+ void (*postHookFunc) (struct map_session_data *sd, unsigned int damage, bool received);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_validate_mob_damage_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_achievement_validate_mob_damage_post[hIndex].func;
+ postHookFunc(sd, damage, received);
+ }
+ }
+ return;
+}
+void HP_achievement_validate_pc_kill(struct map_session_data *sd, struct map_session_data *dstsd) {
+ int hIndex = 0;
+ if (HPMHooks.count.HP_achievement_validate_pc_kill_pre > 0) {
+ void (*preHookFunc) (struct map_session_data **sd, struct map_session_data **dstsd);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_validate_pc_kill_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_achievement_validate_pc_kill_pre[hIndex].func;
+ preHookFunc(&sd, &dstsd);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.achievement.validate_pc_kill(sd, dstsd);
+ }
+ if (HPMHooks.count.HP_achievement_validate_pc_kill_post > 0) {
+ void (*postHookFunc) (struct map_session_data *sd, struct map_session_data *dstsd);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_validate_pc_kill_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_achievement_validate_pc_kill_post[hIndex].func;
+ postHookFunc(sd, dstsd);
+ }
+ }
+ return;
+}
+void HP_achievement_validate_pc_damage(struct map_session_data *sd, struct map_session_data *dstsd, unsigned int damage) {
+ int hIndex = 0;
+ if (HPMHooks.count.HP_achievement_validate_pc_damage_pre > 0) {
+ void (*preHookFunc) (struct map_session_data **sd, struct map_session_data **dstsd, unsigned int *damage);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_validate_pc_damage_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_achievement_validate_pc_damage_pre[hIndex].func;
+ preHookFunc(&sd, &dstsd, &damage);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.achievement.validate_pc_damage(sd, dstsd, damage);
+ }
+ if (HPMHooks.count.HP_achievement_validate_pc_damage_post > 0) {
+ void (*postHookFunc) (struct map_session_data *sd, struct map_session_data *dstsd, unsigned int damage);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_validate_pc_damage_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_achievement_validate_pc_damage_post[hIndex].func;
+ postHookFunc(sd, dstsd, damage);
+ }
+ }
+ return;
+}
+void HP_achievement_validate_jobchange(struct map_session_data *sd) {
+ int hIndex = 0;
+ if (HPMHooks.count.HP_achievement_validate_jobchange_pre > 0) {
+ void (*preHookFunc) (struct map_session_data **sd);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_validate_jobchange_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_achievement_validate_jobchange_pre[hIndex].func;
+ preHookFunc(&sd);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.achievement.validate_jobchange(sd);
+ }
+ if (HPMHooks.count.HP_achievement_validate_jobchange_post > 0) {
+ void (*postHookFunc) (struct map_session_data *sd);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_validate_jobchange_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_achievement_validate_jobchange_post[hIndex].func;
+ postHookFunc(sd);
+ }
+ }
+ return;
+}
+void HP_achievement_validate_stats(struct map_session_data *sd, enum status_point_types stat_type, int progress) {
+ int hIndex = 0;
+ if (HPMHooks.count.HP_achievement_validate_stats_pre > 0) {
+ void (*preHookFunc) (struct map_session_data **sd, enum status_point_types *stat_type, int *progress);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_validate_stats_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_achievement_validate_stats_pre[hIndex].func;
+ preHookFunc(&sd, &stat_type, &progress);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.achievement.validate_stats(sd, stat_type, progress);
+ }
+ if (HPMHooks.count.HP_achievement_validate_stats_post > 0) {
+ void (*postHookFunc) (struct map_session_data *sd, enum status_point_types stat_type, int progress);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_validate_stats_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_achievement_validate_stats_post[hIndex].func;
+ postHookFunc(sd, stat_type, progress);
+ }
+ }
+ return;
+}
+void HP_achievement_validate_chatroom_create(struct map_session_data *sd) {
+ int hIndex = 0;
+ if (HPMHooks.count.HP_achievement_validate_chatroom_create_pre > 0) {
+ void (*preHookFunc) (struct map_session_data **sd);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_validate_chatroom_create_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_achievement_validate_chatroom_create_pre[hIndex].func;
+ preHookFunc(&sd);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.achievement.validate_chatroom_create(sd);
+ }
+ if (HPMHooks.count.HP_achievement_validate_chatroom_create_post > 0) {
+ void (*postHookFunc) (struct map_session_data *sd);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_validate_chatroom_create_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_achievement_validate_chatroom_create_post[hIndex].func;
+ postHookFunc(sd);
+ }
+ }
+ return;
+}
+void HP_achievement_validate_chatroom_members(struct map_session_data *sd, int progress) {
+ int hIndex = 0;
+ if (HPMHooks.count.HP_achievement_validate_chatroom_members_pre > 0) {
+ void (*preHookFunc) (struct map_session_data **sd, int *progress);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_validate_chatroom_members_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_achievement_validate_chatroom_members_pre[hIndex].func;
+ preHookFunc(&sd, &progress);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.achievement.validate_chatroom_members(sd, progress);
+ }
+ if (HPMHooks.count.HP_achievement_validate_chatroom_members_post > 0) {
+ void (*postHookFunc) (struct map_session_data *sd, int progress);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_validate_chatroom_members_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_achievement_validate_chatroom_members_post[hIndex].func;
+ postHookFunc(sd, progress);
+ }
+ }
+ return;
+}
+void HP_achievement_validate_friend_add(struct map_session_data *sd) {
+ int hIndex = 0;
+ if (HPMHooks.count.HP_achievement_validate_friend_add_pre > 0) {
+ void (*preHookFunc) (struct map_session_data **sd);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_validate_friend_add_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_achievement_validate_friend_add_pre[hIndex].func;
+ preHookFunc(&sd);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.achievement.validate_friend_add(sd);
+ }
+ if (HPMHooks.count.HP_achievement_validate_friend_add_post > 0) {
+ void (*postHookFunc) (struct map_session_data *sd);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_validate_friend_add_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_achievement_validate_friend_add_post[hIndex].func;
+ postHookFunc(sd);
+ }
+ }
+ return;
+}
+void HP_achievement_validate_party_create(struct map_session_data *sd) {
+ int hIndex = 0;
+ if (HPMHooks.count.HP_achievement_validate_party_create_pre > 0) {
+ void (*preHookFunc) (struct map_session_data **sd);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_validate_party_create_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_achievement_validate_party_create_pre[hIndex].func;
+ preHookFunc(&sd);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.achievement.validate_party_create(sd);
+ }
+ if (HPMHooks.count.HP_achievement_validate_party_create_post > 0) {
+ void (*postHookFunc) (struct map_session_data *sd);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_validate_party_create_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_achievement_validate_party_create_post[hIndex].func;
+ postHookFunc(sd);
+ }
+ }
+ return;
+}
+void HP_achievement_validate_marry(struct map_session_data *sd) {
+ int hIndex = 0;
+ if (HPMHooks.count.HP_achievement_validate_marry_pre > 0) {
+ void (*preHookFunc) (struct map_session_data **sd);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_validate_marry_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_achievement_validate_marry_pre[hIndex].func;
+ preHookFunc(&sd);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.achievement.validate_marry(sd);
+ }
+ if (HPMHooks.count.HP_achievement_validate_marry_post > 0) {
+ void (*postHookFunc) (struct map_session_data *sd);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_validate_marry_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_achievement_validate_marry_post[hIndex].func;
+ postHookFunc(sd);
+ }
+ }
+ return;
+}
+void HP_achievement_validate_adopt(struct map_session_data *sd, bool parent) {
+ int hIndex = 0;
+ if (HPMHooks.count.HP_achievement_validate_adopt_pre > 0) {
+ void (*preHookFunc) (struct map_session_data **sd, bool *parent);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_validate_adopt_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_achievement_validate_adopt_pre[hIndex].func;
+ preHookFunc(&sd, &parent);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.achievement.validate_adopt(sd, parent);
+ }
+ if (HPMHooks.count.HP_achievement_validate_adopt_post > 0) {
+ void (*postHookFunc) (struct map_session_data *sd, bool parent);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_validate_adopt_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_achievement_validate_adopt_post[hIndex].func;
+ postHookFunc(sd, parent);
+ }
+ }
+ return;
+}
+void HP_achievement_validate_zeny(struct map_session_data *sd, int amount) {
+ int hIndex = 0;
+ if (HPMHooks.count.HP_achievement_validate_zeny_pre > 0) {
+ void (*preHookFunc) (struct map_session_data **sd, int *amount);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_validate_zeny_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_achievement_validate_zeny_pre[hIndex].func;
+ preHookFunc(&sd, &amount);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.achievement.validate_zeny(sd, amount);
+ }
+ if (HPMHooks.count.HP_achievement_validate_zeny_post > 0) {
+ void (*postHookFunc) (struct map_session_data *sd, int amount);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_validate_zeny_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_achievement_validate_zeny_post[hIndex].func;
+ postHookFunc(sd, amount);
+ }
+ }
+ return;
+}
+void HP_achievement_validate_refine(struct map_session_data *sd, unsigned int idx, bool success) {
+ int hIndex = 0;
+ if (HPMHooks.count.HP_achievement_validate_refine_pre > 0) {
+ void (*preHookFunc) (struct map_session_data **sd, unsigned int *idx, bool *success);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_validate_refine_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_achievement_validate_refine_pre[hIndex].func;
+ preHookFunc(&sd, &idx, &success);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.achievement.validate_refine(sd, idx, success);
+ }
+ if (HPMHooks.count.HP_achievement_validate_refine_post > 0) {
+ void (*postHookFunc) (struct map_session_data *sd, unsigned int idx, bool success);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_validate_refine_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_achievement_validate_refine_post[hIndex].func;
+ postHookFunc(sd, idx, success);
+ }
+ }
+ return;
+}
+void HP_achievement_validate_item_get(struct map_session_data *sd, int nameid, int amount) {
+ int hIndex = 0;
+ if (HPMHooks.count.HP_achievement_validate_item_get_pre > 0) {
+ void (*preHookFunc) (struct map_session_data **sd, int *nameid, int *amount);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_validate_item_get_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_achievement_validate_item_get_pre[hIndex].func;
+ preHookFunc(&sd, &nameid, &amount);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.achievement.validate_item_get(sd, nameid, amount);
+ }
+ if (HPMHooks.count.HP_achievement_validate_item_get_post > 0) {
+ void (*postHookFunc) (struct map_session_data *sd, int nameid, int amount);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_validate_item_get_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_achievement_validate_item_get_post[hIndex].func;
+ postHookFunc(sd, nameid, amount);
+ }
+ }
+ return;
+}
+void HP_achievement_validate_item_sell(struct map_session_data *sd, int nameid, int amount) {
+ int hIndex = 0;
+ if (HPMHooks.count.HP_achievement_validate_item_sell_pre > 0) {
+ void (*preHookFunc) (struct map_session_data **sd, int *nameid, int *amount);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_validate_item_sell_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_achievement_validate_item_sell_pre[hIndex].func;
+ preHookFunc(&sd, &nameid, &amount);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.achievement.validate_item_sell(sd, nameid, amount);
+ }
+ if (HPMHooks.count.HP_achievement_validate_item_sell_post > 0) {
+ void (*postHookFunc) (struct map_session_data *sd, int nameid, int amount);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_validate_item_sell_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_achievement_validate_item_sell_post[hIndex].func;
+ postHookFunc(sd, nameid, amount);
+ }
+ }
+ return;
+}
+void HP_achievement_validate_achieve(struct map_session_data *sd, int achid) {
+ int hIndex = 0;
+ if (HPMHooks.count.HP_achievement_validate_achieve_pre > 0) {
+ void (*preHookFunc) (struct map_session_data **sd, int *achid);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_validate_achieve_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_achievement_validate_achieve_pre[hIndex].func;
+ preHookFunc(&sd, &achid);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.achievement.validate_achieve(sd, achid);
+ }
+ if (HPMHooks.count.HP_achievement_validate_achieve_post > 0) {
+ void (*postHookFunc) (struct map_session_data *sd, int achid);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_validate_achieve_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_achievement_validate_achieve_post[hIndex].func;
+ postHookFunc(sd, achid);
+ }
+ }
+ return;
+}
+void HP_achievement_validate_taming(struct map_session_data *sd, int class) {
+ int hIndex = 0;
+ if (HPMHooks.count.HP_achievement_validate_taming_pre > 0) {
+ void (*preHookFunc) (struct map_session_data **sd, int *class);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_validate_taming_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_achievement_validate_taming_pre[hIndex].func;
+ preHookFunc(&sd, &class);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.achievement.validate_taming(sd, class);
+ }
+ if (HPMHooks.count.HP_achievement_validate_taming_post > 0) {
+ void (*postHookFunc) (struct map_session_data *sd, int class);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_validate_taming_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_achievement_validate_taming_post[hIndex].func;
+ postHookFunc(sd, class);
+ }
+ }
+ return;
+}
+void HP_achievement_validate_achievement_rank(struct map_session_data *sd, int rank) {
+ int hIndex = 0;
+ if (HPMHooks.count.HP_achievement_validate_achievement_rank_pre > 0) {
+ void (*preHookFunc) (struct map_session_data **sd, int *rank);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_validate_achievement_rank_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_achievement_validate_achievement_rank_pre[hIndex].func;
+ preHookFunc(&sd, &rank);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.achievement.validate_achievement_rank(sd, rank);
+ }
+ if (HPMHooks.count.HP_achievement_validate_achievement_rank_post > 0) {
+ void (*postHookFunc) (struct map_session_data *sd, int rank);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_validate_achievement_rank_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_achievement_validate_achievement_rank_post[hIndex].func;
+ postHookFunc(sd, rank);
+ }
+ }
+ return;
+}
+bool HP_achievement_type_requires_criteria(enum achievement_types type) {
+ int hIndex = 0;
+ bool retVal___ = false;
+ if (HPMHooks.count.HP_achievement_type_requires_criteria_pre > 0) {
+ bool (*preHookFunc) (enum achievement_types *type);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_type_requires_criteria_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_achievement_type_requires_criteria_pre[hIndex].func;
+ retVal___ = preHookFunc(&type);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return retVal___;
+ }
+ }
+ {
+ retVal___ = HPMHooks.source.achievement.type_requires_criteria(type);
+ }
+ if (HPMHooks.count.HP_achievement_type_requires_criteria_post > 0) {
+ bool (*postHookFunc) (bool retVal___, enum achievement_types type);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_type_requires_criteria_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_achievement_type_requires_criteria_post[hIndex].func;
+ retVal___ = postHookFunc(retVal___, type);
+ }
+ }
+ return retVal___;
+}
+void HP_achievement_init_titles(struct map_session_data *sd) {
+ int hIndex = 0;
+ if (HPMHooks.count.HP_achievement_init_titles_pre > 0) {
+ void (*preHookFunc) (struct map_session_data **sd);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_init_titles_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_achievement_init_titles_pre[hIndex].func;
+ preHookFunc(&sd);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.achievement.init_titles(sd);
+ }
+ if (HPMHooks.count.HP_achievement_init_titles_post > 0) {
+ void (*postHookFunc) (struct map_session_data *sd);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_init_titles_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_achievement_init_titles_post[hIndex].func;
+ postHookFunc(sd);
+ }
+ }
+ return;
+}
+bool HP_achievement_check_title(struct map_session_data *sd, int title_id) {
+ int hIndex = 0;
+ bool retVal___ = false;
+ if (HPMHooks.count.HP_achievement_check_title_pre > 0) {
+ bool (*preHookFunc) (struct map_session_data **sd, int *title_id);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_check_title_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_achievement_check_title_pre[hIndex].func;
+ retVal___ = preHookFunc(&sd, &title_id);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return retVal___;
+ }
+ }
+ {
+ retVal___ = HPMHooks.source.achievement.check_title(sd, title_id);
+ }
+ if (HPMHooks.count.HP_achievement_check_title_post > 0) {
+ bool (*postHookFunc) (bool retVal___, struct map_session_data *sd, int title_id);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_check_title_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_achievement_check_title_post[hIndex].func;
+ retVal___ = postHookFunc(retVal___, sd, title_id);
+ }
+ }
+ return retVal___;
+}
+void HP_achievement_get_rewards(struct map_session_data *sd, const struct achievement_data *ad) {
+ int hIndex = 0;
+ if (HPMHooks.count.HP_achievement_get_rewards_pre > 0) {
+ void (*preHookFunc) (struct map_session_data **sd, const struct achievement_data **ad);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_get_rewards_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_achievement_get_rewards_pre[hIndex].func;
+ preHookFunc(&sd, &ad);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.achievement.get_rewards(sd, ad);
+ }
+ if (HPMHooks.count.HP_achievement_get_rewards_post > 0) {
+ void (*postHookFunc) (struct map_session_data *sd, const struct achievement_data *ad);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_achievement_get_rewards_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_achievement_get_rewards_post[hIndex].func;
+ postHookFunc(sd, ad);
+ }
+ }
+ return;
+}
/* atcommand_interface */
void HP_atcommand_init(bool minimal) {
int hIndex = 0;
@@ -19256,6 +20635,162 @@ unsigned char HP_clif_bl_type(struct block_list *bl) {
}
return retVal___;
}
+void HP_clif_achievement_send_list(int fd, struct map_session_data *sd) {
+ int hIndex = 0;
+ if (HPMHooks.count.HP_clif_achievement_send_list_pre > 0) {
+ void (*preHookFunc) (int *fd, struct map_session_data **sd);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_clif_achievement_send_list_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_clif_achievement_send_list_pre[hIndex].func;
+ preHookFunc(&fd, &sd);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.clif.achievement_send_list(fd, sd);
+ }
+ if (HPMHooks.count.HP_clif_achievement_send_list_post > 0) {
+ void (*postHookFunc) (int fd, struct map_session_data *sd);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_clif_achievement_send_list_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_clif_achievement_send_list_post[hIndex].func;
+ postHookFunc(fd, sd);
+ }
+ }
+ return;
+}
+void HP_clif_achievement_send_update(int fd, struct map_session_data *sd, const struct achievement_data *ad) {
+ int hIndex = 0;
+ if (HPMHooks.count.HP_clif_achievement_send_update_pre > 0) {
+ void (*preHookFunc) (int *fd, struct map_session_data **sd, const struct achievement_data **ad);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_clif_achievement_send_update_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_clif_achievement_send_update_pre[hIndex].func;
+ preHookFunc(&fd, &sd, &ad);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.clif.achievement_send_update(fd, sd, ad);
+ }
+ if (HPMHooks.count.HP_clif_achievement_send_update_post > 0) {
+ void (*postHookFunc) (int fd, struct map_session_data *sd, const struct achievement_data *ad);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_clif_achievement_send_update_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_clif_achievement_send_update_post[hIndex].func;
+ postHookFunc(fd, sd, ad);
+ }
+ }
+ return;
+}
+void HP_clif_pAchievementGetReward(int fd, struct map_session_data *sd) {
+ int hIndex = 0;
+ if (HPMHooks.count.HP_clif_pAchievementGetReward_pre > 0) {
+ void (*preHookFunc) (int *fd, struct map_session_data **sd);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_clif_pAchievementGetReward_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_clif_pAchievementGetReward_pre[hIndex].func;
+ preHookFunc(&fd, &sd);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.clif.pAchievementGetReward(fd, sd);
+ }
+ if (HPMHooks.count.HP_clif_pAchievementGetReward_post > 0) {
+ void (*postHookFunc) (int fd, struct map_session_data *sd);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_clif_pAchievementGetReward_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_clif_pAchievementGetReward_post[hIndex].func;
+ postHookFunc(fd, sd);
+ }
+ }
+ return;
+}
+void HP_clif_achievement_reward_ack(int fd, struct map_session_data *sd, const struct achievement_data *ad) {
+ int hIndex = 0;
+ if (HPMHooks.count.HP_clif_achievement_reward_ack_pre > 0) {
+ void (*preHookFunc) (int *fd, struct map_session_data **sd, const struct achievement_data **ad);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_clif_achievement_reward_ack_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_clif_achievement_reward_ack_pre[hIndex].func;
+ preHookFunc(&fd, &sd, &ad);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.clif.achievement_reward_ack(fd, sd, ad);
+ }
+ if (HPMHooks.count.HP_clif_achievement_reward_ack_post > 0) {
+ void (*postHookFunc) (int fd, struct map_session_data *sd, const struct achievement_data *ad);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_clif_achievement_reward_ack_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_clif_achievement_reward_ack_post[hIndex].func;
+ postHookFunc(fd, sd, ad);
+ }
+ }
+ return;
+}
+void HP_clif_change_title_ack(int fd, struct map_session_data *sd, int title_id) {
+ int hIndex = 0;
+ if (HPMHooks.count.HP_clif_change_title_ack_pre > 0) {
+ void (*preHookFunc) (int *fd, struct map_session_data **sd, int *title_id);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_clif_change_title_ack_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_clif_change_title_ack_pre[hIndex].func;
+ preHookFunc(&fd, &sd, &title_id);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.clif.change_title_ack(fd, sd, title_id);
+ }
+ if (HPMHooks.count.HP_clif_change_title_ack_post > 0) {
+ void (*postHookFunc) (int fd, struct map_session_data *sd, int title_id);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_clif_change_title_ack_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_clif_change_title_ack_post[hIndex].func;
+ postHookFunc(fd, sd, title_id);
+ }
+ }
+ return;
+}
+void HP_clif_pChangeTitle(int fd, struct map_session_data *sd) {
+ int hIndex = 0;
+ if (HPMHooks.count.HP_clif_pChangeTitle_pre > 0) {
+ void (*preHookFunc) (int *fd, struct map_session_data **sd);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_clif_pChangeTitle_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_clif_pChangeTitle_pre[hIndex].func;
+ preHookFunc(&fd, &sd);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.clif.pChangeTitle(fd, sd);
+ }
+ if (HPMHooks.count.HP_clif_pChangeTitle_post > 0) {
+ void (*postHookFunc) (int fd, struct map_session_data *sd);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_clif_pChangeTitle_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_clif_pChangeTitle_post[hIndex].func;
+ postHookFunc(fd, sd);
+ }
+ }
+ return;
+}
void HP_clif_pWantToConnection(int fd, struct map_session_data *sd) {
int hIndex = 0;
if (HPMHooks.count.HP_clif_pWantToConnection_pre > 0) {
@@ -35627,6 +37162,58 @@ int HP_intif_CheckForCharServer(void) {
}
return retVal___;
}
+void HP_intif_achievements_request(struct map_session_data *sd) {
+ int hIndex = 0;
+ if (HPMHooks.count.HP_intif_achievements_request_pre > 0) {
+ void (*preHookFunc) (struct map_session_data **sd);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_intif_achievements_request_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_intif_achievements_request_pre[hIndex].func;
+ preHookFunc(&sd);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.intif.achievements_request(sd);
+ }
+ if (HPMHooks.count.HP_intif_achievements_request_post > 0) {
+ void (*postHookFunc) (struct map_session_data *sd);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_intif_achievements_request_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_intif_achievements_request_post[hIndex].func;
+ postHookFunc(sd);
+ }
+ }
+ return;
+}
+void HP_intif_achievements_save(struct map_session_data *sd) {
+ int hIndex = 0;
+ if (HPMHooks.count.HP_intif_achievements_save_pre > 0) {
+ void (*preHookFunc) (struct map_session_data **sd);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_intif_achievements_save_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_intif_achievements_save_pre[hIndex].func;
+ preHookFunc(&sd);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.intif.achievements_save(sd);
+ }
+ if (HPMHooks.count.HP_intif_achievements_save_post > 0) {
+ void (*postHookFunc) (struct map_session_data *sd);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_intif_achievements_save_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_intif_achievements_save_post[hIndex].func;
+ postHookFunc(sd);
+ }
+ }
+ return;
+}
void HP_intif_pWisMessage(int fd) {
int hIndex = 0;
if (HPMHooks.count.HP_intif_pWisMessage_pre > 0) {
@@ -37428,6 +39015,32 @@ void HP_intif_pRecvClanMemberAction(int fd) {
}
return;
}
+void HP_intif_pAchievementsLoad(int fd) {
+ int hIndex = 0;
+ if (HPMHooks.count.HP_intif_pAchievementsLoad_pre > 0) {
+ void (*preHookFunc) (int *fd);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_intif_pAchievementsLoad_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_intif_pAchievementsLoad_pre[hIndex].func;
+ preHookFunc(&fd);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.intif.pAchievementsLoad(fd);
+ }
+ if (HPMHooks.count.HP_intif_pAchievementsLoad_post > 0) {
+ void (*postHookFunc) (int fd);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_intif_pAchievementsLoad_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_intif_pAchievementsLoad_post[hIndex].func;
+ postHookFunc(fd);
+ }
+ }
+ return;
+}
/* irc_bot_interface */
void HP_ircbot_init(bool minimal) {
int hIndex = 0;
diff --git a/src/plugins/HPMHooking/HPMHooking_map.sources.inc b/src/plugins/HPMHooking/HPMHooking_map.sources.inc
index e6f305726..151a5d8a1 100644
--- a/src/plugins/HPMHooking/HPMHooking_map.sources.inc
+++ b/src/plugins/HPMHooking/HPMHooking_map.sources.inc
@@ -26,6 +26,7 @@
/* GENERATED FILE DO NOT EDIT */
HPMHooks.source.HCache = *HCache;
+HPMHooks.source.achievement = *achievement;
HPMHooks.source.atcommand = *atcommand;
HPMHooks.source.battle = *battle;
HPMHooks.source.bg = *bg;
diff --git a/vcproj-12/char-server.vcxproj b/vcproj-12/char-server.vcxproj
index 3baf26e37..411191400 100644
--- a/vcproj-12/char-server.vcxproj
+++ b/vcproj-12/char-server.vcxproj
@@ -174,6 +174,7 @@
<ClInclude Include="..\src\char\HPMchar.h" />
<ClInclude Include="..\src\char\char.h" />
<ClInclude Include="..\src\char\geoip.h" />
+ <ClInclude Include="..\src\char\int_achievement.h" />
<ClInclude Include="..\src\char\int_auction.h" />
<ClInclude Include="..\src\char\int_clan.h" />
<ClInclude Include="..\src\char\int_elemental.h" />
@@ -228,6 +229,7 @@
<ClCompile Include="..\src\char\HPMchar.c" />
<ClCompile Include="..\src\char\char.c" />
<ClCompile Include="..\src\char\geoip.c" />
+ <ClCompile Include="..\src\char\int_achievement.c" />
<ClCompile Include="..\src\char\int_auction.c" />
<ClCompile Include="..\src\char\int_clan.c" />
<ClCompile Include="..\src\char\int_elemental.c" />
diff --git a/vcproj-12/char-server.vcxproj.filters b/vcproj-12/char-server.vcxproj.filters
index af34d2efd..52d3bde16 100644
--- a/vcproj-12/char-server.vcxproj.filters
+++ b/vcproj-12/char-server.vcxproj.filters
@@ -67,6 +67,9 @@
<ClCompile Include="..\src\char\geoip.c">
<Filter>char</Filter>
</ClCompile>
+ <ClCompile Include="..\src\char\int_achievement.c">
+ <Filter>char</Filter>
+ </ClCompile>
<ClCompile Include="..\src\char\int_auction.c">
<Filter>char</Filter>
</ClCompile>
@@ -219,6 +222,9 @@
<ClInclude Include="..\src\char\geoip.h">
<Filter>char</Filter>
</ClInclude>
+ <ClInclude Include="..\src\char\int_achievement.h">
+ <Filter>char</Filter>
+ </ClInclude>
<ClInclude Include="..\src\char\int_auction.h">
<Filter>char</Filter>
</ClInclude>
diff --git a/vcproj-12/map-server.vcxproj b/vcproj-12/map-server.vcxproj
index e9196c5df..4756cca2a 100644
--- a/vcproj-12/map-server.vcxproj
+++ b/vcproj-12/map-server.vcxproj
@@ -169,6 +169,7 @@
<ClInclude Include="..\src\common\timer.h" />
<ClInclude Include="..\src\common\utils.h" />
<ClInclude Include="..\src\common\winapi.h" />
+ <ClInclude Include="..\src\map\achievement.h" />
<ClInclude Include="..\src\map\atcommand.h" />
<ClInclude Include="..\src\map\battle.h" />
<ClInclude Include="..\src\map\battleground.h" />
@@ -251,6 +252,7 @@
<ClCompile Include="..\src\common\thread.c" />
<ClCompile Include="..\src\common\timer.c" />
<ClCompile Include="..\src\common\utils.c" />
+ <ClCompile Include="..\src\map\achievement.c" />
<ClCompile Include="..\src\map\atcommand.c" />
<ClCompile Include="..\src\map\battle.c" />
<ClCompile Include="..\src\map\battleground.c" />
diff --git a/vcproj-12/map-server.vcxproj.filters b/vcproj-12/map-server.vcxproj.filters
index c8aaffc5d..e3bf78fb9 100644
--- a/vcproj-12/map-server.vcxproj.filters
+++ b/vcproj-12/map-server.vcxproj.filters
@@ -1,6 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
+ <ClCompile Include="..\src\map\achievement.c">
+ <Filter>map</Filter>
+ </ClCompile>
<ClCompile Include="..\src\map\atcommand.c">
<Filter>map</Filter>
</ClCompile>
@@ -213,6 +216,9 @@
</ClCompile>
</ItemGroup>
<ItemGroup>
+ <ClInclude Include="..\src\map\achievement.h">
+ <Filter>map</Filter>
+ </ClInclude>
<ClInclude Include="..\src\map\atcommand.h">
<Filter>map</Filter>
</ClInclude>
diff --git a/vcproj-14/char-server.vcxproj b/vcproj-14/char-server.vcxproj
index a766d504d..692210a15 100644
--- a/vcproj-14/char-server.vcxproj
+++ b/vcproj-14/char-server.vcxproj
@@ -173,6 +173,7 @@
<ClInclude Include="..\src\char\HPMchar.h" />
<ClInclude Include="..\src\char\char.h" />
<ClInclude Include="..\src\char\geoip.h" />
+ <ClInclude Include="..\src\char\int_achievement.h" />
<ClInclude Include="..\src\char\int_auction.h" />
<ClInclude Include="..\src\char\int_clan.h" />
<ClInclude Include="..\src\char\int_elemental.h" />
@@ -227,6 +228,7 @@
<ClCompile Include="..\src\char\HPMchar.c" />
<ClCompile Include="..\src\char\char.c" />
<ClCompile Include="..\src\char\geoip.c" />
+ <ClCompile Include="..\src\char\int_achievement.c" />
<ClCompile Include="..\src\char\int_auction.c" />
<ClCompile Include="..\src\char\int_clan.c" />
<ClCompile Include="..\src\char\int_elemental.c" />
diff --git a/vcproj-14/char-server.vcxproj.filters b/vcproj-14/char-server.vcxproj.filters
index af34d2efd..52d3bde16 100644
--- a/vcproj-14/char-server.vcxproj.filters
+++ b/vcproj-14/char-server.vcxproj.filters
@@ -67,6 +67,9 @@
<ClCompile Include="..\src\char\geoip.c">
<Filter>char</Filter>
</ClCompile>
+ <ClCompile Include="..\src\char\int_achievement.c">
+ <Filter>char</Filter>
+ </ClCompile>
<ClCompile Include="..\src\char\int_auction.c">
<Filter>char</Filter>
</ClCompile>
@@ -219,6 +222,9 @@
<ClInclude Include="..\src\char\geoip.h">
<Filter>char</Filter>
</ClInclude>
+ <ClInclude Include="..\src\char\int_achievement.h">
+ <Filter>char</Filter>
+ </ClInclude>
<ClInclude Include="..\src\char\int_auction.h">
<Filter>char</Filter>
</ClInclude>
diff --git a/vcproj-14/map-server.vcxproj b/vcproj-14/map-server.vcxproj
index ccc80d15d..ae834de75 100644
--- a/vcproj-14/map-server.vcxproj
+++ b/vcproj-14/map-server.vcxproj
@@ -167,6 +167,7 @@
<ClInclude Include="..\src\common\timer.h" />
<ClInclude Include="..\src\common\utils.h" />
<ClInclude Include="..\src\common\winapi.h" />
+ <ClInclude Include="..\src\map\achievement.h" />
<ClInclude Include="..\src\map\atcommand.h" />
<ClInclude Include="..\src\map\battle.h" />
<ClInclude Include="..\src\map\battleground.h" />
@@ -249,6 +250,7 @@
<ClCompile Include="..\src\common\thread.c" />
<ClCompile Include="..\src\common\timer.c" />
<ClCompile Include="..\src\common\utils.c" />
+ <ClCompile Include="..\src\map\achievement.c" />
<ClCompile Include="..\src\map\atcommand.c" />
<ClCompile Include="..\src\map\battle.c" />
<ClCompile Include="..\src\map\battleground.c" />
diff --git a/vcproj-14/map-server.vcxproj.filters b/vcproj-14/map-server.vcxproj.filters
index bf3004a77..9bf13d9f7 100644
--- a/vcproj-14/map-server.vcxproj.filters
+++ b/vcproj-14/map-server.vcxproj.filters
@@ -1,6 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
+ <ClCompile Include="..\src\map\achievement.c">
+ <Filter>map</Filter>
+ </ClCompile>
<ClCompile Include="..\src\map\atcommand.c">
<Filter>map</Filter>
</ClCompile>
@@ -213,6 +216,9 @@
</ClCompile>
</ItemGroup>
<ItemGroup>
+ <ClInclude Include="..\src\map\achievement.h">
+ <Filter>map</Filter>
+ </ClInclude>
<ClInclude Include="..\src\map\atcommand.h">
<Filter>map</Filter>
</ClInclude>
diff --git a/vcproj-15/char-server.vcxproj b/vcproj-15/char-server.vcxproj
index ed5898a89..ad4de5be4 100644
--- a/vcproj-15/char-server.vcxproj
+++ b/vcproj-15/char-server.vcxproj
@@ -173,6 +173,7 @@
<ClInclude Include="..\src\char\HPMchar.h" />
<ClInclude Include="..\src\char\char.h" />
<ClInclude Include="..\src\char\geoip.h" />
+ <ClInclude Include="..\src\char\int_achievement.h" />
<ClInclude Include="..\src\char\int_auction.h" />
<ClInclude Include="..\src\char\int_clan.h" />
<ClInclude Include="..\src\char\int_elemental.h" />
@@ -227,6 +228,7 @@
<ClCompile Include="..\src\char\HPMchar.c" />
<ClCompile Include="..\src\char\char.c" />
<ClCompile Include="..\src\char\geoip.c" />
+ <ClCompile Include="..\src\char\int_achievement.c" />
<ClCompile Include="..\src\char\int_auction.c" />
<ClCompile Include="..\src\char\int_clan.c" />
<ClCompile Include="..\src\char\int_elemental.c" />
diff --git a/vcproj-15/char-server.vcxproj.filters b/vcproj-15/char-server.vcxproj.filters
index af34d2efd..52d3bde16 100644
--- a/vcproj-15/char-server.vcxproj.filters
+++ b/vcproj-15/char-server.vcxproj.filters
@@ -67,6 +67,9 @@
<ClCompile Include="..\src\char\geoip.c">
<Filter>char</Filter>
</ClCompile>
+ <ClCompile Include="..\src\char\int_achievement.c">
+ <Filter>char</Filter>
+ </ClCompile>
<ClCompile Include="..\src\char\int_auction.c">
<Filter>char</Filter>
</ClCompile>
@@ -219,6 +222,9 @@
<ClInclude Include="..\src\char\geoip.h">
<Filter>char</Filter>
</ClInclude>
+ <ClInclude Include="..\src\char\int_achievement.h">
+ <Filter>char</Filter>
+ </ClInclude>
<ClInclude Include="..\src\char\int_auction.h">
<Filter>char</Filter>
</ClInclude>
diff --git a/vcproj-15/map-server.vcxproj b/vcproj-15/map-server.vcxproj
index f3f170daa..fb9d57e9c 100644
--- a/vcproj-15/map-server.vcxproj
+++ b/vcproj-15/map-server.vcxproj
@@ -168,6 +168,7 @@
<ClInclude Include="..\src\common\timer.h" />
<ClInclude Include="..\src\common\utils.h" />
<ClInclude Include="..\src\common\winapi.h" />
+ <ClInclude Include="..\src\map\achievement.h" />
<ClInclude Include="..\src\map\atcommand.h" />
<ClInclude Include="..\src\map\battle.h" />
<ClInclude Include="..\src\map\battleground.h" />
@@ -250,6 +251,7 @@
<ClCompile Include="..\src\common\thread.c" />
<ClCompile Include="..\src\common\timer.c" />
<ClCompile Include="..\src\common\utils.c" />
+ <ClCompile Include="..\src\map\achievement.c" />
<ClCompile Include="..\src\map\atcommand.c" />
<ClCompile Include="..\src\map\battle.c" />
<ClCompile Include="..\src\map\battleground.c" />
diff --git a/vcproj-15/map-server.vcxproj.filters b/vcproj-15/map-server.vcxproj.filters
index c8aaffc5d..8c91df7c7 100644
--- a/vcproj-15/map-server.vcxproj.filters
+++ b/vcproj-15/map-server.vcxproj.filters
@@ -1,6 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
+ <ClCompile Include="..\src\map\achievement.c">
+ <Filter>map</Filter>
+ </ClCompile>
<ClCompile Include="..\src\map\atcommand.c">
<Filter>map</Filter>
</ClCompile>
@@ -213,6 +216,9 @@
</ClCompile>
</ItemGroup>
<ItemGroup>
+ <ClInclude Include="..\src\map\achievement.h">
+ <Filter>map</Filter>
+ </ClInclude>
<ClInclude Include="..\src\map\atcommand.h">
<Filter>map</Filter>
</ClInclude>