Bladeren bron

Merge branch 'master' into feature/blocking_play

aleos 4 jaren geleden
bovenliggende
commit
428e0c3744
100 gewijzigde bestanden met toevoegingen van 5538 en 1646 verwijderingen
  1. 3 5
      appveyor.yml
  2. 4 0
      conf/battle/battleground.conf
  3. 12 1
      conf/battle/client.conf
  4. 3 0
      conf/battle/items.conf
  5. 8 0
      conf/battle/monster.conf
  6. 4 4
      conf/battle/skill.conf
  7. 2 1
      conf/msg_conf/map_msg.conf
  8. 91 54
      db/battleground_db.yml
  9. 8 1
      db/import-tmpl/battleground_db.yml
  10. 0 31
      db/import-tmpl/improvise_db.yml
  11. 2 0
      db/import-tmpl/instance_db.yml
  12. 0 37
      db/improvise_db.yml
  13. 2 0
      db/instance_db.yml
  14. 1 1
      db/item_avail.txt
  15. 2 2
      db/job_db2.txt
  16. 2 0
      db/pre-re/instance_db.yml
  17. 2 2
      db/pre-re/mob_race2_db.txt
  18. 5 5
      db/pre-re/produce_db.txt
  19. 95 37
      db/pre-re/skill_db.yml
  20. 1 0
      db/pre-re/skill_nocast_db.txt
  21. 21 12
      db/pre-re/skill_tree.txt
  22. 0 65
      db/re/improvise_db.yml
  23. 2 0
      db/re/instance_db.yml
  24. 8 2
      db/re/item_combo_db.txt
  25. 319 137
      db/re/item_db.txt
  26. 2 0
      db/re/item_delay.txt
  27. 429 0
      db/re/item_misc.txt
  28. 0 9
      db/re/item_stack.txt
  29. 1 1
      db/re/job_db1.txt
  30. 192 8
      db/re/mob_db.txt
  31. 2 2
      db/re/mob_race2_db.txt
  32. 42 32
      db/re/produce_db.txt
  33. 193 191
      db/re/skill_db.yml
  34. 9 0
      db/re/skill_nocast_db.txt
  35. 77 26
      db/re/skill_tree.txt
  36. 1 1
      doc/atcommands.txt
  37. 3 2
      doc/item_bonus.txt
  38. 1 1
      doc/mapflags.txt
  39. 44 15
      doc/script_commands.txt
  40. 2 2
      doc/skill_db.txt
  41. 0 10
      doc/yaml/db/improvise_db.yml
  42. 2 0
      doc/yaml/db/instance_db.yml
  43. 52 40
      npc/battleground/flavius/flavius01.txt
  44. 56 44
      npc/battleground/flavius/flavius02.txt
  45. 11 1
      npc/battleground/kvm/kvm01.txt
  46. 11 1
      npc/battleground/kvm/kvm02.txt
  47. 11 1
      npc/battleground/kvm/kvm03.txt
  48. 57 32
      npc/battleground/tierra/tierra01.txt
  49. 58 32
      npc/battleground/tierra/tierra02.txt
  50. 31 10
      npc/custom/woe_controller.txt
  51. 10 0
      npc/pre-re/quests/quests_niflheim.txt
  52. 1 0
      npc/pre-re/scripts_athena.conf
  53. 58 17
      npc/quests/quests_lighthalzen.txt
  54. 10 14
      npc/quests/quests_morocc.txt
  55. 1 1
      npc/quests/quests_niflheim.txt
  56. 1 1
      npc/re/instances/MalangdoCulvert.txt
  57. 1 0
      npc/re/instances/NightmarishJitterbug.txt
  58. 2 2
      npc/re/instances/OctopusCave.txt
  59. 257 0
      npc/re/merchants/OldGlastHeim_merchants.txt
  60. 2 2
      npc/re/merchants/bio4_reward.txt
  61. 1431 0
      npc/re/merchants/malangdo_costume.txt
  62. 169 0
      npc/re/merchants/pet_trader.txt
  63. 2 2
      npc/re/merchants/te_merchant.txt
  64. 10 0
      npc/re/quests/quests_niflheim.txt
  65. 1 0
      npc/re/quests/quests_rockridge.txt
  66. 1 1
      npc/re/quests/woe_te/te_goditem_alde1.txt
  67. 3 0
      npc/re/scripts_athena.conf
  68. 319 137
      sql-files/item_db_re.sql
  69. 2 1
      sql-files/main.sql
  70. 192 8
      sql-files/mob_db_re.sql
  71. 11 0
      sql-files/upgrades/upgrade_20200506.sql
  72. 3 0
      sql-files/upgrades/upgrade_20200518.sql
  73. 1 0
      sql-files/upgrades/upgrade_20200603.sql
  74. 13 0
      sql-files/upgrades/upgrade_20200604.sql
  75. 67 86
      src/char/char.cpp
  76. 1 7
      src/char/char.hpp
  77. 74 9
      src/char/char_clif.cpp
  78. 26 30
      src/char/char_logif.cpp
  79. 9 9
      src/char/char_logif.hpp
  80. 0 4
      src/char/char_mapif.cpp
  81. 12 0
      src/common/core.cpp
  82. 11 5
      src/common/mmo.hpp
  83. 4 0
      src/common/socket.cpp
  84. 1 0
      src/common/socket.hpp
  85. 7 0
      src/config/core.hpp
  86. 18 1
      src/config/packets.hpp
  87. 1 1
      src/login/account.cpp
  88. 18 0
      src/login/loginclif.cpp
  89. 28 0
      src/map/achievement.cpp
  90. 1 0
      src/map/achievement.hpp
  91. 20 8
      src/map/atcommand.cpp
  92. 243 188
      src/map/battle.cpp
  93. 7 0
      src/map/battle.hpp
  94. 463 126
      src/map/battleground.cpp
  95. 26 7
      src/map/battleground.hpp
  96. 97 107
      src/map/buyingstore.cpp
  97. 2 2
      src/map/buyingstore.hpp
  98. 12 11
      src/map/cashshop.cpp
  99. 1 1
      src/map/cashshop.hpp
  100. 4 0
      src/map/clan.cpp

+ 3 - 5
appveyor.yml

@@ -1,4 +1,4 @@
-image: Visual Studio 2013
+image: Visual Studio 2015
 # This is the default location, but we put it here for safety reasons, since we use it in our test script
 clone_folder: c:\projects\rathena
 # We do not need the git history for our integration tests
@@ -8,10 +8,8 @@ pull_requests:
   do_not_increment_build_number: true
 environment:
   matrix:
-  - VisualStudioVersion: 14.0
-    Defines: "\"BUILDBOT\""
-  - VisualStudioVersion: 14.0
-    Defines: "\"BUILDBOT;PRERE\""
+  - Defines: "\"BUILDBOT\""
+  - Defines: "\"BUILDBOT;PRERE\""
 platform:
   - Win32
   - x64

+ 4 - 0
conf/battle/battleground.conf

@@ -30,3 +30,7 @@ bg_flee_penalty: 20
 
 // Interval before updating the bg-member map mini-dots (milliseconds)
 bg_update_interval: 1000
+
+// Before a player is warped into a Battleground from the Battleground Queue,
+// check to see if the player's current map has MF_NOWARP.
+bgqueue_nowarp_mapflag: no

+ 12 - 1
conf/battle/client.conf

@@ -38,7 +38,7 @@ hide_woe_damage: no
 pet_hair_style: 100
 
 // Visible area size (how many squares away from a player they can see)
-area_size: 15
+area_size: 14
 
 // Maximum walk path (how many cells a player can walk going to cursor)
 max_walk_path: 17
@@ -138,3 +138,14 @@ spawn_direction: no
 // kRO removed the packet and this re-enables the message.
 // Official: Disabled.
 mvp_exp_reward_message: no
+
+// Send ping timer
+// Interval in seconds for each timer invoke.
+ping_timer_inverval: 30
+
+// Send packets timeout in seconds before ping packet can be sent.
+ping_time: 20
+
+// Show skill scale for clients 2015-12-23 and newer? (Note 1)
+// Official: yes
+show_skill_scale: yes

+ 3 - 0
conf/battle/items.conf

@@ -134,6 +134,9 @@ broadcast_hide_name: 2
 // Enable to sell rental item to NPC shop? (Note 1)
 rental_transaction: yes
 
+// Sell rental item for 0 to NPC shop regardless of the item value in item_db? (Note 1)
+rental_item_novalue: no
+
 // Minimum purchase price of items at a normal Shop
 // Officially items cannot be purchased for less than 1 Zeny
 min_shop_buy: 1

+ 8 - 0
conf/battle/monster.conf

@@ -276,3 +276,11 @@ boss_nopc_idleskill_rate: 100
 // To switch it off, set it to 0.
 mob_nopc_move_rate: 100
 boss_nopc_move_rate: 100
+
+// When killing a monster, do AG_BATTLE type achievements trigger for everyone in the same party within the area?
+// Area is limited to area_size battle config.
+achievement_mob_share: no
+
+// Should slaves teleport back to their master if they get too far during chase? (Note 1)
+// Default (Official): no
+slave_stick_with_master: no

+ 4 - 4
conf/battle/skill.conf

@@ -85,7 +85,7 @@ clear_skills_on_warp: 15
 
 //Setting this to YES will override the target mode of ground-based skills with the flag 0x01 to "No Enemies"
 //The two skills affected by default are Pneuma and Safety Wall (if set to yes, those two skills will not protect everyone, but only allies)
-//See db/skill_unit_db.txt for more info.
+//See db/(pre-)re/skill_db.yml for more info.
 defunit_not_enemy: no
 
 // Should skills always do at least 'hits' damage when they don't miss/are blocked?
@@ -107,11 +107,11 @@ auto_counter_type: 15
 
 // Can ground skills be placed on top of each other? (Note 3)
 // By default, skills with UF_NOREITERATION set cannot be stacked on top of 
-// other skills, this setting will override that. (skill_unit_db)
+// other skills, this setting will override that.
 skill_reiteration: 0
 
 // Can ground skills NOT be placed underneath/near players/monsters? (Note 3)
-// If set, only skills with UF_NOFOOTSET set will be affected (skill_unit_db)
+// If set, only skills with UF_NOFOOTSET set will be affected.
 skill_nofootset: 1
 
 // Should traps (hunter traps + quagmire) change their target to "all" inside gvg/pvp grounds? (Note 3)
@@ -343,7 +343,7 @@ stormgust_knockback: yes
 // For RENEWAL_CAST (Note 2)
 // By default skill that has '0' value for Fixed Casting Time will use 20% of cast time
 // as Fixed Casting Time, and the rest (80%) as Variable Casting Time.
-// Put it 0 to disable default Fixed Casting Time (just like -1 is the skill_cast_db.txt).
+// Put it 0 to disable default Fixed Casting Time (just like -1 in the skill_db.yml).
 default_fixed_castrate: 20
 
 // On official servers, skills that hit all targets on a path (e.g. Focused Arrow Strike and First Wind) first

+ 2 - 1
conf/msg_conf/map_msg.conf

@@ -354,9 +354,10 @@
 334: Total Domination
 
 // Battlegrounds Queue
-337: You may not join a battleground queue when you're in a battleground map.
+337: You can't apply to a battleground queue from this map.
 338: You can't apply to a battleground queue due to recently deserting a battleground. Time remaining: %d minutes and %d seconds.
 339: You can't apply to a battleground queue for %d seconds due to recently leaving one.
+340: Participants were unable to join. Delaying entry for more participants.
 
 // Templates for @who output
 343: Name: %s

+ 91 - 54
db/battleground_db.yml

@@ -29,7 +29,12 @@
 #   MinLevel          Minimum level required to join the battleground. (Default: 1)
 #   MaxLevel          Maximum level to join the battleground. (Default: MAX_LEVEL value)
 #   Deserter          Amount of time in seconds a player is marked deserter. (Default: 600)
-#   StartDelay        Amount of time in seconds once a queue is filled before a start message is sent to players. (Default: 30)
+#   StartDelay        Amount of time in seconds once a queue is filled before players are warped. (Default: 0)
+#   Join:             Which application type is accepted. The entryqueuelist.lub can visually disable these options.
+#     Solo            Able to join a queue as an individual. (Default: true)
+#     Party           Able to join a queue as a party. (Default: true)
+#     Guild           Able to join a queue as a guild. (Default: true)
+#   JobRestrictions   List of jobs that are unable to join the battleground.
 #   Locations:        Battleground location settings.
 #     - Map           The map on which the battleground will be played.
 #       StartEvent    NPC event triggered when the battleground starts.
@@ -38,12 +43,14 @@
 #         RespawnY    Y coordinate for warping on death.
 #         DeathEvent  NPC event triggered when a player dies.
 #         QuitEvent   NPC event triggered when a player quits.
+#         ActiveEvent NPC event triggered when a player joints an active battleground.
 #         Variable    Name of BG ID variable used in the battleground script.
 #       TeamB:        TeamB settings.
 #         RespawnX    X coordinate for warping on death.
 #         RespawnY    Y coordinate for warping on death.
 #         DeathEvent  NPC event triggered when a player dies.
 #         QuitEvent   NPC event triggered when a player quits.
+#         ActiveEvent NPC event triggered when a player joints an active battleground.
 #         Variable    Name of BG ID variable used in the battleground script.
 ###########################################################################
 
@@ -53,121 +60,151 @@ Header:
 
 Body:
   - Id: 1
-    Name: "Tierra Gorge"
+    Name: Tierra Gorge
     MinPlayers: 6
     MinLevel: 80
+    JobRestrictions:
+      Novice: true
+      SuperNovice: true
+      Novice_High: true
+      Baby: true
+      Super_Baby: true
+      Super_Novice_E: true
+      Super_Baby_E: true
     Locations:
-      - Map: "bat_a01"
-        StartEvent: "start#bat_a01::OnReadyCheck"
+      - Map: bat_a01
+        StartEvent: start#bat_a01::OnReadyCheck
         TeamA:
           RespawnX: 50
           RespawnY: 374
-          QuitEvent: "start#bat_a01::OnGuillaumeQuit"
-          Variable: "$@TierraBG1_id1"
+          QuitEvent: start#bat_a01::OnGuillaumeQuit
+          ActiveEvent: start#bat_a01::OnGuillaumeActive
+          Variable: $@TierraBG1_id1
         TeamB:
           RespawnX: 42
           RespawnY: 16
-          QuitEvent: "start#bat_a01::OnCroixQuit"
-          Variable: "$@TierraBG1_id2"
-      - Map: "bat_a02"
-        StartEvent: "start#bat_a02::OnReadyCheck"
+          QuitEvent: start#bat_a01::OnCroixQuit
+          ActiveEvent: start#bat_a01::OnCroixActive
+          Variable: $@TierraBG1_id2
+      - Map: bat_a02
+        StartEvent: start#bat_a02::OnReadyCheck
         TeamA:
           RespawnX: 50
           RespawnY: 374
-          QuitEvent: "start#bat_a02::OnGuillaumeQuit"
-          Variable: "$@TierraBG2_id1"
+          QuitEvent: start#bat_a02::OnGuillaumeQuit
+          ActiveEvent: start#bat_a02::OnGuillaumeActive
+          Variable: $@TierraBG2_id1
         TeamB:
           RespawnX: 42
           RespawnY: 16
-          QuitEvent: "start#bat_a02::OnCroixQuit"
-          Variable: "$@TierraBG2_id2"
+          QuitEvent: start#bat_a02::OnCroixQuit
+          ActiveEvent: start#bat_a02::OnCroixActive
+          Variable: $@TierraBG2_id2
   - Id: 2
-    Name: "Flavius"
+    Name: Flavius
     MinPlayers: 6
     MinLevel: 80
+    JobRestrictions:
+      Novice: true
+      SuperNovice: true
+      Novice_High: true
+      Baby: true
+      Super_Baby: true
+      Super_Novice_E: true
+      Super_Baby_E: true
     Locations:
-      - Map: "bat_b01"
-        StartEvent: "start#bat_b01::OnReadyCheck"
+      - Map: bat_b01
+        StartEvent: start#bat_b01::OnReadyCheck
         TeamA:
           RespawnX: 10
           RespawnY: 290
-          QuitEvent: "start#bat_b01::OnGuillaumeQuit"
-          Variable: "$@FlaviusBG1_id1"
+          QuitEvent: start#bat_b01::OnGuillaumeQuit
+          ActiveEvent: start#bat_b01::OnGuillaumeActive
+          Variable: $@FlaviusBG1_id1
         TeamB:
           RespawnX: 390
           RespawnY: 10
-          QuitEvent: "start#bat_b01::OnCroixQuit"
-          Variable: "$@FlaviusBG1_id2"
-      - Map: "bat_b02"
-        StartEvent: "start#bat_b02::OnReadyCheck"
+          QuitEvent: start#bat_b01::OnCroixQuit
+          ActiveEvent: start#bat_b01::OnCroixActive
+          Variable: $@FlaviusBG1_id2
+      - Map: bat_b02
+        StartEvent: start#bat_b02::OnReadyCheck
         TeamA:
           RespawnX: 10
           RespawnY: 290
-          QuitEvent: "start#bat_b02::OnGuillaumeQuit"
-          Variable: "$@FlaviusBG2_id1"
+          QuitEvent: start#bat_b02::OnGuillaumeQuit
+          ActiveEvent: start#bat_b02::OnGuillaumeActive
+          Variable: $@FlaviusBG2_id1
         TeamB:
           RespawnX: 390
           RespawnY: 10
-          QuitEvent: "start#bat_b02::OnCroixQuit"
-          Variable: "$@FlaviusBG2_id2"
+          QuitEvent: start#bat_b02::OnCroixQuit
+          ActiveEvent: start#bat_b02::OnCroixActive
+          Variable: $@FlaviusBG2_id2
   - Id: 3
-    Name: "KVM (Level 80 and up)"
+    Name: KVM (Level 80 and up)
     MinPlayers: 5
     MinLevel: 80
     Locations:
-      - Map: "bat_c01"
-        StartEvent: "KvM01_BG::OnStart"
+      - Map: bat_c01
+        StartEvent: KvM01_BG::OnStart
         TeamA:
           RespawnX: 52
           RespawnY: 129
-          DeathEvent: "KvM01_BG::OnGuillaumeDie"
-          QuitEvent: "KvM01_BG::OnGuillaumeQuit"
-          Variable: "$@KvM01BG_id1"
+          DeathEvent: KvM01_BG::OnGuillaumeDie
+          QuitEvent: KvM01_BG::OnGuillaumeQuit
+          ActiveEvent: KvM01_BG::OnGuillaumeActive
+          Variable: $@KvM01BG_id1
         TeamB:
           RespawnX: 147
           RespawnY: 55
-          DeathEvent: "KvM01_BG::OnCroixDie"
-          QuitEvent: "KvM01_BG::OnCroixQuit"
-          Variable: "$@KvM01BG_id2"
+          DeathEvent: KvM01_BG::OnCroixDie
+          QuitEvent: KvM01_BG::OnCroixQuit
+          ActiveEvent: KvM01_BG::OnCroixActive
+          Variable: $@KvM01BG_id2
   - Id: 4
-    Name: "KVM (Level 60~79)"
+    Name: KVM (Level 60~79)
     MinPlayers: 5
     MinLevel: 60
     MaxLevel: 79
     Locations:
-      - Map: "bat_c02"
-        StartEvent: "KvM02_BG::OnStart"
+      - Map: bat_c02
+        StartEvent: KvM02_BG::OnStart
         TeamA:
           RespawnX: 52
           RespawnY: 129
-          DeathEvent: "KvM02_BG::OnGuillaumeDie"
-          QuitEvent: "KvM02_BG::OnGuillaumeQuit"
-          Variable: "$@KvM02BG_id1"
+          DeathEvent: KvM02_BG::OnGuillaumeDie
+          QuitEvent: KvM02_BG::OnGuillaumeQuit
+          ActiveEvent: KvM02_BG::OnGuillaumeActive
+          Variable: $@KvM02BG_id1
         TeamB:
           RespawnX: 147
           RespawnY: 55
-          DeathEvent: "KvM02_BG::OnCroixDie"
-          QuitEvent: "KvM02_BG::OnCroixQuit"
-          Variable: "$@KvM02BG_id2"
+          DeathEvent: KvM02_BG::OnCroixDie
+          QuitEvent: KvM02_BG::OnCroixQuit
+          ActiveEvent: KvM02_BG::OnCroixActive
+          Variable: $@KvM02BG_id2
   - Id: 5
-    Name: "KVM (Level 59 and below"
+    Name: KVM (Level 59 and below
     MinPlayers: 5
     MaxLevel: 59
     Locations:
-      - Map: "bat_c03"
-        StartEvent: "KvM03_BG::OnStart"
+      - Map: bat_c03
+        StartEvent: KvM03_BG::OnStart
         TeamA:
           RespawnX: 52
           RespawnY: 129
-          DeathEvent: "KvM03_BG::OnGuillaumeDie"
-          QuitEvent: "KvM03_BG::OnGuillaumeQuit"
-          Variable: "$@KvM03BG_id1"
+          DeathEvent: KvM03_BG::OnGuillaumeDie
+          QuitEvent: KvM03_BG::OnGuillaumeQuit
+          ActiveEvent: KvM03_BG::OnGuillaumeActive
+          Variable: $@KvM03BG_id1
         TeamB:
           RespawnX: 147
           RespawnY: 55
-          DeathEvent: "KvM03_BG::OnCroixDie"
-          QuitEvent: "KvM03_BG::OnCroixQuit"
-          Variable: "$@KvM03BG_id2"
+          DeathEvent: KvM03_BG::OnCroixDie
+          QuitEvent: KvM03_BG::OnCroixQuit
+          ActiveEvent: KvM03_BG::OnCroixActive
+          Variable: $@KvM03BG_id2
 
 Footer:
   Imports:

+ 8 - 1
db/import-tmpl/battleground_db.yml

@@ -29,7 +29,12 @@
 #   MinLevel          Minimum level required to join the battleground. (Default: 1)
 #   MaxLevel          Maximum level to join the battleground. (Default: MAX_LEVEL value)
 #   Deserter          Amount of time in seconds a player is marked deserter. (Default: 600)
-#   StartDelay        Amount of time in seconds once a queue is filled before a start message is sent to players. (Default: 30)
+#   StartDelay        Amount of time in seconds once a queue is filled before players are warped. (Default: 0)
+#   Join:             Which application type is accepted. The entryqueuelist.lub can visually disable these options.
+#     Solo            Able to join a queue as an individual. (Default: true)
+#     Party           Able to join a queue as a party. (Default: true)
+#     Guild           Able to join a queue as a guild. (Default: true)
+#   JobRestrictions   List of jobs that are unable to join the battleground.
 #   Locations:        Battleground location settings.
 #     - Map           The map on which the battleground will be played.
 #       StartEvent    NPC event triggered when the battleground starts.
@@ -38,12 +43,14 @@
 #         RespawnY    Y coordinate for warping on death.
 #         DeathEvent  NPC event triggered when a player dies.
 #         QuitEvent   NPC event triggered when a player quits.
+#         ActiveEvent NPC event triggered when a player joints an active battleground.
 #         Variable    Name of BG ID variable used in the battleground script.
 #       TeamB:        TeamB settings.
 #         RespawnX    X coordinate for warping on death.
 #         RespawnY    Y coordinate for warping on death.
 #         DeathEvent  NPC event triggered when a player dies.
 #         QuitEvent   NPC event triggered when a player quits.
+#         ActiveEvent NPC event triggered when a player joints an active battleground.
 #         Variable    Name of BG ID variable used in the battleground script.
 ###########################################################################
 

+ 0 - 31
db/import-tmpl/improvise_db.yml

@@ -1,31 +0,0 @@
-# This file is a part of rAthena.
-#   Copyright(C) 2019 rAthena Development Team
-#   https://rathena.org - https://github.com/rathena
-#
-# This program 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/>.
-#
-###########################################################################
-# Improvised Song Database
-###########################################################################
-#
-# Improvised Song Settings
-#
-###########################################################################
-# - Skill             Skill to be casted by Improvised Song.
-#   Probability       Probability of skill compared to others in database (1 = 0.01%, 10000 = 100%).
-###########################################################################
-
-Header:
-  Type: IMPROVISED_SONG_DB
-  Version: 1

+ 2 - 0
db/import-tmpl/instance_db.yml

@@ -26,6 +26,8 @@
 #   Name              Instance Name.
 #   TimeLimit         Total lifetime of instance in seconds. (Default: 3600)
 #   IdleTimeOut       Time before an idle instance is destroyed in seconds. (Default: 300)
+#   Destroyable       Toggles the ability to destroy the instance using instance 'Destroy' button. (Default: true)
+#                     Note: the button is displayed based on parties. For any mode, it requires the party leader to be the instance owner to destroy it.
 #   Enter:            Instance entrance coordinates.
 #     Map             Map Name where players start.
 #     X               X Coordinate where players start.

+ 0 - 37
db/improvise_db.yml

@@ -1,37 +0,0 @@
-# This file is a part of rAthena.
-#   Copyright(C) 2019 rAthena Development Team
-#   https://rathena.org - https://github.com/rathena
-#
-# This program 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/>.
-#
-###########################################################################
-# Improvised Song Database
-###########################################################################
-#
-# Improvised Song Settings
-#
-###########################################################################
-# - Skill             Skill to be casted by Improvised Song.
-#   Probability       Probability of skill compared to others in database (1 = 0.01%, 10000 = 100%).
-###########################################################################
-
-Header:
-  Type: IMPROVISED_SONG_DB
-  Version: 1
-
-Footer:
-  Imports:
-  - Path: db/re/improvise_db.yml
-    Mode: Renewal
-  - Path: db/import/improvise_db.yml

+ 2 - 0
db/instance_db.yml

@@ -26,6 +26,8 @@
 #   Name              Instance Name.
 #   TimeLimit         Total lifetime of instance in seconds. (Default: 3600)
 #   IdleTimeOut       Time before an idle instance is destroyed in seconds. (Default: 300)
+#   Destroyable       Toggles the ability to destroy the instance using instance 'Destroy' button. (Default: true)
+#                     Note: the button is displayed based on parties. For any mode, it requires the party leader to be the instance owner to destroy it.
 #   Enter:            Instance entrance coordinates.
 #     Map             Map Name where players start.
 #     X               X Coordinate where players start.

+ 1 - 1
db/item_avail.txt

@@ -11,7 +11,7 @@
 // Think of it as a way to disguise items.
 // Don't sell the item in same shop with the source. Example, don't put 2240 & 2241 in same place!
 
-2240,2241 //Beard - Grampa Beard
+//2240,2241 //Beard - Grampa Beard
 
 //Treasure Hunters Quest Items
 //use these aliases if your game client doesn't support them normally

+ 2 - 2
db/job_db2.txt

@@ -280,9 +280,9 @@
 // Baby Mechanic (Mado)
 4112,6,1,0,0,1,0,6,2,5,4,0,0,4,6,0,0,2,0,3,3,4,5,0,0,3,6,0,0,3,0,1,1,3,6,0,0,4,4,0,0,0,3,3,1,1,0,0,5,2,0,6,1,5,0,4,3,2,0,5,1
 // Super Novice (Expanded)
-4190,1,2,0,3,0,4,5,0,6,0,1,2,0,3,0,4,5,0,6,0,1,2,0,3,0,4,5,0,6,0,1,2,0,3,0,4,5,0,6,0,1,2,0,3,0,4,5,0,6,0
+4190,1,2,0,3,0,4,5,0,6,0,1,2,0,3,0,4,5,0,6,0,1,2,0,3,0,4,5,0,6,0,1,2,0,3,0,4,5,0,6,0,1,2,0,3,0,4,5,0,6,0,1,2,0,3,0,4,5,0,6,0,1,2,4,5,0
 // Super Baby (Expanded)
-4191,1,2,0,3,0,4,5,0,6,0,1,2,0,3,0,4,5,0,6,0,1,2,0,3,0,4,5,0,6,0,1,2,0,3,0,4,5,0,6,0,1,2,0,3,0,4,5,0,6,0
+4191,1,2,0,3,0,4,5,0,6,0,1,2,0,3,0,4,5,0,6,0,1,2,0,3,0,4,5,0,6,0,1,2,0,3,0,4,5,0,6,0,1,2,0,3,0,4,5,0,6,0,1,2,0,3,0,4,5,0,6,0,1,2,4,5,0
 // Kagerou
 4211,5,0,4,0,2,3,0,1,6,0,5,1,2,0,4,6,3,0,1,5,2,0,6,3,4,0,5,0,2,0,1,4,0,5,4,0,3,5,1,0,2,4,1,0,5,6,2,1,0,5
 // Oboro

+ 2 - 0
db/pre-re/instance_db.yml

@@ -26,6 +26,8 @@
 #   Name              Instance Name.
 #   TimeLimit         Total lifetime of instance in seconds. (Default: 3600)
 #   IdleTimeOut       Time before an idle instance is destroyed in seconds. (Default: 300)
+#   Destroyable       Toggles the ability to destroy the instance using instance 'Destroy' button. (Default: true)
+#                     Note: the button is displayed based on parties. For any mode, it requires the party leader to be the instance owner to destroy it.
 #   Enter:            Instance entrance coordinates.
 #     Map             Map Name where players start.
 #     X               X Coordinate where players start.

+ 2 - 2
db/pre-re/mob_race2_db.txt

@@ -16,9 +16,9 @@ RC2_GUARDIAN,1285,1286,1287,2081
 // Ninja Classes (Pirate's_Pride)
 RC2_NINJA,1315,1364,1401,1560
 // GvG
-RC2_GVG,1143,1905,1906,1907
+RC2_GVG,1288,1905,1907,1908
 // Battlefield
-RC2_BATTLEFIELD,1906,1909,1914,1915
+RC2_BATTLEFIELD,1906,1909,1910,1911,1912,1913,1914,1915
 // Treasure Chests
 RC2_TREASURE,1324,1325,1326,1327,1328,1329,1330,1331,1332,1333,1334,1335,1336,1337,1338,1339,1340,1341,1342,1343,1344,1345,1346,1347,1348,1349,1350,1351,1352,1353,1354,1355,1356,1357,1358,1359,1360,1361,1362,1363,1938,1939,1940,1941,1942,1943,1944,1945,1946
 // Manuk

+ 5 - 5
db/pre-re/produce_db.txt

@@ -618,15 +618,15 @@
 
 //---- Create Bomb --- ItemLV=28 ---------------
 //-- Apple Bomb <-- GN_MAKEBOMB Lv1, Apple Bomb CB, 1 Apple, 1 Scell, 1 Detonator, 1 Gun Powder
-246,13260,28,2496,1,6279,0,512,1,911,1,1051,1,6244,1
+//246,13260,28,2496,1,6279,0,512,1,911,1,1051,1,6244,1
 //-- Coconut Bomb <-- GN_MAKEBOMB Lv1, Coconut Bomb CB, 1 Detonator, 1 Coconut Fruit, 2 Gun Powder
-247,13261,28,2496,1,6281,0,1051,1,6263,1,6244,2
+//247,13261,28,2496,1,6281,0,1051,1,6263,1,6244,2
 //-- Melon Bomb <-- GN_MAKEBOMB Lv1, Melon Bomb CB, 1 Sticky Mucus, 1 Detonator, 2 Gun Powder, 1 Melon
-248,13262,28,2496,1,6282,0,938,1,1051,1,6244,2,6264,1
+//248,13262,28,2496,1,6282,0,938,1,1051,1,6244,2,6264,1
 //-- Pineapple Bomb <-- GN_MAKEBOMB Lv1, Pinepple Bomb CB, 1 Cactus Needle, 1 Detonator, 3 Gun Powder, 1 Pineapple
-249,13263,28,2496,1,6280,0,952,1,1051,1,6244,3,6265,1
+//249,13263,28,2496,1,6280,0,952,1,1051,1,6244,3,6265,1
 //-- Banana Bomb <-- GN_MAKEBOMB Lv1, Banana Bomb CB, 1 Banana, 1 Detonator, 4 Gun Powder, 1 Mould Powder
-250,13264,28,2496,1,6283,0,513,1,1051,1,6244,4,7001,1
+//250,13264,28,2496,1,6283,0,513,1,1051,1,6244,4,7001,1
 
 //---- Special Pharmacy --- ItemLV=29 ----------
 //-- Seed Of Horny Plant <-- GN_S_PHARMACY Lv1, Plant Genetic Grow, 10 Prickly Fruit

+ 95 - 37
db/pre-re/skill_db.yml

@@ -2071,8 +2071,6 @@ Body:
     TargetType: Attack
     DamageFlags:
       NoDamage: true
-    Flags:
-      IncreaseGloomyDayDamage: true
     Range: -2
     Hit: Single
     HitCount: 1
@@ -5838,11 +5836,8 @@ Body:
     Name: NPC_DARKBREATH
     Description: Dark Breath
     MaxLevel: 5
-    Type: Misc
+    Type: Magic
     TargetType: Attack
-    DamageFlags:
-      IgnoreFlee: true
-      IgnoreDefCard: true
     Flags:
       IsNpc: true
     Range: 9
@@ -6699,8 +6694,6 @@ Body:
     MaxLevel: 5
     Type: Weapon
     TargetType: Attack
-    Flags:
-      IncreaseGloomyDayDamage: true
     Range:
       - Level: 1
         Size: 3
@@ -10658,7 +10651,6 @@ Body:
       IgnoreDefense: true
     Flags:
       TargetTrap: true
-      IncreaseGloomyDayDamage: true
     Range: 5
     Hit: Multi_Hit
     HitCount: 5
@@ -12834,8 +12826,6 @@ Body:
     MaxLevel: 5
     Type: Weapon
     TargetType: Attack
-    Flags:
-      IncreaseGloomyDayDamage: true
     Range: 4
     Hit: Multi_Hit
     HitCount: 5
@@ -15319,6 +15309,7 @@ Body:
     Flags:
       IsNpc: true
       TargetTrap: true
+      ShowScale: true
     Hit: Multi_Hit
     HitCount: 1
     SplashArea:
@@ -15424,6 +15415,7 @@ Body:
       Splash: true
     Flags:
       IsNpc: true
+      ShowScale: true
     Hit: Single
     HitCount: 1
     SplashArea:
@@ -15470,6 +15462,7 @@ Body:
     Flags:
       IsNpc: true
       TargetTrap: true
+      ShowScale: true
     Hit: Single
     HitCount: 1
     SplashArea: 7
@@ -15485,6 +15478,7 @@ Body:
     Flags:
       IsNpc: true
       TargetTrap: true
+      ShowScale: true
     Hit: Single
     HitCount: 1
     SplashArea: 14
@@ -15499,6 +15493,7 @@ Body:
       Splash: true
     Flags:
       IsNpc: true
+      ShowScale: true
     Hit: Single
     HitCount: 1
     SplashArea:
@@ -15523,6 +15518,7 @@ Body:
       Splash: true
     Flags:
       IsNpc: true
+      ShowScale: true
     Hit: Single
     HitCount: 1
     SplashArea:
@@ -15547,6 +15543,7 @@ Body:
       Splash: true
     Flags:
       IsNpc: true
+      ShowScale: true
     Hit: Single
     HitCount: 1
     SplashArea:
@@ -15571,6 +15568,7 @@ Body:
       Splash: true
     Flags:
       IsNpc: true
+      ShowScale: true
     Hit: Single
     HitCount: 1
     SplashArea:
@@ -15595,6 +15593,7 @@ Body:
       Splash: true
     Flags:
       IsNpc: true
+      ShowScale: true
     Hit: Single
     HitCount: 1
     SplashArea:
@@ -15619,6 +15618,7 @@ Body:
       Splash: true
     Flags:
       IsNpc: true
+      ShowScale: true
     Hit: Single
     HitCount: 1
     SplashArea:
@@ -15644,6 +15644,7 @@ Body:
       Splash: true
     Flags:
       IsNpc: true
+      ShowScale: true
     Hit: Single
     HitCount: 1
     Element: Fire
@@ -15662,6 +15663,7 @@ Body:
       IgnoreDefCard: true
     Flags:
       IsNpc: true
+      ShowScale: true
     Range: 7
     Hit: Single
     HitCount: 1
@@ -15758,6 +15760,7 @@ Body:
       Splash: true
     Flags:
       IsNpc: true
+      ShowScale: true
     Hit: Single
     HitCount: 1
     SplashArea:
@@ -15874,6 +15877,7 @@ Body:
       Splash: true
     Flags:
       IsNpc: true
+      ShowScale: true
     Hit: Single
     HitCount: 1
     SplashArea:
@@ -15898,6 +15902,7 @@ Body:
       Splash: true
     Flags:
       IsNpc: true
+      ShowScale: true
     Hit: Single
     HitCount: 1
     SplashArea:
@@ -15922,6 +15927,7 @@ Body:
       Splash: true
     Flags:
       IsNpc: true
+      ShowScale: true
     Hit: Single
     HitCount: 1
     SplashArea:
@@ -15955,6 +15961,7 @@ Body:
       Splash: true
     Flags:
       IsNpc: true
+      ShowScale: true
     Hit: Single
     HitCount: 1
     SplashArea:
@@ -16234,6 +16241,7 @@ Body:
     Flags:
       IsNpc: true
       IgnoreLandProtector: true
+      ShowScale: true
     Hit: Single
     HitCount: 1
     Element: Poison
@@ -16250,6 +16258,8 @@ Body:
     Name: NPC_COMET
     Description: Comet 2
     MaxLevel: 1
+    Flags:
+      ShowScale: true
   - Id: 716
     Name: NPC_MAXPAIN
     Description: Max Pain
@@ -16281,6 +16291,8 @@ Body:
     Name: NPC_JACKFROST
     Description: Jack Frost 2
     MaxLevel: 1
+    Flags:
+      ShowScale: true
   - Id: 725
     Name: NPC_REVERBERATION
     Description: Reverberation 2
@@ -16293,6 +16305,7 @@ Body:
       IsNpc: true
       IsTrap: true
       DisableNearNpc: true
+      ShowScale: true
     Range: 1
     Hit: Single
     HitCount: 1
@@ -16333,6 +16346,8 @@ Body:
     Name: NPC_LEX_AETERNA
     Description: Lex Aeterna 2
     MaxLevel: 1
+    Flags:
+      ShowScale: true
   - Id: 728
     Name: NPC_ARROWSTORM
     Description: NPC Arrow Storm
@@ -16847,8 +16862,6 @@ Body:
     MaxLevel: 10
     Type: Weapon
     TargetType: Attack
-    Flags:
-      IncreaseGloomyDayDamage: true
     Range: 5
     Hit: Multi_Hit
     HitCount: -5
@@ -18583,6 +18596,8 @@ Body:
     Duration1: 60000
     Requires:
       SpCost: 20
+      Status:
+        Weaponblock_On: true
   - Id: 2031
     Name: GC_VENOMPRESSURE
     Description: Venom Pressure
@@ -19244,10 +19259,10 @@ Body:
           Amount: 70
         - Level: 4
           Amount: 80
-#  - Id: 2049 # Removed on kRO
-#    Name: AB_EUCHARISTICA
-#    Description: Eucharistica
-#    MaxLevel: 10
+  - Id: 2049 # Removed on kRO
+    Name: AB_EUCHARISTICA
+    Description: Eucharistica
+    MaxLevel: 10
   - Id: 2050
     Name: AB_RENOVATIO
     Description: Renovatio
@@ -19887,9 +19902,9 @@ Body:
       IgnoreDefCard: true
     Flags:
       AllowOnWarg: true
-      IncreaseDanceWithWugDamage: true
       IgnoreAutoGuard: true
       IgnoreCicada: true
+      IncreaseDanceWithWugDamage: true
     Range: 9
     Hit: Single
     HitCount: 1
@@ -19917,9 +19932,9 @@ Body:
       IgnoreDefCard: true
     Flags:
       AlterRangeVulture: true
-      IncreaseDanceWithWugDamage: true
       IgnoreAutoGuard: true
       IgnoreCicada: true
+      IncreaseDanceWithWugDamage: true
     Range: 9
     Hit: Single
     HitCount: 1
@@ -24311,7 +24326,7 @@ Body:
         Reproduce: true
     Requires:
       SpCost: 1
-  - Id: 2417
+  - Id: 2417 # Removed on kRO
     Name: WM_DOMINION_IMPULSE
     Description: Dominion Impulse
     MaxLevel: 1
@@ -24324,6 +24339,7 @@ Body:
     HitCount: 1
     SplashArea: 5
     AfterCastActDelay: 1000
+    FixedCastTime: -1
     Requires:
       SpCost: 10
   - Id: 2418
@@ -26704,8 +26720,8 @@ Body:
     DamageFlags:
       Splash: true
     Range: 11
-    Hit: Single
-    HitCount: 3
+    Hit: Multi_Hit
+    HitCount: 2
     Element: Weapon
     SplashArea:
       - Level: 1
@@ -27233,10 +27249,25 @@ Body:
       ItemCost:
         - Item: Mandragora_Flowerpot
           Amount: 1
-#  - Id: 2493 # Removed on kRO
-#    Name: GN_SLINGITEM
-#    Description: Sling Item
-#    MaxLevel: 1
+  - Id: 2493 # Removed on kRO
+    Name: GN_SLINGITEM
+    Description: Sling Item
+    MaxLevel: 1
+    TargetType: Support
+    DamageFlags:
+      NoDamage: true
+    Flags:
+      NoTargetSelf: true
+    Range: 11
+    Hit: Single
+    HitCount: 1
+    Cooldown: 1000
+    FixedCastTime: -1
+    Requires:
+      SpCost: 4
+      Ammo:
+        Throwweapon: true
+      AmmoAmount: 1
   - Id: 2494
     Name: GN_CHANGEMATERIAL
     Description: Change Material
@@ -27263,10 +27294,21 @@ Body:
           Amount: 5
         - Level: 2
           Amount: 40
-#  - Id: 2496 # Removed on kRO
-#    Name: GN_MAKEBOMB
-#    Description: Create Bomb
-#    MaxLevel: 2
+  - Id: 2496 # Removed on kRO
+    Name: GN_MAKEBOMB
+    Description: Create Bomb
+    MaxLevel: 2
+    TargetType: Self
+    DamageFlags:
+      NoDamage: true
+    Hit: Single
+    HitCount: 1
+    Requires:
+      SpCost:
+        - Level: 1
+          Amount: 5
+        - Level: 2
+          Amount: 40
   - Id: 2497
     Name: GN_S_PHARMACY
     Description: Special Pharmacy
@@ -27278,10 +27320,17 @@ Body:
     HitCount: 1
     Requires:
       SpCost: 12
-#  - Id: 2498 # Removed on kRO
-#    Name: GN_SLINGITEM_RANGEMELEEATK
-#    Description: Sling Item Attack
-#    MaxLevel: 1
+  - Id: 2498 # Removed on kRO
+    Name: GN_SLINGITEM_RANGEMELEEATK
+    Description: Sling Item Attack
+    MaxLevel: 1
+    Type: Weapon
+    TargetType: Attack
+    Range: 11
+    Hit: Single
+    HitCount: 1
+    Requires:
+      SpCost: 1
   - Id: 2533
     Name: ALL_ODINS_RECALL
     Description: Odin's Recall
@@ -30080,6 +30129,18 @@ Body:
     Name: AB_CONVENIO
     Description: Convenio
     MaxLevel: 1
+  - Id: 5075
+    Name: NV_BREAKTHROUGH
+    Description: Break Through
+    MaxLevel: 1
+  - Id: 5076
+    Name: NV_HELPANGEL
+    Description: Help Angel
+    MaxLevel: 1
+  - Id: 5077
+    Name: NV_TRANSCENDENCE
+    Description: Transcendence
+    MaxLevel: 1
   - Id: 8001
     Name: HLIF_HEAL
     Description: Healing Touch
@@ -32089,8 +32150,6 @@ Body:
     TargetType: Attack
     DamageFlags:
       NoDamage: true
-    Flags:
-      IncreaseGloomyDayDamage: true
     Range: -2
     Hit: Single
     HitCount: 1
@@ -32115,7 +32174,6 @@ Body:
       IgnoreDefense: true
     Flags:
       TargetTrap: true
-      IncreaseGloomyDayDamage: true
     Range: 5
     Hit: Multi_Hit
     HitCount: 5

+ 1 - 0
db/pre-re/skill_nocast_db.txt

@@ -179,3 +179,4 @@
 2303,2048	//SC_BLOODYLUST
 2419,2048	//WM_POEMOFNETHERWORLD
 2482,2048	//GN_WALLOFTHORN
+2493,2048	//GN_SLINGITEM

+ 21 - 12
db/pre-re/skill_tree.txt

@@ -2577,6 +2577,7 @@
 4057,2046,10,2045,5,0,0,0,0,0,0,0,0 //AB_ORATIO#Oratio#
 4057,2047,4,72,1,0,0,0,0,0,0,0,0 //AB_LAUDAAGNUS#Lauda Agnus#
 4057,2048,4,2047,2,0,0,0,0,0,0,0,0 //AB_LAUDARAMUS#Lauda Ramus#
+//4057,2049,10,2044,1,2053,1,0,0,0,0,0,0 //AB_EUCHARISTICA#Eucharistica#
 4057,2050,4,2043,3,0,0,0,0,0,0,0,0 //AB_RENOVATIO#Renovatio#
 4057,2051,5,2050,1,0,0,0,0,0,0,0,0 //AB_HIGHNESSHEAL#Highness Heal#
 4057,2052,5,2048,2,0,0,0,0,0,0,0,0 //AB_CLEARANCE#Clearance#
@@ -2923,6 +2924,7 @@
 4063,2046,10,2045,5,0,0,0,0,0,0,0,0 //AB_ORATIO#Oratio#
 4063,2047,4,72,1,0,0,0,0,0,0,0,0 //AB_LAUDAAGNUS#Lauda Agnus#
 4063,2048,4,2047,2,0,0,0,0,0,0,0,0 //AB_LAUDARAMUS#Lauda Ramus#
+//4063,2049,10,2044,1,2053,1,0,0,0,0,0,0 //AB_EUCHARISTICA#Eucharistica#
 4063,2050,4,2043,3,0,0,0,0,0,0,0,0 //AB_RENOVATIO#Renovatio#
 4063,2051,5,2050,1,0,0,0,0,0,0,0,0 //AB_HIGHNESSHEAL#Highness Heal#
 4063,2052,5,2048,2,0,0,0,0,0,0,0,0 //AB_CLEARANCE#Clearance#
@@ -3217,9 +3219,9 @@
 4068,2382,5,2422,1,0,0,0,0,0,0,0,0 //MI_ECHOSONG#Echo Song#
 4068,2383,5,2422,1,0,0,0,0,0,0,0,0 //MI_HARMONIZE#Harmonize#
 4068,2412,10,0,0,0,0,0,0,0,0,0,0 //WM_LESSON#Lesson#
-4068,2413,10,2417,1,0,0,0,0,0,0,0,0 //WM_METALICSOUND#Metallic Sound#
+4068,2413,5,0,0,0,0,0,0,0,0,0,0 //WM_METALICSOUND#Metallic Sound#
 4068,2414,5,317,5,0,0,0,0,0,0,0,0 //WM_REVERBERATION#Reverberation#
-4068,2417,1,2414,1,0,0,0,0,0,0,0,0 //WM_DOMINION_IMPULSE#Dominion Impulse#
+//4068,2417,1,2414,1,0,0,0,0,0,0,0,0 //WM_DOMINION_IMPULSE#Dominion Impulse#
 4068,2418,5,316,5,0,0,0,0,0,0,0,0 //WM_SEVERE_RAINSTORM#Severe Rainstorm#
 4068,2419,5,2412,1,0,0,0,0,0,0,0,0 //WM_POEMOFNETHERWORLD#Poem Of The Netherworld#
 4068,2420,5,2419,3,0,0,0,0,0,0,0,0 //WM_VOICEOFSIREN#Voice Of Siren#
@@ -3273,9 +3275,9 @@
 4069,2351,5,2422,1,0,0,0,0,0,0,0,0 //WA_SYMPHONY_OF_LOVER#Symphony of Lovers#
 4069,2352,5,2422,1,0,0,0,0,0,0,0,0 //WA_MOONLIT_SERENADE#Moonlit Serenade#
 4069,2412,10,0,0,0,0,0,0,0,0,0,0 //WM_LESSON#Lesson#
-4069,2413,10,2417,1,0,0,0,0,0,0,0,0 //WM_METALICSOUND#Metallic Sound#
+4069,2413,5,0,0,0,0,0,0,0,0,0,0 //WM_METALICSOUND#Metallic Sound#
 4069,2414,5,325,5,0,0,0,0,0,0,0,0 //WM_REVERBERATION#Reverberation#
-4069,2417,1,2414,1,0,0,0,0,0,0,0,0 //WM_DOMINION_IMPULSE#Dominion Impulse#
+//4069,2417,1,2414,1,0,0,0,0,0,0,0,0 //WM_DOMINION_IMPULSE#Dominion Impulse#
 4069,2418,5,324,5,0,0,0,0,0,0,0,0 //WM_SEVERE_RAINSTORM#Severe Rainstorm#
 4069,2419,5,2412,1,0,0,0,0,0,0,0,0 //WM_POEMOFNETHERWORLD#Poem Of The Netherworld#
 4069,2420,5,2419,3,0,0,0,0,0,0,0,0 //WM_VOICEOFSIREN#Voice Of Siren#
@@ -3403,8 +3405,10 @@
 4071,2486,5,2485,3,0,0,0,0,0,0,0,0 //GN_FIRE_EXPANSION#Fire Expansion#
 4071,2490,5,2480,3,0,0,0,0,0,0,0,0 //GN_HELLS_PLANT#Hell's Plant#
 4071,2492,5,2490,3,0,0,0,0,0,0,0,0 //GN_MANDRAGORA#Howling of Mandragora#
+//4071,2493,1,2494,1,0,0,0,0,0,0,0,0 //GN_SLINGITEM#Sling Item#
 4071,2494,1,0,0,0,0,0,0,0,0,0,0 //GN_CHANGEMATERIAL#Change Material#
 4071,2495,2,2497,1,0,0,0,0,0,0,0,0 //GN_MIX_COOKING#Mix Cooking#
+//4071,2496,2,2495,1,0,0,0,0,0,0,0,0 //GN_MAKEBOMB#Create Bomb#
 4071,2497,10,0,0,0,0,0,0,0,0,0,0 //GN_S_PHARMACY#Special Pharmacy#
 4071,5003,5,2497,1,0,0,0,0,0,0,0,0 //GN_ILLUSIONDOOPING#Hallucination Drug#
 4071,5014,5,0,0,0,0,0,0,0,0,0,0 //ALL_FULL_THROTTLE#Full Throttle#
@@ -3645,9 +3649,9 @@
 4075,2382,5,2422,1,0,0,0,0,0,0,0,0 //MI_ECHOSONG#Echo Song#
 4075,2383,5,2422,1,0,0,0,0,0,0,0,0 //MI_HARMONIZE#Harmonize#
 4075,2412,10,0,0,0,0,0,0,0,0,0,0 //WM_LESSON#Lesson#
-4075,2413,10,2417,1,0,0,0,0,0,0,0,0 //WM_METALICSOUND#Metallic Sound#
+4075,2413,5,0,0,0,0,0,0,0,0,0,0 //WM_METALICSOUND#Metallic Sound#
 4075,2414,5,317,5,0,0,0,0,0,0,0,0 //WM_REVERBERATION#Reverberation#
-4075,2417,1,2414,1,0,0,0,0,0,0,0,0 //WM_DOMINION_IMPULSE#Dominion Impulse#
+//4075,2417,1,2414,1,0,0,0,0,0,0,0,0 //WM_DOMINION_IMPULSE#Dominion Impulse#
 4075,2418,5,316,5,0,0,0,0,0,0,0,0 //WM_SEVERE_RAINSTORM#Severe Rainstorm#
 4075,2419,5,2412,1,0,0,0,0,0,0,0,0 //WM_POEMOFNETHERWORLD#Poem Of The Netherworld#
 4075,2420,5,2419,3,0,0,0,0,0,0,0,0 //WM_VOICEOFSIREN#Voice Of Siren#
@@ -3707,9 +3711,9 @@
 4076,2351,5,2422,1,0,0,0,0,0,0,0,0 //WA_SYMPHONY_OF_LOVER#Symphony of Lovers#
 4076,2352,5,2422,1,0,0,0,0,0,0,0,0 //WA_MOONLIT_SERENADE#Moonlit Serenade#
 4076,2412,10,0,0,0,0,0,0,0,0,0,0 //WM_LESSON#Lesson#
-4076,2413,10,2417,1,0,0,0,0,0,0,0,0 //WM_METALICSOUND#Metallic Sound#
+4076,2413,5,0,0,0,0,0,0,0,0,0,0 //WM_METALICSOUND#Metallic Sound#
 4076,2414,5,325,5,0,0,0,0,0,0,0,0 //WM_REVERBERATION#Reverberation#
-4076,2417,1,2414,1,0,0,0,0,0,0,0,0 //WM_DOMINION_IMPULSE#Dominion Impulse#
+//4076,2417,1,2414,1,0,0,0,0,0,0,0,0 //WM_DOMINION_IMPULSE#Dominion Impulse#
 4076,2418,5,324,5,0,0,0,0,0,0,0,0 //WM_SEVERE_RAINSTORM#Severe Rainstorm#
 4076,2419,5,2412,1,0,0,0,0,0,0,0,0 //WM_POEMOFNETHERWORLD#Poem Of The Netherworld#
 4076,2420,5,2419,3,0,0,0,0,0,0,0,0 //WM_VOICEOFSIREN#Voice Of Siren#
@@ -3845,8 +3849,10 @@
 4078,2486,5,2485,3,0,0,0,0,0,0,0,0 //GN_FIRE_EXPANSION#Fire Expansion#
 4078,2490,5,2480,3,0,0,0,0,0,0,0,0 //GN_HELLS_PLANT#Hell's Plant#
 4078,2492,5,2490,3,0,0,0,0,0,0,0,0 //GN_MANDRAGORA#Howling of Mandragora#
+//4078,2493,1,2494,1,0,0,0,0,0,0,0,0 //GN_SLINGITEM#Sling Item#
 4078,2494,1,0,0,0,0,0,0,0,0,0,0 //GN_CHANGEMATERIAL#Change Material#
 4078,2495,2,2497,1,0,0,0,0,0,0,0,0 //GN_MIX_COOKING#Mix Cooking#
+//4078,2496,2,2495,1,0,0,0,0,0,0,0,0 //GN_MAKEBOMB#Create Bomb#
 4078,2497,10,0,0,0,0,0,0,0,0,0,0 //GN_S_PHARMACY#Special Pharmacy#
 4078,5003,5,2497,1,0,0,0,0,0,0,0,0 //GN_ILLUSIONDOOPING#Hallucination Drug#
 4078,5014,5,0,0,0,0,0,0,0,0,0,0 //ALL_FULL_THROTTLE#Full Throttle#
@@ -4574,6 +4580,7 @@
 4099,2046,10,2045,5,0,0,0,0,0,0,0,0 //AB_ORATIO#Oratio#
 4099,2047,4,72,1,0,0,0,0,0,0,0,0 //AB_LAUDAAGNUS#Lauda Agnus#
 4099,2048,4,2047,2,0,0,0,0,0,0,0,0 //AB_LAUDARAMUS#Lauda Ramus#
+//4099,2049,10,2044,1,2053,1,0,0,0,0,0,0 //AB_EUCHARISTICA#Eucharistica#
 4099,2050,4,2043,3,0,0,0,0,0,0,0,0 //AB_RENOVATIO#Renovatio#
 4099,2051,5,2050,1,0,0,0,0,0,0,0,0 //AB_HIGHNESSHEAL#Highness Heal#
 4099,2052,5,2048,2,0,0,0,0,0,0,0,0 //AB_CLEARANCE#Clearance#
@@ -4863,9 +4870,9 @@
 4104,2382,5,2422,1,0,0,0,0,0,0,0,0 //MI_ECHOSONG#Echo Song#
 4104,2383,5,2422,1,0,0,0,0,0,0,0,0 //MI_HARMONIZE#Harmonize#
 4104,2412,10,0,0,0,0,0,0,0,0,0,0 //WM_LESSON#Lesson#
-4104,2413,10,2417,1,0,0,0,0,0,0,0,0 //WM_METALICSOUND#Metallic Sound#
+4104,2413,5,0,0,0,0,0,0,0,0,0,0 //WM_METALICSOUND#Metallic Sound#
 4104,2414,5,317,5,0,0,0,0,0,0,0,0 //WM_REVERBERATION#Reverberation#
-4104,2417,1,2414,1,0,0,0,0,0,0,0,0 //WM_DOMINION_IMPULSE#Dominion Impulse#
+//4104,2417,1,2414,1,0,0,0,0,0,0,0,0 //WM_DOMINION_IMPULSE#Dominion Impulse#
 4104,2418,5,316,5,0,0,0,0,0,0,0,0 //WM_SEVERE_RAINSTORM#Severe Rainstorm#
 4104,2419,5,2412,1,0,0,0,0,0,0,0,0 //WM_POEMOFNETHERWORLD#Poem Of The Netherworld#
 4104,2420,5,2419,3,0,0,0,0,0,0,0,0 //WM_VOICEOFSIREN#Voice Of Siren#
@@ -4920,9 +4927,9 @@
 4105,2351,5,2422,1,0,0,0,0,0,0,0,0 //WA_SYMPHONY_OF_LOVER#Symphony of Lovers#
 4105,2352,5,2422,1,0,0,0,0,0,0,0,0 //WA_MOONLIT_SERENADE#Moonlit Serenade#
 4105,2412,10,0,0,0,0,0,0,0,0,0,0 //WM_LESSON#Lesson#
-4105,2413,10,2417,1,0,0,0,0,0,0,0,0 //WM_METALICSOUND#Metallic Sound#
+4105,2413,5,0,0,0,0,0,0,0,0,0,0 //WM_METALICSOUND#Metallic Sound#
 4105,2414,5,325,5,0,0,0,0,0,0,0,0 //WM_REVERBERATION#Reverberation#
-4105,2417,1,2414,1,0,0,0,0,0,0,0,0 //WM_DOMINION_IMPULSE#Dominion Impulse#
+//4105,2417,1,2414,1,0,0,0,0,0,0,0,0 //WM_DOMINION_IMPULSE#Dominion Impulse#
 4105,2418,5,324,5,0,0,0,0,0,0,0,0 //WM_SEVERE_RAINSTORM#Severe Rainstorm#
 4105,2419,5,2412,1,0,0,0,0,0,0,0,0 //WM_POEMOFNETHERWORLD#Poem Of The Netherworld#
 4105,2420,5,2419,3,0,0,0,0,0,0,0,0 //WM_VOICEOFSIREN#Voice Of Siren#
@@ -5052,8 +5059,10 @@
 4107,2486,5,2485,3,0,0,0,0,0,0,0,0 //GN_FIRE_EXPANSION#Fire Expansion#
 4107,2490,5,2480,3,0,0,0,0,0,0,0,0 //GN_HELLS_PLANT#Hell's Plant#
 4107,2492,5,2490,3,0,0,0,0,0,0,0,0 //GN_MANDRAGORA#Howling of Mandragora#
+//4107,2493,1,2494,1,0,0,0,0,0,0,0,0 //GN_SLINGITEM#Sling Item#
 4107,2494,1,0,0,0,0,0,0,0,0,0,0 //GN_CHANGEMATERIAL#Change Material#
 4107,2495,2,2497,1,0,0,0,0,0,0,0,0 //GN_MIX_COOKING#Mix Cooking#
+//4107,2496,2,2495,1,0,0,0,0,0,0,0,0 //GN_MAKEBOMB#Create Bomb#
 4107,2497,10,0,0,0,0,0,0,0,0,0,0 //GN_S_PHARMACY#Special Pharmacy#
 4107,5003,5,2497,1,0,0,0,0,0,0,0,0 //GN_ILLUSIONDOOPING#Hallucination Drug#
 4107,5014,5,0,0,0,0,0,0,0,0,0,0 //ALL_FULL_THROTTLE#Full Throttle#

+ 0 - 65
db/re/improvise_db.yml

@@ -1,65 +0,0 @@
-# This file is a part of rAthena.
-#   Copyright(C) 2019 rAthena Development Team
-#   https://rathena.org - https://github.com/rathena
-#
-# This program 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/>.
-#
-###########################################################################
-# Improvised Song Database
-###########################################################################
-#
-# Improvised Song Settings
-#
-###########################################################################
-# - Skill             Skill to be casted by Improvised Song.
-#   Probability       Probability of skill compared to others in database (1 = 0.01%, 10000 = 100%).
-###########################################################################
-
-Header:
-  Type: IMPROVISED_SONG_DB
-  Version: 1
-
-Body:
-  - Skill: MG_NAPALMBEAT
-    Probability: 6000
-  - Skill: MG_SAFETYWALL
-    Probability: 4000
-  - Skill: MG_SOULSTRIKE
-    Probability: 6000
-  - Skill: MG_COLDBOLT
-    Probability: 6000
-  - Skill: MG_FROSTDIVER
-    Probability: 6000
-  - Skill: MG_FIREBALL
-    Probability: 6000
-  - Skill: MG_FIREWALL
-    Probability: 4000
-  - Skill: MG_FIREBOLT
-    Probability: 6000
-  - Skill: MG_LIGHTNINGBOLT
-    Probability: 6000
-  - Skill: MG_THUNDERSTORM
-    Probability: 4000
-  - Skill: WZ_FIREPILLAR
-    Probability: 4000
-  - Skill: WZ_METEOR
-    Probability: 4000
-  - Skill: WZ_JUPITEL
-    Probability: 6000
-  - Skill: WZ_VERMILION
-    Probability: 4000
-  - Skill: WZ_WATERBALL
-    Probability: 6000
-  - Skill: WZ_STORMGUST
-    Probability: 4000

+ 2 - 0
db/re/instance_db.yml

@@ -26,6 +26,8 @@
 #   Name              Instance Name.
 #   TimeLimit         Total lifetime of instance in seconds. (Default: 3600)
 #   IdleTimeOut       Time before an idle instance is destroyed in seconds. (Default: 300)
+#   Destroyable       Toggles the ability to destroy the instance using instance 'Destroy' button. (Default: true)
+#                     Note: the button is displayed based on parties. For any mode, it requires the party leader to be the instance owner to destroy it.
 #   Enter:            Instance entrance coordinates.
 #     Map             Map Name where players start.
 #     X               X Coordinate where players start.

+ 8 - 2
db/re/item_combo_db.txt

@@ -414,7 +414,7 @@
 29598:26158,{ .@r= getequiprefinerycnt(EQI_HAND_R)/3; bonus2 bSkillAtk,"WL_HELLINFERNO",7*.@r; bonus2 bSkillAtk,"WL_CRIMSONROCK",5*.@r; }
 29599:16095,{ .@r= getequiprefinerycnt(EQI_HAND_R)/3; bonus2 bSkillAtk,"AB_JUDEX",10*.@r; bonus2 bSkillAtk,"AB_DUPLELIGHT",5*.@r; }
 29599:2057,{ .@r= getequiprefinerycnt(EQI_HAND_R)/3; bonus2 bMagicAtkEle,Ele_Holy,5*.@r; bonus2 bSkillAtk,"AB_ADORAMUS",5*.@r; }
-29599:26161,{ .@r= getequiprefinerycnt(EQI_HAND_R)3; bonus2 bSkillAtk,"PR_MAGNUS",10*.@r; bonus2 bSkillAtk,"AB_JUDEX",5*.@r; }
+29599:26161,{ .@r= getequiprefinerycnt(EQI_HAND_R)/3; bonus2 bSkillAtk,"PR_MAGNUS",10*.@r; bonus2 bSkillAtk,"AB_JUDEX",5*.@r; }
 29600:18185,{ .@r= getequiprefinerycnt(EQI_HAND_R)/3; bonus bCritAtkRate,5*.@r; bonus2 bSkillAtk,"SN_SHARPSHOOTING",7*.@r; }
 29600:18186,{ .@r= getequiprefinerycnt(EQI_HAND_R)/3; bonus2 bSkillAtk,"RA_AIMEDBOLT",7*.@r; bonus2 bSkillUseSPrate,"RA_AIMEDBOLT",2*.@r; }
 29600:18187,{ .@r= getequiprefinerycnt(EQI_HAND_R)/3; bonus2 bSkillCooldown,"RA_UNLIMIT",-15000*.@r; bonus2 bSkillUseSPrate,"RA_ARROWSTORM",2*.@r; }
@@ -843,7 +843,7 @@
 19203:29351,{ bonus bBaseAtk,20; bonus bMatk,20; if (getskilllv("OB_OBOROGENSOU") == 5) bonus bVariableCastrate,-15; autobonus3 "{ bonus bCritAtkRate,30; }",1000,60000,"KG_KAGEMUSYA"; autobonus "{ bonus bNoSizeFix; }",50,5000,BF_WEAPON;  }
 19204:29352,{ bonus bMaxHP,500; bonus bBaseAtk,10; }
 19204:29353,{ bonus bMaxHP,1000; bonus bBaseAtk,20; skill "WS_CARTBOOST",1; autobonus3 "{ bonus bBaseAtk,30; }",1000,60000,"WS_CARTBOOST"; }
-19204:29354,{ bonus bMaxHP,1500; bonus bBaseAtk,40; skill "WS_CARTBOOST",1; autobonus3 "{ bonus bBaseAtk,50; }",1000,60000,"WS_CARTBOOST"; }
+19204:29354,{ bonus bMaxHP,1500; bonus bBaseAtk,40; skill "WS_CARTBOOST",3; autobonus3 "{ bonus bBaseAtk,50; }",1000,120000,"WS_CARTBOOST"; }
 19205:29355,{ bonus2 bSkillAtk,"SU_CN_METEOR",10; bonus2 bSkillAtk,"SU_LUNATICCARROTBEAT",10; }
 19205:29356,{ bonus2 bSkillAtk,"SU_CN_METEOR",20; bonus2 bSkillAtk,"SU_LUNATICCARROTBEAT",20; bonus bFixedCast,-200; }
 19205:29357,{ bonus2 bSkillAtk,"SU_CN_METEOR",60; bonus2 bSkillAtk,"SU_LUNATICCARROTBEAT",60; bonus bFixedCast,-500; }
@@ -1180,6 +1180,12 @@
 24396:24397:24398,{ .@r = getequiprefinerycnt(EQI_SHADOW_ARMOR) + getequiprefinerycnt(EQI_SHADOW_SHIELD) + getequiprefinerycnt(EQI_SHADOW_SHOES); bonus bMatk,.@r*2; if (.@r >= 25) { bonus bMatkRate,5; } else if (.@r >= 23) { bonus bMatkRate,2; } }
 24399:24400,{ .@r = getequiprefinerycnt(EQI_SHADOW_SHIELD) + getequiprefinerycnt(EQI_SHADOW_SHOES); if (.@r >= 16) { bonus bDef,100; bonus bMaxHPrate,4; bonus bMaxSPrate,4; } else { bonus bDef,50; bonus bMaxHPrate,2; bonus bMaxSPrate,2; } }
 24416:24417:24418:24419:24420:24421,{ bonus bAspd,2; bonus bVariableCastrate,-10; bonus2 bIgnoreDefRaceRate,RC_All,70; bonus2 bIgnoreMdefRaceRate,RC_All,70; bonus2 bIgnoreDefRaceRate,RC_Player,-70; bonus2 bIgnoreMdefRaceRate,RC_Player,-70; }
+29027:29145:29159,{ bonus2 bExpAddRace,RC_All,3; }
+29047:29359:29360,{ bonus bCritAtkRate,6; }
+29047:29359:29360:29361,{ bonus bCritical,10; }
+29053:29054:29055,{ bonus bDelayrate,-2; }
+29156:29157:29158,{ bonus bVariableCastrate,-6; }
+29156:29157:29158:29358,{ bonus bVariableCastrate,-5; }
 27101:28510,{ bonus bMatkRate,(getrefine()/3); }
 27102:28510,{ bonus bFlee2,5; }
 27103:28510,{ bonus2 bAddClass,Class_All,(getrefine()/3); }

File diff suppressed because it is too large
+ 319 - 137
db/re/item_db.txt


+ 2 - 0
db/re/item_delay.txt

@@ -99,6 +99,8 @@
 //12207,60000	//Vit_Dish10_
 22508,1200000	//Para_Team_Mark_
 
+22540,5000,SC_REUSE_LIMIT_LUXANIMA	//Runstone_Lux
+
 // Bed of Honor
 22687,5000,SC_REUSE_LIMIT_F	// Pieces_Of_Sentiment
 

+ 429 - 0
db/re/item_misc.txt

@@ -1407,3 +1407,432 @@ IG_PRIVATE_AIRSHIP,25464,1 // World_Moving_Rights
 IG_Token_Of_Siegfried,6293,1	// F_Token_Of_Siegfried
 IG_Token_Of_Siegfried,6316,1	// E_Token_Of_Siegfried
 IG_Token_Of_Siegfried,7621,1	// Token_Of_Siegfried
+
+// Enchant_Stone_Box5
+IG_Enchant_Stone_Box5,6908,2	// ASPDStone_Robe
+IG_Enchant_Stone_Box5,6642,3	// ATKStone_Middle
+IG_Enchant_Stone_Box5,6643,3	// MATKStone_Middle
+IG_Enchant_Stone_Box5,6943,3	// ATKStone_Top
+IG_Enchant_Stone_Box5,6944,3	// MATKStone_Top
+IG_Enchant_Stone_Box5,6636,4	// STRStone_Top
+IG_Enchant_Stone_Box5,6637,4	// INTStone_Top
+IG_Enchant_Stone_Box5,6638,4	// AGIStone_Top
+IG_Enchant_Stone_Box5,6639,4	// DEXStone_Top
+IG_Enchant_Stone_Box5,6640,4	// VITStone_Top
+IG_Enchant_Stone_Box5,6641,4	// LUKStone_Top
+IG_Enchant_Stone_Box5,6743,4	// HPStone_Middle
+IG_Enchant_Stone_Box5,6744,4	// SPStone_Middle
+IG_Enchant_Stone_Box5,6945,4	// STRStone_Middle
+IG_Enchant_Stone_Box5,6946,4	// INTStone_Middle
+IG_Enchant_Stone_Box5,6947,4	// AGIStone_Middle
+IG_Enchant_Stone_Box5,6948,4	// DEXStone_Middle
+IG_Enchant_Stone_Box5,6949,4	// VITStone_Middle
+IG_Enchant_Stone_Box5,6950,4	// LUKStone_Middle
+IG_Enchant_Stone_Box5,6951,4	// HPStone_Bottom
+IG_Enchant_Stone_Box5,6644,5	// HITStone_Bottom
+IG_Enchant_Stone_Box5,6645,5	// FLEEStone_Bottom
+IG_Enchant_Stone_Box5,6740,5	// HealStone_Top
+IG_Enchant_Stone_Box5,6741,5	// HealStone2_Top
+IG_Enchant_Stone_Box5,6742,5	// HealStone_Middle
+IG_Enchant_Stone_Box5,6745,5	// HealStone_Bottom
+IG_Enchant_Stone_Box5,6790,5	// BigStone_Top
+IG_Enchant_Stone_Box5,6791,5	// MediumStone_Top
+IG_Enchant_Stone_Box5,6792,5	// SmallStone_Top
+
+// Enchant_Stone_Box6
+IG_Enchant_Stone_Box6,6963,83	// HPdrainStone_Robe
+IG_Enchant_Stone_Box6,6964,83	// SPdrainStone_Robe
+IG_Enchant_Stone_Box6,6908,165	// ASPDStone_Robe
+IG_Enchant_Stone_Box6,6642,248	// ATKStone_Middle
+IG_Enchant_Stone_Box6,6643,248	// MATKStone_Middle
+IG_Enchant_Stone_Box6,6943,248	// ATKStone_Top
+IG_Enchant_Stone_Box6,6944,248	// MATKStone_Top
+IG_Enchant_Stone_Box6,6636,331	// STRStone_Top
+IG_Enchant_Stone_Box6,6637,331	// INTStone_Top
+IG_Enchant_Stone_Box6,6638,331	// AGIStone_Top
+IG_Enchant_Stone_Box6,6639,331	// DEXStone_Top
+IG_Enchant_Stone_Box6,6640,331	// VITStone_Top
+IG_Enchant_Stone_Box6,6641,331	// LUKStone_Top
+IG_Enchant_Stone_Box6,6743,331	// HPStone_Middle
+IG_Enchant_Stone_Box6,6744,331	// SPStone_Middle
+IG_Enchant_Stone_Box6,6945,331	// STRStone_Middle
+IG_Enchant_Stone_Box6,6946,331	// INTStone_Middle
+IG_Enchant_Stone_Box6,6947,331	// AGIStone_Middle
+IG_Enchant_Stone_Box6,6948,331	// DEXStone_Middle
+IG_Enchant_Stone_Box6,6949,331	// VITStone_Middle
+IG_Enchant_Stone_Box6,6950,331	// LUKStone_Middle
+IG_Enchant_Stone_Box6,6951,331	// HPStone_Bottom
+IG_Enchant_Stone_Box6,6644,413	// HITStone_Bottom
+IG_Enchant_Stone_Box6,6645,413	// FLEEStone_Bottom
+IG_Enchant_Stone_Box6,6740,413	// HealStone_Top
+IG_Enchant_Stone_Box6,6741,413	// HealStone2_Top
+IG_Enchant_Stone_Box6,6742,413	// HealStone_Middle
+IG_Enchant_Stone_Box6,6745,413	// HealStone_Bottom
+IG_Enchant_Stone_Box6,6790,413	// BigStone_Top
+IG_Enchant_Stone_Box6,6791,413	// MediumStone_Top
+IG_Enchant_Stone_Box6,6792,413	// SmallStone_Top
+
+// Enchant_Stone_Box7
+IG_Enchant_Stone_Box7,6964,85	// SPdrainStone_Robe
+IG_Enchant_Stone_Box7,6963,169	// HPdrainStone_Robe
+IG_Enchant_Stone_Box7,6999,169	// HPdrainStone_Top
+IG_Enchant_Stone_Box7,25000,169	// SPdrainStone_Top
+IG_Enchant_Stone_Box7,6642,254	// ATKStone_Middle
+IG_Enchant_Stone_Box7,6643,254	// MATKStone_Middle
+IG_Enchant_Stone_Box7,6943,254	// ATKStone_Top
+IG_Enchant_Stone_Box7,6944,254	// MATKStone_Top
+IG_Enchant_Stone_Box7,25016,254	// ATKStone_Bottom
+IG_Enchant_Stone_Box7,25017,254	// MATKStone_Bottom
+IG_Enchant_Stone_Box7,25002,339	// ChangeLUK_Middle
+IG_Enchant_Stone_Box7,25003,339	// ChangeSTR_Middle
+IG_Enchant_Stone_Box7,25004,339	// ChangeAGI_Middle
+IG_Enchant_Stone_Box7,25005,339	// ChangeINT_Middle
+IG_Enchant_Stone_Box7,25006,339	// ChangeVIT_Middle
+IG_Enchant_Stone_Box7,25007,339	// ChangeDEX_Middle
+IG_Enchant_Stone_Box7,25008,339	// ChangeVIT_Bottom
+IG_Enchant_Stone_Box7,25009,339	// ChangeAGI_Bottom
+IG_Enchant_Stone_Box7,25010,339	// ChangeDEX_Bottom
+IG_Enchant_Stone_Box7,25011,339	// ChangeLUK_Bottom
+IG_Enchant_Stone_Box7,25012,339	// ChangeSTR_Bottom
+IG_Enchant_Stone_Box7,25013,339	// ChangeINT_Bottom
+IG_Enchant_Stone_Box7,6740,424	// HealStone_Top
+IG_Enchant_Stone_Box7,6741,424	// HealStone2_Top
+IG_Enchant_Stone_Box7,6743,424	// HPStone_Middle
+IG_Enchant_Stone_Box7,6744,424	// SPStone_Middle
+IG_Enchant_Stone_Box7,6745,424	// HealStone_Bottom
+IG_Enchant_Stone_Box7,6951,424	// HPStone_Bottom
+IG_Enchant_Stone_Box7,25001,424	// DEFStone_Middle
+IG_Enchant_Stone_Box7,25014,424	// MDEFStone_Bottom
+IG_Enchant_Stone_Box7,25015,424	// EXPStone_Bottom
+
+// Enchant_Stone_Box8
+IG_Enchant_Stone_Box8,25067,37	// CastingStone_Robe
+IG_Enchant_Stone_Box8,6964,74	// SPdrainStone_Robe
+IG_Enchant_Stone_Box8,25000,74	// SPdrainStone_Top
+IG_Enchant_Stone_Box8,6963,149	// HPdrainStone_Robe
+IG_Enchant_Stone_Box8,6999,149	// HPdrainStone_Top
+IG_Enchant_Stone_Box8,25062,149	// Greed_Stone
+IG_Enchant_Stone_Box8,25068,149	// ASPDStone_Top
+IG_Enchant_Stone_Box8,25072,149	// Kyrie_Stone
+IG_Enchant_Stone_Box8,6642,223	// ATKStone_Middle
+IG_Enchant_Stone_Box8,6643,223	// MATKStone_Middle
+IG_Enchant_Stone_Box8,6943,223	// ATKStone_Top
+IG_Enchant_Stone_Box8,6944,223	// MATKStone_Top
+IG_Enchant_Stone_Box8,25016,223	// ATKStone_Bottom
+IG_Enchant_Stone_Box8,25017,223	// MATKStone_Bottom
+IG_Enchant_Stone_Box8,25058,223	// TwinkleEffect_Top
+IG_Enchant_Stone_Box8,25059,223	// GhostEffect_Middle
+IG_Enchant_Stone_Box8,25060,223	// Critical_Stone
+IG_Enchant_Stone_Box8,25061,223	// Range_Stone
+IG_Enchant_Stone_Box8,25069,223	// ReloadStone_Top
+IG_Enchant_Stone_Box8,25070,223	// ReloadStone_Middle
+IG_Enchant_Stone_Box8,25071,223	// ReloadStone_Bottom
+IG_Enchant_Stone_Box8,25002,297	// ChangeLUK_Middle
+IG_Enchant_Stone_Box8,25003,297	// ChangeSTR_Middle
+IG_Enchant_Stone_Box8,25004,297	// ChangeAGI_Middle
+IG_Enchant_Stone_Box8,25005,297	// ChangeINT_Middle
+IG_Enchant_Stone_Box8,25006,297	// ChangeVIT_Middle
+IG_Enchant_Stone_Box8,25007,297	// ChangeDEX_Middle
+IG_Enchant_Stone_Box8,25008,297	// ChangeVIT_Bottom
+IG_Enchant_Stone_Box8,25009,297	// ChangeAGI_Bottom
+IG_Enchant_Stone_Box8,25010,297	// ChangeDEX_Bottom
+IG_Enchant_Stone_Box8,25011,297	// ChangeLUK_Bottom
+IG_Enchant_Stone_Box8,25012,297	// ChangeSTR_Bottom
+IG_Enchant_Stone_Box8,25013,297	// ChangeINT_Bottom
+IG_Enchant_Stone_Box8,25001,372	// DEFStone_Middle
+IG_Enchant_Stone_Box8,25014,372	// MDEFStone_Bottom
+IG_Enchant_Stone_Box8,25015,372	// EXPStone_Bottom
+IG_Enchant_Stone_Box8,25063,372	// MaxHP2_Stone
+IG_Enchant_Stone_Box8,25064,372	// MaxSP2_Stone
+IG_Enchant_Stone_Box8,25065,372	// Detoxify_Stone
+IG_Enchant_Stone_Box8,6745,372	// HealStone_Bottom
+
+// Enchant_Stone_Box9
+IG_Enchant_Stone_Box9,6964,79	// SPdrainStone_Robe
+IG_Enchant_Stone_Box9,25000,79	// SPdrainStone_Top
+IG_Enchant_Stone_Box9,6963,159	// HPdrainStone_Robe
+IG_Enchant_Stone_Box9,6999,159	// HPdrainStone_Top
+IG_Enchant_Stone_Box9,25062,159	// Greed_Stone
+IG_Enchant_Stone_Box9,25068,159	// ASPDStone_Top
+IG_Enchant_Stone_Box9,25072,159	// Kyrie_Stone
+IG_Enchant_Stone_Box9,25138,159	// ShrinkEffect_Middle
+IG_Enchant_Stone_Box9,6642,238	// ATKStone_Middle
+IG_Enchant_Stone_Box9,6643,238	// MATKStone_Middle
+IG_Enchant_Stone_Box9,6943,238	// ATKStone_Top
+IG_Enchant_Stone_Box9,6944,238	// MATKStone_Top
+IG_Enchant_Stone_Box9,25016,238	// ATKStone_Bottom
+IG_Enchant_Stone_Box9,25017,238	// MATKStone_Bottom
+IG_Enchant_Stone_Box9,25060,238	// Critical_Stone
+IG_Enchant_Stone_Box9,25061,238	// Range_Stone
+IG_Enchant_Stone_Box9,25069,238	// ReloadStone_Top
+IG_Enchant_Stone_Box9,25070,238	// ReloadStone_Middle
+IG_Enchant_Stone_Box9,25071,238	// ReloadStone_Bottom
+IG_Enchant_Stone_Box9,25136,238	// ElectricEffect_Middle
+IG_Enchant_Stone_Box9,25137,238	// GreenFloor_Bottom
+IG_Enchant_Stone_Box9,25002,317	// ChangeLUK_Middle
+IG_Enchant_Stone_Box9,25003,317	// ChangeSTR_Middle
+IG_Enchant_Stone_Box9,25004,317	// ChangeAGI_Middle
+IG_Enchant_Stone_Box9,25005,317	// ChangeINT_Middle
+IG_Enchant_Stone_Box9,25006,317	// ChangeVIT_Middle
+IG_Enchant_Stone_Box9,25007,317	// ChangeDEX_Middle
+IG_Enchant_Stone_Box9,25008,317	// ChangeVIT_Bottom
+IG_Enchant_Stone_Box9,25009,317	// ChangeAGI_Bottom
+IG_Enchant_Stone_Box9,25010,317	// ChangeDEX_Bottom
+IG_Enchant_Stone_Box9,25011,317	// ChangeLUK_Bottom
+IG_Enchant_Stone_Box9,25012,317	// ChangeSTR_Bottom
+IG_Enchant_Stone_Box9,25013,317	// ChangeINT_Bottom
+IG_Enchant_Stone_Box9,25015,397	// EXPStone_Bottom
+IG_Enchant_Stone_Box9,25063,397	// MaxHP2_Stone
+IG_Enchant_Stone_Box9,25064,397	// MaxSP2_Stone
+IG_Enchant_Stone_Box9,25139,397	// Identify_Stone
+IG_Enchant_Stone_Box9,25141,397	// EXPStone_Middle
+
+// Enchant_Stone_Box10
+IG_Enchant_Stone_Box10,6964,78	// SPdrainStone_Robe
+IG_Enchant_Stone_Box10,25000,78	// SPdrainStone_Top
+IG_Enchant_Stone_Box10,6999,156	// HPdrainStone_Top
+IG_Enchant_Stone_Box10,25062,156	// Greed_Stone
+IG_Enchant_Stone_Box10,25068,156	// ASPDStone_Top
+IG_Enchant_Stone_Box10,25072,156	// Kyrie_Stone
+IG_Enchant_Stone_Box10,25170,156	// MinorCastingStone_Robe
+IG_Enchant_Stone_Box10,25175,156	// LexAeternaStone_Middle
+IG_Enchant_Stone_Box10,25176,156	// BlueAuraEffect_Middle
+IG_Enchant_Stone_Box10,6642,234	// ATKStone_Middle
+IG_Enchant_Stone_Box10,6643,234	// MATKStone_Middle
+IG_Enchant_Stone_Box10,6943,234	// ATKStone_Top
+IG_Enchant_Stone_Box10,6944,234	// MATKStone_Top
+IG_Enchant_Stone_Box10,25016,234	// ATKStone_Bottom
+IG_Enchant_Stone_Box10,25017,234	// MATKStone_Bottom
+IG_Enchant_Stone_Box10,25060,234	// Critical_Stone
+IG_Enchant_Stone_Box10,25061,234	// Range_Stone
+IG_Enchant_Stone_Box10,25172,234	// CastingStone_Top
+IG_Enchant_Stone_Box10,25173,234	// CastingStone_Middle
+IG_Enchant_Stone_Box10,25174,234	// CastingStone_Bottom
+IG_Enchant_Stone_Box10,25176,234	// BlueAuraEffect_Middle
+IG_Enchant_Stone_Box10,25178,234	// PinkGlowEffect_Middle
+IG_Enchant_Stone_Box10,25002,312	// ChangeLUK_Middle
+IG_Enchant_Stone_Box10,25003,312	// ChangeSTR_Middle
+IG_Enchant_Stone_Box10,25004,312	// ChangeAGI_Middle
+IG_Enchant_Stone_Box10,25005,312	// ChangeINT_Middle
+IG_Enchant_Stone_Box10,25006,312	// ChangeVIT_Middle
+IG_Enchant_Stone_Box10,25007,312	// ChangeDEX_Middle
+IG_Enchant_Stone_Box10,25008,312	// ChangeVIT_Bottom
+IG_Enchant_Stone_Box10,25009,312	// ChangeAGI_Bottom
+IG_Enchant_Stone_Box10,25010,312	// ChangeDEX_Bottom
+IG_Enchant_Stone_Box10,25011,312	// ChangeLUK_Bottom
+IG_Enchant_Stone_Box10,25012,312	// ChangeSTR_Bottom
+IG_Enchant_Stone_Box10,25013,312	// ChangeINT_Bottom
+IG_Enchant_Stone_Box10,25015,391	// EXPStone_Bottom
+IG_Enchant_Stone_Box10,25063,391	// MaxHP2_Stone
+IG_Enchant_Stone_Box10,25064,391	// MaxSP2_Stone
+IG_Enchant_Stone_Box10,25141,391	// EXPStone_Middle
+IG_Enchant_Stone_Box10,25171,391	// EXPStone_Top
+
+// Enchant_Stone_Box11
+IG_Enchant_Stone_Box11,25067,2	// CastingStone_Robe
+IG_Enchant_Stone_Box11,6964,8	// SPdrainStone_Robe
+IG_Enchant_Stone_Box11,25000,8	// SPdrainStone_Top
+IG_Enchant_Stone_Box11,6908,16	// ASPDStone_Robe
+IG_Enchant_Stone_Box11,6963,16	// HPdrainStone_Robe
+IG_Enchant_Stone_Box11,6999,16	// HPdrainStone_Top
+IG_Enchant_Stone_Box11,25068,16	// ASPDStone_Top
+IG_Enchant_Stone_Box11,25170,16	// MinorCastingStone_Robe
+IG_Enchant_Stone_Box11,25224,16	// WhiteBodyEffect_Middle
+IG_Enchant_Stone_Box11,6642,24	// ATKStone_Middle
+IG_Enchant_Stone_Box11,6643,24	// MATKStone_Middle
+IG_Enchant_Stone_Box11,6943,24	// ATKStone_Top
+IG_Enchant_Stone_Box11,6944,24	// MATKStone_Top
+IG_Enchant_Stone_Box11,25016,24	// ATKStone_Bottom
+IG_Enchant_Stone_Box11,25017,24	// MATKStone_Bottom
+IG_Enchant_Stone_Box11,25060,24	// Critical_Stone
+IG_Enchant_Stone_Box11,25061,24	// Range_Stone
+IG_Enchant_Stone_Box11,25225,24	// ExplodingEffect_Middle
+IG_Enchant_Stone_Box11,25226,24	// WaterFieldEffect_Bottom
+IG_Enchant_Stone_Box11,25227,24	// Heal_Stone
+IG_Enchant_Stone_Box11,25228,24	// Teleport_Stone
+IG_Enchant_Stone_Box11,25229,24	// Steal_Stone
+IG_Enchant_Stone_Box11,25002,32	// ChangeLUK_Middle
+IG_Enchant_Stone_Box11,25003,32	// ChangeSTR_Middle
+IG_Enchant_Stone_Box11,25004,32	// ChangeAGI_Middle
+IG_Enchant_Stone_Box11,25005,32	// ChangeINT_Middle
+IG_Enchant_Stone_Box11,25006,32	// ChangeVIT_Middle
+IG_Enchant_Stone_Box11,25007,32	// ChangeDEX_Middle
+IG_Enchant_Stone_Box11,25008,32	// ChangeVIT_Bottom
+IG_Enchant_Stone_Box11,25009,32	// ChangeAGI_Bottom
+IG_Enchant_Stone_Box11,25010,32	// ChangeDEX_Bottom
+IG_Enchant_Stone_Box11,25011,32	// ChangeLUK_Bottom
+IG_Enchant_Stone_Box11,25012,32	// ChangeSTR_Bottom
+IG_Enchant_Stone_Box11,25013,32	// ChangeINT_Bottom
+IG_Enchant_Stone_Box11,25015,38	// EXPStone_Bottom
+IG_Enchant_Stone_Box11,25063,38	// MaxHP2_Stone
+IG_Enchant_Stone_Box11,25064,38	// MaxSP2_Stone
+IG_Enchant_Stone_Box11,25141,38	// EXPStone_Middle
+IG_Enchant_Stone_Box11,25171,38	// EXPStone_Top
+
+// Enchant_Stone_Box12
+IG_Enchant_Stone_Box12,25067,2	// CastingStone_Robe
+IG_Enchant_Stone_Box12,25302,2	// DoubleAttack_Stone
+IG_Enchant_Stone_Box12,25303,2	// Critical_Stone_Robe
+IG_Enchant_Stone_Box12,6964,8	// SPdrainStone_Robe
+IG_Enchant_Stone_Box12,25000,8	// SPdrainStone_Top
+IG_Enchant_Stone_Box12,25205,8	// ShrinkEffect_Bottom
+IG_Enchant_Stone_Box12,25306,8	// CastStone_Robe
+IG_Enchant_Stone_Box12,6908,16	// ASPDStone_Robe
+IG_Enchant_Stone_Box12,6963,16	// HPdrainStone_Robe
+IG_Enchant_Stone_Box12,6999,16	// HPdrainStone_Top
+IG_Enchant_Stone_Box12,25068,16	// ASPDStone_Top
+IG_Enchant_Stone_Box12,25170,16	// MinorCastingStone_Robe
+IG_Enchant_Stone_Box12,6642,24	// ATKStone_Middle
+IG_Enchant_Stone_Box12,6643,24	// MATKStone_Middle
+IG_Enchant_Stone_Box12,6943,24	// ATKStone_Top
+IG_Enchant_Stone_Box12,6944,24	// MATKStone_Top
+IG_Enchant_Stone_Box12,25015,24	// EXPStone_Bottom
+IG_Enchant_Stone_Box12,25016,24	// ATKStone_Bottom
+IG_Enchant_Stone_Box12,25017,24	// MATKStone_Bottom
+IG_Enchant_Stone_Box12,25061,24	// Range_Stone
+IG_Enchant_Stone_Box12,25141,24	// EXPStone_Middle
+IG_Enchant_Stone_Box12,25171,24	// EXPStone_Top
+IG_Enchant_Stone_Box12,25172,24	// CastingStone_Top
+IG_Enchant_Stone_Box12,25173,24	// CastingStone_Middle
+IG_Enchant_Stone_Box12,25174,24	// CastingStone_Bottom
+IG_Enchant_Stone_Box12,25002,38	// ChangeLUK_Middle
+IG_Enchant_Stone_Box12,25003,38	// ChangeSTR_Middle
+IG_Enchant_Stone_Box12,25004,38	// ChangeAGI_Middle
+IG_Enchant_Stone_Box12,25005,38	// ChangeINT_Middle
+IG_Enchant_Stone_Box12,25006,38	// ChangeVIT_Middle
+IG_Enchant_Stone_Box12,25007,38	// ChangeDEX_Middle
+IG_Enchant_Stone_Box12,25008,38	// ChangeVIT_Bottom
+IG_Enchant_Stone_Box12,25009,38	// ChangeAGI_Bottom
+IG_Enchant_Stone_Box12,25010,38	// ChangeDEX_Bottom
+IG_Enchant_Stone_Box12,25011,38	// ChangeLUK_Bottom
+IG_Enchant_Stone_Box12,25012,38	// ChangeSTR_Bottom
+IG_Enchant_Stone_Box12,25013,38	// ChangeINT_Bottom
+IG_Enchant_Stone_Box12,25060,38	// Critical_Stone
+IG_Enchant_Stone_Box12,25304,38	// Critical_Stone_Top
+IG_Enchant_Stone_Box12,25305,38	// Critical_Stone_Bottom
+
+// Enchant_Stone_Box13
+IG_Enchant_Stone_Box13,25067,2	// CastingStone_Robe
+IG_Enchant_Stone_Box13,25302,2	// DoubleAttack_Stone
+IG_Enchant_Stone_Box13,25303,2	// Critical_Stone_Robe
+IG_Enchant_Stone_Box13,6964,8	// SPdrainStone_Robe
+IG_Enchant_Stone_Box13,25000,8	// SPdrainStone_Top
+IG_Enchant_Stone_Box13,25205,8	// ShrinkEffect_Bottom
+IG_Enchant_Stone_Box13,25306,8	// CastStone_Robe
+IG_Enchant_Stone_Box13,6908,16	// ASPDStone_Robe
+IG_Enchant_Stone_Box13,6963,16	// HPdrainStone_Robe
+IG_Enchant_Stone_Box13,6999,16	// HPdrainStone_Top
+IG_Enchant_Stone_Box13,25068,16	// ASPDStone_Top
+IG_Enchant_Stone_Box13,25170,16	// MinorCastingStone_Robe
+IG_Enchant_Stone_Box13,25412,16	// SuraStone_Robe
+IG_Enchant_Stone_Box13,25416,16	// RangerStone_Robe
+IG_Enchant_Stone_Box13,25420,16	// SorcererStone_Robe
+IG_Enchant_Stone_Box13,25015,24	// EXPStone_Bottom
+IG_Enchant_Stone_Box13,25061,24	// Range_Stone
+IG_Enchant_Stone_Box13,25141,24	// EXPStone_Middle
+IG_Enchant_Stone_Box13,25171,24	// EXPStone_Top
+IG_Enchant_Stone_Box13,25172,24	// CastingStone_Top
+IG_Enchant_Stone_Box13,25173,24	// CastingStone_Middle
+IG_Enchant_Stone_Box13,25174,24	// CastingStone_Bottom
+IG_Enchant_Stone_Box13,6642,37	// ATKStone_Middle
+IG_Enchant_Stone_Box13,6643,37	// MATKStone_Middle
+IG_Enchant_Stone_Box13,6943,37	// ATKStone_Top
+IG_Enchant_Stone_Box13,6944,37	// MATKStone_Top
+IG_Enchant_Stone_Box13,25016,37	// ATKStone_Bottom
+IG_Enchant_Stone_Box13,25017,37	// MATKStone_Bottom
+IG_Enchant_Stone_Box13,25060,37	// Critical_Stone
+IG_Enchant_Stone_Box13,25304,37	// Critical_Stone_Top
+IG_Enchant_Stone_Box13,25305,37	// Critical_Stone_Bottom
+IG_Enchant_Stone_Box13,25409,37	// SuraStone_Top
+IG_Enchant_Stone_Box13,25410,37	// SuraStone_Middle
+IG_Enchant_Stone_Box13,25411,37	// SuraStone_Lower
+IG_Enchant_Stone_Box13,25413,37	// RangerStone_Top
+IG_Enchant_Stone_Box13,25414,37	// RangerStone_Middle
+IG_Enchant_Stone_Box13,25415,37	// RangerStone_Lower
+IG_Enchant_Stone_Box13,25417,37	// SorcererStone_Top
+IG_Enchant_Stone_Box13,25418,37	// SorcererStone_Middle
+IG_Enchant_Stone_Box13,25419,37	// SorcererStone_Lower
+
+// Enchant_Stone_Box14
+IG_Enchant_Stone_Box14,25067,2	// CastingStone_Robe
+IG_Enchant_Stone_Box14,25302,2	// DoubleAttack_Stone
+IG_Enchant_Stone_Box14,25303,2	// Critical_Stone_Robe
+IG_Enchant_Stone_Box14,6964,8	// SPdrainStone_Robe
+IG_Enchant_Stone_Box14,25000,8	// SPdrainStone_Top
+IG_Enchant_Stone_Box14,25205,8	// ShrinkEffect_Bottom
+IG_Enchant_Stone_Box14,25306,8	// CastStone_Robe
+IG_Enchant_Stone_Box14,6908,16	// ASPDStone_Robe
+IG_Enchant_Stone_Box14,6963,16	// HPdrainStone_Robe
+IG_Enchant_Stone_Box14,6999,16	// HPdrainStone_Top
+IG_Enchant_Stone_Box14,25068,16	// ASPDStone_Top
+IG_Enchant_Stone_Box14,25170,16	// MinorCastingStone_Robe
+IG_Enchant_Stone_Box14,25448,16	// RuneknightStone_Robe
+IG_Enchant_Stone_Box14,25449,16	// GeneticStone_Robe
+IG_Enchant_Stone_Box14,25456,16	// WarlockStone_Robe
+IG_Enchant_Stone_Box14,25015,24	// EXPStone_Bottom
+IG_Enchant_Stone_Box14,25061,24	// Range_Stone
+IG_Enchant_Stone_Box14,25141,24	// EXPStone_Middle
+IG_Enchant_Stone_Box14,25171,24	// EXPStone_Top
+IG_Enchant_Stone_Box14,25172,24	// CastingStone_Top
+IG_Enchant_Stone_Box14,25173,24	// CastingStone_Middle
+IG_Enchant_Stone_Box14,25174,24	// CastingStone_Bottom
+IG_Enchant_Stone_Box14,6642,37	// ATKStone_Middle
+IG_Enchant_Stone_Box14,6643,37	// MATKStone_Middle
+IG_Enchant_Stone_Box14,6943,37	// ATKStone_Top
+IG_Enchant_Stone_Box14,6944,37	// MATKStone_Top
+IG_Enchant_Stone_Box14,25016,37	// ATKStone_Bottom
+IG_Enchant_Stone_Box14,25017,37	// MATKStone_Bottom
+IG_Enchant_Stone_Box14,25060,37	// Critical_Stone
+IG_Enchant_Stone_Box14,25304,37	// Critical_Stone_Top
+IG_Enchant_Stone_Box14,25305,37	// Critical_Stone_Bottom
+IG_Enchant_Stone_Box14,25445,37	// RuneknightStone_Top
+IG_Enchant_Stone_Box14,25446,37	// RuneknightStone_Middle
+IG_Enchant_Stone_Box14,25447,37	// RuneknightStone_Lower
+IG_Enchant_Stone_Box14,25450,37	// GeneticStone_Top
+IG_Enchant_Stone_Box14,25451,37	// GeneticStone_Middle
+IG_Enchant_Stone_Box14,25452,37	// GeneticStone_Lower
+IG_Enchant_Stone_Box14,25453,37	// WarlockStone_Top
+IG_Enchant_Stone_Box14,25454,37	// WarlockStone_Middle
+IG_Enchant_Stone_Box14,25455,37	// WarlockStone_Lower
+
+// Enchant_Stone_Box15
+IG_Enchant_Stone_Box15,25067,2	// CastingStone_Robe
+IG_Enchant_Stone_Box15,25302,2	// DoubleAttack_Stone
+IG_Enchant_Stone_Box15,25303,2	// Critical_Stone_Robe
+IG_Enchant_Stone_Box15,6964,8	// SPdrainStone_Robe
+IG_Enchant_Stone_Box15,25000,8	// SPdrainStone_Top
+IG_Enchant_Stone_Box15,25205,8	// ShrinkEffect_Bottom
+IG_Enchant_Stone_Box15,25306,8	// CastStone_Robe
+IG_Enchant_Stone_Box15,6908,16	// ASPDStone_Robe
+IG_Enchant_Stone_Box15,6963,16	// HPdrainStone_Robe
+IG_Enchant_Stone_Box15,6999,16	// HPdrainStone_Top
+IG_Enchant_Stone_Box15,25068,16	// ASPDStone_Top
+IG_Enchant_Stone_Box15,25170,16	// MinorCastingStone_Robe
+IG_Enchant_Stone_Box15,25493,16	// ShadowchaserStone_Robe
+IG_Enchant_Stone_Box15,25497,16	// MechanicStone_Robe
+IG_Enchant_Stone_Box15,25501,16	// WanderMinstrelStone_Robe
+IG_Enchant_Stone_Box15,25015,24	// EXPStone_Bottom
+IG_Enchant_Stone_Box15,25061,24	// Range_Stone
+IG_Enchant_Stone_Box15,25141,24	// EXPStone_Middle
+IG_Enchant_Stone_Box15,25171,24	// EXPStone_Top
+IG_Enchant_Stone_Box15,25172,24	// CastingStone_Top
+IG_Enchant_Stone_Box15,25173,24	// CastingStone_Middle
+IG_Enchant_Stone_Box15,25174,24	// CastingStone_Bottom
+IG_Enchant_Stone_Box15,6642,37	// ATKStone_Middle
+IG_Enchant_Stone_Box15,6643,37	// MATKStone_Middle
+IG_Enchant_Stone_Box15,6943,37	// ATKStone_Top
+IG_Enchant_Stone_Box15,6944,37	// MATKStone_Top
+IG_Enchant_Stone_Box15,25016,37	// ATKStone_Bottom
+IG_Enchant_Stone_Box15,25017,37	// MATKStone_Bottom
+IG_Enchant_Stone_Box15,25060,37	// Critical_Stone
+IG_Enchant_Stone_Box15,25304,37	// Critical_Stone_Top
+IG_Enchant_Stone_Box15,25305,37	// Critical_Stone_Bottom
+IG_Enchant_Stone_Box15,25490,37	// ShadowchaserStone_Top
+IG_Enchant_Stone_Box15,25491,37	// ShadowchaserStone_Middle
+IG_Enchant_Stone_Box15,25492,37	// ShadowchaserStone_Lower
+IG_Enchant_Stone_Box15,25494,37	// MechanicStone_Top
+IG_Enchant_Stone_Box15,25495,37	// MechanicStone_Middle
+IG_Enchant_Stone_Box15,25496,37	// MechanicStone_Lower
+IG_Enchant_Stone_Box15,25498,37	// WanderMinstrelStone_Top
+IG_Enchant_Stone_Box15,25499,37	// WanderMinstrelStone_Middle
+IG_Enchant_Stone_Box15,25500,37	// WanderMinstrelStone_Lower

+ 0 - 9
db/re/item_stack.txt

@@ -17,14 +17,5 @@
 // Example:
 // 512,4,12  // Will not allow more than 4 Apples in storages.
 
-// Rune Knight
-12725,60,1  // Nauthiz Rune
-12726,60,1  // Raido Rune
-12727,60,1  // Berkana Rune
-12728,60,1  // Isa Rune
-12730,60,1  // Uruz Rune
-12733,60,1  // Hagalaz Rune
-22540,60,1  // Lux Anima Rune
-
 // Arch Bishop
 12333,3,1  // Ancilla

+ 1 - 1
db/re/job_db1.txt

@@ -262,7 +262,7 @@
 // Baby Mechanic (Mado)
 4112,	30000,90   ,500  ,400  ,40  ,60  ,65  ,200 ,200 ,200 ,45  ,48  ,48  ,50  ,200 ,200 ,200 ,200 ,200 ,200 ,200 ,200 ,200 ,200 ,200 ,200 ,200 ,200 ,6
 // Super Novice (Expanded)
-4190,	20000,0    ,500  ,100  ,40  ,55  ,57  ,200 ,200 ,200 ,50  ,200 ,50  ,55  ,65  ,200 ,200 ,200 ,200 ,200 ,200 ,200 ,200 ,200 ,200 ,200 ,200 ,65  ,10
+4190,	20000,0    ,5000 ,500  ,40  ,55  ,57  ,200 ,200 ,200 ,50  ,200 ,50  ,55  ,65  ,200 ,200 ,200 ,200 ,200 ,200 ,200 ,200 ,200 ,200 ,200 ,200 ,65  ,10
 // Super Baby (Expanded)
 4191,	20000,0    ,500  ,100  ,40  ,55  ,57  ,200 ,200 ,200 ,50  ,200 ,50  ,55  ,65  ,200 ,200 ,200 ,200 ,200 ,200 ,200 ,200 ,200 ,200 ,200 ,200 ,65  ,10
 // Kagerou

+ 192 - 8
db/re/mob_db.txt

@@ -302,7 +302,7 @@
 1290,SKELETON_GENERAL,Skeleton General,Skeleton General,88,6720,0,1368,1553,1,1317,1701,100,35,72,34,52,31,84,25,10,12,1,1,29,0x3695,150,2276,576,432,0,0,0,0,0,0,0,7068,2550,756,160,508,800,0,0,1219,80,13035,15,2274,1,0,0,0,0,4221,1
 1291,WRAITH_DEAD,Wraith Dead,Wraith Dead,86,10035,0,2518,1824,2,1002,160,88,56,63,69,55,45,88,45,10,12,2,1,89,0x3695,175,1816,576,240,0,0,0,0,0,0,0,1059,4413,2206,10,2506,8,716,700,732,5,603,100,568,300,0,0,0,0,4189,1
 1292,MINI_DEMON,Mini Demon,Mini Demon,117,19402,1,2700,2025,1,938,114,80,25,130,69,55,56,79,40,10,12,0,6,27,0x2003695,150,1000,600,384,0,0,0,0,0,0,0,1038,4413,1039,450,2255,3,757,160,912,2500,1009,10,1478,5,0,0,0,0,4204,1
-1293,CREMY_FEAR,Creamy Fear,Creamy Fear,77,3420,0,945,1067,2,757,110,76,37,65,36,33,49,66,30,10,12,0,4,24,0x2003695,155,1136,720,840,0,0,0,0,0,0,0,924,4550,2333,10,518,550,602,200,1550,8,2726,5,522,50,0,0,0,0,4298,1
+1293,CREMY_FEAR,Creamy Fear,Creamy Fear,117,18211,0,2583,2475,2,731,243,76,37,65,36,33,49,79,30,10,12,0,4,24,0x2003695,155,1136,720,840,0,0,0,0,0,0,0,924,4550,2333,10,518,550,2899,1,12676,8,2726,5,522,50,0,0,0,0,4298,1
 1294,KILLER_MANTIS,Killer Mantis,Killer Mantis,91,7650,0,1485,1674,1,1521,1201,107,45,82,56,58,45,69,40,10,12,1,4,22,0x2003695,175,1528,660,432,0,0,0,0,0,0,0,1031,4550,943,2500,721,10,509,15,514,25,1262,1,2108,1,0,0,0,0,4301,1
 1295,OWL_BARON,Owl Baron,Owl Baron,120,21000,1,3042,2282,2,629,201,88,25,72,65,55,102,77,72,10,12,2,6,60,0x6203695,175,1345,824,440,0,0,0,0,0,0,0,7071,3500,7063,2500,0,0,1472,1,1629,2,693,100,5045,5,0,0,0,0,4238,1
 1296,KOBOLD_LEADER,Kobold Leader,Kobold Leader,112,13520,1,2643,2383,1,995,96,90,62,135,34,68,56,83,47,10,12,1,7,44,0x3695,150,1028,528,360,0,0,0,0,0,0,0,999,450,1034,6305,912,1200,0,0,1613,2,525,150,526,100,0,0,0,0,4291,1
@@ -2096,10 +2096,10 @@
 2936,E_GHOSTRING,Ghostring,Ghostring,1,10,0,0,0,1,1,1,100,99,0,0,0,0,0,0,7,12,0,3,20,0x0,300,1220,1080,648,0,0,0,0,0,0,0,535,1500,535,1500,535,1500,535,1500,12192,2000,7225,2000,6658,500,0,0,0,0,6658,10000
 //2937,M_LOKI,M Loki,M Loki,145,1215600,1,1,1,2,1835,444,15,89,76,66,90,55,189,22,10,12,1,7,20,0x0,175,800,750,300,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
 2938,MM_MAGIC_SEAL,Magic Seal,Magic Seal,140,10000000,1,1,6999,1,1,1,80,200,16,26,30,115,79,5,10,12,2,0,20,0x0,300,1000,1000,1000,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
-2939,MM_EVIL_SHADOW1,Evil Shadow,Evil Shadow,138,112000,1,7456,5983,1,3266,1307,30,30,88,44,88,21,95,44,10,12,2,6,47,0x2000085,200,1500,600,500,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
-2940,MM_EVIL_SHADOW2,Evil Shadow,Evil Shadow,141,127650,1,8103,7738,1,2678,1071,121,36,60,103,45,35,172,15,10,12,1,6,47,0x2000085,200,1000,500,600,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
-2941,MM_EVIL_SHADOW3,Evil Shadow,Evil Shadow,142,153400,1,8863,6736,1,3167,1267,89,44,120,87,66,33,106,27,10,12,2,6,47,0x2000085,200,1800,780,480,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
-2942,MM_EVIL_FANATICS,Evil Fanatics,Evil Fanatics,151,8256000,1,1008653,988954,3,3350,167,166,103,118,72,40,55,213,30,10,12,2,6,67,0x6280085,200,1000,500,350,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
+2939,MM_EVIL_SHADOW1,Evil Shadow,Evil Shadow,138,112000,1,7456,5983,1,3266,1307,30,30,88,44,88,21,95,44,10,12,2,6,47,0x2000085,200,1500,600,500,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,27264,1
+2940,MM_EVIL_SHADOW2,Evil Shadow,Evil Shadow,141,127650,1,8103,7738,1,2678,1071,121,36,60,103,45,35,172,15,10,12,1,6,47,0x2000085,200,1000,500,600,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,27264,1
+2941,MM_EVIL_SHADOW3,Evil Shadow,Evil Shadow,142,153400,1,8863,6736,1,3167,1267,89,44,120,87,66,33,106,27,10,12,2,6,47,0x2000085,200,1800,780,480,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,27264,1
+2942,MM_EVIL_FANATICS,Evil Fanatics,Evil Fanatics,151,8256000,1,1008653,988954,3,3350,167,166,103,118,72,40,55,213,30,10,12,2,6,67,0x6280085,200,1000,500,350,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,27265,1
 2943,MM_ICE_MINE,Icemine,Icemine,149,10000,200,0,0,7,200,1,200,10,200,200,200,200,200,200,12,12,0,4,88,0xE170000,2000,0,1000,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,0
 //2944,J_HORNET
 //2945,J_MUMMY
@@ -3946,12 +3946,42 @@
 //20813,MD_EVENT_AMDARAIS
 //20814,G_PAYONSOLDIER
 //20815,G_PAYONSOLDIER2
-
+//20816,EM_DILUVIO
+//20817,EM_ARDOR
+//20818,EM_PROCELLA
+//20819,EM_TERREMOTUS
+//20820,EM_SERPENS
+//20821,4JOB_VOID
+//20822,4JOB_WRAITH
+//20823,4JOB_KINGS_NIGHT
+//20824,4JOB_AGONY_NIGHT
+//20825,4JOB_DEVOTION_NIGHT
+//20826,4JOB_ARMED_NIGHT
+//20827,4JOB_DOOMK
+//20828,4JOB_VERKHASEL
+//20829,4JOB_BAPHOMET
+//20830,4JOB_H_FALCON
+//20831,4JOB_S_FALCON
+//20832,4JOB_R_FALCON
+//20833,4JOB_WORG
+//20834,MEISTER_ABR1
+//20835,MEISTER_ABR2
+//20836,MEISTER_ABR3
+//20837,MEISTER_ABR4
+//20838,ELEMETAL_MASTER_S1
+//20839,ELEMETAL_MASTER_S2
+//20840,ELEMETAL_MASTER_S3
+//20841,ELEMETAL_MASTER_S4
+//20842,ELEMETAL_MASTER_S5
 //20843,ILL_ABYSMAL_WITCH
 //20844,PRAY_GIVER
 //20845,SMILE_GIVER
 //20846,MD_HIDDEN_GROUND01
 //20847,MD_HIDDEN_GROUND02
+//20848,SUMMON_WOODENWARRIOR
+//20849,SUMMON_WOODEN_FAIRY
+//20850,SUMMON_CREEPER
+//20851,SUMMON_HELLTREE
 
 //20856,MD_N_ARENA_1
 //20857,MD_N_ARENA_2
@@ -3972,7 +4002,8 @@
 //20872,MD_GEFFEN_FENRIR_N
 //20873,WAR_NUT
 //20874,MOLE_TW
-
+//20875,4JOB_LETICIA
+//20876,4JOB_ACIDUS
 //20877,G_ILL_SROPHO
 //20878,G_ILL_OBEAUNE
 //20879,G_ILL_DEVIACE
@@ -3982,8 +4013,161 @@
 //20883,G_ILL_SWORD_FISH
 //20884,G_ILL_STROUF
 //20885,G_ILL_PHEN
-
+//20886,MD_Airboat_Tree
+//20887,MD_Airboat_Poring
+//20888,MD_Airboat_Worm
+//20889,MD_Airboat_LEECH
+//20890,MD_Airboat_Mos
+//20891,MD_Airboat_Boss
+//20892,MD_SAKRAY
+//20893,MD_TIARA
+//20894,MD_UNDEAD_KNIGHT
+//20895,MD_UNDEAD_SOLDIER
+//20896,MD_UNDEAD_ARCHER
+//20897,MD_UNDEAD_WIZARD
+//20898,MD_UNDEAD_MAGICIAN
+//20899,MD_UNDEAD_NOBLE
+//20900,MD_UNDEAD_SERVANT
+//20901,DISASTER_OMEN
+//20902,DISASTER_WIND
+//20903,CONQUER_INCARNATION
+//20904,FAMINE_INCARNATION
+//20905,APPETITE_INCARNATION
+//20906,DISASTER_SYMBOL
+//20907,DEVIL_EYE
+//20908,WAR_INCARNATION
+//20909,DEATH_INCARNATION
+//20910,CARNIVOROUS
+//20911,SINS_JUSTICE
+//20912,SINS_BRAVE
+//20913,SINS_MODERATION
+//20914,SINS_WISDOM
+//20915,G_SINS_JUSTICE
+//20916,G_SINS_BRAVE
+//20917,G_SINS_MODERATION
+//20918,G_SINS_WISDOM
 //20919,CARAT_TWEVENT
+//20920,CHIMERA_LAVA
+//20921,CHIMERA_FULGOR
+//20922,CHIMERA_NAPEO
+//20923,CHIMERA_GALENSIS
+//20924,CHIMERA_AMITERA
+//20925,CHIMERA_LITUS
+//20926,CHIMERA_FILLIA
+//20927,CHIMERA_VANILAQUS
+//20928,CHIMERA_THEONE
+//20929,GIANT_CAPUT
+//20930,DOLORIAN
+//20931,PLAGARION
+//20932,DEADRE
+//20933,VENEDI
+//20934,R001_BESTIA
+//20935,GAN_CEANN
+//20936,DISGUISER
+//20937,BRUTAL_MURDERER
+//20938,GHOST_CUBE
+//20939,LUDE_GAL
+//20940,BLUEMOON_LOLI_RURI
+//20941,GROTE
+//20942,PIERROTZOIST
+//20943,DEATH_WITCH
+
+//20994,MD_BETELGEUSE
+//20995,MD_G_DEADSOUL
+//20996,MD_NAGHT_SIEGER
+//20997,MD_G_ENTWEIHEN_M
+//20998,MD_T_JAKK
+//20999,MD_T_STONE_SHOOTER
+//21000,MD_T_GRIZZLY
+//21001,MD_T_STALACTIC_GOLEM
+//21002,MD_T_CHIMERA
+//21003,MD_T_KARAKASA
+//21004,MD_T_RIDEWORD
+//21005,MD_T_PARASITE
+//21006,MD_T_WRAITH
+//21007,MD_T_PETIT_
+//21008,MD_T_WIND_GHOST
+//21009,MD_T_CLOCK
+//21010,MD_T_RAYDRIC_ARCHER
+//21011,MD_T_INCREASE_SOIL
+//21012,MD_T_PENOMENA
+//21013,MD_T_PETIT
+//21014,MD_T_ALARM
+//21015,MD_T_ZOMBIE_PRISONER
+//21016,MD_T_MARIONETTE
+//21017,MD_T_PERMETER
+//21018,MD_T_SKEL_PRISONER
+//21019,MD_T_OWL_DUKE
+//21020,MD_T_DEVIRUCHI
+//21021,MD_T_BLOOD_BUTTERFLY
+//21022,MD_T_STAPO
+//21023,MD_T_EVIL_CLOUD_HERMIT
+//21024,MD_T_THE_PAPER
+//21025,MD_T_TENGU
+//21026,MD_T_ALICE
+//21027,MD_T_ANACONDAQ
+//21028,MD_T_GARGOYLE
+//21029,MD_T_CARAT
+//21030,MD_T_STING
+//21031,MD_T_GRYPHON
+//21032,MD_T_GIBBET
+//21033,MD_T_NIGHTMARE_TERROR
+//21034,MD_T_ANOLIAN
+//21035,MD_T_BLOODY_MURDERER
+//21036,MD_T_ALIOT
+//21037,MD_T_VENATU
+//21038,MD_T_DEATHWORD
+//21039,MD_T_PLASMA_B
+//21040,MD_T_DIMIK
+//21041,MD_T_MINI_DEMON
+//21042,MD_T_LEIB_OLMAI
+//21043,MD_T_WANDER_MAN
+//21044,MD_T_RETRIBUTION
+//21045,MD_T_FLAME_SKULL
+//21046,MD_T_KNIGHT_OF_ABYSS
+//21047,MD_T_BANSHEE
+//21048,G_CHIMERA_LAVA
+//21049,G_CHIMERA_FULGOR
+//21050,G_CHIMERA_NAPEO
+//21051,G_CHIMERA_GALENSIS
+//21052,G_DISGUISER
+//21053,G_BLUEMOON_LOLI_RURI
+//21054,G_GROTE
+//21055,G_PIERROTZOIST
+//21056,G_GIANT_CAPUT
+//21057,G_DOLORIAN
+//21058,G_PLAGARION
+//21059,G_DEADRE
+//21060,G_VENEDI
+//21061,MD_Airboat_Boss2
+//21062,MD_Airboat_Boss3
+//21063,MD_Airboat_Boss4
+//21064,S_DUMMY_100_SMALL
+//21065,S_DUMMY_100_MEDIUM
+//21066,S_DUMMY_100_LARGE
+//21067,S_DUMMY_100_NOTHING
+//21068,S_DUMMY_100_DRAGON
+//21069,S_DUMMY_100_ANIMAL
+//21070,S_DUMMY_100_HUMAN
+//21071,S_DUMMY_100_INSECT
+//21072,S_DUMMY_100_FISH
+//21073,S_DUMMY_100_DEMON
+//21074,S_DUMMY_100_PLANT
+//21075,S_DUMMY_100_ANGEL
+//21076,S_DUMMY_100_UNDEAD
+//21077,S_DUMMY_100_NOTHING2
+//21078,S_DUMMY_100_WATER
+//21079,S_DUMMY_100_GROUND
+//21080,S_DUMMY_100_FIRE
+//21081,S_DUMMY_100_WIND
+//21082,S_DUMMY_100_POISON
+//21083,S_DUMMY_100_SAINT
+//21084,S_DUMMY_100_DARKNESS
+//21085,S_DUMMY_100_TELEKINESIS
+//21086,S_DUMMY_100_UNDEAD2
+//21087,S_DUMMY_100_HUMANP
+//21088,S_DUMMY_100_DORAMP
+//21089,WANDERING_DUCK
 
 //31999,HUNTING_GID_DEFAULT
 //32000,MONSTER_2ND_END

+ 2 - 2
db/re/mob_race2_db.txt

@@ -16,9 +16,9 @@ RC2_GUARDIAN,1285,1286,1287,2081
 // Ninja Classes (Pirate's_Pride)
 RC2_NINJA,1315,1364,1401,1560
 // GvG
-RC2_GVG,1143,1905,1906,1907
+RC2_GVG,1288,1905,1907,1908
 // Battlefield
-RC2_BATTLEFIELD,1906,1909,1914,1915
+RC2_BATTLEFIELD,1906,1909,1910,1911,1912,1913,1914,1915
 // Treasure Chests
 RC2_TREASURE,1324,1325,1326,1327,1328,1329,1330,1331,1332,1333,1334,1335,1336,1337,1338,1339,1340,1341,1342,1343,1344,1345,1346,1347,1348,1349,1350,1351,1352,1353,1354,1355,1356,1357,1358,1359,1360,1361,1362,1363,1938,1939,1940,1941,1942,1943,1944,1945,1946,2452,2453,2454,2455,2456,2457,2458,2459,2460,2461,2462
 // Bio Labs

+ 42 - 32
db/re/produce_db.txt

@@ -616,69 +616,79 @@
 //-- Petti Tail Noodle <-- GN_MIX_COOKING Lv1, Mix Cook Book, 1 Melange Pot, 2 Petti Tail, 1 Fine Noodle, 1 Cool Gravy
 245,12434,27,2495,1,11022,0,6248,1,6260,2,6261,1,6262,1
 
-//---- Create Bomb --- ItemLV=28 --------------- Removed skill (free slot)
+//---- Create Bomb --- ItemLV=28 ---------------
+//-- Apple Bomb <-- GN_MAKEBOMB Lv1, Apple Bomb CB, 1 Apple, 1 Scell, 1 Detonator, 1 Gun Powder
+//246,13260,28,2496,1,6279,0,512,1,911,1,1051,1,6244,1
+//-- Coconut Bomb <-- GN_MAKEBOMB Lv1, Coconut Bomb CB, 1 Detonator, 1 Coconut Fruit, 2 Gun Powder
+//247,13261,28,2496,1,6281,0,1051,1,6263,1,6244,2
+//-- Melon Bomb <-- GN_MAKEBOMB Lv1, Melon Bomb CB, 1 Sticky Mucus, 1 Detonator, 2 Gun Powder, 1 Melon
+//248,13262,28,2496,1,6282,0,938,1,1051,1,6244,2,6264,1
+//-- Pineapple Bomb <-- GN_MAKEBOMB Lv1, Pinepple Bomb CB, 1 Cactus Needle, 1 Detonator, 3 Gun Powder, 1 Pineapple
+//249,13263,28,2496,1,6280,0,952,1,1051,1,6244,3,6265,1
+//-- Banana Bomb <-- GN_MAKEBOMB Lv1, Banana Bomb CB, 1 Banana, 1 Detonator, 4 Gun Powder, 1 Mould Powder
+//250,13264,28,2496,1,6283,0,513,1,1051,1,6244,4,7001,1
 
 //---- Special Pharmacy --- ItemLV=29 ----------
 //-- Seed Of Horny Plant <-- GN_S_PHARMACY Lv1, Plant Genetic Grow, 10 Prickly Fruit
-246,6210,29,2497,1,6284,0,576,10
+251,6210,29,2497,1,6284,0,576,10
 //-- Bloodsuck Plant Seed <-- GN_S_PHARMACY Lv1, Plant Genetic Grow, 10 Root Of Maneater
-247,6211,29,2497,1,6284,0,1033,10
+252,6211,29,2497,1,6284,0,1033,10
 //-- Bomb Mushroom Spore <-- GN_S_PHARMACY Lv1, Plant Genetic Grow, 10 Mushroom Spore, 2 Gun Powder, 5 Poison Spore
-248,6212,29,2497,1,6284,0,921,10,6244,2,7033,5
+253,6212,29,2497,1,6284,0,921,10,6244,2,7033,5
 //-- HP Increase Potion (Small) <-- GN_S_PHARMACY Lv1, Increase Stamina Study, 10 White Herb, 5 Monster's Feed, 10 Empty Bottle, 1 Hot Sauce
-249,12422,29,2497,1,11023,0,509,10,528,5,713,10,7455,1
+254,12422,29,2497,1,11023,0,509,10,528,5,713,10,7455,1
 //-- HP Increase Potion (Medium) <-- GN_S_PHARMACY Lv1, Increase Stamina Study, 10 Yellow Herb, 10 White Herb, 10 Empty Bottle, 1 Hot Sauce
-250,12423,29,2497,1,11023,0,508,10,509,10,713,10,7455,1
+255,12423,29,2497,1,11023,0,508,10,509,10,713,10,7455,1
 //-- HP Increase Potion (Large) <-- GN_S_PHARMACY Lv1, Increase Stamina Study, 15 White Herb, 3 Fruit Of Mastela, 1 Holy Water, 10 Empty Bottle, 1 Hot Sauce
-251,12424,29,2497,1,11023,0,509,15,522,3,523,1,713,10,7455,1
+256,12424,29,2497,1,11023,0,509,15,522,3,523,1,713,10,7455,1
 //-- SP Increase Potion (Small) <-- GN_S_PHARMACY Lv1, Vital Drink CB, 10 Grape, 10 Lemon, 10 Empty Bottle, 1 Sweet Sauce
-252,12425,29,2497,1,11024,0,514,10,568,10,713,10,7453,1
+257,12425,29,2497,1,11024,0,514,10,568,10,713,10,7453,1
 //-- SP Increase Potion (Medium) <-- GN_S_PHARMACY Lv1, Vital Drink CB, 10 Blue Herb, 10 Honey, 10 Empty Bottle, 1 Sweet Sauce
-253,12426,29,2497,1,11024,0,510,10,518,10,713,10,7453,1
+258,12426,29,2497,1,11024,0,510,10,518,10,713,10,7453,1
 //-- SP Increase Potion (Large) <-- GN_S_PHARMACY Lv1, Vital Drink CB, 15 Blue Herb, 10 Royal Jelly, 10 Empty Bottle, 1 Sweet Sauce
-254,12427,29,2497,1,11024,0,510,15,526,10,713,10,7453,1
+259,12427,29,2497,1,11024,0,510,15,526,10,713,10,7453,1
 //-- Enrich White Potion Z <-- GN_S_PHARMACY Lv1, Quality Potion Book, 20 White Potion, 10 White Herb, 1 Alchol, 10 Empty Cylinder
-255,12428,29,2497,1,6285,0,504,20,509,10,970,1,1092,10
+260,12428,29,2497,1,6285,0,504,20,509,10,970,1,1092,10
 //-- Vitata 500 <-- GN_S_PHARMACY Lv1, Quality Potion Book, 10 Blue Herb, 10 Grape, 10 Honey, 10 Empty Cylinder
-256,12436,29,2497,1,6285,0,510,10,514,10,518,10,1092,10
+261,12436,29,2497,1,6285,0,510,10,514,10,518,10,1092,10
 //-- Enrich Celermine Juice <-- GN_S_PHARMACY Lv1, Quality Potion Book, 5 Center Potion, 5 Awakening Potion, 10 Empty Cylinder, 5 Hot Sauce
-257,12437,29,2497,1,6285,0,645,5,656,5,1092,10,7455,5
+262,12437,29,2497,1,6285,0,645,5,656,5,1092,10,7455,5
 //-- Cure Free <-- GN_S_PHARMACY Lv1, Quality Potion Book, 20 Green Herb, 1 Fruit Of Mastela, 5 Panacea, 1 Leaf Of Yggdrasil, 10 Empty Cylinder
-258,12475,29,2497,1,6285,0,511,20,522,1,525,5,610,1,1092,10
+263,12475,29,2497,1,6285,0,511,20,522,1,525,5,610,1,1092,10
 //-- Golden X <-- GN_S_PHARMACY Lvl, 10 Empty Testtube, 10 Yggdrasilberry, 5 Gold
-//259,100231,29,2497,1,1092,10,607,10,969,5
+//264,100231,29,2497,1,1092,10,607,10,969,5
 //-- Red Herb Activator <-- GN_S_PHARMACY Lvl, 10 Empty Testtube, 45 Red Herb, 5 Yggdrasil Seed
-//260,100232,29,2497,1,1092,10,507,45,608,5
+//265,100232,29,2497,1,1092,10,507,45,608,5
 //-- Blue Herb Activator <-- GN_S_PHARMACY Lvl, 10 Empty Testtube, 15 Blue Herb, 5 Yggdrasil Seed
-//261,100233,29,2497,1,1092,10,510,15,608,5
+//266,100233,29,2497,1,1092,10,510,15,608,5
 //-- Concentrated Red Syrup Potion <-- GN_S_PHARMACY Lvl, 10 Empty Testtube, 10 Empty Potion Bottle, 15 Red Syrup
-//262,1100003,29,2497,1,1092,10,1093,10,11621,15
+//267,1100003,29,2497,1,1092,10,1093,10,11621,15
 //-- Concentrated Blue Syrup Potion <-- GN_S_PHARMACY Lvl, 10 Empty Testtube, 10 Empty Potion Bottle, 15 Blue Syrup
-//263,1100004,29,2497,1,1092,10,1093,10,11624,15
-//-- Concentrated Golden Syrup Potion <-- GN_S_PHARMACY Lvl, 10 Empty Testtube, 10 Empty Potion Bottle, 15 White Syrup, 15 Yellow Syrup
-//264,1100005,29,2497,1,1092,10,1093,10,11623,15,11622,15
+//268,1100004,29,2497,1,1092,10,1093,10,11624,15
+//-- Concentrated Golden Syrup Potion <-- GN_S_PHARMACY Lvl, 10 Empty Testtube, 10 Empty Potion Bottle, 15 White Syrup, 10 Yellow Syrup
+//269,1100005,29,2497,1,1092,10,1093,10,11623,15,11622,10
 //===============================================
 
 //--------------------LEVEL 30-----------
 // Novice Red Potion (569) <-- 2 Red Herbs, 1 Apple
-265,569,30,0,0,11058,0,507,2,512,1
+270,569,30,0,0,11058,0,507,2,512,1
 // Novice Magnifier (12325) <-- 3 Fine-grained Trunk, 1 Jellopy
-266,12325,30,0,0,11058,0,1066,3,909,1
+271,12325,30,0,0,11058,0,1066,3,909,1
 // Novice Fly Wing (12323) <-- 2 Fluffs, 2 Feathers, 2 Jellopies
-267,12323,30,0,0,11058,0,914,2,949,2,909,2
+272,12323,30,0,0,11058,0,914,2,949,2,909,2
 // Novice Cutter (13040) <-- 10 Shells, 10 Worm Peelings, 1 Phracon
-268,13040,30,0,0,11058,0,935,10,955,10,1010,1
+273,13040,30,0,0,11058,0,935,10,955,10,1010,1
 // Little Unripe Apple (12846) <-- 1 Apple, 1 Green Herb
-269,12846,30,0,0,11058,0,512,1,511,1
+274,12846,30,0,0,11058,0,512,1,511,1
 // Four Leaf Clover (706) <-- 200 Clovers, 200 Sticky Mucus
-270,706,30,0,0,11058,0,705,200,938,200
+275,706,30,0,0,11058,0,705,200,938,200
 // Banana Juice (532) <-- 1 Banana, 1 Milk
-271,532,30,0,0,11058,0,513,1,519,1
+276,532,30,0,0,11058,0,513,1,519,1
 // Apple Juice (531) <-- 1 Apple, 1 Milk
-272,531,30,0,0,11058,0,512,1,519,1
+277,531,30,0,0,11058,0,512,1,519,1
 // Carrot Juice (534) <-- 1 Carrot, 1 Milk
-273,534,30,0,0,11058,0,515,1,519,1
+278,534,30,0,0,11058,0,515,1,519,1
 // Grape Juice (533) <-- 1 Grape, 1 Milk
-274,533,30,0,0,11058,0,514,1,519,1
+279,533,30,0,0,11058,0,514,1,519,1
 // Unripe Apple (619) <-- 10 Sticky Mucus, 20 Green Herbs, 10 Apples
-275,619,30,0,0,11058,0,938,10,511,20,512,10
+280,619,30,0,0,11058,0,938,10,511,20,512,10

File diff suppressed because it is too large
+ 193 - 191
db/re/skill_db.yml


+ 9 - 0
db/re/skill_nocast_db.txt

@@ -33,7 +33,11 @@
 328,1	//DC_DONTFORGETME
 2422,1	//WM_LULLABY_DEEPSLEEP
 2423,1	//WM_SIRCLEOFNATURE
+2425,1	//WM_GLOOMYDAY
+2429,1	//WM_SOUND_OF_DESTRUCTION
 2430,1	//WM_SATURDAY_NIGHT_FEVER
+2432,1	//WM_MELODYOFSINK
+2433,1	//WM_BEYOND_OF_WARCRY
 2455,1	//SO_ARRULLO
 2299,1	//SC_MANHOLE
 
@@ -56,6 +60,7 @@
 395,4	//CG_MOONLIT
 409,4	//WE_CALLPARENT
 410,4	//WE_CALLBABY
+491,4	//CR_CULTIVATION
 530,4	//NJ_KIRIKAGE
 691,4	//CASH_ASSUMPTIO
 2284,4	//SC_FATALMENACE
@@ -94,6 +99,7 @@
 438,8	//SG_SUN_BLESS
 439,8	//SG_MOON_BLESS
 440,8	//SG_STAR_BLESS
+491,8	//CR_CULTIVATION
 530,8	//NJ_KIRIKAGE
 691,8	//CASH_ASSUMPITO
 2284,8	//SC_FATALMENACE
@@ -130,6 +136,7 @@
 409,16	// WE_CALLPARENT
 410,16	// WE_CALLBABY
 426,16	// TK_HIGHJUMP
+491,16	//CR_CULTIVATION
 529,16	// NJ_SHADOWJUMP
 // 530,16	// NJ_KIRIKAGE
 691,16	// CASH_ASSUMPTIO
@@ -216,9 +223,11 @@
 //----------------------------------------------------------------------------
 232,2048	//AM_CANNIBALIZE
 233,2048	//AM_SPHEREMINE
+491,2048	//CR_CULTIVATION
 1013,2048	//BS_GREED
 2419,2048	//WM_POEMOFNETHERWORLD
 2482,2048	//GN_WALLOFTHORN
+2493,2048	//GN_SLINGITEM
 
 //----------------------------------------------------------------------------
 // Zone 8 - WOE:TE Dungeons

+ 77 - 26
db/re/skill_tree.txt

@@ -1266,6 +1266,7 @@
 4019,478,10,231,5,0,0,0,0,0,0,0,0 //CR_SLIMPITCHER#Aid Condensed Potion#
 4019,479,5,234,5,235,5,236,5,237,5,0,0 //CR_FULLPROTECTION#Full Protection#
 4019,490,10,229,5,230,5,0,0,0,0,0,0 //CR_ACIDDEMONSTRATION#Acid Demonstration#
+//4019,491,2,0,0,0,0,0,0,0,0,0,0 //CR_CULTIVATION#Cultivation#
 4019,410,1,0,0,0,0,0,0,0,0,0,0 //WE_CALLBABY#Call Baby#
 4019,446,1,0,0,0,0,0,0,0,0,0,0	//AM_BERSERKPITCHER#Berserk Pitcher#
 4019,496,1,228,10,0,0,0,0,0,0,0,0	//AM_TWILIGHT1#Twilight Alchemy 1#
@@ -2603,6 +2604,7 @@
 4057,2046,10,2045,5,0,0,0,0,0,0,0,0 //AB_ORATIO#Oratio#
 4057,2047,4,72,1,0,0,0,0,0,0,0,0 //AB_LAUDAAGNUS#Lauda Agnus#
 4057,2048,4,2047,2,0,0,0,0,0,0,0,0 //AB_LAUDARAMUS#Lauda Ramus#
+//4057,2049,10,2044,1,2053,1,0,0,0,0,0,0 //AB_EUCHARISTICA#Eucharistica#
 4057,2050,4,2043,3,0,0,0,0,0,0,0,0 //AB_RENOVATIO#Renovatio#
 4057,2051,5,2050,1,0,0,0,0,0,0,0,0 //AB_HIGHNESSHEAL#Highness Heal#
 4057,2052,5,2048,2,0,0,0,0,0,0,0,0 //AB_CLEARANCE#Clearance#
@@ -2951,6 +2953,7 @@
 4063,2046,10,2045,5,0,0,0,0,0,0,0,0 //AB_ORATIO#Oratio#
 4063,2047,4,72,1,0,0,0,0,0,0,0,0 //AB_LAUDAAGNUS#Lauda Agnus#
 4063,2048,4,2047,2,0,0,0,0,0,0,0,0 //AB_LAUDARAMUS#Lauda Ramus#
+//4063,2049,10,2044,1,2053,1,0,0,0,0,0,0 //AB_EUCHARISTICA#Eucharistica#
 4063,2050,4,2043,3,0,0,0,0,0,0,0,0 //AB_RENOVATIO#Renovatio#
 4063,2051,5,2050,1,0,0,0,0,0,0,0,0 //AB_HIGHNESSHEAL#Highness Heal#
 4063,2052,5,2048,2,0,0,0,0,0,0,0,0 //AB_CLEARANCE#Clearance#
@@ -3247,9 +3250,9 @@
 4068,2382,5,2422,1,0,0,0,0,0,0,0,0 //MI_ECHOSONG#Echo Song#
 4068,2383,5,2422,1,0,0,0,0,0,0,0,0 //MI_HARMONIZE#Harmonize#
 4068,2412,10,0,0,0,0,0,0,0,0,0,0 //WM_LESSON#Lesson#
-4068,2413,10,2417,1,0,0,0,0,0,0,0,0 //WM_METALICSOUND#Metallic Sound#
+4068,2413,10,2414,5,0,0,0,0,0,0,0,0 //WM_METALICSOUND#Metallic Sound#
 4068,2414,5,317,5,0,0,0,0,0,0,0,0 //WM_REVERBERATION#Reverberation#
-4068,2417,1,2414,1,0,0,0,0,0,0,0,0 //WM_DOMINION_IMPULSE#Dominion Impulse#
+//4068,2417,1,2414,1,0,0,0,0,0,0,0,0 //WM_DOMINION_IMPULSE#Dominion Impulse#
 4068,2418,5,316,5,0,0,0,0,0,0,0,0 //WM_SEVERE_RAINSTORM#Severe Rainstorm#
 4068,2419,5,2412,1,0,0,0,0,0,0,0,0 //WM_POEMOFNETHERWORLD#Poem Of The Netherworld#
 4068,2420,5,2419,3,0,0,0,0,0,0,0,0 //WM_VOICEOFSIREN#Voice Of Siren#
@@ -3303,9 +3306,9 @@
 4069,2351,5,2422,1,0,0,0,0,0,0,0,0 //WA_SYMPHONY_OF_LOVER#Symphony of Lovers#
 4069,2352,5,2422,1,0,0,0,0,0,0,0,0 //WA_MOONLIT_SERENADE#Moonlit Serenade#
 4069,2412,10,0,0,0,0,0,0,0,0,0,0 //WM_LESSON#Lesson#
-4069,2413,10,2417,1,0,0,0,0,0,0,0,0 //WM_METALICSOUND#Metallic Sound#
+4069,2413,10,2414,5,0,0,0,0,0,0,0,0 //WM_METALICSOUND#Metallic Sound#
 4069,2414,5,325,5,0,0,0,0,0,0,0,0 //WM_REVERBERATION#Reverberation#
-4069,2417,1,2414,1,0,0,0,0,0,0,0,0 //WM_DOMINION_IMPULSE#Dominion Impulse#
+//4069,2417,1,2414,1,0,0,0,0,0,0,0,0 //WM_DOMINION_IMPULSE#Dominion Impulse#
 4069,2418,5,324,5,0,0,0,0,0,0,0,0 //WM_SEVERE_RAINSTORM#Severe Rainstorm#
 4069,2419,5,2412,1,0,0,0,0,0,0,0,0 //WM_POEMOFNETHERWORLD#Poem Of The Netherworld#
 4069,2420,5,2419,3,0,0,0,0,0,0,0,0 //WM_VOICEOFSIREN#Voice Of Siren#
@@ -3433,8 +3436,10 @@
 4071,2486,5,2485,3,0,0,0,0,0,0,0,0 //GN_FIRE_EXPANSION#Fire Expansion#
 4071,2490,5,2480,3,0,0,0,0,0,0,0,0 //GN_HELLS_PLANT#Hell's Plant#
 4071,2492,5,2490,3,0,0,0,0,0,0,0,0 //GN_MANDRAGORA#Howling of Mandragora#
+//4071,2493,1,2494,1,0,0,0,0,0,0,0,0 //GN_SLINGITEM#Sling Item#
 4071,2494,1,0,0,0,0,0,0,0,0,0,0 //GN_CHANGEMATERIAL#Change Material#
 4071,2495,2,2497,1,0,0,0,0,0,0,0,0 //GN_MIX_COOKING#Mix Cooking#
+//4071,2496,2,2495,1,0,0,0,0,0,0,0,0 //GN_MAKEBOMB#Create Bomb#
 4071,2497,10,0,0,0,0,0,0,0,0,0,0 //GN_S_PHARMACY#Special Pharmacy#
 4071,5003,5,2497,1,0,0,0,0,0,0,0,0 //GN_ILLUSIONDOOPING#Hallucination Drug#
 4071,5014,5,0,0,0,0,0,0,0,0,0,0 //ALL_FULL_THROTTLE#Full Throttle#
@@ -3676,9 +3681,9 @@
 4075,2382,5,2422,1,0,0,0,0,0,0,0,0 //MI_ECHOSONG#Echo Song#
 4075,2383,5,2422,1,0,0,0,0,0,0,0,0 //MI_HARMONIZE#Harmonize#
 4075,2412,10,0,0,0,0,0,0,0,0,0,0 //WM_LESSON#Lesson#
-4075,2413,10,2417,1,0,0,0,0,0,0,0,0 //WM_METALICSOUND#Metallic Sound#
+4075,2413,10,2414,5,0,0,0,0,0,0,0,0 //WM_METALICSOUND#Metallic Sound#
 4075,2414,5,317,5,0,0,0,0,0,0,0,0 //WM_REVERBERATION#Reverberation#
-4075,2417,1,2414,1,0,0,0,0,0,0,0,0 //WM_DOMINION_IMPULSE#Dominion Impulse#
+//4075,2417,1,2414,1,0,0,0,0,0,0,0,0 //WM_DOMINION_IMPULSE#Dominion Impulse#
 4075,2418,5,316,5,0,0,0,0,0,0,0,0 //WM_SEVERE_RAINSTORM#Severe Rainstorm#
 4075,2419,5,2412,1,0,0,0,0,0,0,0,0 //WM_POEMOFNETHERWORLD#Poem Of The Netherworld#
 4075,2420,5,2419,3,0,0,0,0,0,0,0,0 //WM_VOICEOFSIREN#Voice Of Siren#
@@ -3739,9 +3744,9 @@
 4076,2351,5,2422,1,0,0,0,0,0,0,0,0 //WA_SYMPHONY_OF_LOVER#Symphony of Lovers#
 4076,2352,5,2422,1,0,0,0,0,0,0,0,0 //WA_MOONLIT_SERENADE#Moonlit Serenade#
 4076,2412,10,0,0,0,0,0,0,0,0,0,0 //WM_LESSON#Lesson#
-4076,2413,10,2417,1,0,0,0,0,0,0,0,0 //WM_METALICSOUND#Metallic Sound#
+4076,2413,10,2414,5,0,0,0,0,0,0,0,0 //WM_METALICSOUND#Metallic Sound#
 4076,2414,5,325,5,0,0,0,0,0,0,0,0 //WM_REVERBERATION#Reverberation#
-4076,2417,1,2414,1,0,0,0,0,0,0,0,0 //WM_DOMINION_IMPULSE#Dominion Impulse#
+//4076,2417,1,2414,1,0,0,0,0,0,0,0,0 //WM_DOMINION_IMPULSE#Dominion Impulse#
 4076,2418,5,324,5,0,0,0,0,0,0,0,0 //WM_SEVERE_RAINSTORM#Severe Rainstorm#
 4076,2419,5,2412,1,0,0,0,0,0,0,0,0 //WM_POEMOFNETHERWORLD#Poem Of The Netherworld#
 4076,2420,5,2419,3,0,0,0,0,0,0,0,0 //WM_VOICEOFSIREN#Voice Of Siren#
@@ -3857,6 +3862,7 @@
 4078,478,10,231,5,0,0,0,0,0,0,0,0 //CR_SLIMPITCHER#Aid Condensed Potion#
 4078,479,5,234,5,235,5,236,5,237,5,0,0 //CR_FULLPROTECTION#Full Protection#
 4078,490,10,229,5,230,5,0,0,0,0,0,0 //CR_ACIDDEMONSTRATION#Acid Demonstration#
+//4078,491,2,0,0,0,0,0,0,0,0,0,0 //CR_CULTIVATION#Cultivation#
 4078,410,1,0,0,0,0,0,0,0,0,0,0 //WE_CALLBABY#Call Baby#
 4078,446,1,0,0,0,0,0,0,0,0,0,0	//AM_BERSERKPITCHER#Berserk Pitcher#
 4078,496,1,228,10,0,0,0,0,0,0,0,0	//AM_TWILIGHT1#Twilight Alchemy 1#
@@ -3876,8 +3882,10 @@
 4078,2486,5,2485,3,0,0,0,0,0,0,0,0 //GN_FIRE_EXPANSION#Fire Expansion#
 4078,2490,5,2480,3,0,0,0,0,0,0,0,0 //GN_HELLS_PLANT#Hell's Plant#
 4078,2492,5,2490,3,0,0,0,0,0,0,0,0 //GN_MANDRAGORA#Howling of Mandragora#
+//4078,2493,1,2494,1,0,0,0,0,0,0,0,0 //GN_SLINGITEM#Sling Item#
 4078,2494,1,0,0,0,0,0,0,0,0,0,0 //GN_CHANGEMATERIAL#Change Material#
 4078,2495,2,2497,1,0,0,0,0,0,0,0,0 //GN_MIX_COOKING#Mix Cooking#
+//4078,2496,2,2495,1,0,0,0,0,0,0,0,0 //GN_MAKEBOMB#Create Bomb#
 4078,2497,10,0,0,0,0,0,0,0,0,0,0 //GN_S_PHARMACY#Special Pharmacy#
 4078,5003,5,2497,1,0,0,0,0,0,0,0,0 //GN_ILLUSIONDOOPING#Hallucination Drug#
 4078,5014,5,0,0,0,0,0,0,0,0,0,0 //ALL_FULL_THROTTLE#Full Throttle#
@@ -4608,6 +4616,7 @@
 4099,2046,10,2045,5,0,0,0,0,0,0,0,0 //AB_ORATIO#Oratio#
 4099,2047,4,72,1,0,0,0,0,0,0,0,0 //AB_LAUDAAGNUS#Lauda Agnus#
 4099,2048,4,2047,2,0,0,0,0,0,0,0,0 //AB_LAUDARAMUS#Lauda Ramus#
+//4099,2049,10,2044,1,2053,1,0,0,0,0,0,0 //AB_EUCHARISTICA#Eucharistica#
 4099,2050,4,2043,3,0,0,0,0,0,0,0,0 //AB_RENOVATIO#Renovatio#
 4099,2051,5,2050,1,0,0,0,0,0,0,0,0 //AB_HIGHNESSHEAL#Highness Heal#
 4099,2052,5,2048,2,0,0,0,0,0,0,0,0 //AB_CLEARANCE#Clearance#
@@ -4904,9 +4913,9 @@
 4104,2382,5,2422,1,0,0,0,0,0,0,0,0 //MI_ECHOSONG#Echo Song#
 4104,2383,5,2422,1,0,0,0,0,0,0,0,0 //MI_HARMONIZE#Harmonize#
 4104,2412,10,0,0,0,0,0,0,0,0,0,0 //WM_LESSON#Lesson#
-4104,2413,10,2417,1,0,0,0,0,0,0,0,0 //WM_METALICSOUND#Metallic Sound#
+4104,2413,10,2414,5,0,0,0,0,0,0,0,0 //WM_METALICSOUND#Metallic Sound#
 4104,2414,5,317,5,0,0,0,0,0,0,0,0 //WM_REVERBERATION#Reverberation#
-4104,2417,1,2414,1,0,0,0,0,0,0,0,0 //WM_DOMINION_IMPULSE#Dominion Impulse#
+//4104,2417,1,2414,1,0,0,0,0,0,0,0,0 //WM_DOMINION_IMPULSE#Dominion Impulse#
 4104,2418,5,316,5,0,0,0,0,0,0,0,0 //WM_SEVERE_RAINSTORM#Severe Rainstorm#
 4104,2419,5,2412,1,0,0,0,0,0,0,0,0 //WM_POEMOFNETHERWORLD#Poem Of The Netherworld#
 4104,2420,5,2419,3,0,0,0,0,0,0,0,0 //WM_VOICEOFSIREN#Voice Of Siren#
@@ -4962,9 +4971,9 @@
 4105,2351,5,2422,1,0,0,0,0,0,0,0,0 //WA_SYMPHONY_OF_LOVER#Symphony of Lovers#
 4105,2352,5,2422,1,0,0,0,0,0,0,0,0 //WA_MOONLIT_SERENADE#Moonlit Serenade#
 4105,2412,10,0,0,0,0,0,0,0,0,0,0 //WM_LESSON#Lesson#
-4105,2413,10,2417,1,0,0,0,0,0,0,0,0 //WM_METALICSOUND#Metallic Sound#
+4105,2413,10,2414,5,0,0,0,0,0,0,0,0 //WM_METALICSOUND#Metallic Sound#
 4105,2414,5,325,5,0,0,0,0,0,0,0,0 //WM_REVERBERATION#Reverberation#
-4105,2417,1,2414,1,0,0,0,0,0,0,0,0 //WM_DOMINION_IMPULSE#Dominion Impulse#
+//4105,2417,1,2414,1,0,0,0,0,0,0,0,0 //WM_DOMINION_IMPULSE#Dominion Impulse#
 4105,2418,5,324,5,0,0,0,0,0,0,0,0 //WM_SEVERE_RAINSTORM#Severe Rainstorm#
 4105,2419,5,2412,1,0,0,0,0,0,0,0,0 //WM_POEMOFNETHERWORLD#Poem Of The Netherworld#
 4105,2420,5,2419,3,0,0,0,0,0,0,0,0 //WM_VOICEOFSIREN#Voice Of Siren#
@@ -5096,8 +5105,10 @@
 4107,2486,5,2485,3,0,0,0,0,0,0,0,0 //GN_FIRE_EXPANSION#Fire Expansion#
 4107,2490,5,2480,3,0,0,0,0,0,0,0,0 //GN_HELLS_PLANT#Hell's Plant#
 4107,2492,5,2490,3,0,0,0,0,0,0,0,0 //GN_MANDRAGORA#Howling of Mandragora#
+//4107,2493,1,2494,1,0,0,0,0,0,0,0,0 //GN_SLINGITEM#Sling Item#
 4107,2494,1,0,0,0,0,0,0,0,0,0,0 //GN_CHANGEMATERIAL#Change Material#
 4107,2495,2,2497,1,0,0,0,0,0,0,0,0 //GN_MIX_COOKING#Mix Cooking#
+//4107,2496,2,2495,1,0,0,0,0,0,0,0,0 //GN_MAKEBOMB#Create Bomb#
 4107,2497,10,0,0,0,0,0,0,0,0,0,0 //GN_S_PHARMACY#Special Pharmacy#
 4107,5003,5,2497,1,0,0,0,0,0,0,0,0 //GN_ILLUSIONDOOPING#Hallucination Drug#
 4107,5014,5,0,0,0,0,0,0,0,0,0,0 //ALL_FULL_THROTTLE#Full Throttle#
@@ -5444,34 +5455,54 @@
 4190,53,1,52,3,0,0,0,0,0,0,0,0 //TF_DETOXIFY#Detoxify#
 4190,410,1,0,0,0,0,0,0,0,0,0,0 //WE_CALLBABY#Call Baby#
 4190,66,5,0,0,0,0,0,0,0,0,0,0 //PR_IMPOSITIO#Impositio Manus#
+4190,68,5,31,1,66,3,0,0,0,0,0,0 //PR_ASPERSIO#Aspersio#
 4190,70,10,28,1,0,0,0,0,0,0,0,0 //PR_SANCTUARY#Sanctuary#
 4190,72,1,0,0,0,0,0,0,0,0,0,0 //PR_STRECOVERY#Status Recovery#
+4190,74,5,0,0,0,0,0,0,0,0,0,0 //PR_MAGNIFICAT#Magnificat#
 4190,75,5,70,7,0,0,0,0,0,0,0,0 //PR_GLORIA#Gloria#
 4190,80,10,18,1,0,0,0,0,0,0,0,0 //WZ_FIREPILLAR#Fire Pillar#
 4190,81,10,20,1,10,1,0,0,0,0,0,0 //WZ_SIGHTRASHER#Sightrasher#
+4190,83,10,81,2,21,1,0,0,0,0,0,0 //WZ_METEOR#Meteor Storm#
 4190,84,10,11,1,20,1,0,0,0,0,0,0 //WZ_JUPITEL#Jupiter Thunder#
+4190,85,10,21,1,84,5,0,0,0,0,0,0 //WZ_VERMILION#Lord of Vermilion#
 4190,86,5,14,1,20,1,0,0,0,0,0,0 //WZ_WATERBALL#Water Ball#
 4190,87,10,16,1,15,1,0,0,0,0,0,0 //WZ_ICEWALL#Ice Wall#
 4190,88,10,87,1,0,0,0,0,0,0,0,0 //WZ_FROSTNOVA#Frost Nova#
+4190,89,10,15,1,84,3,0,0,0,0,0,0 //WZ_STORMGUST#Storm Gust#
 4190,90,5,16,1,0,0,0,0,0,0,0,0 //WZ_EARTHSPIKE#Earth Spike#
 4190,91,5,90,3,0,0,0,0,0,0,0,0 //WZ_HEAVENDRIVE#Heaven's Drive#
 4190,92,5,91,1,0,0,0,0,0,0,0,0 //WZ_QUAGMIRE#Quagmire#
 4190,93,1,0,0,0,0,0,0,0,0,0,0 //WZ_ESTIMATION#Sense#
 4190,105,1,0,0,0,0,0,0,0,0,0,0 //BS_HILTBINDING#Hilt Binding#
 4190,107,10,105,1,0,0,0,0,0,0,0,0 //BS_WEAPONRESEARCH#Weaponry Research#
+4190,108,1,107,1,0,0,0,0,0,0,0,0 //BS_REPAIRWEAPON#Weapon Repair#
 4190,115,5,0,0,0,0,0,0,0,0,0,0 //HT_SKIDTRAP#Skid Trap#
-4190,119,5,120,1,0,0,0,0,0,0,0,0 //HT_SANDMAN#Sandman#
-4190,120,5,115,1,0,0,0,0,0,0,0,0 //HT_FLASHER#Flasher#
-4190,121,5,120,1,0,0,0,0,0,0,0,0 //HT_FREEZINGTRAP#Freezing Trap#
+4190,116,5,0,0,0,0,0,0,0,0,0,0 //HT_LANDMINE#Land Mine#
+4190,126,10,0,0,0,0,0,0,0,0,0,0 //HT_BEASTBANE#Beast Bane#
 4190,138,10,52,1,0,0,0,0,0,0,0,0 //AS_ENCHANTPOISON#Enchant Poison#
+4190,139,10,138,3,0,0,0,0,0,0,0,0 //AS_POISONREACT#Poison React#
+4190,140,10,138,5,0,0,0,0,0,0,0,0 //AS_VENOMDUST#Venom Dust#
+4190,141,10,139,5,140,5,0,0,0,0,0,0 //AS_SPLASHER#Venom Splasher#
+4190,210,10,50,1,0,0,0,0,0,0,0,0 //RG_SNATCHER#Gank#
+4190,211,10,210,4,0,0,0,0,0,0,0,0 //RG_STEALCOIN#Mug#
+4190,212,10,211,4,0,0,0,0,0,0,0,0 //RG_BACKSTAP#Back Stab#
 4190,213,5,51,1,0,0,0,0,0,0,0,0 //RG_TUNNELDRIVE#Stalk#
+4190,214,5,212,2,213,2,0,0,0,0,0,0 //RG_RAID#Sightless Raid#
 4190,226,10,0,0,0,0,0,0,0,0,0,0 //AM_AXEMASTERY#Axe Mastery#
 4190,248,10,0,0,0,0,0,0,0,0,0,0 //CR_TRUST#Faith#
+4190,249,10,0,0,0,0,0,0,0,0,0,0 //CR_AUTOGUARD#Guard#
+4190,250,5,249,5,0,0,0,0,0,0,0,0 //CR_SHIELDCHARGE#Smite#
+4190,251,5,250,3,0,0,0,0,0,0,0,0 //CR_SHIELDBOOMERANG#Shield Boomerang#
 4190,253,10,248,7,0,0,0,0,0,0,0,0 //CR_HOLYCROSS#Holy Cross#
 4190,259,10,23,10,22,10,0,0,0,0,0,0 //MO_IRONHAND#Iron Fists#
 4190,261,5,259,2,0,0,0,0,0,0,0,0 //MO_CALLSPIRITS#Summon Spirit Sphere#
 4190,262,1,261,5,0,0,0,0,0,0,0,0 //MO_ABSORBSPIRITS#Absorb Spirit Sphere#
+4190,270,5,262,1,0,0,0,0,0,0,0,0 //MO_EXPLOSIONSPIRITS#Fury#
 4190,365,1,9,1,0,0,0,0,0,0,0,0 //HW_MAGICCRASHER#Stave Crasher#
+4190,401,1,261,5,262,1,270,5,0,0,0,0 //CH_SOULCOLLECT#Hyper Spirit Sphere#
+4190,5075,5,0,0,0,0,0,0,0,0,0,0 //NV_BREAKTHROUGH#Break Through#
+4190,5076,1,0,0,0,0,0,0,0,0,0,0 //NV_HELPANGEL#Help Angel#
+4190,5077,5,0,0,0,0,0,0,0,0,0,0 //NV_TRANSCENDENCE#Transcendence#
 4190,2535,1,41,1,0,0,0,0,0,0,0,0 //ALL_BUYING_STORE#Open Buying Store#
 4190,2544,1,0,0,0,0,0,0,0,0,0,0 //MC_CARTDECORATE#Cart Decorate#
 //Super Baby (Expanded)
@@ -5529,34 +5560,54 @@
 4191,408,1,0,0,0,0,0,0,0,0,0,0 //WE_BABY#Baby#
 4191,409,1,0,0,0,0,0,0,0,0,0,0 //WE_CALLPARENT#Call Parent#
 4191,66,5,0,0,0,0,0,0,0,0,0,0 //PR_IMPOSITIO#Impositio Manus#
+4191,68,5,31,1,66,3,0,0,0,0,0,0 //PR_ASPERSIO#Aspersio#
 4191,70,10,28,1,0,0,0,0,0,0,0,0 //PR_SANCTUARY#Sanctuary#
 4191,72,1,0,0,0,0,0,0,0,0,0,0 //PR_STRECOVERY#Status Recovery#
+4191,74,5,0,0,0,0,0,0,0,0,0,0 //PR_MAGNIFICAT#Magnificat#
 4191,75,5,70,7,0,0,0,0,0,0,0,0 //PR_GLORIA#Gloria#
 4191,80,10,18,1,0,0,0,0,0,0,0,0 //WZ_FIREPILLAR#Fire Pillar#
 4191,81,10,20,1,10,1,0,0,0,0,0,0 //WZ_SIGHTRASHER#Sightrasher#
+4191,83,10,81,2,21,1,0,0,0,0,0,0 //WZ_METEOR#Meteor Storm#
 4191,84,10,11,1,20,1,0,0,0,0,0,0 //WZ_JUPITEL#Jupiter Thunder#
+4191,85,10,21,1,84,5,0,0,0,0,0,0 //WZ_VERMILION#Lord of Vermilion#
 4191,86,5,14,1,20,1,0,0,0,0,0,0 //WZ_WATERBALL#Water Ball#
 4191,87,10,16,1,15,1,0,0,0,0,0,0 //WZ_ICEWALL#Ice Wall#
 4191,88,10,87,1,0,0,0,0,0,0,0,0 //WZ_FROSTNOVA#Frost Nova#
+4191,89,10,15,1,84,3,0,0,0,0,0,0 //WZ_STORMGUST#Storm Gust#
 4191,90,5,16,1,0,0,0,0,0,0,0,0 //WZ_EARTHSPIKE#Earth Spike#
 4191,91,5,90,3,0,0,0,0,0,0,0,0 //WZ_HEAVENDRIVE#Heaven's Drive#
 4191,92,5,91,1,0,0,0,0,0,0,0,0 //WZ_QUAGMIRE#Quagmire#
 4191,93,1,0,0,0,0,0,0,0,0,0,0 //WZ_ESTIMATION#Sense#
 4191,105,1,0,0,0,0,0,0,0,0,0,0 //BS_HILTBINDING#Hilt Binding#
 4191,107,10,105,1,0,0,0,0,0,0,0,0 //BS_WEAPONRESEARCH#Weaponry Research#
+4191,108,1,107,1,0,0,0,0,0,0,0,0 //BS_REPAIRWEAPON#Weapon Repair#
 4191,115,5,0,0,0,0,0,0,0,0,0,0 //HT_SKIDTRAP#Skid Trap#
-4191,119,5,120,1,0,0,0,0,0,0,0,0 //HT_SANDMAN#Sandman#
-4191,120,5,115,1,0,0,0,0,0,0,0,0 //HT_FLASHER#Flasher#
-4191,121,5,120,1,0,0,0,0,0,0,0,0 //HT_FREEZINGTRAP#Freezing Trap#
+4191,116,5,0,0,0,0,0,0,0,0,0,0 //HT_LANDMINE#Land Mine#
+4191,126,10,0,0,0,0,0,0,0,0,0,0 //HT_BEASTBANE#Beast Bane#
 4191,138,10,52,1,0,0,0,0,0,0,0,0 //AS_ENCHANTPOISON#Enchant Poison#
+4191,139,10,138,3,0,0,0,0,0,0,0,0 //AS_POISONREACT#Poison React#
+4191,140,10,138,5,0,0,0,0,0,0,0,0 //AS_VENOMDUST#Venom Dust#
+4191,141,10,139,5,140,5,0,0,0,0,0,0 //AS_SPLASHER#Venom Splasher#
+4191,210,10,50,1,0,0,0,0,0,0,0,0 //RG_SNATCHER#Gank#
+4191,211,10,210,4,0,0,0,0,0,0,0,0 //RG_STEALCOIN#Mug#
+4191,212,10,211,4,0,0,0,0,0,0,0,0 //RG_BACKSTAP#Back Stab#
 4191,213,5,51,1,0,0,0,0,0,0,0,0 //RG_TUNNELDRIVE#Stalk#
+4191,214,5,212,2,213,2,0,0,0,0,0,0 //RG_RAID#Sightless Raid#
 4191,226,10,0,0,0,0,0,0,0,0,0,0 //AM_AXEMASTERY#Axe Mastery#
 4191,248,10,0,0,0,0,0,0,0,0,0,0 //CR_TRUST#Faith#
+4191,249,10,0,0,0,0,0,0,0,0,0,0 //CR_AUTOGUARD#Guard#
+4191,250,5,249,5,0,0,0,0,0,0,0,0 //CR_SHIELDCHARGE#Smite#
+4191,251,5,250,3,0,0,0,0,0,0,0,0 //CR_SHIELDBOOMERANG#Shield Boomerang#
 4191,253,10,248,7,0,0,0,0,0,0,0,0 //CR_HOLYCROSS#Holy Cross#
 4191,259,10,23,10,22,10,0,0,0,0,0,0 //MO_IRONHAND#Iron Fists#
 4191,261,5,259,2,0,0,0,0,0,0,0,0 //MO_CALLSPIRITS#Summon Spirit Sphere#
 4191,262,1,261,5,0,0,0,0,0,0,0,0 //MO_ABSORBSPIRITS#Absorb Spirit Sphere#
+4191,270,5,262,1,0,0,0,0,0,0,0,0 //MO_EXPLOSIONSPIRITS#Fury#
 4191,365,1,9,1,0,0,0,0,0,0,0,0 //HW_MAGICCRASHER#Stave Crasher#
+4191,401,1,261,5,262,1,270,5,0,0,0,0 //CH_SOULCOLLECT#Hyper Spirit Sphere#
+4191,5075,5,0,0,0,0,0,0,0,0,0,0 //NV_BREAKTHROUGH#Break Through#
+4191,5076,1,0,0,0,0,0,0,0,0,0,0 //NV_HELPANGEL#Help Angel#
+4191,5077,5,0,0,0,0,0,0,0,0,0,0 //NV_TRANSCENDENCE#Transcendence#
 4191,2535,1,41,1,0,0,0,0,0,0,0,0 //ALL_BUYING_STORE#Open Buying Store#
 4191,2544,1,0,0,0,0,0,0,0,0,0,0 //MC_CARTDECORATE#Cart Decorate#
 4191,5065,1,0,0,0,0,0,0,0,0,0,0 //WE_CHEERUP#Cheer Up#
@@ -5590,12 +5641,12 @@
 4211,3001,1,530,5,0,0,0,0,0,0,0,0 //KO_YAMIKUMO##
 4211,3002,5,0,0,0,0,0,0,0,0,0,0 //KO_RIGHT##
 4211,3003,5,0,0,0,0,0,0,0,0,0,0 //KO_LEFT##
-4211,3004,5,3001,1,0,0,0,0,0,0,0,0 //KO_JYUMONJIKIRI##
+4211,3004,10,3001,1,0,0,0,0,0,0,0,0 //KO_JYUMONJIKIRI##
 4211,3005,5,3004,2,0,0,0,0,0,0,0,0 //KO_SETSUDAN##
 4211,3006,5,524,5,0,0,0,0,0,0,0,0 //KO_BAKURETSU##
 4211,3007,5,3006,1,0,0,0,0,0,0,0,0 //KO_HAPPOKUNAI##
 4211,3008,10,3010,3,0,0,0,0,0,0,0,0 //KO_MUCHANAGE##
-4211,3009,5,525,5,0,0,0,0,0,0,0,0 //KO_HUUMARANKA##
+4211,3009,10,525,5,0,0,0,0,0,0,0,0 //KO_HUUMARANKA##
 4211,3010,5,526,1,0,0,0,0,0,0,0,0 //KO_MAKIBISHI##
 4211,3011,5,533,10,0,0,0,0,0,0,0,0 //KO_MEIKYOUSISUI##
 4211,3012,5,531,1,0,0,0,0,0,0,0,0 //KO_ZANZOU##
@@ -5642,12 +5693,12 @@
 4212,3001,1,530,5,0,0,0,0,0,0,0,0 //KO_YAMIKUMO##
 4212,3002,5,0,0,0,0,0,0,0,0,0,0 //KO_RIGHT##
 4212,3003,5,0,0,0,0,0,0,0,0,0,0 //KO_LEFT##
-4212,3004,5,3001,1,0,0,0,0,0,0,0,0 //KO_JYUMONJIKIRI##
+4212,3004,10,3001,1,0,0,0,0,0,0,0,0 //KO_JYUMONJIKIRI##
 4212,3005,5,3004,2,0,0,0,0,0,0,0,0 //KO_SETSUDAN##
 4212,3006,5,524,5,0,0,0,0,0,0,0,0 //KO_BAKURETSU##
 4212,3007,5,3006,1,0,0,0,0,0,0,0,0 //KO_HAPPOKUNAI##
 4212,3008,10,3010,3,0,0,0,0,0,0,0,0 //KO_MUCHANAGE##
-4212,3009,5,525,5,0,0,0,0,0,0,0,0 //KO_HUUMARANKA##
+4212,3009,10,525,5,0,0,0,0,0,0,0,0 //KO_HUUMARANKA##
 4212,3010,5,526,1,0,0,0,0,0,0,0,0 //KO_MAKIBISHI##
 4212,3011,5,533,10,0,0,0,0,0,0,0,0 //KO_MEIKYOUSISUI##
 4212,3012,5,531,1,0,0,0,0,0,0,0,0 //KO_ZANZOU##
@@ -5846,12 +5897,12 @@
 4223,3001,1,530,5,0,0,0,0,0,0,0,0 //KO_YAMIKUMO##
 4223,3002,5,0,0,0,0,0,0,0,0,0,0 //KO_RIGHT##
 4223,3003,5,0,0,0,0,0,0,0,0,0,0 //KO_LEFT##
-4223,3004,5,3001,1,0,0,0,0,0,0,0,0 //KO_JYUMONJIKIRI##
+4223,3004,10,3001,1,0,0,0,0,0,0,0,0 //KO_JYUMONJIKIRI##
 4223,3005,5,3004,2,0,0,0,0,0,0,0,0 //KO_SETSUDAN##
 4223,3006,5,524,5,0,0,0,0,0,0,0,0 //KO_BAKURETSU##
 4223,3007,5,3006,1,0,0,0,0,0,0,0,0 //KO_HAPPOKUNAI##
 4223,3008,10,3010,3,0,0,0,0,0,0,0,0 //KO_MUCHANAGE##
-4223,3009,5,525,5,0,0,0,0,0,0,0,0 //KO_HUUMARANKA##
+4223,3009,10,525,5,0,0,0,0,0,0,0,0 //KO_HUUMARANKA##
 4223,3010,5,526,1,0,0,0,0,0,0,0,0 //KO_MAKIBISHI##
 4223,3011,5,533,10,0,0,0,0,0,0,0,0 //KO_MEIKYOUSISUI##
 4223,3012,5,531,1,0,0,0,0,0,0,0,0 //KO_ZANZOU##
@@ -5900,12 +5951,12 @@
 4224,3001,1,530,5,0,0,0,0,0,0,0,0 //KO_YAMIKUMO##
 4224,3002,5,0,0,0,0,0,0,0,0,0,0 //KO_RIGHT##
 4224,3003,5,0,0,0,0,0,0,0,0,0,0 //KO_LEFT##
-4224,3004,5,3001,1,0,0,0,0,0,0,0,0 //KO_JYUMONJIKIRI##
+4224,3004,10,3001,1,0,0,0,0,0,0,0,0 //KO_JYUMONJIKIRI##
 4224,3005,5,3004,2,0,0,0,0,0,0,0,0 //KO_SETSUDAN##
 4224,3006,5,524,5,0,0,0,0,0,0,0,0 //KO_BAKURETSU##
 4224,3007,5,3006,1,0,0,0,0,0,0,0,0 //KO_HAPPOKUNAI##
 4224,3008,10,3010,3,0,0,0,0,0,0,0,0 //KO_MUCHANAGE##
-4224,3009,5,525,5,0,0,0,0,0,0,0,0 //KO_HUUMARANKA##
+4224,3009,10,525,5,0,0,0,0,0,0,0,0 //KO_HUUMARANKA##
 4224,3010,5,526,1,0,0,0,0,0,0,0,0 //KO_MAKIBISHI##
 4224,3011,5,533,10,0,0,0,0,0,0,0,0 //KO_MEIKYOUSISUI##
 4224,3012,5,531,1,0,0,0,0,0,0,0,0 //KO_ZANZOU##

+ 1 - 1
doc/atcommands.txt

@@ -1367,7 +1367,7 @@ Affected files:
 -- pcdb: statpoint.txt, job_exp.txt, skill_tree.txt, attr_fix.txt, job_db1.txt, job_db2.txt, job_basehpsp_db.txt, job_maxhpsp_db.txt, job_param_db.txt, level_penalty.txt
 -- questdb: quest_db.txt
 -- script: /npc/*.txt, /npc/*.conf
--- skilldb: skill_db.txt, const.txt, skill_require_db.txt, skill_cast_db.txt, skill_castnodex_db.txt, skill_nocast_db.txt, skill_copyable_db.txt, skill_improvise_db.txt, skill_changematerial_db.txt, skill_nonearnpc_db.txt, skill_damage_db.txt, skill_unit_db.txt, abra_db.txt, create_arrow_db.txt, produce_db.txt, spellbook_db.txt, magicmushroom_db.txt
+-- skilldb: skill_db.yml, const.txt, skill_nocast_db.txt, skill_changematerial_db.txt, skill_damage_db.txt, abra_db.yml, create_arrow_db.txt, produce_db.txt, spellbook_db.yml, magicmushroom_db.yml
 -- statusdb: attr_fix.txt, size_fix.txt, refine_db.txt
 -- achievementdb: achievement_db.conf
 

+ 3 - 2
doc/item_bonus.txt

@@ -65,7 +65,7 @@ This list contains all available constants referenced in the 'bonus' commands.
 	ATF_MISC	= Trigger on misc skills
 
 * Other values:
-	Skill (sk): see 'db/(pre-)re/skill_db.txt' (NOTE: Both skill IDs and names, in quotes, are supported.)
+	Skill (sk): see 'db/(pre-)re/skill_db.yml' (NOTE: Both skill IDs and names, in quotes, are supported.)
 	Monster id (mid): see 'db/(pre-)re/mob_db.txt'
 	Item id (iid): see 'db/(pre-)re/item_db.txt'
 	Item group (ig): see 'db/(pre-)re/item_group_db.txt' and the constants in 'db/const.txt', prefixed with IG_*
@@ -168,7 +168,8 @@ bonus2 bSkillUseSPrate,sk,n;		Decreases SP consumption of skill sk by n%
 Atk/Def
 -------
 bonus2 bSkillAtk,sk,n;    		Increases damage of skill sk by n%
-bonus bLongAtkRate,n;     		Increases damage of ranged attacks by n%
+bonus bShortAtkRate,n;			Increases damage of short ranged attacks by n%
+bonus bLongAtkRate,n;     		Increases damage of long ranged attacks by n%
 bonus bCritAtkRate,n;     		Increases critical damage by +n%
 bonus bCriticalDef,n;     		Decreases the chance of being hit by critical hits by n%
 bonus2 bWeaponAtk,w,n;    		Adds n ATK when weapon of type w is equipped

+ 1 - 1
doc/mapflags.txt

@@ -304,7 +304,7 @@ for 'Map' type 16 will be applied.
 
 This mapflag can also be used to adjust the damage of one skill by a percentage:
  - skill_name:
-	Name of the skill in 'db/(pre-)re/skill_db.txt' (ex. SM_BASH).
+	Name of the skill in 'db/(pre-)re/skill_db.yml' (ex. SM_BASH).
 	To adjust all skill damage, write "all" (without quotes).
  - caster: the groups for which the adjustment takes effect. (bitmask)
 	BL_PC = Player

+ 44 - 15
doc/script_commands.txt

@@ -2910,6 +2910,7 @@ recreate these items perfectly if they are destroyed. Here's what you get:
 @inventorylist_option_id5[]        - fifth array of random option IDs
 @inventorylist_option_value5[]     - fifth array of random option values
 @inventorylist_option_parameter5[] - fifth array of random option parameters
+@inventorylist_tradable            - Returns if an item is tradable or not (Pass item_trade.txt, bound, and rental restrictions).
 
 This could be handy to save/restore a character's inventory, since no other
 command returns such a complete set of data, and could also be the only way to
@@ -3426,7 +3427,7 @@ recalculating guardians' HP.
 This function returns the level of the skill <skill id> of the guild <guild id>.
 If the guild does not have that skill, 0 is returned.
 If the guild does not exist, -1 is returned.
-Refer to 'db/(pre-)re/skill_db.txt' for the full list of skills. (GD_* are guild skills)
+Refer to 'db/(pre-)re/skill_db.yml' for the full list of skills. (GD_* are guild skills)
 
 ---------------------------------------
 
@@ -3459,7 +3460,7 @@ mes "You have " + getMapGuildUsers("prontera",getcharid(2)) + " guild members in
 
 This function returns the level of the specified skill that the invoking
 character has. If they don't have the skill, 0 will be returned. The full list
-of character skills is available in 'db/(pre-)re/skill_db.txt'.
+of character skills is available in 'db/(pre-)re/skill_db.yml'.
 
 There are two main uses for this function, it can check whether the character
 has a skill or not, and it can tell you if the level is high enough.
@@ -4798,8 +4799,9 @@ for special cases such as removing a status change or resetting a variable or st
 of the player.
 
 This command can not be used to rent stackable items. Rental items cannot be
-dropped, traded, sold to NPCs, or placed in guild storage. (i.e. trade mask 75)
+dropped, traded, or placed in guild storage. (i.e. trade mask 67)
 Note: 'delitem' in an NPC script can still remove rental items.
+Note: 'countitem' will not count any item with a rental timer. Use 'rentalcountitem' instead.
 
 ---------------------------------------
 
@@ -5030,6 +5032,32 @@ If player is not in a guild or storage is open, 'guildstoragecountitem2' will re
 
 ---------------------------------------
 
+*rentalcountitem(<item id>{,<accountID>})
+*rentalcountitem("<item name>"{,<accountID>})
+
+This function will return the number of rental items for the specified item ID that the
+invoking character has in the inventory.
+
+---------------------------------------
+
+*rentalcountitem2(<item id>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<accountID>})
+*rentalcountitem2("<item name>",<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<accountID>})
+*rentalcountitem3(<item id>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>,<RandomIDArray>,<RandomValueArray>,<RandomParamArray>{,<accountID>})
+*rentalcountitem3("<item name>",<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>,<RandomIDArray>,<RandomValueArray>,<RandomParamArray>{,<accountID>})
+
+Expanded version of 'rentalcountitem' function, used for created/carded/forged items.
+
+This function will return the number of rental items for the specified item ID and
+other parameters that the invoking character has in the inventory.
+See 'getitem2' for an explanation of the expanded parameters.
+
+'rentalcountitem3' is advance version of 'rentalcountitem2' that also use Item Random Option as criteria.
+<RandomIDArray>    : Array variable of ID for item random option, see db/[pre-]re/item_randomopt_db.txt
+<RandomValueArray> : Array variable of item random option's value.
+<RandomParamArray> : Array variable of item random option's param.
+
+---------------------------------------
+
 *countbound({<bound type>{,<char_id>}})
 
 This function will return the number of bounded items in the character's
@@ -5583,7 +5611,7 @@ levels. This refers to the invoking character and will only work if the invoking
 character is a member of a guild AND its guild master, otherwise no failure
 message will be given and no error will occur, but nothing will happen - same
 about the guild skill trying to exceed the possible maximum. The full list of
-guild skills is available in 'db/(pre-)re/skill_db.txt', these are all the GD_ skills at
+guild skills is available in 'db/(pre-)re/skill_db.yml', these are all the GD_ skills at
 the end.
 
 // This would give your character's guild one level of Approval (GD_APPROVAL ID
@@ -5970,7 +5998,7 @@ These commands will give the invoking character a specified skill. This is also
 used for item scripts.
 
 Level is obvious. Skill id is the ID number of the skill in question as per
-'db/(pre-)re/skill_db.txt'. It is not known for certain whether this can be used to give
+'db/(pre-)re/skill_db.yml'. It is not known for certain whether this can be used to give
 a character a monster's skill, but you're welcome to try with the numbers given
 in 'db/(pre-)re/mob_skill_db.txt'.
 
@@ -6596,13 +6624,14 @@ Returns true if the command was executed on the other NPC successfully, false if
 
 ---------------------------------------
 
-*npctalk "<message>"{,"<NPC name>","<flag>"};
+*npctalk "<message>"{,"<NPC name>",<flag>{,<color>}};
 
 This command will display a message as if the NPC object running it was a player
 talking - that is, above their head and in the chat window.
 The display name of the NPC won't get appended in front of the message.
 If the <NPC name> option is given and not empty, then that NPC will display the message,
-else the attached NPC will display the message.
+else the attached NPC will display the message,
+the color format is in RGB (0xRRGGBB). The color is White by default.
 
 Target for <flag>:
 - bc_all  : Broadcast message is sent server-wide (only in the chat window).
@@ -9392,19 +9421,19 @@ Example:
 
 ---------------------------------------
 
-*bg_reserve("<battleground_name>");
+*bg_reserve("<battleground_map_name>"{,<ended>});
 
-Reserves a slot for the given Battleground for the Battleground UI System.
+Reserves a Battleground map for the Battleground UI System. When a map is booked it prevents another similar
+queue from being created and will allow players to join an active Battlegrounds event.
 
-Note: 'bg_reserve' and 'bg_unbook' prevent the Battlegrounds queue from joining players in an active Battleground.
+If <ended> is true, then the Battleground is marked as over to prevent new players from joining. This state is meant
+for the period where players can get their Badges.
 
 ---------------------------------------
 
-*bg_unbook("<battleground_name>");
-
-Removes a spot for the given Battleground for the Battleground UI System.
+*bg_unbook("<battleground_map_name>");
 
-Note: 'bg_reserve' and 'bg_unbook' prevent the Battlegrounds queue from joining players in an active Battleground.
+Removes a Battleground map for the Battleground UI System. When a map is unbooked it allows a queue to be created.
 
 ---------------------------------------
 
@@ -9701,7 +9730,7 @@ when pet performance is activated.
 
 This will make the pet use a specified support skill on the owner whenever the
 HP and SP are below the given percent values, with a specified delay time
-between activations. The skill numbers are as per 'db/(pre-)re/skill_db.txt'.
+between activations. The skill numbers are as per 'db/(pre-)re/skill_db.yml'.
 
 It's not quite certain who's stats will be used for the skills cast, the
 character's or the pets. Probably, Skotlex can answer that question.

+ 2 - 2
doc/skill_db.txt

@@ -97,11 +97,11 @@ AllowOnWarg					- Usable while riding Warg.
 AllowOnMado					- Usable while on Madogear.
 TargetManHole				- Target enemy with SC__MANHOLE.
 TargetHidden				- Target enemy with OPTION_HIDE.
-IncreaseGloomyDayDamage		- Increase SC_GLOOMYDAY_SK damage.
 IncreaseDanceWithWugDamage	- Increase SC_DANCEWITHWUG damage.
 IgnoreWugBite				- Ignore RA_WUGBITE.
-IgnoreAutoGuard			- Not blocked by SC_AUTOGUARD (When TargetType is Weapon only).
+IgnoreAutoGuard				- Not blocked by SC_AUTOGUARD (When TargetType is Weapon only).
 IgnoreCicada				- Not blocked by SC_UTSUSEMI or SC_BUNSINJYUTSU (When TargetType is Weapon only).
+ShowScale					- Shows AoE area while casting
 
 ---------------------------------------
 

+ 0 - 10
doc/yaml/db/improvise_db.yml

@@ -1,10 +0,0 @@
-###########################################################################
-# Improvised Song Database
-###########################################################################
-#
-# Improvised Song Settings
-#
-###########################################################################
-# - Skill             Skill to be casted by Improvised Song.
-#   Probability       Probability of skill compared to others in database (1 = 0.01%, 10000 = 100%).
-###########################################################################

+ 2 - 0
doc/yaml/db/instance_db.yml

@@ -9,6 +9,8 @@
 #   Name              Instance Name.
 #   TimeLimit         Total lifetime of instance in seconds. (Default: 3600)
 #   IdleTimeOut       Time before an idle instance is destroyed in seconds. (Default: 300)
+#   Destroyable       Toggles the ability to destroy the instance using instance 'Destroy' button. (Default: true)
+#                     Note: the button is displayed based on parties. For any mode, it requires the party leader to be the instance owner to destroy it.
 #   Enter:            Instance entrance coordinates.
 #     Map             Map Name where players start.
 #     X               X Coordinate where players start.

+ 52 - 40
npc/battleground/flavius/flavius01.txt

@@ -58,25 +58,21 @@ OnStop:
 
 OnTimer1000:
 	stopnpctimer;
-	if (!getbattleflag("feature.bgqueue"))
-		initnpctimer;
-	set .@chk_bat_a01,getmapusers("bat_b01");
-	if (.@chk_bat_a01 < 1) {
-		set $@FlaviusBG1, 0;
-		if( $@FlaviusBG1_id1 ) { bg_destroy $@FlaviusBG1_id1; set $@FlaviusBG1_id1, 0; }
-		if( $@FlaviusBG1_id2 ) { bg_destroy $@FlaviusBG1_id2; set $@FlaviusBG1_id2, 0; }
-		if (getbattleflag("feature.bgqueue")) {
+	if (bg_get_data($@FlaviusBG1_id1, 0) == 0 && bg_get_data($@FlaviusBG1_id2, 0) == 0) {
+		donpcevent "countdown#bat_b01::OnStop";
+		if (getbattleflag("feature.bgqueue"))
+			bg_reserve "bat_b01", true;
+		$@FlaviusBG1 = 0;
+		if( $@FlaviusBG1_id1 ) { bg_destroy $@FlaviusBG1_id1; $@FlaviusBG1_id1 = 0; }
+		if( $@FlaviusBG1_id2 ) { bg_destroy $@FlaviusBG1_id2; $@FlaviusBG1_id2 = 0; }
+		if (getbattleflag("feature.bgqueue"))
 			bg_unbook "bat_b01";
-			end;
-		} else
-			donpcevent "start#bat_b01::OnReadyCheck";
+		end;
 	}
-	if (getbattleflag("feature.bgqueue"))
-		initnpctimer;
+	initnpctimer;
 	end;
 }
 
-
 // Flavius Battleground Engine
 //============================================================
 bat_b01,15,15,3	script	start#bat_b01	844,{
@@ -139,13 +135,14 @@ OnReset:
 	donpcevent "guardian#bat_b01_b::OnEnable";
 	donpcevent "cell#bat_b01_a::OnRed";
 	donpcevent "cell#bat_b01_b::OnRed";
-	donpcevent "time#bat_b01::OnEnable";
-	disablenpc "Guillaume Vintenar#b01_a";
-	disablenpc "Croix Vintenar#b01_b";
-	disablenpc "Vintenar#bat_b01_aover";
-	disablenpc "Vintenar#bat_b01_bover";
-	bg_warp $@FlaviusBG1_id1,"bat_b01",87,75;
-	bg_warp $@FlaviusBG1_id2,"bat_b01",311,224;
+	end;
+
+OnGuillaumeActive:
+	warp "bat_b01",87,75;
+	end;
+
+OnCroixActive:
+	warp "bat_b01",311,224;
 	end;
 
 OnGuillaumeQuit:
@@ -181,6 +178,8 @@ OnMyMobDead:
 			enablenpc "Guillaume Vintenar#b01_a";
 			enablenpc "Croix Vintenar#b01_b";
 			donpcevent "time#bat_b01::OnStop";
+			if (getbattleflag("feature.bgqueue"))
+				bg_reserve "bat_b01", true;
 		}
 		else {
 			set $@Croix_ScoreBG1,1;
@@ -215,6 +214,8 @@ OnMyMobDead:
 			enablenpc "Guillaume Vintenar#b01_a";
 			enablenpc "Croix Vintenar#b01_b";
 			donpcevent "time#bat_b01::OnStop";
+			if (getbattleflag("feature.bgqueue"))
+				bg_reserve "bat_b01", true;
 		}
 		else {
 			set $@Guill_ScoreBG1,1;
@@ -314,12 +315,14 @@ bat_b01,10,294,3	script	Battle Therapist#b01_a	95,{
 
 OnTimer25000:
 	specialeffect EF_SANCTUARY;
-	enablenpc "bat_b01_rp1_a_warp";
+	// enablenpc "bat_b01_rp1_a_warp";
+	areapercentheal "bat_b01",0,280,20,300,100,100;
+	areawarp "bat_b01",0,280,20,300,"bat_b01",87,73;
 	end;
 
-OnTimer26000:
-	disablenpc "bat_b01_rp1_a_warp";
-	end;
+// OnTimer26000:
+	// disablenpc "bat_b01_rp1_a_warp";
+	// end;
 
 OnTimer26500:
 	stopnpctimer;
@@ -332,22 +335,25 @@ OnEnable:
 	end;
 
 OnStop:
-	disablenpc "bat_b01_rp1_a_warp";
+	// disablenpc "bat_b01_rp1_a_warp";
 	disablenpc "Battle Therapist#b01_a";
 	stopnpctimer;
 	end;
 }
 
+/*
+// replaced by areapercentheal and areawarp to prevent enqueue issue
 bat_b01,10,290,0	script	bat_b01_rp1_a_warp	45,10,10,{
 OnInit:
 	disablenpc "bat_b01_rp1_a_warp";
 	end;
 
-OnTouch_:
+OnTouch:
 	percentheal 100,100;
 	warp "bat_b01",87,73;
 	end;
 }
+*/
 
 bat_b01,389,14,3	script	Battle Therapist#b01_b	95,{
 	specialeffect2 EF_HEAL;
@@ -359,12 +365,14 @@ bat_b01,389,14,3	script	Battle Therapist#b01_b	95,{
 
 OnTimer25000:
 	specialeffect EF_SANCTUARY;
-	enablenpc "bat_b01_rp1_b_warp";
+	// enablenpc "bat_b01_rp1_b_warp";
+	areapercentheal "bat_b01",379,0,399,20,100,100;
+	areawarp "bat_b01",379,0,399,20,"bat_b01",312,225;
 	end;
 
-OnTimer26000:
-	disablenpc "bat_b01_rp1_b_warp";
-	end;
+// OnTimer26000:
+	// disablenpc "bat_b01_rp1_b_warp";
+	// end;
 
 OnTimer26500:
 	stopnpctimer;
@@ -377,15 +385,16 @@ OnEnable:
 	end;
 
 OnStop:
-	disablenpc "bat_b01_rp1_b_warp";
+	// disablenpc "bat_b01_rp1_b_warp";
 	disablenpc "Battle Therapist#b01_b";
 	stopnpctimer;
 	end;
 }
 
-bat_b01,389,10,0	script	bat_b01_rp1_b_warp	45,9,9,{
+/*
+bat_b01,389,10,0	script	bat_b01_rp1_b_warp	45,10,10,{
 OnInit:
-	disablenpc "bat_b01_rp1_a_warp";
+	disablenpc "bat_b01_rp1_b_warp";
 	end;
 
 OnTouch:
@@ -393,6 +402,7 @@ OnTouch:
 	warp "bat_b01",312,225;
 	end;
 }
+*/
 
 bat_b01,87,76,0	script	A_CODE#bat_b01	-1,5,5,{
 OnTouch:
@@ -490,6 +500,8 @@ OnTimer1830000:
 	bg_warp $@FlaviusBG1_id2,"bat_b01",390,10;
 	enablenpc "Vintenar#bat_b01_aover";
 	enablenpc "Vintenar#bat_b01_bover";
+	if (getbattleflag("feature.bgqueue"))
+		bg_reserve "bat_b01", true;
 	end;
 
 OnTimer1900000:
@@ -526,11 +538,11 @@ bat_b01,10,294,3	script	Vintenar#bat_b01_aover	419,{
 	set .@A_B_gap,$@Guill_ScoreBG1 - $@Croix_ScoreBG1;
 	if ($@FlaviusBG1_id1 == getcharid(4)) {
 		if (.@A_B_gap > 0)
-			callfunc "F_BG_Badge",1,"Guillaume","Flavius";
+			callfunc "F_BG_Badge",1,"Guillaume","Flavius"; //Guillaume wins
 		else if (.@A_B_gap == 0)
-			callfunc "F_BG_Badge",0,"Guillaume","Flavius";
+			callfunc "F_BG_Badge",0,"Guillaume","Flavius"; //Tie
 		else
-			callfunc "F_BG_Badge",0,"Guillaume","Flavius";
+			callfunc "F_BG_Badge",0,"Guillaume","Flavius"; //Croix wins
 	}
 	else {
 		mes "[Axl Rose]";
@@ -551,11 +563,11 @@ bat_b01,389,14,3	script	Vintenar#bat_b01_bover	415,{
 	set .@A_B_gap,$@Guill_ScoreBG1 - $@Croix_ScoreBG1;
 	if ($@FlaviusBG1_id2 == getcharid(4)) {
 		if (.@A_B_gap > 0)
-			callfunc "F_BG_Badge",1,"Croix","Flavius";
+			callfunc "F_BG_Badge",0,"Croix","Flavius"; //Guillaume wins
 		else if (.@A_B_gap == 0)
-			callfunc "F_BG_Badge",0,"Croix","Flavius";
+			callfunc "F_BG_Badge",0,"Croix","Flavius"; //Tie
 		else
-			callfunc "F_BG_Badge",1,"Croix","Flavius";
+			callfunc "F_BG_Badge",1,"Croix","Flavius"; //Croix wins
 	}
 	else {
 		mes "[Swandery]";

+ 56 - 44
npc/battleground/flavius/flavius02.txt

@@ -59,21 +59,18 @@ OnStop:
 
 OnTimer1000:
 	stopnpctimer;
-	if (!getbattleflag("feature.bgqueue"))
-		initnpctimer;
-	set .@chk_bat_a01,getmapusers("bat_b02");
-	if (.@chk_bat_a01 < 1) {
-		set $@FlaviusBG2, 0;
-		if( $@FlaviusBG2_id1 ) { bg_destroy $@FlaviusBG2_id1; set $@FlaviusBG2_id1, 0; }
-		if( $@FlaviusBG2_id2 ) { bg_destroy $@FlaviusBG2_id2; set $@FlaviusBG2_id2, 0; }
-		if (getbattleflag("feature.bgqueue")) {
-			bg_unbook "bat_b01";
-			end;
-		} else
-			donpcevent "start#bat_b01::OnReadyCheck";
+	if (bg_get_data($@FlaviusBG2_id1, 0) == 0 && bg_get_data($@FlaviusBG2_id2, 0) == 0) {
+		donpcevent "countdown#bat_b02::OnStop";
+		if (getbattleflag("feature.bgqueue"))
+			bg_reserve "bat_b02", true;
+		$@FlaviusBG2 = 0;
+		if( $@FlaviusBG2_id1 ) { bg_destroy $@FlaviusBG2_id1; $@FlaviusBG2_id1 = 0; }
+		if( $@FlaviusBG2_id2 ) { bg_destroy $@FlaviusBG2_id2; $@FlaviusBG2_id2 = 0; }
+		if (getbattleflag("feature.bgqueue"))
+			bg_unbook "bat_b02";
+		end;
 	}
-	if (getbattleflag("feature.bgqueue"))
-		initnpctimer;
+	initnpctimer;
 	end;
 }
 
@@ -89,7 +86,7 @@ OnReadyCheck:
 	if( $@FlaviusBG2 )
 		end;
 	if (!getbattleflag("feature.bgqueue")) {
-			set .@Guillaume, getwaitingroomstate(0,"Lieutenant Huvas");
+		set .@Guillaume, getwaitingroomstate(0,"Lieutenant Huvas");
 		set .@Croix, getwaitingroomstate(0,"Lieutenant Yukon");
 		if( !.@Guillaume && !.@Croix ) {
 			donpcevent "#bat_b02_timer::OnStop";
@@ -102,8 +99,8 @@ OnReadyCheck:
 	set $@FlaviusBG2_Victory, 0;
 	set $@Croix_ScoreBG2, 0;
 	set $@Guill_ScoreBG2, 0;
-
 	bg_updatescore "bat_b02",$@Guill_ScoreBG2,$@Croix_ScoreBG2;
+
 	if (!getbattleflag("feature.bgqueue")) {
 		donpcevent "Lieutenant Huvas::OnEnterBG";
 		donpcevent "Lieutenant Yukon::OnEnterBG";
@@ -140,13 +137,14 @@ OnReset:
 	donpcevent "guardian#bat_b02_b::OnEnable";
 	donpcevent "cell#bat_b02_a::OnRed";
 	donpcevent "cell#bat_b02_b::OnRed";
-	donpcevent "time#bat_b02::OnEnable";
-	disablenpc "Guillaume Vintenar#b02_a";
-	disablenpc "Croix Vintenar#b02_b";
-	disablenpc "Vintenar#bat_b02_aover";
-	disablenpc "Vintenar#bat_b02_bover";
-	bg_warp $@FlaviusBG2_id1,"bat_b02",87,75;
-	bg_warp $@FlaviusBG2_id2,"bat_b02",311,224;
+	end;
+
+OnGuillaumeActive:
+	warp "bat_b02",87,75;
+	end;
+
+OnCroixActive:
+	warp "bat_b02",311,224;
 	end;
 
 OnGuillaumeQuit:
@@ -182,6 +180,8 @@ OnMyMobDead:
 			enablenpc "Guillaume Vintenar#b02_a";
 			enablenpc "Croix Vintenar#b02_b";
 			donpcevent "time#bat_b02::OnStop";
+			if (getbattleflag("feature.bgqueue"))
+				bg_reserve "bat_b02", true;
 		}
 		else {
 			set $@Croix_ScoreBG2,1;
@@ -216,6 +216,8 @@ OnMyMobDead:
 			enablenpc "Guillaume Vintenar#b02_a";
 			enablenpc "Croix Vintenar#b02_b";
 			donpcevent "time#bat_b02::OnStop";
+			if (getbattleflag("feature.bgqueue"))
+				bg_reserve "bat_b02", true;
 		}
 		else {
 			set $@Guill_ScoreBG2,1;
@@ -315,12 +317,14 @@ bat_b02,10,294,3	script	Battle Therapist#b02_a	95,{
 
 OnTimer25000:
 	specialeffect EF_SANCTUARY;
-	enablenpc "bat_b02_rp1_a_warp";
+	// enablenpc "bat_b02_rp1_a_warp";
+	areapercentheal "bat_b02",0,280,20,300,100,100;
+	areawarp "bat_b02",0,280,20,300,"bat_b02",87,73;
 	end;
 
-OnTimer26000:
-	disablenpc "bat_b02_rp1_a_warp";
-	end;
+// OnTimer26000:
+	// disablenpc "bat_b02_rp1_a_warp";
+	// end;
 
 OnTimer26500:
 	stopnpctimer;
@@ -333,22 +337,24 @@ OnEnable:
 	end;
 
 OnStop:
-	disablenpc "bat_b02_rp1_a_warp";
+	// disablenpc "bat_b02_rp1_a_warp";
 	disablenpc "Battle Therapist#b02_a";
 	stopnpctimer;
 	end;
 }
 
+/*
 bat_b02,10,290,0	script	bat_b02_rp1_a_warp	45,10,10,{
 OnInit:
 	disablenpc "bat_b02_rp1_a_warp";
 	end;
 
-OnTouch_:
+OnTouch:
 	percentheal 100,100;
 	warp "bat_b02",87,73;
 	end;
 }
+*/
 
 bat_b02,389,14,3	script	Battle Therapist#b02_b	95,{
 	specialeffect2 EF_HEAL;
@@ -360,12 +366,14 @@ bat_b02,389,14,3	script	Battle Therapist#b02_b	95,{
 
 OnTimer25000:
 	specialeffect EF_SANCTUARY;
-	enablenpc "bat_b02_rp1_b_warp";
+	areapercentheal "bat_b02",379,0,399,20,100,100;
+	areawarp "bat_b02",379,0,399,20,"bat_b02",312,225;
+	// enablenpc "bat_b02_rp1_b_warp";
 	end;
 
-OnTimer26000:
-	disablenpc "bat_b02_rp1_b_warp";
-	end;
+// OnTimer26000:
+	// disablenpc "bat_b02_rp1_b_warp";
+	// end;
 
 OnTimer26500:
 	stopnpctimer;
@@ -378,15 +386,16 @@ OnEnable:
 	end;
 
 OnStop:
-	disablenpc "bat_b02_rp1_b_warp";
+	// disablenpc "bat_b02_rp1_b_warp";
 	disablenpc "Battle Therapist#b02_b";
 	stopnpctimer;
 	end;
 }
 
-bat_b02,389,10,0	script	bat_b02_rp1_b_warp	45,9,9,{
+/*
+bat_b02,389,10,0	script	bat_b02_rp1_b_warp	45,10,10,{
 OnInit:
-	disablenpc "bat_b02_rp1_a_warp";
+	disablenpc "bat_b02_rp1_b_warp";
 	end;
 
 OnTouch:
@@ -394,18 +403,19 @@ OnTouch:
 	warp "bat_b02",312,225;
 	end;
 }
+*/
 
 bat_b02,87,76,0	script	A_CODE#bat_b02	-1,5,5,{
 OnTouch:
 	if (checkquest(2070) < 0)
-		//setquest 2070;
+		setquest 2070;
 	end;
 }
 
 bat_b02,312,224,0	script	B_CODE#bat_b02	-1,5,5,{
 OnTouch:
 	if (checkquest(2070) < 0)
-		//setquest 2070;
+		setquest 2070;
 	end;
 }
 
@@ -491,6 +501,8 @@ OnTimer1830000:
 	bg_warp $@FlaviusBG2_id2,"bat_b02",390,10;
 	enablenpc "Vintenar#bat_b02_aover";
 	enablenpc "Vintenar#bat_b02_bover";
+	if (getbattleflag("feature.bgqueue"))
+		bg_reserve "bat_b02", true;
 	end;
 
 OnTimer1900000:
@@ -527,11 +539,11 @@ bat_b02,10,294,3	script	Vintenar#bat_b02_aover	419,{
 	set .@A_B_gap,$@Guill_ScoreBG2 - $@Croix_ScoreBG2;
 	if ($@FlaviusBG2_id1 == getcharid(4)) {
 		if (.@A_B_gap > 0)
-			callfunc "F_BG_Badge",1,"Guillaume","Flavius";
+			callfunc "F_BG_Badge",1,"Guillaume","Flavius"; //Guillaume wins
 		else if (.@A_B_gap == 0)
-			callfunc "F_BG_Badge",0,"Guillaume","Flavius";
+			callfunc "F_BG_Badge",0,"Guillaume","Flavius"; //Tie
 		else
-			callfunc "F_BG_Badge",0,"Guillaume","Flavius";
+			callfunc "F_BG_Badge",0,"Guillaume","Flavius"; //Croix wins
 	}
 	else {
 		mes "[Axl Rose]";
@@ -552,11 +564,11 @@ bat_b02,389,14,3	script	Vintenar#bat_b02_bover	415,{
 	set .@A_B_gap,$@Guill_ScoreBG2 - $@Croix_ScoreBG2;
 	if ($@FlaviusBG2_id2 == getcharid(4)) {
 		if (.@A_B_gap > 0)
-			callfunc "F_BG_Badge",1,"Croix","Flavius";
+			callfunc "F_BG_Badge",0,"Croix","Flavius"; //Guillaume wins
 		else if (.@A_B_gap == 0)
-			callfunc "F_BG_Badge",0,"Croix","Flavius";
+			callfunc "F_BG_Badge",0,"Croix","Flavius"; //Tie
 		else
-			callfunc "F_BG_Badge",1,"Croix","Flavius";
+			callfunc "F_BG_Badge",1,"Croix","Flavius"; //Croix wins
 	}
 	else {
 		mes "[Swandery]";

+ 11 - 1
npc/battleground/kvm/kvm01.txt

@@ -155,6 +155,14 @@ OnCroixDie:
 	}
 	end;
 
+OnGuillaumeActive:
+	warp "bat_c01",61,120;
+	end;
+
+OnCroixActive:
+	warp "bat_c01",138,63;
+	end;
+
 OnStart:
 	disablenpc "KVM Officer#KVM01A";
 	disablenpc "KVM Officer#KVM01B";
@@ -224,6 +232,7 @@ OnTimer61000:
 			end;
 		}
 	}
+	bg_updatescore "bat_c01",.Guillaume_Count,.Croix_Count;
 	set $@KvM01BG, 2; // Playing
 	bg_warp $@KvM01BG_id1,"bat_c01",61,120;
 	bg_warp $@KvM01BG_id2,"bat_c01",138,63;
@@ -292,6 +301,8 @@ OnStop:
 	bg_warp $@KvM01BG_id1,"bat_c01",53,128;
 	bg_warp $@KvM01BG_id2,"bat_c01",146,55;
 	donpcevent "KvM01_BG_Out::OnBegin";
+	if (getbattleflag("feature.bgqueue"))
+		bg_reserve "bat_c01", true;
 	end;
 }
 
@@ -333,7 +344,6 @@ OnTimer60000:
 	disablenpc "KVM Officer#KVM01B";
 	mapwarp "bat_c01","bat_room",154,150;
 	maprespawnguildid "bat_c01",0,3; // Just in case someone else
-	bg_updatescore "bat_c01",5,5;
 	set $@KvM01BG, 0;
 
 OnGuillaumeJoin:

+ 11 - 1
npc/battleground/kvm/kvm02.txt

@@ -155,6 +155,14 @@ OnCroixDie:
 	}
 	end;
 
+OnGuillaumeActive:
+	warp "bat_c02",62,119;
+	end;
+
+OnCroixActive:
+	warp "bat_c02",137,64;
+	end;
+
 OnStart:
 	disablenpc "KVM Officer#KVM02A";
 	disablenpc "KVM Officer#KVM02B";
@@ -224,6 +232,7 @@ OnTimer61000:
 			end;
 		}
 	}
+	bg_updatescore "bat_c02",.Guillaume_Count,.Croix_Count;
 	set $@KvM02BG, 2; // Playing
 	bg_warp $@KvM02BG_id1,"bat_c02",62,119;
 	bg_warp $@KvM02BG_id2,"bat_c02",137,64;
@@ -292,6 +301,8 @@ OnStop:
 	bg_warp $@KvM02BG_id1,"bat_c02",53,128;
 	bg_warp $@KvM02BG_id2,"bat_c02",146,55;
 	donpcevent "KvM02_BG_Out::OnBegin";
+	if (getbattleflag("feature.bgqueue"))
+		bg_reserve "bat_c02", true;
 	end;
 }
 
@@ -333,7 +344,6 @@ OnTimer60000:
 	disablenpc "KVM Officer#KVM02B";
 	mapwarp "bat_c02","bat_room",154,150;
 	maprespawnguildid "bat_c02",0,3; // Just in case someone else
-	bg_updatescore "bat_c02",5,5;
 	set $@KvM02BG, 0;
 
 OnGuillaumeJoin:

+ 11 - 1
npc/battleground/kvm/kvm03.txt

@@ -155,6 +155,14 @@ OnCroixDie:
 	}
 	end;
 
+OnGuillaumeActive:
+	warp "bat_c03",62,119;
+	end;
+
+OnCroixActive:
+	warp "bat_c03",137,64;
+	end;
+
 OnStart:
 	disablenpc "KVM Officer#KVM03A";
 	disablenpc "KVM Officer#KVM03B";
@@ -224,6 +232,7 @@ OnTimer61000:
 			end;
 		}
 	}
+	bg_updatescore "bat_c03",.Guillaume_Count,.Croix_Count;
 	set $@KvM03BG, 2; // Playing
 	bg_warp $@KvM03BG_id1,"bat_c03",62,119;
 	bg_warp $@KvM03BG_id2,"bat_c03",137,64;
@@ -292,6 +301,8 @@ OnStop:
 	bg_warp $@KvM03BG_id1,"bat_c03",53,128;
 	bg_warp $@KvM03BG_id2,"bat_c03",146,55;
 	donpcevent "KvM03_BG_Out::OnBegin";
+	if (getbattleflag("feature.bgqueue"))
+		bg_reserve "bat_c03", true;
 	end;
 }
 
@@ -333,7 +344,6 @@ OnTimer60000:
 	disablenpc "KVM Officer#KVM03B";
 	mapwarp "bat_c03","bat_room",154,150;
 	maprespawnguildid "bat_c03",0,3; // Just in case someone else
-	bg_updatescore "bat_c03",5,5;
 	set $@KvM03BG, 0;
 
 OnGuillaumeJoin:

+ 57 - 32
npc/battleground/tierra/tierra01.txt

@@ -58,21 +58,18 @@ OnStop:
 
 OnTimer1000:
 	stopnpctimer;
-	if (!getbattleflag("feature.bgqueue"))
-		initnpctimer;
-	set .@chk_bat_a01,getmapusers("bat_a01");
-	if (.@chk_bat_a01 < 1) {
-		set $@TierraBG1,0; set $@TierraBG1_Victory, 0;
-		if( $@TierraBG1_id1 ) { bg_destroy $@TierraBG1_id1; set $@TierraBG1_id1, 0; }
-		if( $@TierraBG1_id2 ) { bg_destroy $@TierraBG1_id2; set $@TierraBG1_id2, 0; }
-		if (getbattleflag("feature.bgqueue")) {
+	if (bg_get_data($@TierraBG1_id1, 0) == 0 && bg_get_data($@TierraBG1_id2, 0) == 0) {
+		donpcevent "countdown#bat_a01::OnStop";
+		if (getbattleflag("feature.bgqueue"))
+			bg_reserve "bat_a01", true;
+		$@TierraBG1 = 0; $@TierraBG1_Victory = 0;
+		if( $@TierraBG1_id1 ) { bg_destroy $@TierraBG1_id1; $@TierraBG1_id1 = 0; }
+		if( $@TierraBG1_id2 ) { bg_destroy $@TierraBG1_id2; $@TierraBG1_id2 = 0; }
+		if (getbattleflag("feature.bgqueue"))
 			bg_unbook "bat_a01";
-			end;
-		} else
-			donpcevent "start#bat_a01::OnReadyCheck";
+		end;
 	}
-	if (getbattleflag("feature.bgqueue"))
-		initnpctimer;
+	initnpctimer;
 	end;
 }
 
@@ -126,6 +123,14 @@ OnEnable:
 	disablenpc "Croix Vintenar#a01_b";
 	end;
 
+OnGuillaumeActive:
+	warp "bat_a01",352,342;
+	end;
+
+OnCroixActive:
+	warp "bat_a01",353,52;
+	end;
+
 OnGuillaumeQuit:
 OnCroixQuit:
 	if (getbattleflag("feature.bgqueue"))
@@ -183,6 +188,8 @@ OnMyMobDead:
 		mapannounce "bat_a01", "Croix Vintenar Swandery: We destroyed Guillaume's Food Storage. We won that! Wow!",bc_map,"0xFFCE00";
 		bg_warp $@TierraBG1_id1,"bat_a01",50,374;
 		bg_warp $@TierraBG1_id2,"bat_a01",42,16;
+		if (getbattleflag("feature.bgqueue"))
+			bg_reserve "bat_a01", true;
 	}
 	end;
 }
@@ -206,6 +213,8 @@ OnMyMobDead:
 		mapannounce "bat_a01", "Guillaume Vintenar Axl Rose : We destroyed Croix's Food Storage. We won that! Wow!",bc_map,"0xFFCE00";
 		bg_warp $@TierraBG1_id1,"bat_a01",50,374;
 		bg_warp $@TierraBG1_id2,"bat_a01",42,16;
+		if (getbattleflag("feature.bgqueue"))
+			bg_reserve "bat_a01", true;
 	}
 	end;
 }
@@ -364,8 +373,10 @@ bat_a01,185,270,1	script	Guillaume Blacksmith#a01	851,{
 				mes "[Guillaume Blacksmith]";
 				mes "Wow! It's done.";
 				mes "We are relieved.";
-				delitem 7049,50; //Stone
-				donpcevent "barricade#bat_a01_a::OnEnable";
+				if (mobcount("bat_a01","barricade#bat_a01_a::OnMyMobDead") < 17) {
+					delitem 7049,50; //Stone
+					donpcevent "barricade#bat_a01_a::OnEnable";
+				}
 				close2;
 				disablenpc "Guillaume Blacksmith#a01";
 				end;
@@ -448,8 +459,10 @@ bat_a01,170,121,5	script	Croix Blacksmith#bat_a01	851,{
 				mes "[Croix Blacksmith]";
 				mes "Wow! It's done.";
 				mes "We are relieved.";
-				delitem 7049,50; //Stone
-				donpcevent "barricade#bat_a01_b::OnEnable";
+				if (mobcount("bat_a01","barricade#bat_a01_b::OnMyMobDead") < 17) {
+					delitem 7049,50; //Stone
+					donpcevent "barricade#bat_a01_b::OnEnable";
+				}
 				close2;
 				disablenpc "Croix Blacksmith#bat_a01";
 				end;
@@ -500,35 +513,39 @@ OnEnable:
 	end;
 
 OnStop:
-	disablenpc "bat_a01_rp1_a_warp";
+	// disablenpc "bat_a01_rp1_a_warp";
 	disablenpc "Battle Therapist#a01_a";
 	stopnpctimer;
 	end;
 
 OnTimer25000:
 	specialeffect EF_SANCTUARY;
-	enablenpc "bat_a01_rp1_a_warp";
+	// enablenpc "bat_a01_rp1_a_warp";
+	areapercentheal "bat_a01",41,365,61,385,100,100;
+	areawarp "bat_a01",41,365,61,385,"bat_a01",352,342;
 	end;
 
-OnTimer26000:
-	disablenpc "bat_a01_rp1_a_warp";
-	end;
+// OnTimer26000:
+	// disablenpc "bat_a01_rp1_a_warp";
+	// end;
 
 OnTimer26500:
 	donpcevent "Battle Therapist#a01_a::OnEnable";
 	end;
 }
 
+/*
 bat_a01,51,375,0	script	bat_a01_rp1_a_warp	-1,10,10,{
 OnInit:
 	disablenpc "bat_a01_rp1_a_warp";
 	end;
 
-OnTouch_:
+OnTouch:
 	percentheal 100,100;
 	warp "bat_a01",352,342;
 	end;
 }
+*/
 
 bat_a01,45,19,3	script	Battle Therapist#a01_b	95,{
 	specialeffect2 EF_HEAL;
@@ -550,25 +567,28 @@ OnEnable:
 	end;
 
 OnStop:
-	disablenpc "bat_a01_rp1_b_warp";
+	// disablenpc "bat_a01_rp1_b_warp";
 	disablenpc "Battle Therapist#a01_b";
 	stopnpctimer;
 	end;
 
 OnTimer25000:
 	specialeffect EF_SANCTUARY;
-	enablenpc "bat_a01_rp1_b_warp";
+	areapercentheal "bat_a01",33,7,53,27,100,100;
+	areawarp "bat_a01",33,7,53,27,"bat_a01",353,52;
+	// enablenpc "bat_a01_rp1_b_warp";
 	end;
 
-OnTimer26000:
-	disablenpc "bat_a01_rp1_b_warp";
-	end;
+// OnTimer26000:
+	// disablenpc "bat_a01_rp1_b_warp";
+	// end;
 
 OnTimer26500:
 	donpcevent "Battle Therapist#a01_b::OnEnable";
 	end;
 }
 
+/*
 bat_a01,43,17,0	script	bat_a01_rp1_b_warp	-1,10,10,{
 OnInit:
 	disablenpc "bat_a01_rp1_b_warp";
@@ -579,6 +599,7 @@ OnTouch:
 	warp "bat_a01",353,52;
 	end;
 }
+*/
 
 bat_a01,60,216,3	script	Valley Ghost#bat_a01_n	950,{
 	specialeffect2 EF_HEAL;
@@ -597,18 +618,21 @@ OnEnable:
 
 OnTimer25000:
 	specialeffect EF_SANCTUARY;
-	enablenpc "bat_a01_rp1_n_warp";
+	areapercentheal "bat_a01",45,203,65,223,100,100;
+	areawarp "bat_a01",45,203,65,223,"bat_a01",301,209;
+	// enablenpc "bat_a01_rp1_n_warp";
 	end;
 
-OnTimer26000:
-	disablenpc "bat_a01_rp1_n_warp";
-	end;
+// OnTimer26000:
+	// disablenpc "bat_a01_rp1_n_warp";
+	// end;
 
 OnTimer26500:
 	donpcevent "Valley Ghost#bat_a01_n::OnEnable";
 	end;
 }
 
+/*
 bat_a01,55,213,0	script	bat_a01_rp1_n_warp	-1,10,10,{
 OnInit:
 	disablenpc "bat_a01_rp1_n_warp";
@@ -619,6 +643,7 @@ OnTouch:
 	warp "bat_a01",301,209;
 	end;
 }
+*/
 
 bat_a01,194,267,0	script	barri_warp_up#bat_a01_a	-1,7,0,{
 OnTouch:

+ 58 - 32
npc/battleground/tierra/tierra02.txt

@@ -57,21 +57,19 @@ OnStop:
 
 OnTimer1000:
 	stopnpctimer;
-	if (!getbattleflag("feature.bgqueue"))
-		initnpctimer;
-	set .@chk_bat_a02,getmapusers("bat_a02");
-	if (.@chk_bat_a02 < 1) {
-		set $@TierraBG2,0; set $@TierraBG2_Victory, 0;
-		if( $@TierraBG2_id1 ) { bg_destroy $@TierraBG2_id1; set $@TierraBG2_id1, 0; }
-		if( $@TierraBG2_id2 ) { bg_destroy $@TierraBG2_id2; set $@TierraBG2_id2, 0; }
-		if (getbattleflag("feature.bgqueue")) {
+	if (!bg_get_data($@TierraBG2_id1, 0) && !bg_get_data($@TierraBG2_id2, 0)) {
+		donpcevent "countdown#bat_a02::OnStop";
+		if (getbattleflag("feature.bgqueue"))
+			bg_reserve "bat_a02", true;
+		mapwarp "bat_a02","bat_room",154,150;
+		$@TierraBG2 = 0; $@TierraBG2_Victory = 0;
+		if( $@TierraBG2_id1 ) { bg_destroy $@TierraBG2_id1; $@TierraBG2_id1 = 0; }
+		if( $@TierraBG2_id2 ) { bg_destroy $@TierraBG2_id2; $@TierraBG2_id2 = 0; }
+		if (getbattleflag("feature.bgqueue"))
 			bg_unbook "bat_a02";
-			end;
-		} else
-			donpcevent "start#bat_a02::OnReadyCheck";
+		end;
 	}
-	if (getbattleflag("feature.bgqueue"))
-		initnpctimer;
+	initnpctimer;
 	end;
 }
 
@@ -125,6 +123,14 @@ OnEnable:
 	disablenpc "Croix Vintenar#a02_b";
 	end;
 
+OnGuillaumeActive:
+	warp "bat_a02",352,342;
+	end;
+
+OnCroixActive:
+	warp "bat_a02",353,52;
+	end;
+
 OnGuillaumeQuit:
 OnCroixQuit:
 	if (getbattleflag("feature.bgqueue"))
@@ -182,6 +188,8 @@ OnMyMobDead:
 		mapannounce "bat_a02", "Croix Vintenar Swandery: We destroyed Guillaume's Food Storage. We won that! Wow!",bc_map,"0xFFCE00";
 		bg_warp $@TierraBG2_id1,"bat_a02",50,374;
 		bg_warp $@TierraBG2_id2,"bat_a02",42,16;
+		if (getbattleflag("feature.bgqueue"))
+			bg_reserve "bat_a02", true;
 	}
 	end;
 }
@@ -205,6 +213,8 @@ OnMyMobDead:
 		mapannounce "bat_a02", "Guillaume Vintenar Axl Rose : We destroyed Croix's Food Storage. We won that! Wow!",bc_map,"0xFFCE00";
 		bg_warp $@TierraBG2_id1,"bat_a02",50,374;
 		bg_warp $@TierraBG2_id2,"bat_a02",42,16;
+		if (getbattleflag("feature.bgqueue"))
+			bg_reserve "bat_a02", true;
 	}
 	end;
 }
@@ -363,8 +373,10 @@ bat_a02,185,270,1	script	Guillaume Blacksmith#a02	851,{
 				mes "[Guillaume Blacksmith]";
 				mes "Wow! It's done.";
 				mes "We are relieved.";
-				delitem 7049,50; //Stone
-				donpcevent "barricade#bat_a02_a::OnEnable";
+				if (mobcount("bat_a02","barricade#bat_a02_a::OnMyMobDead") < 17) {
+					delitem 7049,50; //Stone
+					donpcevent "barricade#bat_a02_a::OnEnable";
+				}
 				close2;
 				disablenpc "Guillaume Blacksmith#a02";
 				end;
@@ -447,8 +459,10 @@ bat_a02,170,121,5	script	Croix Blacksmith#bat_a02	851,{
 				mes "[Croix Blacksmith]";
 				mes "Wow! It's done.";
 				mes "We are relieved.";
-				delitem 7049,50; //Stone
-				donpcevent "barricade#bat_a02_b::OnEnable";
+				if (mobcount("bat_a02","barricade#bat_a02_b::OnMyMobDead") < 17) {
+					delitem 7049,50; //Stone
+					donpcevent "barricade#bat_a02_b::OnEnable";
+				}
 				close2;
 				disablenpc "Croix Blacksmith#bat_a02";
 				end;
@@ -499,35 +513,39 @@ OnEnable:
 	end;
 
 OnStop:
-	disablenpc "bat_a02_rp1_a_warp";
+	// disablenpc "bat_a02_rp1_a_warp";
 	disablenpc "Battle Therapist#a02_a";
 	stopnpctimer;
 	end;
 
 OnTimer25000:
 	specialeffect EF_SANCTUARY;
-	enablenpc "bat_a02_rp1_a_warp";
+	// enablenpc "bat_a02_rp1_a_warp";
+	areapercentheal "bat_a02",41,365,61,385,100,100;
+	areawarp "bat_a02",41,365,61,385,"bat_a02",352,342;
 	end;
 
-OnTimer26000:
-	disablenpc "bat_a02_rp1_a_warp";
-	end;
+// OnTimer26000:
+	// disablenpc "bat_a02_rp1_a_warp";
+	// end;
 
 OnTimer26500:
 	donpcevent "Battle Therapist#a02_a::OnEnable";
 	end;
 }
 
+/*
 bat_a02,51,375,0	script	bat_a02_rp1_a_warp	-1,10,10,{
 OnInit:
 	disablenpc "bat_a02_rp1_a_warp";
 	end;
 
-OnTouch_:
+OnTouch:
 	percentheal 100,100;
 	warp "bat_a02",352,342;
 	end;
 }
+*/
 
 bat_a02,45,19,3	script	Battle Therapist#a02_b	95,{
 	specialeffect2 EF_HEAL;
@@ -549,25 +567,28 @@ OnEnable:
 	end;
 
 OnStop:
-	disablenpc "bat_a02_rp1_b_warp";
+	// disablenpc "bat_a02_rp1_b_warp";
 	disablenpc "Battle Therapist#a02_b";
 	stopnpctimer;
 	end;
 
 OnTimer25000:
 	specialeffect EF_SANCTUARY;
-	enablenpc "bat_a02_rp1_b_warp";
+	// enablenpc "bat_a02_rp1_b_warp";
+	areapercentheal "bat_a02",33,7,53,27,100,100;
+	areawarp "bat_a02",33,7,53,27,"bat_a02",353,52;
 	end;
 
-OnTimer26000:
-	disablenpc "bat_a02_rp1_b_warp";
-	end;
+// OnTimer26000:
+	// disablenpc "bat_a02_rp1_b_warp";
+	// end;
 
 OnTimer26500:
 	donpcevent "Battle Therapist#a02_b::OnEnable";
 	end;
 }
 
+/*
 bat_a02,43,17,0	script	bat_a02_rp1_b_warp	-1,10,10,{
 OnInit:
 	disablenpc "bat_a02_rp1_b_warp";
@@ -578,6 +599,7 @@ OnTouch:
 	warp "bat_a02",353,52;
 	end;
 }
+*/
 
 bat_a02,60,216,3	script	Valley Ghost#bat_a02_n	950,{
 	specialeffect2 EF_HEAL;
@@ -596,18 +618,21 @@ OnEnable:
 
 OnTimer25000:
 	specialeffect EF_SANCTUARY;
-	enablenpc "bat_a02_rp1_n_warp";
+	// enablenpc "bat_a02_rp1_n_warp";
+	areapercentheal "bat_a02",45,203,65,223,100,100;
+	areawarp "bat_a02",45,203,65,223,"bat_a02",301,209;
 	end;
 
-OnTimer26000:
-	disablenpc "bat_a02_rp1_n_warp";
-	end;
+// OnTimer26000:
+	// disablenpc "bat_a02_rp1_n_warp";
+	// end;
 
 OnTimer26500:
 	donpcevent "Valley Ghost#bat_a02_n::OnEnable";
 	end;
 }
 
+/*
 bat_a02,55,213,0	script	bat_a02_rp1_n_warp	-1,10,10,{
 OnInit:
 	disablenpc "bat_a02_rp1_n_warp";
@@ -618,6 +643,7 @@ OnTouch:
 	warp "bat_a02",301,209;
 	end;
 }
+*/
 
 bat_a02,194,267,0	script	barri_warp_up#bat_a02_a	-1,7,0,{
 OnTouch:

+ 31 - 10
npc/custom/woe_controller.txt

@@ -283,13 +283,36 @@ OnReward:
 				.@cid[0] = .@master_cid;
 				.@aid[0] = .@master_aid;
 			}
-
-			for(set .@j,0; .@j<.@size_guild; set .@j,.@j+1) {
-				if ((.Options&8) && !(.Options&4)) {
-					set .@ip$, replacestr(getcharip(.@aid[.@j]),".","a");
-					if (getd(".@ip_"+.@i+"_"+.@ip$)) continue;
-					setd ".@ip_"+.@i+"_"+.@ip$,1;
+			else if (.Options&8) {
+				for ( .@j = 0; .@j < .@size_guild; ++.@j ) {
+					.@is_online[.@j] = isloggedin( .@aid[.@j], .@cid[.@j] );
+					if (.@is_online[.@j])
+						.@ip$ = replacestr(getcharip(.@aid[.@j]),".","a");
+					else {
+						if (query_sql("SELECT `last_ip` FROM `login` WHERE `account_id` = '" + .@aid[.@j] + "'", .@last_ip$) < 1)
+							continue;
+						.@ip$ = replacestr(.@last_ip$, ".", "a");
+					}
+					.@variable$ = ".@ip_" + .@i + "_" + .@ip$;
+					.@index = getd(.@variable$) - 1;
+				
+					if (.@index >= 0) {
+						if (.@is_online[.@j]) {
+							.@tmp_account_id[.@index] = .@aid[.@j];
+							.@tmp_char_id[.@index] = .@cid[.@j];
+						}
+						continue;
+					}
+					setd .@variable$, .@j+1;
+					.@tmp_account_id[.@k] = .@aid[.@j];
+					.@tmp_char_id[.@k] = .@cid[.@j];
+					.@k++;
 				}
+				copyarray .@aid[0], .@tmp_account_id[0], .@k;
+				copyarray .@cid[0], .@tmp_char_id[0], .@k;
+				.@size_guild = .@k;
+			}
+			for(set .@j,0; .@j<.@size_guild; set .@j,.@j+1) {
 				if (.Options&2) {
 					.@charid = .@cid[.@j];
 					.@sender$ = "no-reply";
@@ -318,7 +341,6 @@ OnReward:
 					}
 					Zeny += .reward_zeny;
 					dispbottom "You have been rewarded for conquering " + .@castle_name$ + ".";
-					detachrid;
 				}
 			}
 		}
@@ -326,15 +348,14 @@ OnReward:
 	return;
 
 OnPCLoadMapEvent:
-	.@compare_val = compare(strcharinfo(3),"g_cas");
-	if (!.@compare_val) end;
+	if (!compare(strcharinfo(3),"g_cas")) end;
 	if (((.AutoKick && .Active[0]) || (.NoOwner && !getcastledata(strcharinfo(3),1))) && !(.Active[0]&(1<<getd("."+strcharinfo(3))))) {
 		if (getcharid(2) && getcastledata(strcharinfo(3),1) == getcharid(2)) end;
 		.@castle_name$ = getcastlename(strcharinfo(3));
 		sleep2 1000;
 		message strcharinfo(0), .@castle_name$ + " is currently inactive.";
 		sleep2 5000;
-		if (.@compare_val) warp "SavePoint",0,0;
+		if (compare(strcharinfo(3),"g_cas")) warp "SavePoint",0,0;
 	}
 	end;
 

+ 10 - 0
npc/pre-re/quests/quests_niflheim.txt

@@ -0,0 +1,10 @@
+//===== rAthena Script =======================================
+//= Quest NPCs related to Niflheim
+//===== Description: =========================================
+//= [Official Conversion]
+//= Piano Key Ouest
+//===== Additional Comments: =================================
+//= 1.0 Moved Piano3 to pre-re/re paths. [Daegaladh]
+//============================================================
+
+nif_in,114,181,0	duplicate(Piano3)	#Piano3	HIDDEN_NPC,1,1

+ 1 - 0
npc/pre-re/scripts_athena.conf

@@ -93,5 +93,6 @@ npc: npc/pre-re/quests/quests_izlude.txt
 npc: npc/pre-re/quests/quests_lighthalzen.txt
 npc: npc/pre-re/quests/quests_morocc.txt
 npc: npc/pre-re/quests/quests_nameless.txt
+npc: npc/pre-re/quests/quests_niflheim.txt
 npc: npc/pre-re/quests/the_sign_quest.txt
 npc: npc/pre-re/quests/quests_veins.txt

+ 58 - 17
npc/quests/quests_lighthalzen.txt

@@ -2044,11 +2044,12 @@ lhz_in02,201,210,5	script	Digotz	4_M_LGTMAN,{
 		close;
 	}
 	if (friendship > 14) {
+		cutin "lhz_diguts05.bmp",2;
 		mes "^3355FFDigotz has passed";
 		mes "away, but the look on";
 		mes "his face seems very";
 		mes "peaceful and content.^000000";
-		close;
+		close3;
 	}
 	if (friendship == 14) {
 		mes "^3355FFDigotz is seriously";
@@ -2061,6 +2062,7 @@ lhz_in02,201,210,5	script	Digotz	4_M_LGTMAN,{
 		mes "Oh no, let me";
 		mes "get you some help!";
 		next;
+		cutin "lhz_diguts04.bmp",2;
 		mes "[Digotz]";
 		mes "H-hey... It's the";
 		mes "adventurer... Man,";
@@ -2085,6 +2087,7 @@ lhz_in02,201,210,5	script	Digotz	4_M_LGTMAN,{
 		mes "to him. We'll hang out and have";
 		mes "fun, just like the good old days.";
 		next;
+		cutin "lhz_diguts05.bmp",2;
 		mes "[Digotz]";
 		mes "I missed my buddies, but now...";
 		mes "Now I can hear them calling me.";
@@ -2114,9 +2117,11 @@ lhz_in02,201,210,5	script	Digotz	4_M_LGTMAN,{
 		set friendship,15;
 		changequest 12005,12006;
 		getitem 1201,1; //Knife
+		cutin "",255;
 		close;
 	}
 	if (friendship == 13) {
+		cutin "lhz_diguts08.bmp",2;
 		mes "[Digotz]";
 		mes "Wh-whoa, I need to";
 		mes "get ready! That Maku's";
@@ -2124,9 +2129,10 @@ lhz_in02,201,210,5	script	Digotz	4_M_LGTMAN,{
 		mes "I look too rich and pampered.";
 		mes "Damn! Where did I put all of";
 		mes "my fashionable street clothes?";
-		close;
+		close3;
 	}
-	if ((friendship == 12 && countitem(7351) > 0)) {
+	if (friendship == 12 && countitem(7351) > 0) {
+		cutin "lhz_diguts08.bmp",2;
 		mes "[Digotz]";
 		mes "Even if Benkaistein";
 		mes "did come back, I don't";
@@ -2135,6 +2141,7 @@ lhz_in02,201,210,5	script	Digotz	4_M_LGTMAN,{
 		mes "I think I'd even be madder!";
 		next;
 		if (select("Show Benkaistein's Journal.:Don't show Benkaistein's Journal.") == 1) {
+			cutin "",255;
 			mes "[Digotz]";
 			mes "Why am I so ticked off?";
 			mes "^3355FF*Sigh*^000000 You have something";
@@ -2159,6 +2166,7 @@ lhz_in02,201,210,5	script	Digotz	4_M_LGTMAN,{
 			mes "I think about it. Boy, I hope";
 			mes "we don't do that again.^000000";
 			next;
+			cutin "lhz_diguts02.bmp",2;
 			mes "[Digotz]";
 			mes "Oh yeah, I remember that!";
 			mes "Maku wore the wings most";
@@ -2167,6 +2175,7 @@ lhz_in02,201,210,5	script	Digotz	4_M_LGTMAN,{
 			mes "air the longest! Yeah, I was";
 			mes "a regular Kid Pegasus~";
 			next;
+			cutin "",255;
 			mes "[Benkaistein's Journal]";
 			mes "^856363Maku, Digotz and me went";
 			mes "outside of town. Of course,";
@@ -2183,6 +2192,7 @@ lhz_in02,201,210,5	script	Digotz	4_M_LGTMAN,{
 			mes "bad and the monster got away.";
 			mes "Boy, mom was not happy...^000000";
 			next;
+			cutin "lhz_diguts03.bmp",2;
 			mes "[Digotz]";
 			mes "Huh. I don't remember";
 			mes "that so well. But I know that";
@@ -2191,6 +2201,7 @@ lhz_in02,201,210,5	script	Digotz	4_M_LGTMAN,{
 			mes "then. We must have been totally";
 			mes "nuts to fight a monster, though.";
 			next;
+			cutin "",255;
 			mes "[Benkaistein's Journal]";
 			mes "^856363Digotz's been sick for three";
 			mes "days now. It's just a normal";
@@ -2198,6 +2209,7 @@ lhz_in02,201,210,5	script	Digotz	4_M_LGTMAN,{
 			mes "it's Digotz's fault he got sick.^FFFFFF ^856363 But he's always asking me to";
 			mes "go visit him and see if he's okay.^000000";
 			next;
+			cutin "lhz_diguts01.bmp",2;
 			mes "[Digotz]";
 			mes "I think I remember being";
 			mes "pretty sick. Maku was worried?";
@@ -2206,6 +2218,7 @@ lhz_in02,201,210,5	script	Digotz	4_M_LGTMAN,{
 			mes "um, Gonorrhitis. You know.";
 			mes "That might have been it.";
 			next;
+			cutin "",255;
 			mes "[Benkaistein's Journal]";
 			mes "^856363Mom and dad keep telling";
 			mes "me not to hang out with Maku";
@@ -2221,12 +2234,14 @@ lhz_in02,201,210,5	script	Digotz	4_M_LGTMAN,{
 			mes "But Digotz doesn't care.";
 			mes "I know he likes Maku a lot.^000000";
 			next;
+			cutin "lhz_diguts07.bmp",2;
 			mes "[Digotz]";
 			mes "Well, we were a lot";
 			mes "younger and closer back";
 			mes "then, so... ^333333*Ahem!*^000000 Why did";
 			mes "Benkaistein even write that?!";
 			next;
+			cutin "",255;
 			mes "[Benkaistein's Journal]";
 			mes "^856363Today, the three of us";
 			mes "made an oath of brotherhood,";
@@ -2235,6 +2250,7 @@ lhz_in02,201,210,5	script	Digotz	4_M_LGTMAN,{
 			mes "be friends no matter what.";
 			mes "For always and for always.^000000";
 			next;
+			cutin "lhz_diguts07.bmp",2;
 			mes "[Digotz]";
 			mes "I... I was forced to make";
 			mes "that oath! And people do";
@@ -2243,6 +2259,7 @@ lhz_in02,201,210,5	script	Digotz	4_M_LGTMAN,{
 			mes "it's not like that oath really";
 			mes "means anything now, does it?";
 			next;
+			cutin "",255;
 			set friendship,13;
 			mes "[Digotz]";
 			mes "That does it. I'm gonna";
@@ -2260,9 +2277,10 @@ lhz_in02,201,210,5	script	Digotz	4_M_LGTMAN,{
 		mes "more like Maku, though,";
 		mes "don't get me wrong, it's";
 		mes "not like I care about the guy.";
-		close;
+		close3;
 	}
 	if (friendship == 7) {
+		cutin "lhz_diguts03.bmp",2;
 		mes "[Digotz]";
 		mes "Even if Benkaistein came";
 		mes "back from wherever he was";
@@ -2270,9 +2288,10 @@ lhz_in02,201,210,5	script	Digotz	4_M_LGTMAN,{
 		mes "able to get Maku to apologize";
 		mes "to me. That guy is just way";
 		mes "too stubborn for his own good!";
-		close;
+		close3;
 	}
 	if (friendship == 6) {
+		cutin "lhz_diguts01.bmp",2;
 		mes "[Digotz]";
 		mes "Oh, it's been a while.";
 		mes "What are you doing back";
@@ -2288,6 +2307,7 @@ lhz_in02,201,210,5	script	Digotz	4_M_LGTMAN,{
 		mes "and has been threatening to";
 		mes "beat you up pretty badly.";
 		next;
+		cutin "lhz_diguts08.bmp",2;
 		mes "[Digotz]";
 		mes "That no-good, dirty";
 		mes "lying rotten scoundrel!";
@@ -2296,6 +2316,7 @@ lhz_in02,201,210,5	script	Digotz	4_M_LGTMAN,{
 		mes "the ghetto and beat Maku";
 		mes "up myself! That stupid guy!";
 		next;
+		cutin "lhz_diguts03.bmp",2;
 		mes "[Digotz]";
 		mes "During times like this,";
 		mes "I really miss ^FF0000Benkaistein^000000.";
@@ -2322,6 +2343,7 @@ lhz_in02,201,210,5	script	Digotz	4_M_LGTMAN,{
 		set friendship,7;
 		changequest 12002,12003;
 		next;
+		cutin "",255;
 		mes "[Digotz]";
 		mes "I don't know why,";
 		mes "but I'm so angry!";
@@ -2329,7 +2351,8 @@ lhz_in02,201,210,5	script	Digotz	4_M_LGTMAN,{
 		mes "out so much over this?!";
 		close;
 	}
-	if ((friendship == 4 || friendship == 5)) {
+	if (friendship == 4 || friendship == 5) {
+		cutin "lhz_diguts01.bmp",2;
 		mes "[Digotz]";
 		mes "Still checking out";
 		mes "Uptown Lighthalzen?";
@@ -2345,9 +2368,10 @@ lhz_in02,201,210,5	script	Digotz	4_M_LGTMAN,{
 		mes "^FF0000Not to mention an apology!";
 		mes "^FF0000But who cares what you think?!";
 		mes "I'm so goddamn happy without you!^000000";
-		close;
+		close3;
 	}
 	if (friendship == 3) {
+		cutin "lhz_diguts01.bmp",2;
 		mes "[Digotz]";
 		mes "I know that the";
 		mes "opulence of Uptown";
@@ -2369,7 +2393,9 @@ lhz_in02,201,210,5	script	Digotz	4_M_LGTMAN,{
 		mes "says, unless it's an apology";
 		mes "for being a fully blown jerk.";
 		mes "Ever since we were kids...";
+		cutin "",255;
 		next;
+		cutin "lhz_diguts08.bmp",2;
 		mes "[Digotz]";
 		mes "Anyway, we used to be close,";
 		mes "but that guy was never a true";
@@ -2386,6 +2412,7 @@ lhz_in02,201,210,5	script	Digotz	4_M_LGTMAN,{
 		mes "on the worst blind dates a";
 		mes "man can possibly experience!";
 		next;
+		cutin "lhz_diguts01.bmp",2;
 		mes "[Digotz]";
 		mes "Maku doesn't know a damn";
 		mes "about friendship! Even if I did";
@@ -2401,6 +2428,7 @@ lhz_in02,201,210,5	script	Digotz	4_M_LGTMAN,{
 		mes "and check up on him! I only";
 		mes "have one regret though...";
 		next;
+		cutin "lhz_diguts07.bmp",2;
 		mes "[Digotz]";
 		mes "I only wish I had one";
 		mes "last chance to see Maku...";
@@ -2432,9 +2460,10 @@ lhz_in02,201,210,5	script	Digotz	4_M_LGTMAN,{
 		mes "^FF0000But who cares what you think?!";
 		mes "I'm so goddamn happy without you!^000000";
 		set friendship,4;
-		close;
+		close3;
 	}
 	if (friendship == 2) {
+		cutin "lhz_diguts01.bmp",2;
 		mes "[Digotz]";
 		mes "What are you still";
 		mes "doing hanging around";
@@ -2447,9 +2476,10 @@ lhz_in02,201,210,5	script	Digotz	4_M_LGTMAN,{
 		mes "Just hearing about";
 		mes "Maku makes me so feel";
 		mes "so upset for some reason!";
-		close;
+		close3;
 	}
 	if (friendship == 1) {
+		cutin "lhz_diguts02.bmp",2;
 		mes "[Digotz]";
 		mes "Oh, an adventurer?";
 		mes "Welcome to Uptown";
@@ -2466,6 +2496,7 @@ lhz_in02,201,210,5	script	Digotz	4_M_LGTMAN,{
 		mes "your stay in my hometown.";
 		next;
 		select("Do you know someone named Maku?");
+		cutin "lhz_diguts01.bmp",2;
 		mes "[Digotz]";
 		mes "Maku? Maku. Yes, he's my";
 		mes "childhood friend. Or he was,";
@@ -2483,8 +2514,9 @@ lhz_in02,201,210,5	script	Digotz	4_M_LGTMAN,{
 		mes "Just forget everything I said.";
 		set friendship,2;
 		changequest 12000,12001;
-		close;
+		close3;
 	}
+	cutin "lhz_diguts02.bmp",2;
 	mes "[Digotz]";
 	mes "Oh, an adventurer?";
 	mes "Welcome to Uptown";
@@ -2500,7 +2532,7 @@ lhz_in02,201,210,5	script	Digotz	4_M_LGTMAN,{
 	mes "glad to see somebody";
 	mes "aside from the stuck up";
 	mes "rich people who live here.";
-	close;
+	close3;
 }
 
 lighthalzen,337,232,3	script	Maku	4_M_LGTPOOR,{
@@ -3021,6 +3053,7 @@ yuno_in04,96,106,5	script	Passionate Student	4_M_SAGE_A,{
 		close;
 	}
 	if (friendship == 15) {
+		cutin "lhz_benkaistin01.bmp",2;
 		mes "[Benkaistein]";
 		mes "Were you able to bring";
 		mes "my journal to Digotz and";
@@ -3062,9 +3095,9 @@ yuno_in04,96,106,5	script	Passionate Student	4_M_SAGE_A,{
 		mes "adventurer. When the three";
 		mes "of us get together, I'll be";
 		mes "sure to let you know~";
-		close;
+		close3;
 	}
-	if ((friendship == 11 && countitem(7351) > 0)) {
+	if (friendship == 11 && countitem(7351) > 0) {
 		mes "[Benkaistein]";
 		mes "Aw nuts, this is";
 		mes "taking much longer";
@@ -3072,6 +3105,7 @@ yuno_in04,96,106,5	script	Passionate Student	4_M_SAGE_A,{
 		mes "Now where did I put";
 		mes "that thing? Hmmmm...";
 		next;
+		cutin "lhz_benkaistin02.bmp",2;
 		mes "[Benkaistein]";
 		mes "Oh, is that it?";
 		mes "Did you find my";
@@ -3080,6 +3114,7 @@ yuno_in04,96,106,5	script	Passionate Student	4_M_SAGE_A,{
 		mes "This is it! Thank you";
 		mes "for finding this for me!";
 		next;
+		cutin "",255;
 		mes "[Benkaistein]";
 		mes "Would you mind doing";
 		mes "a favor for me? It'd be";
@@ -3097,6 +3132,7 @@ yuno_in04,96,106,5	script	Passionate Student	4_M_SAGE_A,{
 		next;
 		set friendship,12;
 		changequest 12004,12005;
+		cutin "lhz_benkaistin04.bmp",2;
 		mes "[Benkaistein]";
 		mes "Anyway, this should at";
 		mes "least help them realize";
@@ -3104,9 +3140,9 @@ yuno_in04,96,106,5	script	Passionate Student	4_M_SAGE_A,{
 		mes "acting. Thanks in advance,";
 		mes "and please take care of";
 		mes "Maku and Digotz for me.";
-		close;
+		close3;
 	}
-	if ((friendship == 10 || friendship == 11)) {
+	if (friendship == 10 || friendship == 11) {
 		mes "[Benkaistein]";
 		mes "Aw nuts, this is";
 		mes "taking much longer";
@@ -3121,6 +3157,7 @@ yuno_in04,96,106,5	script	Passionate Student	4_M_SAGE_A,{
 		close;
 	}
 	if (friendship == 9) {
+		cutin "lhz_benkaistin03.bmp",2;
 		mes "[Passionate Student]";
 		mes "Oh, you startled me!";
 		mes "Still, I'm aware that it's";
@@ -3130,6 +3167,7 @@ yuno_in04,96,106,5	script	Passionate Student	4_M_SAGE_A,{
 		mes "I help you, adventurer?";
 		next;
 		select("Tell him about Maku and Digotz.");
+		cutin "lhz_benkaistin02.bmp",2;
 		mes "[Benkaistein]";
 		mes "Oh, how are my friends";
 		mes "doing? Oh, what? They're";
@@ -3154,9 +3192,10 @@ yuno_in04,96,106,5	script	Passionate Student	4_M_SAGE_A,{
 		mes "so important? Wait! Would you";
 		mes "please wait a second while";
 		mes "I look for something?";
-		close;
+		close3;
 	}
 	if (friendship == 8) {
+		cutin "lhz_benkaistin04.bmp",2;
 		mes "[Passionate Student]";
 		mes "Let's see, now.";
 		mes "Wind Magic, Black Magic,";
@@ -3203,7 +3242,9 @@ yuno_in04,96,106,5	script	Passionate Student	4_M_SAGE_A,{
 		mes "["+ strcharinfo(0) +"]";
 		mes "HEY YOU...!";
 		mes "BENKAISTEIN~!";
+		cutin "",255;
 		next;
+		cutin "lhz_benkaistin02.bmp",2;
 		mes "[Passionate Student]";
 		mes "Oh, good heavens!";
 		mes "C-can't you keep";
@@ -3212,7 +3253,7 @@ yuno_in04,96,106,5	script	Passionate Student	4_M_SAGE_A,{
 		mes "No, wait. Have you been";
 		mes "calling me all this time?";
 		set friendship,9;
-		close;
+		close3;
 	}
 	mes "[Passionate Student]";
 	mes "Let's see, now.";

+ 10 - 14
npc/quests/quests_morocc.txt

@@ -948,13 +948,11 @@ moc_fild20,354,183,3	script	Continental Guard#01::MocConGuard	707,3,3,{
 			close;
 		case 2:
 			if ($@re_moc < 3) {
-				getpartymember(getcharid(1));
-				set .@partymembercount,$@partymembercount;
-				copyarray .@partymembername$[0],$@partymembername$[0],.@partymembercount;
-				for(.@i = 0; .@i < .@partymembercount; .@i++) {
-					if (isloggedin(getcharid(3,.@partymembername$[.@i]))) {
-						set .@onlinemembers,.@onlinemembers + 1;
-					}
+				getpartymember getcharid(1), 1, .@partymembercid;
+				.@partymembercount = $@partymembercount;
+				for (.@i = 0; .@i < .@partymembercount; .@i++) {
+					if (convertpcinfo(.@partymembercid[.@i], CPC_ACCOUNT))
+						.@onlinemembers++;
 				}
 				if ((.@onlinemembers > 1) && (countitem(7826) > 0)) {
 					mes "[Continental Guard]";
@@ -1009,13 +1007,11 @@ moc_fild20,354,183,3	script	Continental Guard#01::MocConGuard	707,3,3,{
 		mes "[Continental Guard]";
 		mes "Ah, you're an adventurer working for the Continental Guard. Nice to meet you. Feel free to ask me if you need my assistance.";
 		next;
-		getpartymember(getcharid(1));
-		set .@partymembercount,$@partymembercount;
-		copyarray .@partymembername$[0],$@partymembername$[0],.@partymembercount;
-		for(.@i = 0; .@i < .@partymembercount; .@i++) {
-			if (isloggedin(getcharid(3,.@partymembername$[.@i]))) {
-				set .@onlinemembers,.@onlinemembers + 1;
-			}
+		getpartymember getcharid(1), 1, .@partymembercid;
+		.@partymembercount = $@partymembercount;
+		for (.@i = 0; .@i < .@partymembercount; .@i++) {
+			if (convertpcinfo(.@partymembercid[.@i], CPC_ACCOUNT))
+				.@onlinemembers++;
 		}
 		switch(select("Enter the First Field to Investigate:Enter the Second Field to Investigate:Return to Morocc's Accident Site:Cancel Conversation")) {
 		case 1:

+ 1 - 1
npc/quests/quests_niflheim.txt

@@ -249,7 +249,7 @@ OnTouch_:
 	end;
 }
 
-nif_in,118,151,0	script	#Piano3	111,1,1,{
+-	script	Piano3	HIDDEN_NPC,{
 	end;
 
 OnTouch_:

+ 1 - 1
npc/re/instances/MalangdoCulvert.txt

@@ -377,7 +377,7 @@ mal_in01,160,34,4	script	Missing, the Cleaner	545,{
 		set in_canal_n,1;
 		close;
 	}
-	if (countitem(6436) == 0) {
+	if (rentalcountitem(6436) == 0) {
 		mes "[Missing, the Cleaner]";
 		mes "You don't look like you have Seagod Protection. I can't open door at the moment!";
 		close;

+ 1 - 0
npc/re/instances/NightmarishJitterbug.txt

@@ -1419,6 +1419,7 @@ OnTouch_:
 		break;
 	case 3:
 		jitterbug_options |= 1;
+		areamonster 'map_jtb$,351,131,389,96, "--ja--", 3108,1;	// no label
 		unittalk getcharid(3), "" + strcharinfo(0) + " : I like your Red Potion (feat. Muka).";
 		mes "[Newoz]";
 		mes "Hah hah, this is embarassing, but thank you.";

+ 2 - 2
npc/re/instances/OctopusCave.txt

@@ -83,7 +83,7 @@ mal_dun01,151,235,5	script	Starfish	551,{
 				close;
 			}
 			if (.@playtime == 2) erasequest 4197;
-			if (countitem(6442)) {
+			if (rentalcountitem(6442)) {
 				if (instance_create(.@md_name$) < 0) {
 					mes "[Starfish]";
 					mes "Party name is... "+getpartyname(.@party_id)+".";
@@ -118,7 +118,7 @@ mal_dun01,153,237,5	script	Weird Entrance	844,{
 	next;
 	switch(select("Go in.:Stop.")) {
 	case 1:
-		if (countitem(6442)) {
+		if (rentalcountitem(6442)) {
 			switch(instance_enter("Octopus Cave")) {
 			case IE_OTHER:
 				mes "[Starfish]";

+ 257 - 0
npc/re/merchants/OldGlastHeim_merchants.txt

@@ -339,3 +339,260 @@ S_Slot:
 	}
 	close;
 }
+
+// Temporal shoes slotted - npc enchant
+glast_01,184,283,4	script	Dark magic master#pa082	1_F_01,{
+	disable_items;
+	if ((MaxWeight - Weight) < 1000) {
+		mes "Your bag is too heavy. Reduce some weight and come back.";
+		close;
+	}
+	if (checkweight(1201,1) == 0) {
+		mes "You seem to be carrying too many items. Put some items in storage and come back again.";
+		close;
+	}
+	// requirements
+	.@coagulated_id = 6608;// Coagulated_Spell
+	.@polluted_id = 6755;// Polluted_Spell
+	.@cost_zeny = 100000;
+
+	mes "[Dark magic master]";
+	mes "I deal with the Temporal Boots with socket only.";
+	next;
+	if (select( "How does the enchanting work?", "Give effect to my Temporal Boots" ) == 1) {
+		mes "[Dark magic master]";
+		mes "You should ask Hugin's magic master all the basic things. I want deeper conversation about enchating work.";
+		next;
+		mes "[Dark magic master]";
+		mes "I need 4 items. ^0000ff" + callfunc("F_InsertComma",.@cost_zeny) + ", " + getitemname(.@polluted_id) + ", " + getitemname(.@coagulated_id) + ", Temporal Boots(Socket) Series^000000. If you don't have any of these, I cannot help you.";
+		next;
+		mes "[Dark magic master]";
+		mes "It's my small hobby.. To enchant Socketed Temporal Boots using polluted and coagulated spell.";
+		next;
+		mes "[Dark magic master]";
+		mes "Of course, you must cope with bigger risk of destruction whenever you'd like to enchant again and again.";
+		next;
+		mes "[Dark magic master]";
+		mes "The enchant order is same as Hugin's magic master's enchantment. Please refer to his explanation.";
+		close;
+	}
+	.@equip_id = getequipid(EQI_SHOES);
+
+	switch(.@equip_id) {
+	case 22006:	// Temporal_Str_Boots_
+	case 22007:	// Temporal_Vit_Boots_
+	case 22008:	// Temporal_Dex_Boots_
+	case 22009:	// Temporal_Int_Boots_
+	case 22010:	// Temporal_Agi_Boots_
+	case 22011:	// Temporal_Luk_Boots_
+	case 22113:	// Modified_Str_Boots_
+	case 22114:	// Modified_Int_Boots_
+	case 22115:	// Modified_Agi_Boots_
+	case 22116:	// Modified_Vit_Boots_
+	case 22117:	// Modified_Dex_Boots_
+	case 22118:	// Modified_Luk_Boots_
+		break;
+	case -1:
+		mes "[Dark magic master]";
+		mes "Are you wearing the item?";
+		close;
+	default:
+		mes "[Dark magic master]";
+		mes "This is not the right item for this enchant. Remember, only those 6 types of Temporal Boots with socket are available for hidden enchanting..";
+		close;
+	}
+	// enchants ID
+	setarray .@enchant_1[0],4808,4832,4814,4741,4869,4752;// Fighting_Spirit4	Expert_Archer1	Spell2	Vitality2	DelayafterAttack1Lv	Luck3
+	setarray .@enchant_2[0],4820,4833,4813,4742,4872,4753;// Fighting_Spirit5	Expert_Archer2	Spell3	Vitality3	DelayafterAttack2Lv	Luck4
+	setarray .@enchant_3[0],4821,4834,4812,4861,4873,4754;// Fighting_Spirit6	Expert_Archer3	Spell4	MHP1		DelayafterAttack3Lv	Luck5
+	setarray .@enchant_4[0],4822,4835,4826,4862,4881,4755;// Fighting_Spirit7	Expert_Archer4	Spell5	MHP2		DelayafterAttack4Lv	Luck6
+
+	// requirements amount
+	setarray .@en_amount_coag[0],3,10,20,40,50;
+	setarray .@en_amount_polluted[0],1,2,4,7,10;
+
+	// (custom) chances of success (official value unknown)
+	setarray .@chances[0],100,70,70,70,70;
+
+	// data of item equipped
+	.@equip_name$ = getequipname(EQI_SHOES);
+	setarray .@card[0],
+		getequipcardid(EQI_SHOES,0),
+		getequipcardid(EQI_SHOES,1),
+		getequipcardid(EQI_SHOES,2),
+		getequipcardid(EQI_SHOES,3);
+	copyarray .@equip_card[0], .@card[0], 4;
+	.@equip_refine = getequiprefinerycnt(EQI_SHOES);
+
+	if (.@card[2] > 0) {
+		mes "[Dark magic master]";
+		mes "These boots have already passed the enchanting limit. We can't enchant them any more.";
+		close;
+	}
+	if (.@card[3] == 0) {// 4th slot 1st try enchanting
+		.@amount_coag = .@en_amount_coag[0];
+		.@amount_poll = .@en_amount_polluted[0];
+
+		mes "[Dark magic master]";
+		mes "Want to enchant ^0000ff" + .@equip_name$ + " (Socket)^000000? For the 1st enchanting, you need ^0000ff" + .@amount_poll + " " + getitemname(.@polluted_id) + ", " + .@amount_coag + " " + getitemname(.@coagulated_id) + ", and " + callfunc("F_InsertComma",.@cost_zeny) + " zeny^000000.";
+		mes "It has some risk of failing..";
+		next;
+		.@s = select( "Quit", "Fighting Spirit", "Archery", "Spell", "Vitality", "Attack Speed", "Lucky" ) - 2;
+		if (.@s == -1) {
+			mes "[Dark magic master]";
+			mes "Ok, come back when you are ready.";
+			close;
+		}
+		.@card[3] = .@enchant_1[.@s];
+		.@string$ = "enchant number ^6300001^000000.";
+		.@num = 0;
+	}
+	else {
+		for ( .@num = 1; .@num < 5; .@num++ ) {
+			for ( .@type = 0; .@type < 6 && .@card[3] != getd( ".@enchant_" + .@num + "[" + .@type + "]" ); .@type++ )
+				continue;
+			if (.@type < 6)
+				break;
+		}
+		if (.@num == 5) {
+			mes "[Dark magic master]";
+			mes "Something wrong happened.";
+			close;
+		}
+		.@amount_coag = .@en_amount_coag[.@num];
+		.@amount_poll = .@en_amount_polluted[.@num];
+
+		mes "[Dark magic master]";
+		if (.@num == 4) {
+			.@card[2] = callfunc("F_Rand",4875,4876,4877,4878,4879,4880);// Bear's_Power, Runaway_Magic, Speed_Of_Light, Muscle_Fool, Hawkeye, Lucky_Day
+			.@string$ = "^990000 Bonus effect ^000000 upgrade.";
+			mes "Would you like a random bonus effect for the 3rd slot? You need ^0000ff" + .@amount_poll + " " + getitemname(.@polluted_id) + ", " + .@amount_coag + " " + getitemname(.@coagulated_id) + ", and " + callfunc("F_InsertComma",.@cost_zeny) + " zeny^000000. But it has high risk of failing..";
+		}
+		else {
+			.@level = .@num + 1;
+			.@card[3] = getd( ".@enchant_" + (.@num+1) + "[" + .@type + "]" );
+			.@string$ = "enchant number ^990000" + .@level + "^000000.";
+			mes "Enchanting ^0000ff" + .@equip_name$ + " (Socket)^000000's 4th slot as ^0000ff" + .@level + "^000000 level effect. Requires ^0000ff" + .@amount_poll + " " + getitemname(.@polluted_id) + ", " + .@amount_coag + " " + getitemname(.@coagulated_id) + ", and " + callfunc("F_InsertComma",.@cost_zeny) + " z^000000. It has some risk of failing..";
+		}
+		next;
+		if (select( "Quit", "Effect Upgrade!" ) == 1) {
+			mes "[Dark magic master]";
+			mes "Ok, come back when you are ready.";
+			close;
+		}
+	}
+	if (countitem(.@coagulated_id) < .@amount_coag) {
+		mes "[Dark magic master]";
+		mes "Hmm, you are missing " + (.@amount_coag - countitem(.@coagulated_id)) + " " + getitemname(.@coagulated_id) + " items. Go get more, and then we can talk about more enchants.";
+		close;
+	}
+	if (countitem(.@polluted_id) < .@amount_poll) {
+		mes "[Dark magic master]";
+		mes "Hmm, you are missing " + (.@amount_poll - countitem(.@polluted_id)) + " " + getitemname(.@polluted_id) + " items. Go get more, and then we can talk about more enchants.";
+		close;
+	}
+	if (Zeny < .@cost_zeny) {
+		mes "[Dark magic master]";
+		mes "You must bring ^0000ff" + callfunc("F_InsertComma",.@cost_zeny) + " zeny^000000. Nothing is free you know...";
+		close;
+	}
+	delitem .@coagulated_id, .@amount_coag;
+	delitem .@polluted_id, .@amount_poll;
+	Zeny -= .@cost_zeny;
+
+	// anti-hack
+	if (callfunc("F_IsEquipIDHack", EQI_SHOES, .@equip_id) || callfunc("F_IsEquipCardHack", EQI_SHOES, .@equip_card[0], .@equip_card[1], .@equip_card[2], .@equip_card[3]) || callfunc("F_IsEquipRefineHack", EQI_SHOES, .@equip_refine))
+		close;
+
+	delequip EQI_SHOES;
+	if (.@chances[.@num] < rand(1,100)) {
+		specialeffect2 EF_LORD;
+		mes "[Dark magic master]";
+		mes "Arrggg, we failed. Better luck next time.";
+		close;
+	}
+	specialeffect2 EF_REPAIRWEAPON;
+	mes "[Hugin's Magician]";
+	mes "Trying for " + .@string$;
+	getitem2 .@equip_id,1,1,.@equip_refine,0,0,0,.@card[2],.@card[3];
+	close;
+}
+
+// Items exchange for card
+glast_01,216,292,5	script	Portrait collector#0002	4_M_OILMAN,{
+	disable_items;
+	if ((MaxWeight - Weight) < 1000) {
+		mes "Your bag is too heavy. Reduce some weight and come back.";
+		close;
+	}
+	if (checkweight(1201,1) == 0) {
+		mes "You seem to be carrying too many items. Put some items in storage and come back again.";
+		close;
+	}
+	.@coagulated_id = 6608;		// Coagulated_Spell
+	.@polluted_id = 6755;		// Polluted_Spell
+	.@white_card = 4608;		// White_Knightage_Card
+	.@khalitzburg_card = 4609;	// Khaliz_Knightage_Card
+
+	mes "[Portrait collector]";
+	mes "I have been collecting portraits for an year already. Now it's time to show people my collection.";
+	next;
+	mes "[Portrait collector]";
+	mes "Hey, do you have a lot of " + getitemname(.@polluted_id) + " or " + getitemname(.@coagulated_id) + "? If so, why don't you trade a nice portrait that I have?";
+	next;
+	switch( select( "Cancel", "Exchange for " + getitemname(.@white_card), "Exchange for " + getitemname(.@khalitzburg_card) ) ) {
+	case 1:
+		mes "[Portrait collector]";
+		mes "Well, OK. Come back when you are ready.";
+		close;
+	case 2:
+		.@reward_id = .@white_card;
+		.@amount_coag = 3000;
+		.@amount_polluted = 70;
+		break;
+	case 3:
+		.@reward_id = .@khalitzburg_card;
+		.@amount_coag = 5000;
+		.@amount_polluted = 100;
+		break;
+	}
+	mes "[Portrait collector]";
+	mes "What would you like in exchange for the " + getitemname(.@reward_id) + "?";
+	next;
+	if (countitem(.@coagulated_id) < .@amount_coag)
+		.@color$[0] = "^666666";
+	if (countitem(.@polluted_id) < .@amount_polluted)
+		.@color$[1] = "^666666";
+	switch( select( "Cancel", sprintf("%s%s %s^000000", .@color$[0], callfunc("F_InsertComma",.@amount_coag), getitemname(.@coagulated_id)), sprintf("%s%s %s^000000", .@color$[1], callfunc("F_InsertComma",.@amount_polluted), getitemname(.@polluted_id)) ) ) {
+	case 1:
+		mes "[Portrait collector]";
+		mes "Well, OK. Come back when you are ready.";
+		close;
+	case 2:
+		.@id = .@coagulated_id;
+		.@amount = .@amount_coag;
+		break;
+	case 3:
+		.@id = .@polluted_id;
+		.@amount = .@amount_polluted;
+		break;
+	}
+	if (countitem(.@id) < .@amount) {
+		mes "[Portrait collector]";
+		mes "Hmm, you don't have enough Spell now. Go get more.";
+		close;
+	}
+	mes "[Portrait collector]";
+	mes "Are you sure that you won't regret it?";
+	next;
+	if (select( "Cancel", "Sure" ) == 1) {
+		mes "[Portrait collector]";
+		mes "Well, OK. Come back when you are ready.";
+		close;
+	}
+	mes "[Portrait collector]";
+	mes "Cool, let's make a deal.";
+	delitem .@id, .@amount;
+	getitem .@reward_id,1;
+	close;
+}

+ 2 - 2
npc/re/merchants/bio4_reward.txt

@@ -489,10 +489,10 @@ lhz_cube,233,24,4	script	Sorcerer#Bio4Reward	4_M_UMDANCEKID,{
 		next;
 		mes "[Pudding]";
 		mes "Let me see.. the equipments discovered until now are....";
-		mes "6 Armors, 14 Weapons.";
+		mes "7 Armors, 14 Weapons.";
 		next;
 		while(1) {
-			switch(select("Ok, I don't have to know more.", "6 Armors", "14 Weapons")) {
+			switch(select("Ok, I don't have to know more.", "7 Armors", "14 Weapons")) {
 			case 1:
 				mes "[Pudding]";
 				mes "If you obtain '^F2766EWill of Warrior^000000' or '^952420Thirst for Blood^000000', and obtain also equipment which is capable to accept their power, bring them to me. I will be waiting.";

+ 1431 - 0
npc/re/merchants/malangdo_costume.txt

@@ -0,0 +1,1431 @@
+//===== rAthena Script =======================================
+//= Costumes NPCs.
+//===== Description: =========================================
+//= [Official Conversion]
+//= Costumes exchange/enchant NPCs in Malangdo.
+//= The database of the following box are left empty 
+//= until high items ID are supported:
+//=   Enchant_Stone_Box19
+//=   Enchant_Stone_Box20
+//=   Enchant_Stone_Box21
+//===== Changelogs: ==========================================
+//= 1.0 First version. [Capuche]
+//============================================================
+
+// Costume exchange
+mal_in01,20,124,5	script	Designer Heidam#eventhat	4_CAT_SAILOR5,{
+	if (checkweight(1301,1) == 0) {
+		mes "- Please stop here!! -";
+		mes "- You have carried too much items, -";
+		mes "- Therefore unable receive any item again, -";
+		mes "- Please reduce your weight, -";
+		mes "- And come back again later! -";
+		close;
+	}
+	disable_items;
+	mes "[Designer Heidam]";
+	mes "I am Designer Heidam, who has all kinds of cool costumes in the World.";
+	mes "If you have any Kitcoins with you, come look for Designer Heidam!";
+	next;
+	if (select( "Exchange costume for random enchant box", "Continue conversation" ) == 2) {
+		mes "[Designer Heidam]";
+		mes "Though I look out of shape right now, I used to be a well known fashion model and designer!";
+		next;
+		mes "[Designer Heidam]";
+		mes "Don't pity me! I am well aware of my looks, but I like who I am inside.";
+		close;
+	}
+	mes "[" + strcharinfo(0) + "]";
+	mes "This item is useless to me! Do you have anything else?";
+	next;
+	mes "[Designer Heidam]";
+	mes "Oh, then I can exchange it for a box of costume enchantment items.";
+	next;
+	mes "- Rummaging -";
+	next;
+	// ===================================================================
+	// =================== Costume Enchant Stone Box 4 ===================
+	// ===================================================================
+	.@box_list[0] = 22826;		// Enchant_Stone_Box4
+	setarray .@item_list_0[0],
+		19608,		// C_Chick_Hat
+		19654,		// C_J_Captain_Hat
+		19712,		// C_Little_Angel_Doll
+		19721,		// C_Darkness_Helm
+		19823,		// C_White_Cat_Hood
+		19876,		// C_Rabbit_Ear_Hat
+		20036,		// C_Sword_Master_Crown
+		20145,		// C_Robo_Eye
+		20146,		// C_Angel_Spirit
+		20147,		// C_Bell_Pigeon
+		20746;		// C_Rudra_Wing
+	// ===================================================================
+	// =================== Costume Enchant Stone Box 5 ===================
+	// ===================================================================
+	.@box_list[1] = 22868;		// Enchant_Stone_Box5
+	setarray .@item_list_1[0],
+		19601,		// Drooping_Aliot
+		19643,		// C_Whikebain_Ears
+		19787,		// C_Devoted_Eyes
+		19836,		// C_L_Magestic_Goat
+		19912,		// C_Cat_Eye
+		19928,		// C_Gothic_Heart_Wing
+		19930,		// C_Angel_Mini_Silk_Hat
+		19668,		// C_Wind_Milestone
+		20070,		// C_Alpaca_Hood
+		20115,		// C_Under_Rim_Glasses
+		20130,		// C_Whisper_Tall_Hat
+		20132,		// C_Subject_Aura
+		20133,		// C_Poring_Mascot_Costume
+		20199,		// C_Evil_Marcher_Hat
+		20200,		// C_Rabbit_Head_Dress
+		20202,		// C_Deviruchi_Balloon
+		20217,		// C_Arabian_Veil
+		20224,		// C_Red_Tailed_Ribbon
+		20230,		// C_Mask_Of_Bankrupt
+		20231,		// C_Snowman_Hat
+		20232,		// C_Celines_Ribbon
+		20233,		// C_Gold_Angel_Sculpture
+		20263,		// C_Hat_Of_Drowsy_Cat
+		20761,		// C_Wing_Of_Happiness
+		20798;		// GrimReaper_Protection
+	// ===================================================================
+	// =================== Costume Enchant Stone Box 6 ===================
+	// ===================================================================
+	.@box_list[2] = 22905;		// Enchant_Stone_Box6
+	setarray .@item_list_2[0],
+		19954,		// C_3D_Glasses
+		20071,		// C_Worg_In_Mouth
+		20239,		// C_Large_Ribbon_Muffler
+		20242,		// C_Snownow_Hat
+		20273,		// C_Soft_Sheep_Hat
+		20762;		// C_GreatDevilWing
+	// ===================================================================
+	// =================== Costume Enchant Stone Box 7 ===================
+	// ===================================================================
+	.@box_list[3] = 22953;		// Enchant_Stone_Box7
+	setarray .@item_list_3[0],
+		18740,		// C_Hair_Of_The_Strong
+		19815,		// C_Lolita_Ten_Gallon_Hat
+		20255,		// C_Love_Cheek
+		20266,		// C_Secret_Zipper
+		20268,		// C_Sleep_Eclipse_Family
+		20286,		// C_Under_Rim_Glasses_Red
+		20329,		// C_Tare_HSchool_Doll_Hat
+		20330;		// C_Sombrero
+	// ===================================================================
+	// =================== Costume Enchant Stone Box 8 ===================
+	// ===================================================================
+	.@box_list[4] = 23001;		// Enchant_Stone_Box8
+	setarray .@item_list_4[0],
+		19158,		// C_Gemini_Eyes
+		19816,		// C_Pecopeco_Cap
+		19925,		// C_One_Eyed_Glasses
+		20071,		// C_Worg_In_Mouth
+		20125,		// C_Mini_Glasses
+		20201,		// C_Banshee_Master_Kiss
+		20204,		// C_Hunting_Cap
+		20235,		// C_Frozen_Land_Rose
+		20253,		// C_Droopy_Alice_Doll
+		20254,		// C_Ribbon_Yellow
+		20258,		// C_Blue_Head_Dress
+		20264,		// C_Blood_Sucker
+		20266,		// C_Secret_Zipper
+		20270,		// C_Gryphon_Wing_Ears
+		20315,		// C_Analyze_Eye
+		20318,		// C_Charleston_Antenna
+		20340,		// C_Straight_Pony_BL
+		20341,		// C_Cowlick_BL
+		20342,		// C_Loose_Wave_Twin_BL
+		20349,		// C_FlyingGalapago
+		20350,		// C_Cowlick_YL
+		20351,		// C_Cowlick_GN
+		20352,		// C_Cowlick_PP
+		20353,		// C_Cowlick_RD
+		20354,		// C_Cowlick_OM
+		20355,		// C_Cowlick_BU
+		20356,		// C_Cowlick_WH
+		20357,		// C_Straight_Pony_YL
+		20358,		// C_Straight_Pony_GN
+		20359,		// C_Straight_Pony_PP
+		20360,		// C_Straight_Pony_RD
+		20361,		// C_Straight_Pony_OM
+		20362,		// C_Straight_Pony_BU
+		20363,		// C_Straight_Pony_WH
+		20364,		// C_Loose_Wave_Twin_YL
+		20365,		// C_Loose_Wave_Twin_GN
+		20366,		// C_Loose_Wave_Twin_PP
+		20367,		// C_Loose_Wave_Twin_RD
+		20368,		// C_Loose_Wave_Twin_OM
+		20369,		// C_Loose_Wave_Twin_BU
+		20370,		// C_Loose_Wave_Twin_WH
+		20396,		// C_Woodie_Hat
+		20448,		// C_Cons_Of_Water
+		20457,		// C_Feather_Fluttering
+		20487,		// C_Floral_Waltz
+		20489,		// C_Pope_Crown
+		20504,		// C_Cupid_Wing_Pink
+		20299,		// C_Face_Crusher
+		19598,		// C_Wondering_Wolf_Helm
+		20300;		// C_Hill_Wind_Mask
+	// ===================================================================
+	// =================== Costume Enchant Stone Box 9 ===================
+	// ===================================================================
+	.@box_list[5] = 23058;		// Enchant_Stone_Box9
+	setarray .@item_list_5[0],
+		18744,		// C_World_Star
+		19600,		// Drooping_Kiehl
+		19760,		// C_Rainbow_Veil
+		19761,		// C_White_Lily
+		19978,		// C_Silver_Exclamation
+		19979,		// C_Golden_Question
+		20172,		// C_Pumpkin_Head
+		20180,		// C_Westren_Grace
+		20278,		// C_Man_Medal
+		20325,		// C_Little_Aquarium
+		20344,		// C_Happy_Balloon_J
+		20398,		// C_Niflheim_Bunny_Hat
+		20399,		// C_Crow_Tengu_Mask
+		20404,		// C_Blessing_Of_Angels
+		20405,		// C_Eremes_Scarf
+		20447,		// C_Small_Poring_Band
+		31331,		// C_Chung_E_Shinyon_Cap
+		31372,		// C_Binit_Doll_Hat
+		31430,		// C_Seppl_Hat_TW
+		31431;	// C_Curupira_Hat_TW
+	// ====================================================================
+	// =================== Costume Enchant Stone Box 10 ===================
+	// ====================================================================
+	.@box_list[6] = 23086;		// Enchant_Stone_Box10
+	setarray .@item_list_6[0],
+		20430,		// C_Morocc_Kid_Servant
+		20432,		// C_Khalitzburg_KN_Helm
+		20433,		// C_Louise_Red_Hat
+		20440,		// C_Tone_Of_Gold
+		20458,		// C_Wild_Poring_Rider
+		20459,		// C_Valhalla_Idol
+		20464,		// C_Monochrome_RibbonHat
+		20491,		// C_Laser_Of_Eagle
+		20502,		// C_Devil_Wing
+		20507,		// C_Poring_Bag
+		31087,		// C_Dwarf_Beard
+		31088;		// C_Mad_Hatter
+	// ====================================================================
+	// =================== Costume Enchant Stone Box 11 ===================
+	// ====================================================================
+	.@box_list[7] = 23174;		// Enchant_Stone_Box11
+	setarray .@item_list_7[0],
+		5909,		// C_Valkyrie_Circlet
+		5979,		// C_Angel_Fluttering
+		19745,		// C_Holy_Marching_Hat_J
+		19825,		// C_Vicious_Stop_Bandage
+		20149,		// C_Hexagon_Spectacles
+		20381,		// C_Steampunk_Hat
+		20383,		// C_Magicdecoy_Doll
+		20483,		// C_Butterfly_Barrettes
+		20490,		// C_Full_Bloom_Hp_Blue
+		20499,		// C_Cat_Ear_Hat
+		20509,		// C_Wings_of_Uriel
+		31029,		// C_Pig_Nose
+		31032,		// C_Tare_Luwmin
+		31040,		// C_Magical_Feather
+		31055,		// C_Poring_Soap_Pipe
+		31057,		// C_Eremes_Scarf_Black
+		31062,		// C_Eleanor_Wig
+		31063,		// C_Hair_Bun_BU
+		31064,		// C_Hair_Bun_RD
+		31065,		// C_Hair_Bun_YL
+		31066,		// C_Hair_Bun_GN
+		31067,		// C_Hair_Bun_BL
+		31068,		// C_Hair_Bun_WH
+		31069,		// C_Hair_Bun_OM
+		31070,		// C_Hair_Bun_PP
+		31071,		// C_Roll_Twin_BU
+		31072,		// C_Roll_Twin_RD
+		31073,		// C_Roll_Twin_YL
+		31074,		// C_Roll_Twin_GN
+		31075,		// C_Roll_Twin_BL
+		31076,		// C_Roll_Twin_WH
+		31077,		// C_Roll_Twin_OM
+		31078,		// C_Roll_Twin_PP
+		31079,		// C_Long_Pony_BU
+		31080,		// C_Long_Pony_RD
+		31081,		// C_Long_Pony_YL
+		31082,		// C_Long_Pony_GN
+		31083,		// C_Long_Pony_BL
+		31084,		// C_Long_Pony_WH
+		31085,		// C_Long_Pony_OM
+		31086,		// C_Long_Pony_PP
+		31120,		// C_Vampire_Familiar
+		31123,		// C_Ghostring_Tall_Hat
+		31125,		// C_QueenAnzRevenge
+		31118,		// C_Assassin_Skull_Mask
+		31370,		// C_Straight_Long_YLK
+		31376,		// C_Jirant_Circlet
+		31391,		// C_Floating_Stone_Of_Int
+		31418,		// C_Leek_In_Mouth
+		20508,		// C_Poster_Girl_Hat
+		20530,		// C_Wings_of_Gabriel
+		19555;		// C_Crescent_Helm
+	// ====================================================================
+	// =================== Costume Enchant Stone Box 12 ===================
+	// ====================================================================
+	.@box_list[8] = 23299;		// Enchant_Stone_Box12
+	setarray .@item_list_8[0],
+		20156,		// C_Fan_In_Mouth
+		20195,		// C_Scratching_Cat
+		20449,		// C_White_Black_Temp
+		20511,		// C_Blue_Fairy_Wing
+		20514,		// C_Thanatos_Sword
+		20765,		// C_Archangel_Wing
+		31134,		// C_Happy_Parrot_J
+		31136,		// C_Clock_Casket
+		31160,		// C_RuneHelm
+		31162,		// C_Shaving_Foam
+		31165,		// C_Piggyback
+		31186,		// C_Black_Cat
+		31300,		// C_Warm_Cat_Muffler
+		31327;		// C_Stretched_Nose_M
+		// 31627;		// C_L_Magesic2_TW
+	// ====================================================================
+	// =================== Costume Enchant Stone Box 13 ===================
+	// ====================================================================
+	.@box_list[9] = 23524;		// Enchant_Stone_Box13
+	setarray .@item_list_9[0],
+		20488,		// C_Pope_Ribbon
+		20495,		// C_Quati_Hat_J
+		31031,		// C_Tare_Pope_Casual
+		31033,		// C_BelieversCap
+		31122,		// C_Bloody_Stop_Bandage
+		31164,		// C_Brown_Stall
+		31166,		// C_Teddy_Bear_Hood
+		31168,		// C_Mouton_Life_BL
+		31178,		// C_Flame_Muffler
+		31294,		// C_Jirant_Circlet_Red
+		31397,		// C_Pope_Sitting_Head
+		31545,		// C_Eremes_Scarf_BU
+		// 31626,		// C_FluffyWing_TW
+		31628;		// C_Bogy_Cap_TW
+	// ====================================================================
+	// =================== Costume Enchant Stone Box 14 ===================
+	// ====================================================================
+	.@box_list[10] = 23629;		// Enchant_Stone_Box14
+	setarray .@item_list_10[0],
+		31415,		// C_Wanderer_Sakkat
+		19289,		// C_Moon_Eyepatch
+		19291,		// C_Shiba_Inu
+		19294,		// C_CatEars_Cyber_HeadP_R
+		19763,		// C_Leaf_Cat_Hat
+		20376,		// C_Memories_Of_Lovers
+		20493,		// C_Wing_Headphone
+		20498,		// C_Elephant_Hat
+		20516,		// C_Wings_of_Michael
+		31180,		// C_Shura_King_Pledge
+		31329,		// C_Alice_Wig
+		31332,		// Khalitzburg_KN_Helm_BL
+		31414,		// C_Cancer_Diadem
+		31504;		// C_Starving_Fish_Hat
+	// ====================================================================
+	// =================== Costume Enchant Stone Box 15 ===================
+	// ====================================================================
+	.@box_list[11] = 23682;		// Enchant_Stone_Box15
+	setarray .@item_list_11[0],
+		19723,		// C_Sacred_Torch_Coronet
+		19953,		// C_Parade_Cap
+		19959,		// C_Drooping_Argiope
+		19960,		// C_Chain_Puppet
+		19992,		// C_Chilly_Breath
+		20179,		// C_Monkey_On_Fur_Hat
+		20510,		// C_SwordWing
+		20515,		// C_Magic_Circle
+		20517,		// C_GiantCatBag_TW
+		31152,		// C_Piamette_BowTie_Red
+		31314,		// C_Ghost_Holiday
+		31396,		// C_Sorcerer_Hood
+		31398,		// C_Blinking_Thin_Eyes
+		31432,		// C_Luwmin_Ice
+		31433,		// C_Astro_Circle
+		31437,		// C_Baby_Penguin
+		31439,		// C_Fluffy_Heart_Earmuffs
+		31452,		// C_White_Cat
+		31460,		// C_Blessing_Sky_Lantern
+		31463,		// C_Flying_Drone
+		31498,		// C_Elephangel_TH
+		// 31722,		// C_Sedora_Hat
+		31412;		// C_Virgo_Crown
+	// ====================================================================
+	// =================== Costume Enchant Stone Box 16 ===================
+	// ====================================================================
+	// Note: The reward is 'Costume Enchant Stone Box 16' on items description but Enchant_Stone_Box21 in the file
+	.@box_list[12] = 100314;		// Enchant_Stone_Box21
+	setarray .@item_list_12[0],
+		20033,		// C_Buddhist_Priest_Crown
+		20098,		// C_Vampire_Hairband
+		20171,		// C_Sepia_Cap
+		20174,		// C_Halloween_Hat_Orange
+		20395,		// C_BlackWitchHat
+		20482,		// C_Heaven_Cage
+		20533,		// C_PinkButterfly_Wing_T
+		20535,		// C_Digital_Space
+		20543,		// C_Halloween_Poring_Bag
+		31139,		// C_White_Rabbit_Ear
+		31249,		// C_Rabbit_Hopping
+		31489,		// C_Bouquet_Hat
+		31490,		// C_Poring_Muffler
+		31529,		// C_Happy_Rabbit_Ribbon
+		31606;		// C_Autumn_Headband
+	// ====================================================================
+	// =================== Costume Enchant Stone Box 17 ===================
+	// ====================================================================
+	.@box_list[13] = 100314;		// Enchant_Stone_Box21
+	setarray .@item_list_13[0],
+		19990,		// C_Snow_Rabbit_Knit_Hat
+		20175,		// C_Diabolic_Headphone
+		20546,		// C_Backside_Ribbon_Bell
+		20764,		// C_Fallen_Angel_Wing
+		31440,		// C_Snow_Bear_Food
+		31565,		// C_Princess_Ribbon_Crown
+		31586,		// C_Poporing_Muffler
+		31616,		// C_Sleep_Sheep_TW
+		31625,		// C_Protect_Cloth
+		31693;		// C_LunaticMuffler
+	// ====================================================================
+	// =================== Costume Enchant Stone Box 18 ===================
+	// ====================================================================
+	.@box_list[14] = 100314;		// Enchant_Stone_Box21
+	setarray .@item_list_14[0],
+		20257,		// C_Black_Rabbit_Bonnet
+		20486,		// C_Twin_Margaret
+		20570,		// C_HeartChocoBag
+		20572,		// C_WingOfHeart
+		31382,		// C_Cat_Ears_Punkish
+		31481,		// C_CatCoffeeCup_TW
+		31624,		// C_HeartOfCat_TW
+		31699;		// C_Smiling_Eyes
+	// ====================================================================
+	// =================== Costume Enchant Stone Box 19 ===================
+	// ====================================================================
+	.@box_list[15] = 100052;		// Enchant_Stone_Box19
+	setarray .@item_list_15[0],
+		20022,		// C_Love_Piece
+		20519,		// C_Full_BloomCherry_Tree
+		20576,		// C_Cat_Fork
+		31027,		// C_Pretty_Bear
+		31483,		// C_CatEarRibbon_TW
+		31512,		// C_Panda_Rabbit
+		31569,		// C_OpenAir_Headset
+		31572,		// C_Mobile_Pursuit_System
+		31573,		// C_Mecha_Cat_Ears
+		31574,		// C_Cyber_Income
+		31600,		// C_Kishu_Inu
+		31614,		// C_Fox
+		31698,		// C_Pigtail_Red_Hood
+		31765,		// C_Garnet_Tiara
+		31766,		// C_Peony_Hair_Ornament
+		440000;		// C_SharkHead
+	// ====================================================================
+	// =================== Costume Enchant Stone Box 20 ===================
+	// ====================================================================
+	.@box_list[16] = 100202;		// Enchant_Stone_Box20
+	setarray .@item_list_16[0],
+		20582,		// C_T_Bear_Bag
+		20584,		// C_Big_Foxtail
+		20588,		// C_Nifl_Bloom
+		31479,		// C_ManyStars_TW
+		31568,		// C_Floating_Ball_TW
+		31611,		// C_Dark_Snake_Lord_Stall
+		31671,		// Costume_Twin_Cannon
+		31673,		// C_Picnic_Basket
+		31688,		// C_Poring_On_Shoulder
+		31735,		// Costume_Yawata_Seal
+		31787,		// C_SavageB_On_Shoulder
+		31798,		// C_Baby_Panda
+		31799,		// C_Pretty_Bear_WH
+		31832,		// C_Bicolor_Cat_Witch_Hat
+		31884,		// C_Magic_Helm
+		400020;		// C_BeachBall
+	// ====================================================================
+	// =================== Costume Enchant Stone Box 21 ===================
+	// ====================================================================
+	.@box_list[17] = 100314;		// Enchant_Stone_Box21
+	setarray .@item_list_17[0],
+		20592,		// C_Santa_Backpack
+		31509,		// C_Fawn_Ear
+		31559,		// C_Royalguard_Necklace
+		440002;		// C_Happy_Cat_TW
+
+	while(1) {
+		for ( .@i = 0; .@i < 18; ++.@i ) {
+			if (getiteminfo(.@box_list[.@i], 2) == -1)	// temporary check
+				continue;
+			.@size = getarraysize( getd(".@item_list_" + .@i) );
+			for ( .@h = 0; .@h < .@size; ++.@h ) {
+				.@id = getd( ".@item_list_" + .@i + "[" + .@h + "]" );
+				if (getiteminfo(.@id, 2) == -1)	// temporary check
+					continue;
+				if (countitem(.@id) < 1)
+					continue;
+				mes "[Designer Heidam]";
+				mes "I see that you have a ^3131FF" + getitemname(.@id) + "^000000. Do you want to exchange this with a costume enchantment box?";
+				next;
+				switch( select( "Exchange", "Look for something else", "Stop Exchanging" ) ) {
+				case 1:
+					mes "[Designer Heidam]";
+					if (countitem(.@id) < 1)
+						mes "Oh~ Something suddenly disappeared...";
+					else {
+						mes "Exchange Completed.";
+						delitem .@id, 1;
+						getitem .@box_list[.@i], 1;
+					}
+					mes "Let me check you for another item to exchange...";
+					next;
+					break;
+				case 2:
+					break;
+				case 3:
+					mes "[Designer Heidam]";
+					mes "Meow? Where are you going?";
+					close;
+				}
+			}
+		}
+		mes "[Designer Heidam]";
+		mes "Guess that is all.";
+		next;
+		if (select( "Look more", "Quit" ) == 2) {
+			mes "[Designer Heidam]";
+			mes "Bye~";
+			close;
+		}
+	}
+}
+
+malangdo,115,154,3	script	Fashion Stone#stone	4_BULLETIN_BOARD2,{ end; }
+
+// Costume enchant (top, mid, low)
+mal_in01,22,113,3	script	Aver De Dosh#cos_ect	4_WHITETIGER,{
+	disable_items;
+	mes "[Aver De Dosh]";
+	mes "Welcome to Fashion Stone!!";
+	next;
+	mes "[Aver De Dosh]";
+	mes "We take various costume items.";
+	next;
+	mes "[Aver De Dosh]";
+	mes "If you want cool styling for your costume Hat, please come to me 'Aver De Dosh'!";
+	mes "Don't forget to bring ^ff0000your own costume Hat and costume stones^000000~";
+	next;
+	if (select( "Apply ability.", "End Conversation." ) == 2) {
+		mes "[Aver De Dosh]";
+		mes "Please check our other upgrading services~";
+		close;
+	}
+	if (checkweight(1119,3) == 0) {
+		mes "[Aver De Dosh]";
+		mes "Kiaaaaach!!!";
+		mes "I hate bulging bags!";
+		mes "No matter how cool your hat looks, that fat bag of yours is a fashion terror you know!";
+		next;
+		mes "[Aver De Dosh]";
+		mes "It seems you have too many items on you.";
+		mes "Come back after clearing some inventory spaces.";
+		close;
+	}
+	.@eq_top = getequipid(EQI_COSTUME_HEAD_TOP);
+	.@eq_mid = getequipid(EQI_COSTUME_HEAD_MID);
+	.@eq_low = getequipid(EQI_COSTUME_HEAD_LOW);
+
+	if (.@eq_top == -1 && .@eq_mid == -1 && .@eq_low == -1) {
+		mes "[Aver De Dosh]";
+		mes "You must wear item you want to add ability.";
+		mes "Then, I will be able to help you out.";
+		close;
+	}
+	if (.@eq_top > -1) {
+		.@part = EQI_COSTUME_HEAD_TOP;
+		.@equip_id = .@eq_top;
+	}
+	else if (.@eq_mid > -1) {
+		.@part = EQI_COSTUME_HEAD_MID;
+		.@equip_id = .@eq_mid;
+	}
+	else if (.@eq_low > -1) {
+		.@part = EQI_COSTUME_HEAD_LOW;
+		.@equip_id = .@eq_low;
+	}
+
+	switch(.@part) {
+	case EQI_COSTUME_HEAD_TOP:
+		switch(.@equip_id) {
+			// top
+		case 18740:	// C_Hair_Of_The_Strong
+		case 18741:	// C_Will_O_Wisp
+		case 19294:	// C_CatEars_Cyber_HeadP_R
+		case 19507:	// Fine_Sun
+		case 19515:	// Yellow_Hat
+		case 19516:	// Singing_Bird
+		case 19517:	// Cocks_Comb
+		case 19518:	// Rainbow
+		case 19519:	// Lightning_Cloud
+		case 19520:	// Rain_Cloud
+		case 19521:	// Charlie_Hat
+		case 19522:	// Mini_Crown1
+		case 19523:	// Donation_Ribbon
+		case 19524:	// C_Green_Feeler
+		case 19525:	// C_Jack_A_Dandy
+		case 19526:	// C_Helm
+		case 19527:	// C_Sharp_Gear
+		case 19529:	// C_Angelic_Chain
+		case 19537:	// C_Gryphon_Hat
+		case 19543:	// Oliver_Wolf_Hood
+		case 19544:	// C_Tare_Neko_Cru
+		case 19545:	// C_Boys_Cap
+		case 19546:	// C_Valkyrie_Helm
+		case 19547:	// C_Deviruchi_Cap
+		case 19548:	// C_Frog_Cap
+		case 19549:	// C_Magestic_Goat
+		case 19573:	// C_Heart_Wing_Hairband
+		case 19575:	// C_Rising_Black_Dragon
+		case 19576:	// C_Tare_Pope
+		case 19577:	// 10th_Anni_Poring_Hat
+		case 19585:	// C_Feather_Beret
+		case 19586:	// C_Pink_Bunny_Band_J
+		case 19587:	// C_King_Poring_Hat
+		case 19590:	// C_Twin_Ribbon_J
+		case 19592:	// C_Hibiscus_J
+		case 19599:	// C_Imp_Hat
+		case 19600:	// Drooping_Kiehl
+		case 19601:	// Drooping_Aliot
+		case 19602:	// C_Invisible_Cap
+		case 19608:	// C_Chick_Hat
+		case 19613:	// C_Valkyrie_Feather_Band
+		case 19618:	// C_Mask_Of_Fox
+		case 19625:	// C_Bunny_Band
+		case 19629:	// C_Tiara
+		case 19630:	// C_Crown
+		case 19632:	// C_Hat
+		case 19633:	// C_Flower_Hairband
+		case 19635:	// C_Mini_Propeller
+		case 19637:	// C_Nurse_Cap
+		case 19639:	// C_Sahkkat
+		case 19643:	// C_Whikebain_Ears
+		case 19646:	// C_Ramen_Hat
+		case 19647:	// C_Red_Deviruchi_Cap
+		case 19650:	// C_Rainbow_Feather_Deco
+		case 19653:	// C_Marcher_Hat
+		case 19654:	// C_J_Captain_Hat
+		case 19655:	// C_Tiraya_Bonnet
+		case 19656:	// C_Minstrel_Hat
+		case 19657:	// C_Captain_Hat
+		case 19659:	// C_Gray_Fur_Hat
+		case 19665:	// C_Poring_Cake_Cap
+		case 19667:	// C_Helm_Of_Dragoon
+		case 19668:	// C_Wind_Milestone
+		case 19677:	// C_Soulless_Wing
+		case 19682:	// C_Santa_Poring_Hat
+		case 19684:	// C_Happy_Wig
+		case 19694:	// C_Vane_Hairpin
+		case 19702:	// C_Santa_Hat_1
+		case 19706:	// C_Red_Dress_Hat
+		case 19712:	// C_Little_Angel_Doll
+		case 19715:	// C_Scarf
+		case 19719:	// C_Coronet
+		case 19721:	// C_Darkness_Helm
+		case 19723:	// C_Sacred_Torch_Coronet
+		case 19728:	// C_Tare_Zonda
+		case 19729:	// C_Neko_Mimi_Kafra
+		case 19731:	// C_Satanic_Chain
+		case 19733:	// C_Panda_Cap
+		case 19737:	// C_Corsair_K
+		case 19738:	// C_Detective_Hat_K
+		case 19739:	// C_Sleeping_Kitty_Cat
+		case 19745:	// C_Holy_Marching_Hat_J
+		case 19750:	// C_Saint_Frill_Ribbon
+		case 19758:	// C_King_Frog_Hat
+		case 19761:	// C_White_Lily
+		case 19762:	// C_Happy_Peace_Proof
+		case 19763:	// C_Leaf_Cat_Hat
+		case 19771:	// C_Butterfly_Hairpin
+		case 19782:	// C_Drooping_Kitty
+		case 19784:	// C_Morrigane's_Helm
+		case 19786:	// C_Mistress_Crown
+		case 19789:	// C_Sweet_Gents
+		case 19790:	// C_Wedding_Veil
+		case 19795:	// C_Lord_Circlet
+		case 19796:	// C_Bone_Helm
+		case 19797:	// C_Apple_Of_Archer
+		case 19799:	// C_Golden_Gear
+		case 19800:	// C_Carnation_Hairband
+		case 19807:	// C_Majestic_Helmet
+		case 19818:	// C_Droop_Morocc_Minion
+		case 19824:	// C_Evil_Druid_Hat
+		case 19825:	// C_Vicious_Stop_Bandage
+		case 19827:	// C_Amistr_Cap
+		case 19828:	// C_Fedora
+		case 19829:	// C_Straw_Hat
+		case 19831:	// C_Filir_Hat
+		case 19833:	// C_Fillet
+		case 19835:	// C_Lif_Doll_Hat
+		case 19836:	// C_L_Magestic_Goat
+		case 19839:	// C_Vanilmirth_Hat
+		case 19842:	// C_Puppy_Hat
+		case 19843:	// C_Cat_Hairband
+		case 19844:	// C_Turban
+		case 19845:	// C_Hair_Protector
+		case 19847:	// C_Big_Sis_Ribbon
+		case 19848:	// C_Angeling_Hat
+		case 19851:	// C_Brown_Bear_Cap
+		case 19852:	// C_Galapago_Cap
+		case 19858:	// C_Leaf_Headgear
+		case 19859:	// C_Flying_Angel
+		case 19860:	// C_Cryptura_Hair_Cap
+		case 19861:	// C_Heart_Hair_Pin
+		case 19862:	// C_Horn_Of_Succubus
+		case 19863:	// C_Inccubus_Horn
+		case 19865:	// C_Joker_Jester
+		case 19866:	// C_Blue_Pajamas_Hat
+		case 19874:	// C_Carnival_Circlet
+		case 19876:	// C_Rabbit_Ear_Hat
+		case 19878:	// C_Drooping_Bunny
+		case 19883:	// C_Piamette_Hood
+		case 19884:	// C_Vanargandr_Helm
+		case 19913:	// C_Poo_Poo_Hat
+		case 19930:	// C_Angel_Mini_Silk_Hat
+		case 19931:	// C_Lazy_Raccoon
+		case 19932:	// C_Cap_Of_Concentration
+		case 19934:	// C_10Gallon_Hat_Of_Flame
+		case 19935:	// C_Hunting_Cap_Of_Gust
+		case 19936:	// C_Knit_Cap_Of_Water
+		case 19937:	// C_Silk_Hat_Of_Earth
+		case 19939:	// C_Antler
+		case 19941:	// C_Ear_Mufs
+		case 19953:	// C_Parade_Cap
+		case 19955:	// C_Mini_Tree_J
+		case 19977:	// C_Golden_Exclamation
+		case 19978:	// C_Silver_Exclamation
+		case 19979:	// C_Golden_Question
+		case 19980:	// C_Silver_Question
+		case 19983:	// C_Flower_Hairpin
+		case 19984:	// C_Winter_Hat
+		case 20017:	// C_Marionette_Doll
+		case 20036:	// C_Sword_Master_Crown
+		case 20046:	// C_Decoration_bluerose
+		case 20049:	// C_Plaster
+		case 20050:	// C_Ph.D_Hat
+		case 20057:	// C_Feather_Bonnet
+		case 20063:	// C_Yellow_Brain_Hat
+		case 20064:	// Blue_Brain_Hat
+		case 20070:	// C_Alpaca_Hood
+		case 20073:	// C_Hair_Band
+		case 20074:	// C_Biretta
+		case 20090:	// C_Egg_Shell
+		case 20092:	// C_Sales_Signboard
+		case 20093:	// C_Star_Sparkling
+		case 20094:	// C_Fillet_Green
+		case 20095:	// C_Fillet_Red
+		case 20096:	// C_Fillet_Blue
+		case 20097:	// C_Fillet_White
+		case 20114:	// C_Funeral_Costume
+		case 20118:	// C_Hat_Of_Cake
+		case 20119:	// C_Fur_Hat
+		case 20120:	// C_Antenna
+		case 20121:	// C_Lotus_Flower_Hat
+		case 20130:	// C_Whisper_Tall_Hat
+		case 20133:	// C_Poring_Mascot_Costume
+		case 20151:	// C_Poison_Spore_Hat
+		case 20157:	// C_Fish_On_Head
+		case 20158:	// C_Circlet
+		case 20159:	// C_Blue_Hair_Band
+		case 20160:	// C_Fried_Egg
+		case 20161:	// C_Prontera_Army_Cap
+		case 20175:	// C_Diabolic_Headphone
+		case 20179:	// C_Monkey_On_Fur_Hat
+		case 20180:	// C_Westren_Grace
+		case 20181:	// C_Mistic_Rose
+		case 20182:	// C_Mottled_Egg_Shell
+		case 20184:	// C_Party_Hat
+		case 20186:	// C_Magni_Cap
+		case 20197:	// C_Amistr_Beret
+		case 20199:	// C_Evil_Marcher_Hat
+		case 20200:	// C_Rabbit_Head_Dress
+		case 20203:	// C_Bandana
+		case 20204:	// C_Hunting_Cap
+		case 20205:	// C_Fancy_Flower
+		case 20207:	// C_Stripe_Band
+		case 20208:	// C_Necktie
+		case 20214:	// C_Evil_Marcher_Hat_J
+		case 20224:	// C_Red_Tailed_Ribbon
+		case 20225:	// C_Pumpkin_Hat
+		case 20226:	// C_Hair_Brush
+		case 20231:	// C_Snowman_Hat
+		case 20232:	// C_Celines_Ribbon
+		case 20233:	// C_Gold_Angel_Sculpture
+		case 20238:	// C_Blue_Drooping_Kitty
+		case 20242:	// C_Snownow_Hat
+		case 20248:	// C_Black_Strong_Hair
+		case 20249:	// C_Red_Strong_Hair
+		case 20250:	// C_White_Strong_Hair
+		case 20253:	// C_Droopy_Alice_Doll
+		case 20254:	// C_Ribbon_Yellow
+		case 20258:	// C_Blue_Head_Dress
+		case 20262:	// C_Fox_Ears_Bell_Ribbon
+		case 20263:	// C_Hat_Of_Drowsy_Cat
+		case 20266:	// C_Secret_Zipper
+		case 20269:	// C_White_Fox_Ear_Ribbon
+		case 20271:	// C_Sunflower
+		case 20272:	// C_Snowy_Horn
+		case 20273:	// C_Soft_Sheep_Hat
+		case 20277:	// C_Balloon_Hat
+		case 20278:	// C_Man_Medal
+		case 20283:	// C_Over_Protector
+		case 20383:	// C_Magicdecoy_Doll
+		case 20433:	// C_Louise_Red_Hat
+		case 20447:	// C_Small_Poring_Band
+		case 20452:	// C_berry_Prince_Crown
+		case 20458:	// C_Wild_Poring_Rider
+		case 20463:	// C_Two_Tone_Beret
+		case 20464:	// C_Monochrome_RibbonHat
+		case 20467:	// C_Elemental_Crown
+		case 20483:	// C_Butterfly_Barrettes
+		case 20489:	// C_Pope_Crown
+		case 20490:	// C_Full_Bloom_Hp_Blue
+		case 20491:	// C_Laser_Of_Eagle
+		case 20495:	// C_Quati_Hat_J
+		case 20498:	// C_Elephant_Hat
+		case 20508:	// C_Poster_Girl_Hat
+		case 31027:	// C_Pretty_Bear
+		case 31031:	// C_Tare_Pope_Casual
+		case 31032:	// C_Tare_Luwmin
+		case 31040:	// C_Magical_Feather
+		case 31062:	// C_Eleanor_Wig
+		case 31123:	// C_Ghostring_Tall_Hat
+		case 31125:	// C_QueenAnzRevenge
+		case 31137:	// C_Blue_Rose_Ornament
+		case 31139:	// C_White_Rabbit_Ear
+		case 31147:	// C_Tare_Domovoi
+		case 31149:	// C_Nydhog_Wig
+		case 31151:	// C_Chasher_Ear
+		case 31158:	// C_Squirrel_Ear_Hat
+		case 31176:	// C_Looking
+		case 31177:	// C_Tail_Hat
+		case 31180:	// C_Shura_King_Pledge
+		case 31200:	// C_Wrapping_Ribbon
+		case 31204:	// C_Drooping_White_Kitty
+		case 31249:	// C_Rabbit_Hopping
+		case 31252:	// C_Cat_Ear_Hat_White
+		case 31294:	// C_Jirant_Circlet_Red
+		case 31314:	// C_Ghost_Holiday
+		case 31318:	// C_Gerhard_Von_Devi
+		case 31329:	// C_Alice_Wig
+		case 31331:	// C_Chung_E_Shinyon_Cap
+		case 31332:	// Khalitzburg_KN_Helm_BL
+		case 31370:	// C_Straight_Long_YLK
+		case 31372:	// C_Binit_Doll_Hat
+		case 31582:	// C_Jirant_Circlet
+		case 31382:	// C_Cat_Ears_Punkish
+		case 31385:	// C_Gothic_Pumpkin_Head
+		case 31396:	// C_Sorcerer_Hood
+		case 31397:	// C_Pope_Sitting_Head
+		case 31405:	// C_Eleanor_Wig_YL
+		case 31406:	// C_Nydhog_Wig_WH
+		case 31407:	// C_Alice_Wig_PK
+		case 31412:	// C_Virgo_Crown
+		case 31414:	// C_Cancer_Diadem
+		case 31430:	// C_Seppl_Hat_TW
+		case 31431:	// C_Curupira_Hat_TW
+		case 31433:	// C_Astro_Circle
+		case 31439:	// C_Fluffy_Heart_Earmuffs
+		case 31440:	// C_Snow_Bear_Food
+		case 31451:	// C_Blue_Frill_Ribbon
+		case 31456:	// C_Baby_Leopard_Cat
+		case 20227:	// C_Husky_Hat
+		case 31474:	// C_Straight_Long_BL
+		case 31475:	// C_Black_Fox_Ear_Ribbon
+		case 31481:	// C_CatCoffeeCup_TW
+		case 31489:	// C_Bouquet_Hat
+		case 31504:	// C_Starving_Fish_Hat
+		case 31509:	// C_Fawn_Ear
+		case 31529:	// C_Happy_Rabbit_Ribbon
+		case 31546:	// C_Clock_Casket_RD
+		case 31564:	// C_Variant_Veil
+		case 31565:	// C_Princess_Ribbon_Crown
+		case 31573:	// C_Mecha_Cat_Ears
+		case 31598:	// C_Forest_Guide
+		case 31624:	// C_HeartOfCat_TW
+		case 31628:	// C_Bogy_Cap_TW
+			// top + mid
+		case 19555:	// C_Crescent_Helm
+		case 19574:	// C_Lord_of_Death
+		case 19578:	// C_Goggle
+		case 19598:	// C_Wondering_Wolf_Helm
+		case 19612:	// C_Headset_OST
+		case 19710:	// C_Wings_Of_Victory
+		case 19760:	// C_Rainbow_Veil
+		case 19775:	// C_Marvelous_Wig
+		case 19823:	// C_White_Cat_Hood
+		case 19864:	// C_Afro_Wig
+		case 19928:	// C_Gothic_Heart_Wing
+		case 20402:	// C_Holy_Klobuk
+		case 20493:	// C_Wing_Headphone
+		case 31205:	// C_L_Orc_Hero_Helm
+		case 31415:	// C_Wanderer_Sakkat
+			// top + low
+		case 20217:	// C_Arabian_Veil
+			// top + mid + low
+		case 19556:	// C_Kabuki_Mask
+		case 19746:	// C_Cap_Of_Blindness
+		case 19821:	// C_Hyegun_Hat
+		case 19849:	// C_Munak_Turban
+		case 19850:	// C_Bongun_Hat
+		case 20481:	// C_Mask_of_Ifrit
+		case 31409:	// C_Barrel_Helm
+			break;
+		default:
+			mes "[Aver De Dosh]";
+			mes "Well...";
+			mes "This hat is currently not available for upgrade.";
+			close;
+		}
+		break;
+
+	case EQI_COSTUME_HEAD_MID:
+		switch(.@equip_id) {
+			// mid
+		case 18742:	// C_MoonStar_Accessory
+		case 18744:	// C_World_Star
+		case 19291:	// C_Shiba_Inu
+		case 19509:	// Butterfly_Wing_Ear
+		case 19510:	// Nut_On_Head
+		case 19511:	// Heart_Eye_Patch1
+		case 19512:	// Heart_Eye_Patch2
+		case 19550:	// C_Blush
+		case 19551:	// C_Elven_Ears
+		case 19603:	// C_Invisible_Sunglasses
+		case 19621:	// C_Ear_Of_Devils_Wing
+		case 19624:	// C_Round_Eyes
+		case 19734:	// C_Binoculars
+		case 19735:	// C_Fin_Helm
+		case 19752:	// C_Shelter_Wing_Ears
+		case 19755:	// C_YinYang_Earring
+		case 19781:	// C_Ear_Of_Angel's_Wing_
+		case 19787:	// C_Devoted_Eyes
+		case 19826:	// C_Ice_Wing_Ear
+		case 19830:	// C_Sunglasses
+		case 19846:	// C_Opera_Ghost_Mask
+		case 19871:	// C_Music_Decoration
+		case 19885:	// C_Blinker
+		case 19886:	// C_Luxury_Sunglasses
+		case 19887:	// C_One_Eyed_Glass
+		case 19888:	// C_Glasses
+		case 19889:	// C_Pair_Of_Red_Ribbon
+		case 19912:	// C_Cat_Eye
+		case 19925:	// C_One_Eyed_Glasses
+		case 19954:	// C_3D_Glasses
+		case 19989:	// C_Mouton_Life
+		case 20115:	// C_Under_Rim_Glasses
+		case 20125:	// C_Mini_Glasses
+		case 20145:	// C_Robo_Eye
+		case 20146:	// C_Angel_Spirit
+		case 20147:	// C_Bell_Pigeon
+		case 20149:	// C_Hexagon_Spectacles
+		case 20215:	// C_Black_Devil_Mask
+		case 20221:	// C_Eyes_Of_Ifrit
+		case 20255:	// C_Love_Cheek
+		case 20270:	// C_Gryphon_Wing_Ears
+		case 20295:	// C_Poring_Sunglasses_J
+		case 20298:	// C_Happy_Lunatic_Ear
+		case 20318:	// C_Charleston_Antenna
+		case 20319:	// C_Crimson_Booster
+		case 20325:	// C_Little_Aquarium
+		case 20376:	// C_Memories_Of_Lovers
+		case 20399:	// C_Crow_Tengu_Mask
+		case 20404:	// C_Blessing_Of_Angels
+		case 20430:	// C_Morocc_Kid_Servant
+		case 31047:	// C_First_Love_Cheek
+		case 31122:	// C_Bloody_Stop_Bandage
+		case 31167:	// C_Lunatic_Ear_Black
+		case 31168:	// C_Mouton_Life_BL
+		case 31183:	// C_Fallen_Angel_Blessing
+		case 31186:	// C_Black_Cat
+		case 31299:	// C_White_Rabbit
+		case 31302:	// C_Black_Magenta_Ribbon
+		case 31308:	// C_Protect_Feathers
+		case 31327:	// C_Stretched_Nose_M
+		case 31391:	// C_Floating_Stone_Of_Int
+		case 31398:	// C_Blinking_Thin_Eyes
+		case 31437:	// C_Baby_Penguin
+		case 31452:	// C_White_Cat
+		case 31463:	// C_Flying_Drone
+		case 31472:	// C_Fairy_Feathers
+		case 31483:	// C_CatEarRibbon_TW
+		case 31488:	// C_Mvp
+		case 31512:	// C_Panda_Rabbit
+		case 31567:	// C_Sheep_Horn
+		case 31568:	// C_Floating_Ball_TW
+		case 31574:	// C_Cyber_Income
+		case 31600:	// C_Kishu_Inu
+		case 31614:	// C_Fox
+		case 31673:	// C_Picnic_Basket
+		case 31688:	// C_Poring_On_Shoulder
+		case 31699:	// C_Smiling_Eyes
+			// mid + low
+		case 19554:	// C_Hahoe_Mask
+		case 19563:	// C_Dragon_Arhat_Mask
+		case 19564:	// C_Tiger_Arhat_Mask
+		case 19638:	// C_Mr_Smile
+		case 19732:	// C_Goblin_Mask_04
+		case 19736:	// C_Gas_Mask
+		case 19791:	// C_Alarm_Mask
+		case 19792:	// C_Goblin_Mask_01
+		case 19793:	// C_Goblin_Mask_02
+		case 19794:	// C_Goblin_Mask_03
+		case 19882:	// C_Flowerpot_Mask
+		case 20166:	// C_Hockey_Mask
+		case 20195:	// C_Scratching_Cat
+		case 20230:	// C_Mask_Of_Bankrupt
+		case 20299:	// C_Face_Crusher
+		case 31505:	// C_Falcon_Mask
+			break;
+		default:
+			mes "[Aver De Dosh]";
+			mes "Well...";
+			mes "This hat is currently not available for upgrade.";
+			close;
+		}
+		break;
+
+	case EQI_COSTUME_HEAD_LOW:
+		switch(.@equip_id) {
+		case 19513:	// Chicken_Beak
+		case 19514:	// Charlie_Beard
+		case 19528:	// C_Iron_Cane
+		case 19552:	// C_Centimental_Flower
+		case 19553:	// C_Assassin_Mask_
+		case 19566:	// C_Samurai_Mask
+		case 19604:	// C_Invisible_Mask
+		case 19606:	// C_Ninja_Scroll
+		case 19634:	// C_Flu_Mask
+		case 19636:	// C_Pierrot_Nose
+		case 19672:	// C_Poring_Letter
+		case 19783:	// C_Granpa_Beard
+		case 19785:	// C_Well_Baked_Toast
+		case 19798:	// C_Angry_Mouth
+		case 19902:	// C_Cigar
+		case 20034:	// C_Jack_Castle_Bat
+		case 20054:	// C_Baby_Pacifier
+		case 20071:	// C_Worg_In_Mouth
+		case 20091:	// C_Smoking_Pipe
+		case 20132:	// C_Subject_Aura
+		case 20156:	// C_Fan_In_Mouth
+		case 20169:	// C_Long_Tongue
+		case 20201:	// C_Banshee_Master_Kiss
+		case 20202:	// C_Deviruchi_Balloon
+		case 20223:	// C_Centimental_Leaf
+		case 20235:	// C_Frozen_Land_Rose
+		case 20239:	// C_Large_Ribbon_Muffler
+		case 20240:	// C_Gift_Of_Snow
+		case 20264:	// C_Blood_Sucker
+		case 20305:	// C_NettyHeart_BalloonGum
+		case 20340:	// C_Straight_Pony_BL
+		case 20342:	// C_Loose_Wave_Twin_BL
+		case 20344:	// C_Happy_Balloon_J
+		case 20357:	// C_Straight_Pony_YL
+		case 20358:	// C_Straight_Pony_GN
+		case 20359:	// C_Straight_Pony_PP
+		case 20360:	// C_Straight_Pony_RD
+		case 20361:	// C_Straight_Pony_OM
+		case 20362:	// C_Straight_Pony_BU
+		case 20363:	// C_Straight_Pony_WH
+		case 20364:	// C_Loose_Wave_Twin_YL
+		case 20365:	// C_Loose_Wave_Twin_GN
+		case 20366:	// C_Loose_Wave_Twin_PP
+		case 20367:	// C_Loose_Wave_Twin_RD
+		case 20368:	// C_Loose_Wave_Twin_OM
+		case 20369:	// C_Loose_Wave_Twin_BU
+		case 20370:	// C_Loose_Wave_Twin_WH
+		case 20405:	// C_Eremes_Scarf
+		case 20407:	// C_Subject_Aura_Red
+		case 20429:	// C_Piamette_BowTie
+		case 20440:	// C_Tone_Of_Gold
+		case 20448:	// C_Cons_Of_Water
+		case 20462:	// C_Cat_Ears_Cape
+		case 20497:	// C_Umbala_Spirit
+		case 20798:	// GrimReaper_Protection
+		case 31029:	// C_Pig_Nose
+		case 31045:	// C_Blue_Rear_Ribbon
+		case 31057:	// C_Eremes_Scarf_Black
+		case 31063:	// C_Hair_Bun_BU
+		case 31064:	// C_Hair_Bun_RD
+		case 31065:	// C_Hair_Bun_YL
+		case 31066:	// C_Hair_Bun_GN
+		case 31067:	// C_Hair_Bun_BL
+		case 31068:	// C_Hair_Bun_WH
+		case 31069:	// C_Hair_Bun_OM
+		case 31070:	// C_Hair_Bun_PP
+		case 31079:	// C_Long_Pony_BU
+		case 31080:	// C_Long_Pony_RD
+		case 31081:	// C_Long_Pony_YL
+		case 31082:	// C_Long_Pony_GN
+		case 31083:	// C_Long_Pony_BL
+		case 31084:	// C_Long_Pony_WH
+		case 31085:	// C_Long_Pony_OM
+		case 31086:	// C_Long_Pony_PP
+		case 31152:	// C_Piamette_BowTie_Red
+		case 31178:	// C_Flame_Muffler
+		case 31189:	// C_Cat_Ears_Cape_Red
+		case 31210:	// C_Side_Pigtail_BU
+		case 31211:	// C_Side_Pigtail_RD
+		case 31212:	// C_Side_Pigtail_YL
+		case 31213:	// C_Side_Pigtail_GN
+		case 31214:	// C_Side_Pigtail_BL
+		case 31215:	// C_Side_Pigtail_WH
+		case 31216:	// C_Side_Pigtail_OM
+		case 31217:	// C_Side_Pigtail_PP
+		case 31226:	// C_Long_Twin_BU
+		case 31227:	// C_Long_Twin_RD
+		case 31228:	// C_Long_Twin_YL
+		case 31229:	// C_Long_Twin_GN
+		case 31230:	// C_Long_Twin_BL
+		case 31231:	// C_Long_Twin_WH
+		case 31232:	// C_Long_Twin_OM
+		case 31233:	// C_Long_Twin_PP
+		case 31251:	// C_Cat_Mouth
+		case 31296:	// C_Strawberry_In_Mouth
+		case 31300:	// C_Warm_Cat_Muffler
+		case 31315:	// C_Stall_Of_Angel
+		case 31330:	// C_Fallen_Angel_Valletta
+		case 31381:	// C_Diabolic_Lapel
+		case 31383:	// C_Volume_Low_Twin
+		case 31393:	// C_Vajra
+		case 31395:	// C_Book_Of_Magic
+		case 31404:	// C_Poring_Traffic_Light
+		case 31418:	// C_Leek_In_Mouth
+		case 31432:	// C_Luwmin_Ice
+		case 31438:	// C_Fluffy_Angel_Cape
+		case 31450:	// C_Lolita_Two_Side_Up
+		case 31453:	// C_L_RibbonMuff_Black
+		case 31460:	// C_Blessing_Sky_Lantern
+		case 31473:	// C_Tipsy
+		case 31490:	// C_Poring_Muffler
+		case 31492:	// C_Cat_Ears_Cape_Brown
+		case 31493:	// C_Volume_Low_Twin_WH
+		case 31498:	// C_Elephangel_TH
+		case 31533:	// C_Warm_Cat_Muffler_BL
+		case 31545:	// C_Eremes_Scarf_BU
+		case 31572:	// C_Mobile_Pursuit_System
+		case 31586:	// C_Poporing_Muffler
+		case 31611:	// C_Dark_Snake_Lord_Stall
+		case 31616:	// C_Sleep_Sheep_TW
+		case 31625:	// C_Protect_Cloth
+		case 31698:	// C_Pigtail_Red_Hood
+			break;
+		default:
+			mes "[Aver De Dosh]";
+			mes "Well...";
+			mes "This hat is currently not available for upgrade.";
+			close;
+		}
+		break;
+
+	default:
+		mes "An unknown error has occurred.";
+		close;
+	}
+
+	.@location = getiteminfo(.@equip_id, 5);
+	.@equip_refine = getequiprefinerycnt(.@part);
+	setarray .@card[0], getequipcardid(.@part, 0), getequipcardid(.@part, 1), getequipcardid(.@part, 2), getequipcardid(.@part, 3);
+
+	mes "[Aver De Dosh]";
+	mes "Wow~ This ^0000FF" + getitemname(.@equip_id) + "^000000!!! looks great on you!!";
+	mes "What kind of stone do you want to use for the upgrade?";
+	next;
+	if (.@part == EQI_COSTUME_HEAD_TOP)
+		.@slot = select( "Upper", "Middle", "Lower", "Cancel" ) - 1;	// the slot enchanted changes according to the location
+	else if (.@part == EQI_COSTUME_HEAD_MID)
+		.@slot = select( "", "Middle", "Lower", "Cancel" ) - 1;
+	else if (.@part == EQI_COSTUME_HEAD_LOW)
+		.@slot = 2;
+
+	switch(.@slot) {
+	case 0:
+		if (!(.@location & 1024)) {
+			mes "[Aver De Dosh]";
+			mes "The costume can't be enhanced at this location.";	// custom
+			close;
+		}
+		setarray .@stone_id[0],
+			6636, 4700,	// STRStone_Top	Strength1
+			6637, 4710,	// INTStone_Top	Inteligence1
+			6638, 4730,	// AGIStone_Top	Agility1
+			6639, 4720,	// DEXStone_Top	Dexterity1
+			6640, 4740,	// VITStone_Top	Vitality1
+			6641, 4750,	// LUKStone_Top	Luck1
+			6716, 4926,	// Cri_Stone	Critical1
+			6740, 4930,	// HealStone_Top	HEAL2
+			6741, 4805,	// HealStone2_Top	Heal_Amount2
+			6790, 4936,	// BigStone_Top	ATK_BIG1
+			6791, 4937,	// MediumStone_Top	ATK_MEDIUM1
+			6792, 4938,	// SmallStone_Top	ATK_SMALL1
+			6943, 29028,	// ATKStone_Top	Atk1p_Top
+			6944, 29030,	// MATKStone_Top	Matk1p_Top
+			6999, 29013,	// HPdrainStone_Top	HPdrain3
+			25000, 29032,	// SPdrainStone_Top	SPdrain1_Top
+			25068, 4807,	// ASPDStone_Top	Atk_Speed1
+			25069, 29053,	// ReloadStone_Top	Skill_Delay1_Top
+			25171, 29159,	// EXPStone_Top	EXP2TOP
+			25172, 29156,	// CastingStone_Top	Casting_Top
+			25304, 29359;	// Critical_Stone_Top	Fatal_Top
+		break;
+	case 1:
+		if (!(.@location & 2048)) {
+			mes "[Aver De Dosh]";
+			mes "The costume can't be enhanced at this location.";	// custom
+			close;
+		}
+		setarray .@stone_id[0],
+			6642, 4882,	// ATKStone_Middle	Atk1p
+			6643, 4883,	// MATKStone_Middle	Matk1p
+			6717, 4927,	// MaxHP_Stone	HP50
+			6742, 4931,	// HealStone_Middle	HEALHP1
+			6743, 4861,	// HPStone_Middle	MHP1
+			6744, 4929,	// SPStone_Middle	MSP1
+			6945, 4700,	// STRStone_Middle	Strength1
+			6946, 4710,	// INTStone_Middle	Inteligence1
+			6947, 4730,	// AGIStone_Middle	Agility1
+			6948, 4720,	// DEXStone_Middle	Dexterity1
+			6949, 4740,	// VITStone_Middle	Vitality1
+			6950, 4750,	// LUKStone_Middle	Luck1
+			25001, 29026,	// DEFStone_Middle	Def20
+			25002, 29024,	// ChangeLUK_Middle	LUK3STR
+			25003, 29014,	// ChangeSTR_Middle	STR3INT
+			25004, 29022,	// ChangeAGI_Middle	AGI3LUK
+			25005, 29016,	// ChangeINT_Middle	INT3DEX
+			25006, 29020,	// ChangeVIT_Middle	VIT3AGI
+			25007, 29018,	// ChangeDEX_Middle	DEX3VIT
+			25060, 29047,	// Critical_Stone	Fatal0
+			25061, 29048,	// Range_Stone	Expert_Archer0
+			25070, 29054,	// ReloadStone_Middle	Skill_Delay1_Middle
+			25141, 29145,	// EXPStone_Middle	EXP2MIDDLE
+			25173, 29157,	// CastingStone_Middle	Casting_Middle
+			25175, 29155;	// LexAeternaStone_Middle	LexAeterna
+		break;
+	case 2:
+		if (!(.@location & 4096)) {
+			mes "[Aver De Dosh]";
+			mes "The costume can't be enhanced at this location.";	// custom
+			close;
+		}
+		setarray .@stone_id[0],
+			6644, 4884,	// HITStone_Bottom	HIT1
+			6645, 4859,	// FLEEStone_Bottom	Evasion1
+			6718, 4928,	// MaxSP_Stone	SP10
+			6745, 4932,	// HealStone_Bottom	HEALSP1
+			6951, 4861,	// HPStone_Bottom	MHP1
+			25008, 29021,	// ChangeVIT_Bottom	VIT3LUK
+			25009, 29023,	// ChangeAGI_Bottom	AGI3STR
+			25010, 29019,	// ChangeDEX_Bottom	DEX3AGI
+			25011, 29025,	// ChangeLUK_Bottom	LUK3INT
+			25012, 29015,	// ChangeSTR_Bottom	STR3DEX
+			25013, 29017,	// ChangeINT_Bottom	INT3VIT
+			25014, 29033,	// MDEFStone_Bottom	Mdef4_Bottom
+			25015, 29027,	// EXPStone_Bottom	EXP2
+			25016, 29029,	// ATKStone_Bottom	Atk1p_Bottom
+			25017, 29031,	// MATKStone_Bottom	Matk1p_Bottom
+			25062, 29046,	// Greed_Stone	Greed
+			25063, 29049,	// MaxHP2_Stone	HP100_
+			25064, 29050,	// MaxSP2_Stone	SP50_
+			25065, 29051,	// Detoxify_Stone	Detoxify
+			25066, 29052,	// Recovery_Stone	Recovery
+			25071, 29055,	// ReloadStone_Bottom	Skill_Delay1_Bottom
+			25072, 29057,	// Kyrie_Stone	Kyrie
+			25139, 29146,	// Identify_Stone	Identify
+			25174, 29158,	// CastingStone_Bottom	Casting_Bottom
+			25227, 29227,	// Heal_Stone	Heal
+			25228, 29229,	// Teleport_Stone	Teleport
+			25229, 29228,	// Steal_Stone	Steal
+			25305, 29360;	// Critical_Stone_Bottom	Fatal_Bottom
+		break;
+	default:
+		mes "[Aver De Dosh]";
+		mes "Please check our other upgrading services~";
+		close;
+	}
+	.@size = getarraysize(.@stone_id);
+	for ( .@i = 0; .@i < .@size; .@i += 2 )
+		.@menu$ += sprintf( "%d. %s [%d] left:", (.@i/2)+1, getitemname(.@stone_id[.@i]), countitem(.@stone_id[.@i]) );
+	.@s = (select(.@menu$) - 1) * 2;
+	.@stone = .@stone_id[.@s];
+	.@enchant = .@stone_id[.@s+1];
+
+	if (getequipid(.@part) < 0 || countitem(.@stone) < 1) {
+		mes "[Aver De Dosh]";
+		mes "Hmm? Think you are lack of ingredients.";
+		mes "You must have both costume item and ability stone for this upgrading work.";
+		close;
+	}
+	mes "^FF0000   !!! Caution !!!^000000";
+	mes "^FF0000This upgrade can be failed.^000000";
+	mes "^FF0000If the item already has extra ability,^000000";
+	mes "^FF0000we will reset item's ability.^000000";
+	mes "^FF0000Are you sure about upgrading this item?^000000";
+	next;
+	if (select( "Yes.", "No." ) == 2) {
+		mes "[Aver De Dosh]";
+		mes "Please check our other upgrading services~";
+		close;
+	}
+	delitem .@stone, 1;
+
+	// anti-hack
+	if (callfunc("F_IsEquipIDHack", .@part, .@equip_id) || callfunc("F_IsEquipCardHack", .@part, .@card[0], .@card[1], .@card[2], .@card[3]) || callfunc("F_IsEquipRefineHack", .@part, .@equip_refine))
+		close;
+
+	delequip .@part;
+	if (rand(1,100) < 51) {
+		mes "[Aver De Dosh]";
+		mes "Wow... Elegance!!";
+		mes "This is perfect... Wow!";
+		.@card[.@slot] = .@enchant;
+	}
+	else {
+		mes "[Aver De Dosh]";
+		mes "History is known for its failure...";
+		mes "History of Fashion also is...";
+		mes "Sorry...to disappoint you..~ LoL.";
+		.@card[.@slot] = 0;
+	}
+	getitem2 .@equip_id,1,1,.@equip_refine,0,.@card[0],.@card[1],.@card[2],.@card[3];
+	close;
+}
+
+// Costume enchant (garment)
+mal_in01,20,107,3	script	Lace La Zard#cos_ect	4_FROG,{
+	disable_items;
+	mes "[Lace La Zard]";
+	mes "Welcome to Fashion Stone!!";
+	mes "My name is Lace La Zard who will make your 'Power Shoulder' dream come true.";
+	next;
+	mes "[Lace La Zard]";
+	mes "Bring your ^ff0000Costume Garment^000000 and ^ff0000Garment Stone^000000, I will complete the perfect upgrade for you.!";
+	mes "I found this formula while working on my own humble body upgrading!";
+	next;
+	if (select( "Apply ability.", "End Conversation." ) == 2) {
+		mes "[Lace La Zard]";
+		mes "Yes? Your want to look more?";
+		close;
+	}
+	if (checkweight(1119,3) == 0) {
+		mes "[Lace La Zard]";
+		mes "Well... Your shoulder doesn't look possilbe for any more upgrade...!";
+		mes "Don't be cruel to your shoulder!";
+		next;
+		mes "It seems you have too many items on you.";
+		mes "Come back after clearing some inventory spaces.";
+		close;
+	}
+	.@part = EQI_COSTUME_GARMENT;
+	.@equip_id = getequipid(.@part);
+	if (.@equip_id == -1) {
+		mes "[Lace La Zard]";
+		mes "Put the garment on your shoulder.";
+		mes "I need to have a look at it to check for upgrading posibility..";
+		close;
+	}
+
+	// costume garment list allowed (incomplete)
+	switch(.@equip_id) {
+	case 20502:	// C_Devil_Wing
+	case 20504:	// C_Cupid_Wing_Pink
+	case 20505:	// C_Cupid_Wing_Skyblue
+	case 20506:	// C_Invisible_Manteau
+	case 20507:	// C_Poring_Bag
+	case 20509:	// C_Wings_of_Uriel
+	case 20510:	// C_SwordWing
+	case 20511:	// C_Blue_Fairy_Wing
+	case 20727:	// Brilliant_Golden_Wings
+	case 20737:	// C_Kirin_Wing
+	case 20746:	// C_Rudra_Wing
+	case 20761:	// C_Wing_Of_Happiness
+	case 20762:	// C_GreatDevilWing
+	case 20763:	// C_Amistr_Bag
+	case 20764:	// C_Fallen_Angel_Wing
+	case 20765:	// C_Archangel_Wing
+		break;
+	default:
+		mes "[Lace La Zard]";
+		mes "I need to have a look at it to check for upgrading posibility..";// custom
+		close;
+	}
+
+	.@equip_refine = getequiprefinerycnt(.@part);
+	setarray .@card[0], getequipcardid(.@part, 0), getequipcardid(.@part, 1), getequipcardid(.@part, 2), getequipcardid(.@part, 3);
+
+	mes "[Lace La Zard]";
+	mes "Wow ^0000FF" + getitemname(.@equip_id) + "^000000!!! You got some sense there, aren't you?";
+	mes "Great!! I'm fully ready for this upgrade!!";
+	next;
+	setarray .@data$[0],
+		6908, 4807, "ASPD+1 only",	// ASPDStone_Robe	Atk_Speed1
+		6963, 4992, "Absorption 1% of damage dealt to enemy into HP with 1% chance",	// HPdrainStone_Robe	HPdrain1
+		6964, 4993, "Absorption 1% of damage dealt to enemy into SP with 1% chance";	// SPdrainStone_Robe	SPdrain1
+		// unknown text
+		// 25067, 29056, "",	// CastingStone_Robe	FixedCasting05
+		// 25170, 29154, "",	// MinorCastingStone_Robe	FixedCasting03
+		// 25302, 29362, "",	// DoubleAttack_Stone	DoubleAttack
+		// 25303, 29361, "",	// Critical_Stone_Robe	Fatal_Robe
+		// 25306, 29358, "";	// CastStone_Robe	Casting_Robe
+
+	.@size = getarraysize(.@data$);
+	for ( .@i = 0; .@i < .@size; .@i += 3 ) {
+		.@id = atoi(.@data$[.@i]);
+		.@menu$ += sprintf( "%d. %s (%d) left:", (.@j+1), getitemname(.@id), countitem(.@id) );
+		.@j++;
+	}
+	.@menu$ += "End Conversation.";
+	.@s = (select(.@menu$) - 1) * 3;
+	if (.@s == .@size) {
+		mes "[Lace La Zard]";
+		mes "Yes? Your want to look more?";
+		close;
+	}
+	.@id = atoi(.@data$[.@s]);
+	.@enchant = atoi(.@data$[.@s+1]);
+	if (getequipid(.@part) < 0 || countitem(.@id) < 1) {
+		mes "[Lace La Zard]";
+		mes "You must have both costume item and ability stone for this upgrading work.";
+		close;
+	}
+	mes "^FF0000   !!! Caution !!!^000000";
+	mes "^ff0000This upgrade can be failed.^000000";
+	mes "^ff0000If the item already has extra ability, we will reset item's ability and give " + .@data$[.@s+2] + ".^000000";
+	mes "^ff0000Are you sure about upgrading this item?^000000";
+	next;
+	if (select( "Yes.", "No." ) == 2) {
+		mes "[Lace La Zard]";
+		mes "Yes? Your want to look more?";
+		close;
+	}
+
+	// anti-hack
+	if (callfunc("F_IsEquipIDHack", .@part, .@equip_id) || callfunc("F_IsEquipCardHack", .@part, .@card[0], .@card[1], .@card[2], .@card[3]) || callfunc("F_IsEquipRefineHack", .@part, .@equip_refine))
+		close;
+
+	delitem .@id, 1;
+	delequip .@part;
+	if (rand(100) < 50) {
+		mes "[Lace La Zard]";
+		mes "Beautiful!!";
+		mes "Did I really made this myself!!!!";
+		.@card[0] = .@enchant;
+	}
+	else {
+		mes "[Lace La Zard]";
+		mes "Oh no!";
+		mes "Crash!!!!! I cannot show this failure to the World!!!";
+		.@card[0] = 0;
+	}
+	getitem2 .@equip_id,1,1,.@equip_refine,0,.@card[0],.@card[1],.@card[2],.@card[3];
+	close;
+}

+ 169 - 0
npc/re/merchants/pet_trader.txt

@@ -0,0 +1,169 @@
+//===== rAthena Script =======================================
+//= Pet Trader NPC
+//===== Description: =========================================
+//= [Walkthrough Conversion]
+//= Exchanges Cute Pet Tickets for Pet Eggs.
+//===== Additional Comments: =================================
+//= 1.0 First version [Latiosu]
+//============================================================
+
+prontera,210,209,5	script	Pet Trader#1	4_M_JPNOJI,{
+	disable_items;
+	mes "[Pet Trader]";
+	mes "Making a living through business ain't easy.";
+	mes "I get real bad motion sickness, yet today I got caught up in a storm on my way here.";
+	next;
+	mes "[Pet Trader]";
+	mes "It was such a horrible experience. Thanks to that, I don't feel so good. Ughh...";
+	next;
+	mes "[Pet Trader]";
+	mes "Anyway, did you come here looking for a Cute Pet?";
+	mes "You've brought a ticket with you, right?";
+	next;
+	switch (select("Examine your tickets:Cancel")) {
+	case 1:
+		setarray .@tickets,
+			6116, //Succu_Pet_Coupon
+			6117, //Imp_Pet_Coupon
+			6118, //Chung_E_Pet_Coupon
+			6129, //Ticket_Nightmare
+			6130, //Ticket_Loli_Ruri
+			6131, //Ticket_Goblin_Leader
+			6132, //Ticket_Incubus
+			6133, //Ticket_Miyabi_Ningyo
+			6134, //Ticket_Whisper
+			6135, //Ticket_Wicked_Nymph
+			6136, //Ticket_Medusa
+			6137, //Ticket_Stoneshooter
+			6138, //Ticket_Marionette
+			6139, //Ticket_Leafcat
+			6140, //Ticket_Dullahan
+			6141, //Ticket_Shinobi
+			6142, //Ticket_Golem
+			6143, //Ticket_Civil_Servant
+			6157, //Poring_Ticket
+			6158, //Drops_Ticket
+			6159, //Poporing_Ticket
+			6160, //Lunatic_Ticket
+			6161, //Picky_Ticket
+			6162, //Pecopeco_Ticket
+			6163, //Savage_Baby_Ticket
+			6164, //Spore_Ticket
+			6165, //Poison_Spore_Ticket
+			6166, //Chonchon_Ticket
+			6167, //Steel_Chonchon_Ticket
+			6168, //Petit_Ticket
+			6169, //Deviruchi_Ticket
+			6170, //Isis_Ticket
+			6171, //Smokie_Ticket
+			6172, //Dokebi_Ticket
+			6173, //Desert_Wolf_B_Ticket
+			6174, //Yoyo_Ticket
+			6175, //Sohee_Ticket
+			6176, //Rocker_Ticket
+			6177, //Hunter_Fly_Ticket
+			6178, //Orc_Warrior_Ticket
+			6179, //Bapho_Jr_Ticket
+			6180, //Munak_Ticket
+			6181, //Bongun_Ticket
+			6182, //Goblin_Ticket
+			6183, //Hardtack_Ticket
+			6184, //Zherlthsh_Ticket
+			6185, //Alice_Ticket
+			6883, //Pet_Snow_Bunny_Ticket
+			6884; //Pet_Tikbalang_Ticket
+		setarray .@eggs,
+			9055, //Succubus_Egg
+			9056, //Imp_Egg
+			9030, //Chung_E_Egg
+			9054, //Nightmare_Terror_Egg
+			9042, //Loli_Ruri_Egg
+			9046, //Goblin_Leader_Egg
+			9052, //Incubus_Egg
+			9048, //Miyabi_Ningyo_Egg
+			9045, //Whisper_Egg
+			9047, //Wicked_Nymph_Egg
+			9050, //Medusa_Egg
+			9051, //Stone_Shooter_Egg
+			9043, //Marionette_Egg
+			9041, //Leaf_Cat_Egg
+			9049, //Dullahan_Egg
+			9044, //Shinobi_Egg
+			9053, //Golem_Egg
+			9040, //Civil_Servant_Egg
+			9001, //Poring_Egg
+			9002, //Drops_Egg
+			9003, //Poporing_Egg
+			9004, //Lunatic_Egg
+			9005, //Picky_Egg
+			9014, //PecoPeco_Egg
+			9009, //Savage_Bebe_Egg
+			9012, //Spore_Egg
+			9013, //Poison_Spore_Egg
+			9006, //Chonchon_Egg
+			9007, //Steel_Chonchon_Egg
+			9022, //Green_Petite_Egg
+			9023, //Deviruchi_Egg
+			9021, //Isis_Egg
+			9015, //Smokie_Egg
+			9019, //Dokkaebi_Egg
+			9010, //Baby_Desert_Wolf_Egg
+			9016, //Yoyo_Egg
+			9020, //Sohee_Egg
+			9011, //Rocker_Egg
+			9008, //Hunter_Fly_Egg
+			9017, //Orc_Warrior_Egg
+			9024, //Bapho_Jr
+			9018, //Munak_Egg
+			9025, //Bongun_Egg
+			9029, //Santa_Goblin_Egg
+			9028, //Rice_Cake_Egg
+			9026, //Zherlthsh_Egg
+			9027, //Alice_Egg
+			9058, //Snow_Rabbit_Egg
+			9059; //Tikbalang_Pet
+		for (.@i = 0; .@i < getarraysize(.@tickets); .@i++) {
+			if (countitem(.@tickets[.@i]) > 0) {
+				.@menu$ += getitemname(.@tickets[.@i]) + ":";
+				.@ticketIndices[.@count++] = .@i;
+			}
+		}
+
+		if (.@count == 0) {
+			mes "[Pet Trader]";
+			mes "I don't think you've got the stuff I want.";
+			close;
+		}
+
+		mes "[Pet Trader]";
+		mes "Which ticket do you want to exchange?";
+		next;
+		.@index = .@ticketIndices[select(.@menu$) - 1];
+
+		mes "[Pet Trader]";
+		mes "Great!";
+		mes "^0000FF"+ getitemname(.@eggs[.@index]) +"^000000";
+		mes "Are you sure you want this pet?";
+		next;
+		if (select("Yes:No") == 2) close;
+		if (!checkweight(.@eggs[.@index], 1)) {
+			mes "You're carrying too much stuff!";
+			mes "Come back when you've made some space.";
+			close;
+		}
+
+		mes "[Pet Trader]";
+		mes "Here's your pet~";
+		delitem .@tickets[.@index], 1;
+		getitem .@eggs[.@index], 1;
+		close;
+	case 2:
+		mes "[Pet Trader]";
+		mes "So you want hear about the land across the sea, but I ain't feeling so well today.";
+		close;
+	}
+	end;
+}
+
+// Duplicate NPCs
+alberta,179,141,5	duplicate(Pet Trader#1)	Pet Trader#2	4_M_JPNOJI

+ 2 - 2
npc/re/merchants/te_merchant.txt

@@ -120,7 +120,7 @@ S_Rent:
 	mes "Select the desired item.";
 	next;
 	for ( .@i = 1; .@i < getargcount(); .@i += 2 ) {
-		if (countitem(getarg(.@i)) > isequippedcnt(getarg(.@i)))// don't count item equipped
+		if (rentalcountitem(getarg(.@i)) > isequippedcnt(getarg(.@i)))// don't count item equipped
 			.@menu$ = .@menu$ + "^4d4dff"+ getarg(.@i+1) +" - Checked out^000000:";
 		else
 			.@menu$ = .@menu$ + getarg(.@i+1) + ":";
@@ -130,7 +130,7 @@ S_Rent:
 	if (.@s <= .@total_item) {
 		.@index = .@s *2 +1;
 		mes "[Rental Items Manager]";
-		if (countitem(getarg(.@index)) > isequippedcnt(getarg(.@index)))
+		if (rentalcountitem(getarg(.@index)) > isequippedcnt(getarg(.@index)))
 			mes "You already have "+ getarg(.@index+1) +".";
 		else {
 			mes "Here is "+ getarg(.@index+1) +".";

+ 10 - 0
npc/re/quests/quests_niflheim.txt

@@ -0,0 +1,10 @@
+//===== rAthena Script =======================================
+//= Quest NPCs related to Niflheim
+//===== Description: =========================================
+//= [Official Conversion]
+//= Piano Key Ouest
+//===== Additional Comments: =================================
+//= 1.0 Moved Piano3 to pre-re/re paths. [Daegaladh]
+//============================================================
+
+nif_in,118,151,0	duplicate(Piano3)	#Piano3	HIDDEN_NPC,1,1

+ 1 - 0
npc/re/quests/quests_rockridge.txt

@@ -5888,6 +5888,7 @@ harboro1,156,215,5	script	Innkeeper#rockridge	1_ETC_01,{
 		mes "Enjoy your stay at the Lazy Owl's.";
 		close2;
 		Zeny = Zeny - 5000;
+		percentheal 100,100;
 		warp "harboro1",157,210;
 		end;
 	case 3:

+ 1 - 1
npc/re/quests/woe_te/te_goditem_alde1.txt

@@ -284,7 +284,7 @@ S_Material:
 	mes "^4d4dff4 Presberk's Leather";
 	mes "1 Spirit of Hugin";
 	mes "1 Spirit of Munin";
-	mes "1 Giant's Chisel";
+	mes "4 Giant's Chisel";
 	mes "1 Jormungand's Rib";
 	mes "1 Wizardry Staff";
 	mes "1 Muspellium and Essence of Rune, respectively^000000";

+ 3 - 0
npc/re/scripts_athena.conf

@@ -111,9 +111,11 @@ npc: npc/re/merchants/guild_warehouse.txt
 npc: npc/re/merchants/hd_refiner.txt
 npc: npc/re/merchants/HorrorToyFactory_merchants.txt
 npc: npc/re/merchants/inn.txt
+npc: npc/re/merchants/malangdo_costume.txt
 npc: npc/re/merchants/moro_cav_exchange.txt
 npc: npc/re/merchants/nightmare_biolab.txt
 npc: npc/re/merchants/OldGlastHeim_merchants.txt
+npc: npc/re/merchants/pet_trader.txt
 npc: npc/re/merchants/quivers.txt
 npc: npc/re/merchants/refine.txt
 npc: npc/re/merchants/renters.txt
@@ -198,6 +200,7 @@ npc: npc/re/quests/quests_malaya.txt
 npc: npc/re/quests/quests_mora.txt
 npc: npc/re/quests/quests_morocc.txt
 npc: npc/re/quests/quests_nameless.txt
+npc: npc/re/quests/quests_niflheim.txt
 npc: npc/re/quests/quests_rockridge.txt
 npc: npc/re/quests/quests_veins.txt
 npc: npc/re/quests/the_sign_quest.txt

File diff suppressed because it is too large
+ 319 - 137
sql-files/item_db_re.sql


+ 2 - 1
sql-files/main.sql

@@ -252,8 +252,9 @@ CREATE TABLE IF NOT EXISTS `char` (
   `unban_time` int(11) unsigned NOT NULL default '0',
   `font` tinyint(3) unsigned NOT NULL default '0',
   `uniqueitem_counter` int(11) unsigned NOT NULL default '0',
-  `sex` ENUM('M','F','U') NOT NULL default 'U',
+  `sex` ENUM('M','F') NOT NULL,
   `hotkey_rowshift` tinyint(3) unsigned NOT NULL default '0',
+  `hotkey_rowshift2` tinyint(3) unsigned NOT NULL default '0',
   `clan_id` int(11) unsigned NOT NULL default '0',
   `last_login` datetime DEFAULT NULL,
   `title_id` INT(11) unsigned NOT NULL default '0',

+ 192 - 8
sql-files/mob_db_re.sql

@@ -369,7 +369,7 @@ REPLACE INTO `mob_db_re` VALUES (1289,'MAYA_PUPLE','Maya Purple','Maya Purple',8
 REPLACE INTO `mob_db_re` VALUES (1290,'SKELETON_GENERAL','Skeleton General','Skeleton General',88,6720,0,1368,1553,1,1317,1701,100,35,72,34,52,31,84,25,10,12,1,1,29,0x3695,150,2276,576,432,0,0,0,0,0,0,0,7068,2550,756,160,508,800,0,0,1219,80,13035,15,2274,1,0,0,0,0,4221,1);
 REPLACE INTO `mob_db_re` VALUES (1291,'WRAITH_DEAD','Wraith Dead','Wraith Dead',86,10035,0,2518,1824,2,1002,160,88,56,63,69,55,45,88,45,10,12,2,1,89,0x3695,175,1816,576,240,0,0,0,0,0,0,0,1059,4413,2206,10,2506,8,716,700,732,5,603,100,568,300,0,0,0,0,4189,1);
 REPLACE INTO `mob_db_re` VALUES (1292,'MINI_DEMON','Mini Demon','Mini Demon',117,19402,1,2700,2025,1,938,114,80,25,130,69,55,56,79,40,10,12,0,6,27,0x2003695,150,1000,600,384,0,0,0,0,0,0,0,1038,4413,1039,450,2255,3,757,160,912,2500,1009,10,1478,5,0,0,0,0,4204,1);
-REPLACE INTO `mob_db_re` VALUES (1293,'CREMY_FEAR','Creamy Fear','Creamy Fear',77,3420,0,945,1067,2,757,110,76,37,65,36,33,49,66,30,10,12,0,4,24,0x2003695,155,1136,720,840,0,0,0,0,0,0,0,924,4550,2333,10,518,550,602,200,1550,8,2726,5,522,50,0,0,0,0,4298,1);
+REPLACE INTO `mob_db_re` VALUES (1293,'CREMY_FEAR','Creamy Fear','Creamy Fear',117,18211,0,2583,2475,2,731,243,76,37,65,36,33,49,79,30,10,12,0,4,24,0x2003695,155,1136,720,840,0,0,0,0,0,0,0,924,4550,2333,10,518,550,2899,1,12676,8,2726,5,522,50,0,0,0,0,4298,1);
 REPLACE INTO `mob_db_re` VALUES (1294,'KILLER_MANTIS','Killer Mantis','Killer Mantis',91,7650,0,1485,1674,1,1521,1201,107,45,82,56,58,45,69,40,10,12,1,4,22,0x2003695,175,1528,660,432,0,0,0,0,0,0,0,1031,4550,943,2500,721,10,509,15,514,25,1262,1,2108,1,0,0,0,0,4301,1);
 REPLACE INTO `mob_db_re` VALUES (1295,'OWL_BARON','Owl Baron','Owl Baron',120,21000,1,3042,2282,2,629,201,88,25,72,65,55,102,77,72,10,12,2,6,60,0x6203695,175,1345,824,440,0,0,0,0,0,0,0,7071,3500,7063,2500,0,0,1472,1,1629,2,693,100,5045,5,0,0,0,0,4238,1);
 REPLACE INTO `mob_db_re` VALUES (1296,'KOBOLD_LEADER','Kobold Leader','Kobold Leader',112,13520,1,2643,2383,1,995,96,90,62,135,34,68,56,83,47,10,12,1,7,44,0x3695,150,1028,528,360,0,0,0,0,0,0,0,999,450,1034,6305,912,1200,0,0,1613,2,525,150,526,100,0,0,0,0,4291,1);
@@ -2163,10 +2163,10 @@ REPLACE INTO `mob_db_re` VALUES (2935,'T_EVIL_CLOUD_HERMIT','Taoist Hermit','Tao
 REPLACE INTO `mob_db_re` VALUES (2936,'E_GHOSTRING','Ghostring','Ghostring',1,10,0,0,0,1,1,1,100,99,0,0,0,0,0,0,7,12,0,3,20,0x0,300,1220,1080,648,0,0,0,0,0,0,0,535,1500,535,1500,535,1500,535,1500,12192,2000,7225,2000,6658,500,0,0,0,0,6658,10000);
 #REPLACE INTO `mob_db_re` VALUES (2937,'M_LOKI','M Loki','M Loki',145,1215600,1,1,1,2,1835,444,15,89,76,66,90,55,189,22,10,12,1,7,20,0x0,175,800,750,300,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_re` VALUES (2938,'MM_MAGIC_SEAL','Magic Seal','Magic Seal',140,10000000,1,1,6999,1,1,1,80,200,16,26,30,115,79,5,10,12,2,0,20,0x0,300,1000,1000,1000,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_re` VALUES (2939,'MM_EVIL_SHADOW1','Evil Shadow','Evil Shadow',138,112000,1,7456,5983,1,3266,1307,30,30,88,44,88,21,95,44,10,12,2,6,47,0x2000085,200,1500,600,500,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_re` VALUES (2940,'MM_EVIL_SHADOW2','Evil Shadow','Evil Shadow',141,127650,1,8103,7738,1,2678,1071,121,36,60,103,45,35,172,15,10,12,1,6,47,0x2000085,200,1000,500,600,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_re` VALUES (2941,'MM_EVIL_SHADOW3','Evil Shadow','Evil Shadow',142,153400,1,8863,6736,1,3167,1267,89,44,120,87,66,33,106,27,10,12,2,6,47,0x2000085,200,1800,780,480,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_re` VALUES (2942,'MM_EVIL_FANATICS','Evil Fanatics','Evil Fanatics',151,8256000,1,1008653,988954,3,3350,167,166,103,118,72,40,55,213,30,10,12,2,6,67,0x6280085,200,1000,500,350,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_re` VALUES (2939,'MM_EVIL_SHADOW1','Evil Shadow','Evil Shadow',138,112000,1,7456,5983,1,3266,1307,30,30,88,44,88,21,95,44,10,12,2,6,47,0x2000085,200,1500,600,500,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,27264,1);
+REPLACE INTO `mob_db_re` VALUES (2940,'MM_EVIL_SHADOW2','Evil Shadow','Evil Shadow',141,127650,1,8103,7738,1,2678,1071,121,36,60,103,45,35,172,15,10,12,1,6,47,0x2000085,200,1000,500,600,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,27264,1);
+REPLACE INTO `mob_db_re` VALUES (2941,'MM_EVIL_SHADOW3','Evil Shadow','Evil Shadow',142,153400,1,8863,6736,1,3167,1267,89,44,120,87,66,33,106,27,10,12,2,6,47,0x2000085,200,1800,780,480,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,27264,1);
+REPLACE INTO `mob_db_re` VALUES (2942,'MM_EVIL_FANATICS','Evil Fanatics','Evil Fanatics',151,8256000,1,1008653,988954,3,3350,167,166,103,118,72,40,55,213,30,10,12,2,6,67,0x6280085,200,1000,500,350,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,27265,1);
 REPLACE INTO `mob_db_re` VALUES (2943,'MM_ICE_MINE','Icemine','Icemine',149,10000,200,0,0,7,200,1,200,10,200,200,200,200,200,200,12,12,0,4,88,0xE170000,2000,0,1000,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,0);
 #2944,J_HORNET
 #2945,J_MUMMY
@@ -4013,12 +4013,42 @@ REPLACE INTO `mob_db_re` VALUES (3790,'SWEETS_DROPS','Sweets Drops','Sweets Drop
 #20813,MD_EVENT_AMDARAIS
 #20814,G_PAYONSOLDIER
 #20815,G_PAYONSOLDIER2
-
+#20816,EM_DILUVIO
+#20817,EM_ARDOR
+#20818,EM_PROCELLA
+#20819,EM_TERREMOTUS
+#20820,EM_SERPENS
+#20821,4JOB_VOID
+#20822,4JOB_WRAITH
+#20823,4JOB_KINGS_NIGHT
+#20824,4JOB_AGONY_NIGHT
+#20825,4JOB_DEVOTION_NIGHT
+#20826,4JOB_ARMED_NIGHT
+#20827,4JOB_DOOMK
+#20828,4JOB_VERKHASEL
+#20829,4JOB_BAPHOMET
+#20830,4JOB_H_FALCON
+#20831,4JOB_S_FALCON
+#20832,4JOB_R_FALCON
+#20833,4JOB_WORG
+#20834,MEISTER_ABR1
+#20835,MEISTER_ABR2
+#20836,MEISTER_ABR3
+#20837,MEISTER_ABR4
+#20838,ELEMETAL_MASTER_S1
+#20839,ELEMETAL_MASTER_S2
+#20840,ELEMETAL_MASTER_S3
+#20841,ELEMETAL_MASTER_S4
+#20842,ELEMETAL_MASTER_S5
 #20843,ILL_ABYSMAL_WITCH
 #20844,PRAY_GIVER
 #20845,SMILE_GIVER
 #20846,MD_HIDDEN_GROUND01
 #20847,MD_HIDDEN_GROUND02
+#20848,SUMMON_WOODENWARRIOR
+#20849,SUMMON_WOODEN_FAIRY
+#20850,SUMMON_CREEPER
+#20851,SUMMON_HELLTREE
 
 #20856,MD_N_ARENA_1
 #20857,MD_N_ARENA_2
@@ -4039,7 +4069,8 @@ REPLACE INTO `mob_db_re` VALUES (3790,'SWEETS_DROPS','Sweets Drops','Sweets Drop
 #20872,MD_GEFFEN_FENRIR_N
 #20873,WAR_NUT
 #20874,MOLE_TW
-
+#20875,4JOB_LETICIA
+#20876,4JOB_ACIDUS
 #20877,G_ILL_SROPHO
 #20878,G_ILL_OBEAUNE
 #20879,G_ILL_DEVIACE
@@ -4049,8 +4080,161 @@ REPLACE INTO `mob_db_re` VALUES (3790,'SWEETS_DROPS','Sweets Drops','Sweets Drop
 #20883,G_ILL_SWORD_FISH
 #20884,G_ILL_STROUF
 #20885,G_ILL_PHEN
-
+#20886,MD_Airboat_Tree
+#20887,MD_Airboat_Poring
+#20888,MD_Airboat_Worm
+#20889,MD_Airboat_LEECH
+#20890,MD_Airboat_Mos
+#20891,MD_Airboat_Boss
+#20892,MD_SAKRAY
+#20893,MD_TIARA
+#20894,MD_UNDEAD_KNIGHT
+#20895,MD_UNDEAD_SOLDIER
+#20896,MD_UNDEAD_ARCHER
+#20897,MD_UNDEAD_WIZARD
+#20898,MD_UNDEAD_MAGICIAN
+#20899,MD_UNDEAD_NOBLE
+#20900,MD_UNDEAD_SERVANT
+#20901,DISASTER_OMEN
+#20902,DISASTER_WIND
+#20903,CONQUER_INCARNATION
+#20904,FAMINE_INCARNATION
+#20905,APPETITE_INCARNATION
+#20906,DISASTER_SYMBOL
+#20907,DEVIL_EYE
+#20908,WAR_INCARNATION
+#20909,DEATH_INCARNATION
+#20910,CARNIVOROUS
+#20911,SINS_JUSTICE
+#20912,SINS_BRAVE
+#20913,SINS_MODERATION
+#20914,SINS_WISDOM
+#20915,G_SINS_JUSTICE
+#20916,G_SINS_BRAVE
+#20917,G_SINS_MODERATION
+#20918,G_SINS_WISDOM
 #20919,CARAT_TWEVENT
+#20920,CHIMERA_LAVA
+#20921,CHIMERA_FULGOR
+#20922,CHIMERA_NAPEO
+#20923,CHIMERA_GALENSIS
+#20924,CHIMERA_AMITERA
+#20925,CHIMERA_LITUS
+#20926,CHIMERA_FILLIA
+#20927,CHIMERA_VANILAQUS
+#20928,CHIMERA_THEONE
+#20929,GIANT_CAPUT
+#20930,DOLORIAN
+#20931,PLAGARION
+#20932,DEADRE
+#20933,VENEDI
+#20934,R001_BESTIA
+#20935,GAN_CEANN
+#20936,DISGUISER
+#20937,BRUTAL_MURDERER
+#20938,GHOST_CUBE
+#20939,LUDE_GAL
+#20940,BLUEMOON_LOLI_RURI
+#20941,GROTE
+#20942,PIERROTZOIST
+#20943,DEATH_WITCH
+
+#20994,MD_BETELGEUSE
+#20995,MD_G_DEADSOUL
+#20996,MD_NAGHT_SIEGER
+#20997,MD_G_ENTWEIHEN_M
+#20998,MD_T_JAKK
+#20999,MD_T_STONE_SHOOTER
+#21000,MD_T_GRIZZLY
+#21001,MD_T_STALACTIC_GOLEM
+#21002,MD_T_CHIMERA
+#21003,MD_T_KARAKASA
+#21004,MD_T_RIDEWORD
+#21005,MD_T_PARASITE
+#21006,MD_T_WRAITH
+#21007,MD_T_PETIT_
+#21008,MD_T_WIND_GHOST
+#21009,MD_T_CLOCK
+#21010,MD_T_RAYDRIC_ARCHER
+#21011,MD_T_INCREASE_SOIL
+#21012,MD_T_PENOMENA
+#21013,MD_T_PETIT
+#21014,MD_T_ALARM
+#21015,MD_T_ZOMBIE_PRISONER
+#21016,MD_T_MARIONETTE
+#21017,MD_T_PERMETER
+#21018,MD_T_SKEL_PRISONER
+#21019,MD_T_OWL_DUKE
+#21020,MD_T_DEVIRUCHI
+#21021,MD_T_BLOOD_BUTTERFLY
+#21022,MD_T_STAPO
+#21023,MD_T_EVIL_CLOUD_HERMIT
+#21024,MD_T_THE_PAPER
+#21025,MD_T_TENGU
+#21026,MD_T_ALICE
+#21027,MD_T_ANACONDAQ
+#21028,MD_T_GARGOYLE
+#21029,MD_T_CARAT
+#21030,MD_T_STING
+#21031,MD_T_GRYPHON
+#21032,MD_T_GIBBET
+#21033,MD_T_NIGHTMARE_TERROR
+#21034,MD_T_ANOLIAN
+#21035,MD_T_BLOODY_MURDERER
+#21036,MD_T_ALIOT
+#21037,MD_T_VENATU
+#21038,MD_T_DEATHWORD
+#21039,MD_T_PLASMA_B
+#21040,MD_T_DIMIK
+#21041,MD_T_MINI_DEMON
+#21042,MD_T_LEIB_OLMAI
+#21043,MD_T_WANDER_MAN
+#21044,MD_T_RETRIBUTION
+#21045,MD_T_FLAME_SKULL
+#21046,MD_T_KNIGHT_OF_ABYSS
+#21047,MD_T_BANSHEE
+#21048,G_CHIMERA_LAVA
+#21049,G_CHIMERA_FULGOR
+#21050,G_CHIMERA_NAPEO
+#21051,G_CHIMERA_GALENSIS
+#21052,G_DISGUISER
+#21053,G_BLUEMOON_LOLI_RURI
+#21054,G_GROTE
+#21055,G_PIERROTZOIST
+#21056,G_GIANT_CAPUT
+#21057,G_DOLORIAN
+#21058,G_PLAGARION
+#21059,G_DEADRE
+#21060,G_VENEDI
+#21061,MD_Airboat_Boss2
+#21062,MD_Airboat_Boss3
+#21063,MD_Airboat_Boss4
+#21064,S_DUMMY_100_SMALL
+#21065,S_DUMMY_100_MEDIUM
+#21066,S_DUMMY_100_LARGE
+#21067,S_DUMMY_100_NOTHING
+#21068,S_DUMMY_100_DRAGON
+#21069,S_DUMMY_100_ANIMAL
+#21070,S_DUMMY_100_HUMAN
+#21071,S_DUMMY_100_INSECT
+#21072,S_DUMMY_100_FISH
+#21073,S_DUMMY_100_DEMON
+#21074,S_DUMMY_100_PLANT
+#21075,S_DUMMY_100_ANGEL
+#21076,S_DUMMY_100_UNDEAD
+#21077,S_DUMMY_100_NOTHING2
+#21078,S_DUMMY_100_WATER
+#21079,S_DUMMY_100_GROUND
+#21080,S_DUMMY_100_FIRE
+#21081,S_DUMMY_100_WIND
+#21082,S_DUMMY_100_POISON
+#21083,S_DUMMY_100_SAINT
+#21084,S_DUMMY_100_DARKNESS
+#21085,S_DUMMY_100_TELEKINESIS
+#21086,S_DUMMY_100_UNDEAD2
+#21087,S_DUMMY_100_HUMANP
+#21088,S_DUMMY_100_DORAMP
+#21089,WANDERING_DUCK
 
 #31999,HUNTING_GID_DEFAULT
 #32000,MONSTER_2ND_END

+ 11 - 0
sql-files/upgrades/upgrade_20200506.sql

@@ -0,0 +1,11 @@
+-- HT_SANDMAN
+UPDATE `char` c, `skill` s SET `c`.skill_point = `c`.skill_point + `s`.lv WHERE (`c`.class = 4190 OR `c`.class = 4191) AND `s`.id = 119 AND `c`.char_id = `s`.char_id;
+DELETE FROM `skill` USING `skill`, `char` WHERE (`char`.class = 4190 OR `char`.class = 4191) AND `skill`.id = 119 AND `char`.char_id = `skill`.char_id;
+
+-- HT_FLASHER
+UPDATE `char` c, `skill` s SET `c`.skill_point = `c`.skill_point + `s`.lv WHERE (`c`.class = 4190 OR `c`.class = 4191) AND `s`.id = 120 AND `c`.char_id = `s`.char_id;
+DELETE FROM `skill` USING `skill`, `char` WHERE (`char`.class = 4190 OR `char`.class = 4191) AND `skill`.id = 120 AND `char`.char_id = `skill`.char_id;
+
+-- HT_FREEZINGTRAP
+UPDATE `char` c, `skill` s SET `c`.skill_point = `c`.skill_point + `s`.lv WHERE (`c`.class = 4190 OR `c`.class = 4191) AND `s`.id = 121 AND `c`.char_id = `s`.char_id;
+DELETE FROM `skill` USING `skill`, `char` WHERE (`char`.class = 4190 OR `char`.class = 4191) AND `skill`.id = 121 AND `char`.char_id = `skill`.char_id;

+ 3 - 0
sql-files/upgrades/upgrade_20200518.sql

@@ -0,0 +1,3 @@
+-- WM_DOMINION_IMPULSE
+UPDATE `char` c, `skill` s SET `c`.skill_point = `c`.skill_point + `s`.lv WHERE `s`.id = 2417 AND `c`.char_id = `s`.char_id;
+DELETE FROM `skill` WHERE `id` = 2417;

+ 1 - 0
sql-files/upgrades/upgrade_20200603.sql

@@ -0,0 +1 @@
+ALTER TABLE  `char` ADD COLUMN `hotkey_rowshift2` TINYINT(3) UNSIGNED NOT NULL DEFAULT  '0' AFTER `hotkey_rowshift`;

+ 13 - 0
sql-files/upgrades/upgrade_20200604.sql

@@ -0,0 +1,13 @@
+UPDATE `char` `c`
+INNER JOIN `login` `l`
+ON `l`.`account_id` = `c`.`account_id`
+SET `c`.`sex` = `l`.`sex`
+WHERE
+	`c`.`sex` = 'U'
+AND
+	`l`.`sex` <> 'S'
+;
+
+ALTER TABLE `char`
+	MODIFY `sex` ENUM('M','F') NOT NULL
+;

+ 67 - 86
src/char/char.cpp

@@ -299,7 +299,7 @@ int char_mmo_char_tosql(uint32 char_id, struct mmo_charstatus* p){
 		(p->rename != cp->rename) || (p->robe != cp->robe) || (p->character_moves != cp->character_moves) ||
 		(p->unban_time != cp->unban_time) || (p->font != cp->font) || (p->uniqueitem_counter != cp->uniqueitem_counter) ||
 		(p->hotkey_rowshift != cp->hotkey_rowshift) || (p->clan_id != cp->clan_id ) || (p->title_id != cp->title_id) ||
-		(p->show_equip != cp->show_equip)
+		(p->show_equip != cp->show_equip) || (p->hotkey_rowshift2 != cp->hotkey_rowshift2)
 	)
 	{	//Save status
 		if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `base_level`='%d', `job_level`='%d',"
@@ -310,7 +310,7 @@ int char_mmo_char_tosql(uint32 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',`moves`='%d',`font`='%u',`uniqueitem_counter`='%u',"
-			"`hotkey_rowshift`='%d', `clan_id`='%d', `title_id`='%lu', `show_equip`='%d'"
+			"`hotkey_rowshift`='%d', `clan_id`='%d', `title_id`='%lu', `show_equip`='%d', `hotkey_rowshift2`='%d'"
 			" WHERE `account_id`='%d' AND `char_id` = '%d'",
 			schema_config.char_db, p->base_level, p->job_level,
 			p->base_exp, p->job_exp, p->zeny,
@@ -322,7 +322,7 @@ int char_mmo_char_tosql(uint32 char_id, struct mmo_charstatus* p){
 			mapindex_id2name(p->save_point.map), p->save_point.x, p->save_point.y, p->rename,
 			(unsigned long)p->delete_date, // FIXME: platform-dependent size
 			p->robe, p->character_moves, p->font, p->uniqueitem_counter,
-			p->hotkey_rowshift, p->clan_id, p->title_id, p->show_equip,
+			p->hotkey_rowshift, p->clan_id, p->title_id, p->show_equip, p->hotkey_rowshift2,
 			p->account_id, p->char_id) )
 		{
 			Sql_ShowDebug(sql_handle);
@@ -857,42 +857,24 @@ bool char_memitemdata_from_sql(struct s_storage* p, int max, int id, enum storag
  *
  * @retval SEX_MALE if the per-character sex is male
  * @retval SEX_FEMALE if the per-character sex is female
- * @retval SEX_ACCOUNT if the per-character sex is not defined or the current PACKETVER doesn't support it.
  */
-int char_mmo_gender(const struct char_session_data *sd, const struct mmo_charstatus *p, char sex)
-{
+int char_mmo_gender( const struct char_session_data *sd, const struct mmo_charstatus *p, char sex ){
+	switch( sex ){
 #if PACKETVER >= 20141016
-	(void)sd; (void)p; // Unused
-	switch (sex) {
 		case 'M':
 			return SEX_MALE;
 		case 'F':
 			return SEX_FEMALE;
-		case 'U':
-		default:
-			return SEX_ACCOUNT;
-	}
 #else
-	if (sex == 'M' || sex == 'F') {
-		if (!sd) {
-			// sd is not available, there isn't much we can do. Just return and print a warning.
-			ShowWarning("Character '%s' (CID: %d, AID: %d) has sex '%c', but PACKETVER does not support per-character sex. Defaulting to 'U'.\n",
-					p->name, p->char_id, p->account_id, sex);
-			return SEX_ACCOUNT;
-		}
-		if ((sex == 'M' && sd->sex == SEX_FEMALE)
-		 || (sex == 'F' && sd->sex == SEX_MALE)) {
-			ShowWarning("Changing sex of character '%s' (CID: %d, AID: %d) to 'U' due to incompatible PACKETVER.\n", p->name, p->char_id, p->account_id);
-			chlogif_parse_ackchangecharsex(p->char_id, sd->sex);
-		} else {
-			ShowInfo("Resetting sex of character '%s' (CID: %d, AID: %d) to 'U' due to incompatible PACKETVER.\n", p->name, p->char_id, p->account_id);
-		}
-		if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `sex` = 'U' WHERE `char_id` = '%d'", schema_config.char_db, p->char_id)) {
-			Sql_ShowDebug(sql_handle);
-		}
-	}
-	return SEX_ACCOUNT;
+		case 'M':
+		case 'F':
+			// No matter what the database says, always return the account gender
+			return sd->sex;
 #endif
+		default:
+			ShowWarning( "Found unknown gender '%c' for character '%s' (CID: %d, AID: %d), returning account gender...\n", sex, p->name, p->char_id, p->account_id );
+			return sd->sex;
+	}
 }
 
 int char_mmo_char_tobuf(uint8* buf, struct mmo_charstatus* p);
@@ -924,7 +906,8 @@ int char_mmo_chars_fromsql(struct char_session_data* sd, uint8* buf, uint8* coun
 		"`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`,`moves`,`unban_time`,`font`,`uniqueitem_counter`,`sex`,`hotkey_rowshift`,`title_id`,`show_equip`"
+		"`robe`,`moves`,`unban_time`,`font`,`uniqueitem_counter`,`sex`,`hotkey_rowshift`,`title_id`,`show_equip`,"
+		"`hotkey_rowshift2`"
 		" FROM `%s` WHERE `account_id`='%d' AND `char_num` < '%d'", schema_config.char_db, sd->account_id, MAX_CHARS)
 	||	SQL_ERROR == SqlStmt_Execute(stmt)
 	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 0,  SQLDT_INT,    &p.char_id, 0, NULL, NULL)
@@ -972,6 +955,7 @@ int char_mmo_chars_fromsql(struct char_session_data* sd, uint8* buf, uint8* coun
 	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 42, SQLDT_UCHAR,  &p.hotkey_rowshift, 0, NULL, NULL)
 	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 43, SQLDT_ULONG,  &p.title_id, 0, NULL, NULL)
 	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 44, SQLDT_UINT16, &p.show_equip, 0, NULL, NULL)
+	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 45, SQLDT_UCHAR,  &p.hotkey_rowshift2, 0, NULL, NULL)
 	)
 	{
 		SqlStmt_ShowDebug(stmt);
@@ -1039,7 +1023,7 @@ int char_mmo_char_fromsql(uint32 char_id, struct mmo_charstatus* p, bool load_ev
 		"`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`, `moves`,"
-		"`unban_time`,`font`,`uniqueitem_counter`,`sex`,`hotkey_rowshift`,`clan_id`,`title_id`,`show_equip`"
+		"`unban_time`,`font`,`uniqueitem_counter`,`sex`,`hotkey_rowshift`,`clan_id`,`title_id`,`show_equip`,`hotkey_rowshift2`"
 		" FROM `%s` WHERE `char_id`=? LIMIT 1", schema_config.char_db)
 	||	SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0)
 	||	SQL_ERROR == SqlStmt_Execute(stmt)
@@ -1105,6 +1089,7 @@ int char_mmo_char_fromsql(uint32 char_id, struct mmo_charstatus* p, bool load_ev
 	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 59, SQLDT_INT,    &p->clan_id, 0, NULL, NULL)
 	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 60, SQLDT_ULONG,  &p->title_id, 0, NULL, NULL)
 	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 61, SQLDT_UINT16, &p->show_equip, 0, NULL, NULL)
+	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 62, SQLDT_UCHAR,  &p->hotkey_rowshift2, 0, NULL, NULL)
 	)
 	{
 		SqlStmt_ShowDebug(stmt);
@@ -1211,7 +1196,7 @@ int char_mmo_char_fromsql(uint32 char_id, struct mmo_charstatus* p, bool load_ev
 
 	while( SQL_SUCCESS == SqlStmt_NextRow(stmt) )
 	{
-		if( hotkey_num >= 0 && hotkey_num < MAX_HOTKEYS )
+		if( hotkey_num >= 0 && hotkey_num < MAX_HOTKEYS_DB )
 			memcpy(&p->hotkeys[hotkey_num], &tmp_hotkey, sizeof(tmp_hotkey));
 		else
 			ShowWarning("mmo_char_fromsql: ignoring invalid hotkey (hotkey=%d,type=%u,id=%u,lv=%u) of character %s (AID=%d,CID=%d)\n", hotkey_num, tmp_hotkey.type, tmp_hotkey.id, tmp_hotkey.lv, p->name, p->account_id, p->char_id);
@@ -1380,22 +1365,14 @@ int char_check_char_name(char * name, char * esc_name)
 //-----------------------------------
 // Function to create a new character
 //-----------------------------------
-#if PACKETVER >= 20120307
-#if PACKETVER >= 20151001
-int char_make_new_char_sql(struct char_session_data* sd, char* name_, int slot, int hair_color, int hair_style, short start_job, short unknown, int sex) { // TODO: Unknown byte
-#else
-int char_make_new_char_sql(struct char_session_data* sd, char* name_, int slot, int hair_color, int hair_style) {
-#endif
-	int str = 1, agi = 1, vit = 1, int_ = 1, dex = 1, luk = 1;
-#else
-int char_make_new_char_sql(struct char_session_data* sd, char* name_, int str, int agi, int vit, int int_, int dex, int luk, int slot, int hair_color, int hair_style) {
-#endif
+int char_make_new_char( struct char_session_data* sd, char* name_, int str, int agi, int vit, int int_, int dex, int luk, int slot, int hair_color, int hair_style, short start_job, int sex ){
 	char name[NAME_LENGTH];
 	char esc_name[NAME_LENGTH*2+1];
 	struct point tmp_start_point[MAX_STARTPOINT];
 	struct startitem tmp_start_items[MAX_STARTITEM];
 	uint32 char_id;
 	int flag, k, start_point_idx = rnd() % charserv_config.start_point_count;
+	int status_points;
 
 	safestrncpy(name, name_, NAME_LENGTH);
 	normalize_name(name,TRIM_CHARS);
@@ -1410,32 +1387,51 @@ int char_make_new_char_sql(struct char_session_data* sd, char* name_, int str, i
 	if( flag < 0 )
 		return flag;
 
-	//check other inputs
-#if PACKETVER >= 20120307
-#if PACKETVER >= 20151001
-	switch(sex) {
-			case SEX_FEMALE:
-				sex = 'F';
-				break;
-			case SEX_MALE:
-				sex = 'M';
-				break;
-			default:
-				sex = 'U';
-				break;
-	}
-#endif
-	if(slot < 0 || slot >= sd->char_slots)
-#else
-	if((slot < 0 || slot >= sd->char_slots) // slots
-	|| (str + agi + vit + int_ + dex + luk != 6*5 ) // stats
-	|| (str < 1 || str > 9 || agi < 1 || agi > 9 || vit < 1 || vit > 9 || int_ < 1 || int_ > 9 || dex < 1 || dex > 9 || luk < 1 || luk > 9) // individual stat values
-	|| (str + int_ != 10 || agi + luk != 10 || vit + dex != 10) ) // pairs
-#endif
-#if PACKETVER >= 20100413
+	// Check inputs from the client - never trust it!
+
+	// Check the slot
+	if( slot < 0 || slot >= sd->char_slots ){
 		return -4; // invalid slot
-#else
+	}
+
+	// Check gender
+	switch( sex ){
+		case SEX_FEMALE:
+			sex = 'F';
+			break;
+		case SEX_MALE:
+			sex = 'M';
+			break;
+		default:
+			ShowWarning( "Received unsupported gender '%d'...\n", sex );
+			return -2; // invalid input
+	}
+
+	// Check status values
+#if PACKETVER < 20120307
+	// All stats together always have to add up to a total of 30 points
+	if( ( str + agi + vit + int_ + dex + luk ) != 30 ){
+		return -2; // invalid input
+	}
+
+	// No status can be below 1
+	if( str < 1 || agi < 1 || vit < 1 || int_ < 1 || dex < 1 || luk < 1 ){
+		return -2; // invalid input
+	}
+
+	// No status can be higher than 9
+	if( str > 9 || agi > 9 || vit > 9 || int_ > 9 || dex > 9 || luk > 9 ){
+		return -2; // invalid input
+	}
+
+	// The status pairs always have to add up to a total of 10 points
+	if( ( str + int_ ) != 10 || ( agi + luk ) != 10 || ( vit + dex ) != 10 ){
 		return -2; // invalid input
+	}
+
+	status_points = 0;
+#else
+	status_points = 48;
 #endif
 
 	// check the number of already existing chars in this account
@@ -1479,28 +1475,12 @@ int char_make_new_char_sql(struct char_session_data* sd, char* name_, int str, i
 #endif
 
 	//Insert the new char entry to the database
-#if PACKETVER >= 20151001
 	if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`account_id`, `char_num`, `name`, `class`, `zeny`, `status_point`, `str`, `agi`, `vit`, `int`, `dex`, `luk`, `max_hp`, `hp`,"
 		"`max_sp`, `sp`, `hair`, `hair_color`, `last_map`, `last_x`, `last_y`, `save_map`, `save_x`, `save_y`, `sex`) VALUES ("
 		"'%d', '%d', '%s', '%d', '%d',  '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%u', '%u', '%u', '%u', '%d', '%d', '%s', '%d', '%d', '%s', '%d', '%d', '%c')",
-		schema_config.char_db, sd->account_id , slot, esc_name, start_job, charserv_config.start_zeny, 48, str, agi, vit, int_, dex, luk,
+		schema_config.char_db, sd->account_id , slot, esc_name, start_job, charserv_config.start_zeny, status_points, str, agi, vit, int_, dex, luk,
 		(40 * (100 + vit)/100) , (40 * (100 + vit)/100 ),  (11 * (100 + int_)/100), (11 * (100 + int_)/100), hair_style, hair_color,
 		mapindex_id2name(tmp_start_point[start_point_idx].map), tmp_start_point[start_point_idx].x, tmp_start_point[start_point_idx].y, mapindex_id2name(tmp_start_point[start_point_idx].map), tmp_start_point[start_point_idx].x, tmp_start_point[start_point_idx].y, sex) )
-#elif PACKETVER >= 20120307
-	if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`account_id`, `char_num`, `name`, `zeny`, `status_point`, `str`, `agi`, `vit`, `int`, `dex`, `luk`, `max_hp`, `hp`,"
-		"`max_sp`, `sp`, `hair`, `hair_color`, `last_map`, `last_x`, `last_y`, `save_map`, `save_x`, `save_y`) VALUES ("
-		"'%d', '%d', '%s', '%d',  '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%u', '%u', '%u', '%u', '%d', '%d', '%s', '%d', '%d', '%s', '%d', '%d')",
-		schema_config.char_db, sd->account_id , slot, esc_name, charserv_config.start_zeny, 48, str, agi, vit, int_, dex, luk,
-		(40 * (100 + vit)/100) , (40 * (100 + vit)/100 ),  (11 * (100 + int_)/100), (11 * (100 + int_)/100), hair_style, hair_color,
-		mapindex_id2name(tmp_start_point[start_point_idx].map), tmp_start_point[start_point_idx].x, tmp_start_point[start_point_idx].y, mapindex_id2name(tmp_start_point[start_point_idx].map), tmp_start_point[start_point_idx].x, tmp_start_point[start_point_idx].y) )
-#else
-	if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`account_id`, `char_num`, `name`, `zeny`, `str`, `agi`, `vit`, `int`, `dex`, `luk`, `max_hp`, `hp`,"
-		"`max_sp`, `sp`, `hair`, `hair_color`, `last_map`, `last_x`, `last_y`, `save_map`, `save_x`, `save_y`) VALUES ("
-		"'%d', '%d', '%s', '%d',  '%d', '%d', '%d', '%d', '%d', '%d', '%u', '%u', '%u', '%u', '%d', '%d', '%s', '%d', '%d', '%s', '%d', '%d')",
-		schema_config.char_db, sd->account_id , slot, esc_name, charserv_config.start_zeny, str, agi, vit, int_, dex, luk,
-		(40 * (100 + vit)/100) , (40 * (100 + vit)/100 ),  (11 * (100 + int_)/100), (11 * (100 + int_)/100), hair_style, hair_color,
-		mapindex_id2name(tmp_start_point[start_point_idx].map), tmp_start_point[start_point_idx].x, tmp_start_point[start_point_idx].y, mapindex_id2name(tmp_start_point[start_point_idx].map), tmp_start_point[start_point_idx].x, tmp_start_point[start_point_idx].y) )
-#endif
 	{
 		Sql_ShowDebug(sql_handle);
 		return -2; //No, stop the procedure!
@@ -2318,7 +2298,8 @@ bool char_checkdb(void){
 		"`guild_id`,`pet_id`,`homun_id`,`elemental_id`,`hair`,`hair_color`,`clothes_color`,`weapon`,"
 		"`shield`,`head_top`,`head_mid`,`head_bottom`,`robe`,`last_map`,`last_x`,`last_y`,`save_map`,"
 		"`save_x`,`save_y`,`partner_id`,`online`,`father`,`mother`,`child`,`fame`,`rename`,`delete_date`,"
-		"`moves`,`unban_time`,`font`,`sex`,`hotkey_rowshift`,`clan_id`,`last_login`,`title_id`,`show_equip`"
+		"`moves`,`unban_time`,`font`,`sex`,`hotkey_rowshift`,`clan_id`,`last_login`,`title_id`,`show_equip`,"
+		"`hotkey_rowshift2`"
 		" FROM `%s` LIMIT 1;", schema_config.char_db) ){
 		Sql_ShowDebug(sql_handle);
 		return false;

+ 1 - 7
src/char/char.hpp

@@ -306,13 +306,7 @@ void char_auth_ok(int fd, struct char_session_data *sd);
 void char_set_charselect(uint32 account_id);
 void char_read_fame_list(void);
 
-#if PACKETVER >= 20151001
-int char_make_new_char_sql(struct char_session_data* sd, char* name_, int slot, int hair_color, int hair_style, short start_job, short unknown, int sex);
-#elif PACKETVER >= 20120307
-int char_make_new_char_sql(struct char_session_data* sd, char* name_, int slot, int hair_color, int hair_style);
-#else
-int char_make_new_char_sql(struct char_session_data* sd, char* name_, int str, int agi, int vit, int int_, int dex, int luk, int slot, int hair_color, int hair_style);
-#endif
+int char_make_new_char( struct char_session_data* sd, char* name_, int str, int agi, int vit, int int_, int dex, int luk, int slot, int hair_color, int hair_style, short start_job, int sex );
 
 void char_set_session_flag_(int account_id, int val, bool set);
 #define char_set_session_flag(account_id, val)   ( char_set_session_flag_((account_id), (val), true)  )

+ 74 - 9
src/char/char_clif.cpp

@@ -811,13 +811,24 @@ int chclif_parse_charselect(int fd, struct char_session_data* sd,uint32 ipl){
 		char* data;
 		uint32 char_id;
 		struct auth_node* node;
-		int i, map_fd;
+		int i, map_fd, server_id;
 		DBMap *auth_db = char_get_authdb();
 		DBMap *char_db_ = char_get_chardb();
 
 		int slot = RFIFOB(fd,2);
 		RFIFOSKIP(fd,3);
 
+		ARR_FIND( 0, ARRAYLENGTH(map_server), server_id, map_server[server_id].fd > 0 && !map_server[server_id].map.empty() );
+		// Map-server not available, tell the client to wait (client wont close, char select will respawn)
+		if (server_id == ARRAYLENGTH(map_server)) {
+			WFIFOHEAD(fd, 24);
+			WFIFOW(fd, 0) = 0x840;
+			WFIFOW(fd, 2) = 24;
+			memcpy(WFIFOP(fd, 4), "0", 20); // we can't send it empty (otherwise the list will pop up)
+			WFIFOSET(fd, 24);
+			return 1;
+		}
+
 		// Check if the character exists and is not scheduled for deletion
 		if ( SQL_SUCCESS != Sql_Query(sql_handle, "SELECT `char_id` FROM `%s` WHERE `account_id`='%d' AND `char_num`='%d' AND `delete_date` = 0", schema_config.char_db, sd->account_id, slot)
 		  || SQL_SUCCESS != Sql_NextRow(sql_handle)
@@ -855,8 +866,6 @@ int chclif_parse_charselect(int fd, struct char_session_data* sd,uint32 ipl){
 
 		//Have to switch over to the DB instance otherwise data won't propagate [Kevin]
 		cd = (struct mmo_charstatus *)idb_get(char_db_, char_id);
-		if (cd->sex == SEX_ACCOUNT)
-			cd->sex = sd->sex;
 
 		if (charserv_config.log_char) {
 			char esc_name[NAME_LENGTH*2+1];
@@ -951,16 +960,72 @@ int chclif_parse_createnewchar(int fd, struct char_session_data* sd,int cmd){
 	if( (charserv_config.char_new)==0 ) //turn character creation on/off [Kevin]
 		char_id = -2;
 	else {
+		char name[NAME_LENGTH];
+		int str, agi, vit, int_, dex, luk;
+		int slot;
+		int hair_color;
+		int hair_style;
+		short start_job;
+		int sex;
+
 #if PACKETVER >= 20151001
-			char_id = char_make_new_char_sql(sd, RFIFOCP(fd,2),RFIFOB(fd,26),RFIFOW(fd,27),RFIFOW(fd,29),RFIFOW(fd,31),RFIFOW(fd,32),RFIFOB(fd,35));
-			RFIFOSKIP(fd,36);
+		// Sent values
+		safestrncpy( name, RFIFOCP( fd, 2 ), NAME_LENGTH );
+		slot = RFIFOB( fd, 26 );
+		hair_color = RFIFOW( fd, 27 );
+		hair_style = RFIFOW( fd, 29 );
+		start_job = RFIFOW( fd, 31 );
+		// Unknown RFIFOW( fd, 32 )
+		sex = RFIFOB( fd, 35 );
+
+		// Default values
+		str = 1;
+		agi = 1;
+		vit = 1;
+		int_ = 1;
+		dex = 1;
+		luk = 1;
+
+		RFIFOSKIP( fd, 36 );
 #elif PACKETVER >= 20120307
-			char_id = char_make_new_char_sql(sd, RFIFOCP(fd,2),RFIFOB(fd,26),RFIFOW(fd,27),RFIFOW(fd,29));
-			RFIFOSKIP(fd,31);
+		// Sent values
+		safestrncpy( name, RFIFOCP( fd, 2 ), NAME_LENGTH );
+		slot = RFIFOB( fd, 26 );
+		hair_color = RFIFOW( fd, 27 );
+		hair_style = RFIFOW( fd, 29 );
+
+		// Default values
+		str = 1;
+		agi = 1;
+		vit = 1;
+		int_ = 1;
+		dex = 1;
+		luk = 1;
+		start_job = JOB_NOVICE;
+		sex = sd->sex;
+
+		RFIFOSKIP( fd, 31 );
 #else
-			char_id = char_make_new_char_sql(sd, RFIFOCP(fd,2),RFIFOB(fd,26),RFIFOB(fd,27),RFIFOB(fd,28),RFIFOB(fd,29),RFIFOB(fd,30),RFIFOB(fd,31),RFIFOB(fd,32),RFIFOW(fd,33),RFIFOW(fd,35));
-			RFIFOSKIP(fd,37);
+		// Sent values
+		safestrncpy( name, RFIFOCP( fd, 2 ), NAME_LENGTH );
+		str = RFIFOB( fd, 26 );
+		agi = RFIFOB( fd, 27 );
+		vit = RFIFOB( fd, 28 );
+		int_ = RFIFOB( fd, 29 );
+		dex = RFIFOB( fd, 30 );
+		luk = RFIFOB( fd, 31 );
+		slot = RFIFOB( fd, 32 );
+		hair_color = RFIFOW( fd, 33 );
+		hair_style = RFIFOW( fd, 35 );
+
+		// Default values
+		start_job = JOB_NOVICE;
+		sex = sd->sex;
+
+		RFIFOSKIP( fd, 37 );
 #endif
+
+		char_id = char_make_new_char( sd, name, str, agi, vit, int_, dex, luk, slot, hair_color, hair_style, start_job, sex );
 	}
 
 	if (char_id < 0) {

+ 26 - 30
src/char/char_logif.cpp

@@ -179,12 +179,12 @@ void chlogif_prepsend_global_accreg(void) {
 }
 
 void chlogif_send_global_accreg(const char *key, unsigned int index, int64 int_value, const char* string_value, bool is_string) {
-	int nlen = WFIFOW(login_fd, 2);
-	size_t len;
-
 	if (!chlogif_isconnected())
 		return;
 
+	int nlen = WFIFOW(login_fd, 2);
+	size_t len;
+
 	len = strlen(key)+1;
 
 	WFIFOB(login_fd, nlen) = (unsigned char)len; // won't be higher; the column size is 32
@@ -275,7 +275,7 @@ void chlogif_send_setaccoffline(int fd, int aid){
 	WFIFOSET(fd,6);
 }
 
-int chlogif_parse_ackconnect(int fd, struct char_session_data* sd){
+int chlogif_parse_ackconnect(int fd){
 	if (RFIFOREST(fd) < 3)
 		return 0;
 
@@ -295,10 +295,11 @@ int chlogif_parse_ackconnect(int fd, struct char_session_data* sd){
 	return 1;
 }
 
-int chlogif_parse_ackaccreq(int fd, struct char_session_data* sd){
+int chlogif_parse_ackaccreq(int fd){
 	if (RFIFOREST(fd) < 21)
 		return 0;
 	{
+		struct char_session_data* sd;
 		uint32 account_id = RFIFOL(fd,2);
 		uint32 login_id1 = RFIFOL(fd,6);
 		uint32 login_id2 = RFIFOL(fd,10);
@@ -332,16 +333,16 @@ int chlogif_parse_ackaccreq(int fd, struct char_session_data* sd){
  * Receive account data from login-server
  * AH 0x2717 <aid>.L <email>.40B <expiration_time>.L <group_id>.B <birthdate>.11B <pincode>.5B <pincode_change>.L <isvip>.B <char_vip>.B <char_billing>.B
  **/
-int chlogif_parse_reqaccdata(int fd, struct char_session_data* sd){
-	int u_fd; //user fd
+int chlogif_parse_reqaccdata(int fd){
 	if (RFIFOREST(fd) < 75)
 		return 0;
+	int u_fd; //user fd
+	struct char_session_data* sd;
 
 	// find the authenticated session with this account id
 	ARR_FIND( 0, fd_max, u_fd, session[u_fd] && (sd = (struct char_session_data*)session[u_fd]->session_data) && sd->auth && sd->account_id == RFIFOL(fd,2) );
 	if( u_fd < fd_max )
 	{
-		int server_id;
 		memcpy(sd->email, RFIFOP(fd,6), 40);
 		sd->expiration_time = (time_t)RFIFOL(fd,46);
 		sd->group_id = RFIFOB(fd,50);
@@ -357,12 +358,10 @@ int chlogif_parse_reqaccdata(int fd, struct char_session_data* sd){
 		sd->isvip = RFIFOB(fd,72);
 		sd->chars_vip = RFIFOB(fd,73);
 		sd->chars_billing = RFIFOB(fd,74);
-		ARR_FIND( 0, ARRAYLENGTH(map_server), server_id, map_server[server_id].fd > 0 && map_server[server_id].map[0] );
 		// continued from char_auth_ok...
-		if( server_id == ARRAYLENGTH(map_server) || //server not online, bugreport:2359
-			(((charserv_config.max_connect_user == 0 || charserv_config.char_maintenance == 1) ||
+		if(((charserv_config.max_connect_user == 0 || charserv_config.char_maintenance == 1) ||
 			(charserv_config.max_connect_user > 0 && char_count_users() >= charserv_config.max_connect_user)) &&
-			sd->group_id < charserv_config.gm_allow_group)) {
+			sd->group_id < charserv_config.gm_allow_group) {
 			// refuse connection (over populated)
 			chclif_reject(u_fd,0);
 		} else {
@@ -377,7 +376,7 @@ int chlogif_parse_reqaccdata(int fd, struct char_session_data* sd){
 	return 1;
 }
 
-int chlogif_parse_keepalive(int fd, struct char_session_data* sd){
+int chlogif_parse_keepalive(int fd){
 	if (RFIFOREST(fd) < 2)
 		return 0;
 	RFIFOSKIP(fd,2);
@@ -425,7 +424,7 @@ void chlogif_parse_change_sex_sub(int sex, int acc, int char_id, int class_, int
 		inter_guild_sex_changed(guild_id, acc, char_id, sex);
 }
 
-int chlogif_parse_ackchangesex(int fd, struct char_session_data* sd)
+int chlogif_parse_ackchangesex(int fd)
 {
 	if (RFIFOREST(fd) < 7)
 		return 0;
@@ -519,7 +518,7 @@ int chlogif_parse_ackchangecharsex(int char_id, int sex)
 	return 0;
 }
 
-int chlogif_parse_ack_global_accreg(int fd, struct char_session_data* sd){
+int chlogif_parse_ack_global_accreg(int fd){
 	if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
 		return 0;
 	else { //Receive account_reg2 registry, forward to map servers.
@@ -530,7 +529,7 @@ int chlogif_parse_ack_global_accreg(int fd, struct char_session_data* sd){
 	return 1;
 }
 
-int chlogif_parse_accbannotification(int fd, struct char_session_data* sd){
+int chlogif_parse_accbannotification(int fd){
 	if (RFIFOREST(fd) < 11)
 		return 0;
 	else { // send to all map-servers to disconnect the player
@@ -547,7 +546,7 @@ int chlogif_parse_accbannotification(int fd, struct char_session_data* sd){
 	return 1;
 }
 
-int chlogif_parse_askkick(int fd, struct char_session_data* sd){
+int chlogif_parse_askkick(int fd){
 	if (RFIFOREST(fd) < 6)
 		return 0;
 	else {
@@ -583,7 +582,7 @@ int chlogif_parse_askkick(int fd, struct char_session_data* sd){
 	return 1;
 }
 
-int chlogif_parse_updip(int fd, struct char_session_data* sd){
+int chlogif_parse_updip(int fd){
 	unsigned char buf[2];
 	uint32 new_ip = 0;
 
@@ -700,7 +699,6 @@ int chlogif_parse_AccInfoAck(int fd) {
 
 
 int chlogif_parse(int fd) {
-	struct char_session_data* sd = NULL;
 
 	// only process data from the login-server
 	if( fd != login_fd ) {
@@ -727,8 +725,6 @@ int chlogif_parse(int fd) {
 		}
 	}
 
-	sd = (struct char_session_data*)session[fd]->session_data;
-
 	while(RFIFOREST(fd) >= 2) {
 		// -1: Login server is not connected
 		//  0: Avoid processing followup packets (prev was probably incomplete) packet
@@ -736,16 +732,16 @@ int chlogif_parse(int fd) {
 		int next = 1;
 		uint16 command = RFIFOW(fd,0);
 		switch( command ) {
-			case 0x2711: next = chlogif_parse_ackconnect(fd,sd); break;
-			case 0x2713: next = chlogif_parse_ackaccreq(fd, sd); break;
-			case 0x2717: next = chlogif_parse_reqaccdata(fd, sd); break;
-			case 0x2718: next = chlogif_parse_keepalive(fd, sd); break;
+			case 0x2711: next = chlogif_parse_ackconnect(fd); break;
+			case 0x2713: next = chlogif_parse_ackaccreq(fd); break;
+			case 0x2717: next = chlogif_parse_reqaccdata(fd); break;
+			case 0x2718: next = chlogif_parse_keepalive(fd); break;
 			case 0x2721: next = chlogif_parse_AccInfoAck(fd); break;
-			case 0x2723: next = chlogif_parse_ackchangesex(fd, sd); break;
-			case 0x2726: next = chlogif_parse_ack_global_accreg(fd, sd); break;
-			case 0x2731: next = chlogif_parse_accbannotification(fd, sd); break;
-			case 0x2734: next = chlogif_parse_askkick(fd,sd); break;
-			case 0x2735: next = chlogif_parse_updip(fd,sd); break;
+			case 0x2723: next = chlogif_parse_ackchangesex(fd); break;
+			case 0x2726: next = chlogif_parse_ack_global_accreg(fd); break;
+			case 0x2731: next = chlogif_parse_accbannotification(fd); break;
+			case 0x2734: next = chlogif_parse_askkick(fd); break;
+			case 0x2735: next = chlogif_parse_updip(fd); break;
 			case 0x2743: next = chlogif_parse_vipack(fd); break;
 			default:
 				ShowError("Unknown packet 0x%04x received from login-server, disconnecting.\n", command);

+ 9 - 9
src/char/char_logif.hpp

@@ -26,17 +26,17 @@ void chlogif_send_setacconline(int aid);
 void chlogif_send_setallaccoffline(int fd);
 void chlogif_send_setaccoffline(int fd, int aid);
 
-int chlogif_parse_ackconnect(int fd, struct char_session_data* sd);
-int chlogif_parse_ackaccreq(int fd, struct char_session_data* sd);
-int chlogif_parse_reqaccdata(int fd, struct char_session_data* sd);
-int chlogif_parse_keepalive(int fd, struct char_session_data* sd);
+int chlogif_parse_ackconnect(int fd);
+int chlogif_parse_ackaccreq(int fd);
+int chlogif_parse_reqaccdata(int fd);
+int chlogif_parse_keepalive(int fd);
 void chlogif_parse_change_sex_sub(int sex, int acc, int char_id, int class_, int guild_id);
-int chlogif_parse_ackchangesex(int fd, struct char_session_data* sd);
+int chlogif_parse_ackchangesex(int fd);
 int chlogif_parse_ackchangecharsex(int char_id, int sex);
-int chlogif_parse_ack_global_accreg(int fd, struct char_session_data* sd);
-int chlogif_parse_accbannotification(int fd, struct char_session_data* sd);
-int chlogif_parse_askkick(int fd, struct char_session_data* sd);
-int chlogif_parse_updip(int fd, struct char_session_data* sd);
+int chlogif_parse_ack_global_accreg(int fd);
+int chlogif_parse_accbannotification(int fd);
+int chlogif_parse_askkick(int fd);
+int chlogif_parse_updip(int fd);
 
 int chlogif_parse_vipack(int fd);
 int chlogif_reqvipdata(uint32 aid, uint8 flag, int32 timediff, int mapfd);

+ 0 - 4
src/char/char_mapif.cpp

@@ -1013,8 +1013,6 @@ int chmapif_parse_reqauth(int fd, int id){
 		}
 		if( runflag == CHARSERVER_ST_RUNNING && autotrade && cd ){
 			uint16 mmo_charstatus_len = sizeof(struct mmo_charstatus) + 25;
-			if (cd->sex == SEX_ACCOUNT)
-				cd->sex = sex;
 
 			WFIFOHEAD(fd,mmo_charstatus_len);
 			WFIFOW(fd,0) = 0x2afd;
@@ -1042,8 +1040,6 @@ int chmapif_parse_reqauth(int fd, int id){
 			)
 		{// auth ok
 			uint16 mmo_charstatus_len = sizeof(struct mmo_charstatus) + 25;
-			if (cd->sex == SEX_ACCOUNT)
-				cd->sex = sex;
 
 			WFIFOHEAD(fd,mmo_charstatus_len);
 			WFIFOW(fd,0) = 0x2afd;

+ 12 - 0
src/common/core.cpp

@@ -3,6 +3,8 @@
 
 #include "core.hpp"
 
+#include "../config/core.hpp"
+
 #ifndef MINICORE
 #include "ers.hpp"
 #include "socket.hpp"
@@ -24,6 +26,16 @@
 #include "showmsg.hpp"
 #include "strlib.hpp"
 
+#ifndef DEPRECATED_COMPILER_SUPPORT
+	#if defined( _MSC_VER ) && _MSC_VER < 1900
+		#error "Visual Studio versions older than Visual Studio 2015 are not officially supported anymore"
+	#elif defined( __clang__ ) && __clang_major__ < 4 && !( __clang_major__ == 3 && __clang_minor__ >= 7 )
+		#error "clang versions older than clang 3.7 are not officially supported anymore"
+	#elif !defined( __clang__ ) && defined( __GNUC__ ) && __GNUC__ < 5
+		#error "GCC versions older than GCC 5 are not officially supported anymore"
+	#endif
+#endif
+
 /// Called when a terminate signal is received.
 void (*shutdown_callback)(void) = NULL;
 

+ 11 - 5
src/common/mmo.hpp

@@ -33,6 +33,12 @@
 	#define MAX_HOTKEYS 38
 #endif
 
+#if PACKETVER_MAIN_NUM >= 20190522 || PACKETVER_RE_NUM >= 20190508 || PACKETVER_ZERO_NUM >= 20190605
+	#define MAX_HOTKEYS_DB ((MAX_HOTKEYS) * 2)
+#else
+	#define MAX_HOTKEYS_DB MAX_HOTKEYS
+#endif
+
 #define MAX_MAP_PER_SERVER 1500 /// Maximum amount of maps available on a server
 #define MAX_INVENTORY 100 ///Maximum items in player inventory
 /** Max number of characters per account. Note that changing this setting alone is not enough if the client is not hexed to support more characters as well.
@@ -377,7 +383,7 @@ struct s_storage {
 		unsigned get : 1;
 		unsigned put : 1;
 	} state;
-	union { // Max for inventory, storage, cart, and guild storage are 1637 each without changing this struct and struct item [2014/10/27]
+	union { // Max for inventory, storage, cart, and guild storage are 818 each without changing this struct and struct item [2016/08/14]
 		struct item items_inventory[MAX_INVENTORY];
 		struct item items_storage[MAX_STORAGE];
 		struct item items_cart[MAX_CART];
@@ -518,7 +524,7 @@ struct mmo_charstatus {
 
 	struct s_friend friends[MAX_FRIENDS]; //New friend system [Skotlex]
 #ifdef HOTKEY_SAVING
-	struct hotkey hotkeys[MAX_HOTKEYS];
+	struct hotkey hotkeys[MAX_HOTKEYS_DB];
 #endif
 	bool show_equip,allow_party;
 	short rename;
@@ -536,6 +542,7 @@ struct mmo_charstatus {
 	uint32 uniqueitem_counter;
 
 	unsigned char hotkey_rowshift;
+	unsigned char hotkey_rowshift2;
 	unsigned long title_id;
 };
 
@@ -673,7 +680,7 @@ struct guild {
 	struct guild_expulsion expulsion[MAX_GUILDEXPULSION];
 	struct guild_skill skill[MAX_GUILDSKILL];
 	struct Channel *channel;
-	unsigned short instance_id;
+	int instance_id;
 	time_t last_leader_change;
 
 	/* Used by char-server to save events for guilds */
@@ -964,8 +971,7 @@ enum e_job {
 enum e_sex {
 	SEX_FEMALE = 0,
 	SEX_MALE,
-	SEX_SERVER,
-	SEX_ACCOUNT = 99
+	SEX_SERVER
 };
 
 /// Item Bound Type

+ 4 - 0
src/common/socket.cpp

@@ -428,6 +428,8 @@ int send_from_fifo(int fd)
 
 	if( len > 0 )
 	{
+		session[fd]->wdata_tick = last_tick;
+
 		// some data could not be transferred?
 		// shift unsent data to the beginning of the queue
 		if( (size_t)len < session[fd]->wdata_size )
@@ -587,6 +589,7 @@ int make_listen_bind(uint32 ip, uint16 port)
 	create_session(fd, connect_client, null_send, null_parse);
 	session[fd]->client_addr = 0; // just listens
 	session[fd]->rdata_tick = 0; // disable timeouts on this socket
+	session[fd]->wdata_tick = 0;
 
 	return fd;
 }
@@ -727,6 +730,7 @@ static int create_session(int fd, RecvFunc func_recv, SendFunc func_send, ParseF
 	session[fd]->func_send  = func_send;
 	session[fd]->func_parse = func_parse;
 	session[fd]->rdata_tick = last_tick;
+	session[fd]->wdata_tick = last_tick;
 	return 0;
 }
 

+ 1 - 0
src/common/socket.hpp

@@ -98,6 +98,7 @@ struct socket_data
 	size_t rdata_size, wdata_size;
 	size_t rdata_pos;
 	time_t rdata_tick; // time of last recv (for detecting timeouts); zero when timeout is disabled
+	time_t wdata_tick; // time of last send (for detecting timeouts);
 
 	RecvFunc func_recv;
 	SendFunc func_send;

+ 7 - 0
src/config/core.hpp

@@ -74,6 +74,13 @@
 // overflows, which is approximately every ~49 days.
 //#define DEPRECATED_WINDOWS_SUPPORT
 
+// Uncomment to enable compilation for unsupported compilers
+// Note:
+// Compilation might work on these compilers, but they might not fully follow newer C++ rules and
+// cause unexpected behavior.
+// Do NOT create any issues or ask for help with these compilers.
+//#define DEPRECATED_COMPILER_SUPPORT
+
 /**
  * No settings past this point
  **/

+ 18 - 1
src/config/packets.hpp

@@ -13,7 +13,7 @@
 	/// Do NOT edit this line! To set your client version, please do this instead:
 	/// In Windows: Add this line in your src\custom\defines_pre.hpp file: #define PACKETVER YYYYMMDD
 	/// In Linux: The same as above or run the following command: ./configure --enable-packetver=YYYYMMDD
-	#define PACKETVER 20180620
+	#define PACKETVER 20200401
 #endif
 
 #ifndef PACKETVER_RE
@@ -24,6 +24,23 @@
 	#endif
 #endif
 
+#ifndef PACKETVER_RE
+	#define PACKETVER_MAIN_NUM PACKETVER
+
+	// Undefine all sakray server definitions
+	#undef PACKETVER_RE
+	#undef PACKETVER_RE_NUM
+#else
+	// Undefine existing definition
+	#undef PACKETVER_RE
+
+	#define PACKETVER_RE PACKETVER
+	#define PACKETVER_RE_NUM PACKETVER
+
+	// Undefine all main server definitions
+	#undef PACKETVER_MAIN_NUM
+#endif
+
 #if PACKETVER >= 20110817
 	/// Comment to disable the official packet obfuscation support.
 	/// This requires PACKETVER 2011-08-17 or newer.

+ 1 - 1
src/login/account.cpp

@@ -81,7 +81,7 @@ AccountDB* account_db_sql(void) {
 	safestrncpy(db->db_hostname, "127.0.0.1", sizeof(db->db_hostname));
 	db->db_port = 3306;
 	safestrncpy(db->db_username, "ragnarok", sizeof(db->db_username));
-	safestrncpy(db->db_password, "ragnarok", sizeof(db->db_password));
+	safestrncpy(db->db_password, "", sizeof(db->db_password));
 	safestrncpy(db->db_database, "ragnarok", sizeof(db->db_database));
 	safestrncpy(db->codepage, "", sizeof(db->codepage));
 	// other settings

+ 18 - 0
src/login/loginclif.cpp

@@ -457,6 +457,20 @@ static int logclif_parse_reqcharconnec(int fd, struct login_session_data *sd, ch
 	return 1;
 }
 
+int logclif_parse_otp_login( int fd, struct login_session_data* sd ){
+	RFIFOSKIP( fd, 68 );
+
+	WFIFOHEAD( fd, 34 );
+	WFIFOW( fd, 0 ) = 0xae3;
+	WFIFOW( fd, 2 ) = 34;
+	WFIFOL( fd, 4 ) = 0; // normal login
+	safestrncpy( WFIFOCP( fd, 8 ), "S1000", 6 );
+	safestrncpy( WFIFOCP( fd, 28 ), "token", 6 );
+	WFIFOSET( fd, 34 );
+
+	return 1;
+}
+
 /**
  * Entry point from client to log-server.
  * Function that checks incoming command, then splits it to the correct handler.
@@ -521,6 +535,10 @@ int logclif_parse(int fd) {
 			break;
 		// Sending request of the coding key
 		case 0x01db: next = logclif_parse_reqkey(fd, sd); break;
+		// OTP token login
+		case 0x0acf:
+			next = logclif_parse_otp_login( fd, sd );
+			break;
 		// Connection request of a char-server
 		case 0x2710: logclif_parse_reqcharconnec(fd,sd, ip); return 0; // processing will continue elsewhere
 		default:

+ 28 - 0
src/map/achievement.cpp

@@ -1040,6 +1040,34 @@ void achievement_update_objective(struct map_session_data *sd, enum e_achievemen
 	}
 }
 
+/**
+ * Map iterator subroutine to update achievement objectives for a party after killing a monster.
+ * @see map_foreachinrange
+ * @param ap: Argument list, expecting:
+ *   int Party ID
+ *   int Mob ID
+ */
+int achievement_update_objective_sub(block_list *bl, va_list ap)
+{
+	map_session_data *sd;
+	int mob_id, party_id;
+
+	nullpo_ret(bl);
+	nullpo_ret(sd = (map_session_data *)bl);
+
+	party_id = va_arg(ap, int);
+	mob_id = va_arg(ap, int);
+
+	if (sd->achievement_data.achievements == nullptr)
+		return 0;
+	if (sd->status.party_id != party_id)
+		return 0;
+
+	achievement_update_objective(sd, AG_BATTLE, 1, mob_id);
+
+	return 1;
+}
+
 /**
  * Loads achievements from the achievement db.
  */

+ 1 - 0
src/map/achievement.hpp

@@ -140,6 +140,7 @@ int *achievement_level(struct map_session_data *sd, bool flag);
 bool achievement_check_condition(struct script_code* condition, struct map_session_data* sd);
 void achievement_get_titles(uint32 char_id);
 void achievement_update_objective(struct map_session_data *sd, enum e_achievement_group group, uint8 arg_count, ...);
+int achievement_update_objective_sub(block_list *bl, va_list ap);
 void achievement_read_db(void);
 void achievement_db_reload(void);
 

+ 20 - 8
src/map/atcommand.cpp

@@ -4851,18 +4851,22 @@ ACMD_FUNC(servertime)
 			clif_displaymessage(fd, msg_txt(sd,232)); // Game time: The game is in permanent night.
 	} else if (battle_config.night_duration == 0)
 		if (night_flag == 1) { // we start with night
-			timer_data = get_timer(day_timer_tid);
-			sprintf(temp, msg_txt(sd,233), txt_time(DIFF_TICK(timer_data->tick,gettick())/1000)); // Game time: The game is in night for %s.
-			clif_displaymessage(fd, temp);
-			clif_displaymessage(fd, msg_txt(sd,234)); // Game time: After, the game will be in permanent daylight.
+			if ((timer_data = get_timer(day_timer_tid)) != nullptr) {
+				sprintf(temp, msg_txt(sd,233), txt_time(DIFF_TICK(timer_data->tick,gettick())/1000)); // Game time: The game is in night for %s.
+				clif_displaymessage(fd, temp);
+				clif_displaymessage(fd, msg_txt(sd,234)); // Game time: After, the game will be in permanent daylight.
+			} else
+				clif_displaymessage(fd, msg_txt(sd,232)); // Game time: The game is in permanent night.
 		} else
 			clif_displaymessage(fd, msg_txt(sd,231)); // Game time: The game is in permanent daylight.
 	else if (battle_config.day_duration == 0)
 		if (night_flag == 0) { // we start with day
-			timer_data = get_timer(night_timer_tid);
-			sprintf(temp, msg_txt(sd,235), txt_time(DIFF_TICK(timer_data->tick,gettick())/1000)); // Game time: The game is in daylight for %s.
-			clif_displaymessage(fd, temp);
-			clif_displaymessage(fd, msg_txt(sd,236)); // Game time: After, the game will be in permanent night.
+			if ((timer_data = get_timer(night_timer_tid)) != nullptr) {
+				sprintf(temp, msg_txt(sd,235), txt_time(DIFF_TICK(timer_data->tick,gettick())/1000)); // Game time: The game is in daylight for %s.
+				clif_displaymessage(fd, temp);
+				clif_displaymessage(fd, msg_txt(sd,236)); // Game time: After, the game will be in permanent night.
+			} else
+				clif_displaymessage(fd, msg_txt(sd,231)); // Game time: The game is in permanent daylight.
 		} else
 			clif_displaymessage(fd, msg_txt(sd,232)); // Game time: The game is in permanent night.
 	else {
@@ -5835,6 +5839,14 @@ ACMD_FUNC(useskill)
 		return -1;
 	}
 
+	if (!skill_id || !skill_db.find(skill_id)) {
+		clif_displaymessage(fd, msg_txt(sd, 198)); // This skill number doesn't exist.
+		return -1;
+	}
+
+	if (!skill_lv)
+		skill_lv = 1;
+
 	if(!strcmp(atcmd_player_name,"self"))
 		pl_sd = sd; //quick keyword
 	else if ( (pl_sd = map_nick2sd(atcmd_player_name,true)) == NULL ){

+ 243 - 188
src/map/battle.cpp

@@ -852,6 +852,8 @@ int battle_calc_cardfix(int attack_type, struct block_list *src, struct block_li
 					}
 				}
 #ifndef RENEWAL
+				if (flag & BF_SHORT)
+					cardfix = cardfix * (100 + sd->bonus.short_attack_atk_rate) / 100;
 				if( flag&BF_LONG )
 					cardfix = cardfix * (100 + sd->bonus.long_attack_atk_rate) / 100;
 #endif
@@ -1171,7 +1173,7 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam
 
 		if( sc->data[SC_WEAPONBLOCKING] && flag&(BF_SHORT|BF_WEAPON) && rnd()%100 < sc->data[SC_WEAPONBLOCKING]->val2 ) {
 			clif_skill_nodamage(bl,src,GC_WEAPONBLOCKING,sc->data[SC_WEAPONBLOCKING]->val1,1);
-			sc_start(src, bl, SC_WEAPONBLOCK_ON, 100, 0, skill_get_time2(GC_WEAPONBLOCKING, 1));
+			sc_start(src, bl, SC_WEAPONBLOCK_ON, 100, src->id, skill_get_time2(GC_WEAPONBLOCKING, 1));
 			d->dmg_lv = ATK_BLOCK;
 			return 0;
 		}
@@ -1340,6 +1342,11 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam
 				status_change_end(bl,SC_VOICEOFSIREN,INVALID_TIMER);
 		}
 
+		if (sc->data[SC_SOUNDOFDESTRUCTION])
+			damage <<= 1;
+		if (sc->data[SC_DARKCROW] && (flag&(BF_SHORT|BF_MAGIC)) == BF_SHORT)
+			damage += damage * sc->data[SC_DARKCROW]->val2 / 100;
+
 		// Damage reductions
 		// Assumptio increases DEF on RE mode, otherwise gives a reduction on the final damage. [Igniz]
 #ifndef RENEWAL
@@ -1351,13 +1358,7 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam
 		}
 #endif
 
-		if (sc->data[SC_DEFENDER] &&
-			skill_id != NJ_ZENYNAGE && skill_id != KO_MUCHANAGE &&
-#ifdef RENEWAL
-			((flag&(BF_LONG|BF_WEAPON)) == (BF_LONG|BF_WEAPON) || skill_id == GN_FIRE_EXPANSION_ACID))
-#else
-			(flag&(BF_LONG|BF_WEAPON)) == (BF_LONG|BF_WEAPON))
-#endif
+		if (sc->data[SC_DEFENDER] && skill_id != NJ_ZENYNAGE && skill_id != KO_MUCHANAGE && (flag&(BF_LONG|BF_WEAPON)) == (BF_LONG|BF_WEAPON))
 			damage -= damage * sc->data[SC_DEFENDER]->val2 / 100;
 
 		if(sc->data[SC_ADJUSTMENT] && (flag&(BF_LONG|BF_WEAPON)) == (BF_LONG|BF_WEAPON))
@@ -1441,9 +1442,6 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam
 			damage = i64max(damage, 1);
 		}
 
-		if( sc->data[SC_DARKCROW] && (flag&(BF_SHORT|BF_MAGIC)) == BF_SHORT )
-			damage += damage * sc->data[SC_DARKCROW]->val2 / 100;
-
 		if( (sce=sc->data[SC_MAGMA_FLOW]) && (rnd()%100 <= sce->val2) )
 			skill_castend_damage_id(bl,src,MH_MAGMA_FLOW,sce->val1,gettick(),0);
 
@@ -1612,10 +1610,11 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam
 			status_change_end(src,SC_SHIELDSPELL_REF,INVALID_TIMER);
 		}
 
-		if( sc->data[SC_POISONINGWEAPON]
-			&& ((flag&BF_WEAPON) && (!skill_id || skill_id == GC_VENOMPRESSURE)) //check skill type poison_smoke is a unit
-			&& (damage > 0 && rnd()%100 < sc->data[SC_POISONINGWEAPON]->val3 )) //did some damage and chance ok (why no additional effect ??)
-			sc_start2(src,bl,(enum sc_type)sc->data[SC_POISONINGWEAPON]->val2,100,sc->data[SC_POISONINGWEAPON]->val1,sc->data[SC_POISONINGWEAPON]->val4,skill_get_time2(GC_POISONINGWEAPON, 1));
+		if (sc->data[SC_POISONINGWEAPON] && flag&BF_SHORT && (skill_id == 0 || skill_id == GC_VENOMPRESSURE) && damage > 0) {
+			damage += damage * 10 / 100;
+			if (rnd() % 100 < sc->data[SC_POISONINGWEAPON]->val3)
+				sc_start4(src, bl, (sc_type)sc->data[SC_POISONINGWEAPON]->val2, 100, sc->data[SC_POISONINGWEAPON]->val1, 0, 1, 0, skill_get_time2(GC_POISONINGWEAPON, 1));
+		}
 
 		if( sc->data[SC__DEADLYINFECT] && (flag&(BF_SHORT|BF_MAGIC)) == BF_SHORT && damage > 0 && rnd()%100 < 30 + 10 * sc->data[SC__DEADLYINFECT]->val1 )
 			status_change_spread(src, bl, 0);
@@ -1625,6 +1624,15 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam
 
 			if (hd && (rnd()%100<50) ) hom_addspiritball(hd, 10); // According to WarpPortal, this is a flat 50% chance
 		}
+
+		if (flag & BF_WEAPON && (sce = sc->data[SC_ADD_ATK_DAMAGE]))
+			damage += damage * sce->val1 / 100;
+		if (flag & BF_MAGIC && (sce = sc->data[SC_ADD_MATK_DAMAGE]))
+			damage += damage * sce->val1 / 100;
+		if (sc->data[SC_DANCEWITHWUG] && (flag&(BF_LONG|BF_WEAPON)) == (BF_LONG|BF_WEAPON))
+			damage += damage * sc->data[SC_DANCEWITHWUG]->val1 / 100;
+		if (sc->data[SC_UNLIMITEDHUMMINGVOICE] && flag&BF_MAGIC)
+			damage += damage * sc->data[SC_UNLIMITEDHUMMINGVOICE]->val3 / 100;
 	} //End of caster SC_ check
 
 	if (tsc && tsc->count) {
@@ -1899,6 +1907,15 @@ int64 battle_addmastery(struct map_session_data *sd,struct block_list *target,in
 		damage += (skill * 2);
 #endif
 
+	// Kagerou/Oboro Spirit Charm bonus
+	if (sd->spiritcharm >= MAX_SPIRITCHARM) {
+		if ((sd->spiritcharm_type == CHARM_TYPE_FIRE && status->def_ele == ELE_EARTH) ||
+			(sd->spiritcharm_type == CHARM_TYPE_WATER && status->def_ele == ELE_FIRE) ||
+			(sd->spiritcharm_type == CHARM_TYPE_LAND && status->def_ele == ELE_WIND) ||
+			(sd->spiritcharm_type == CHARM_TYPE_WIND && status->def_ele == ELE_WATER))
+			damage += damage * 30 / 100;
+	}
+
 	if(type == 0)
 		weapon = sd->weapontype1;
 	else
@@ -2222,6 +2239,10 @@ static int battle_range_type(struct block_list *src, struct block_list *target,
 	if (src->type == BL_MOB && (skill_id == AC_SHOWER || skill_id == AM_DEMONSTRATION))
 		return BF_SHORT;
 
+	// Cast range is 7 cells and player jumps to target but skill is considered melee
+	if (skill_id == GC_CROSSIMPACT)
+		return BF_SHORT;
+
 	//Skill Range Criteria
 	if (battle_config.skillrange_by_distance &&
 		(src->type&battle_config.skillrange_by_distance)
@@ -2385,7 +2406,7 @@ bool is_infinite_defense(struct block_list *target, int flag)
 	if(target->type == BL_SKILL) {
 		TBL_SKILL *su = ((TBL_SKILL*)target);
 
-		if (su && su->group && (su->group->skill_id == WM_REVERBERATION || su->group->skill_id == NPC_REVERBERATION || su->group->skill_id == WM_POEMOFNETHERWORLD))
+		if (su && su->group && (su->group->skill_id == NPC_REVERBERATION || su->group->skill_id == WM_POEMOFNETHERWORLD))
 			return true;
 	}
 
@@ -2553,6 +2574,13 @@ static bool is_attack_critical(struct Damage* wd, struct block_list *src, struct
 			case NJ_KIRIKAGE:
 				cri += 250 + 50*skill_lv;
 				break;
+#ifdef RENEWAL
+			case ASC_BREAKER:
+#endif
+			case RK_IGNITIONBREAK:
+			case GC_CROSSIMPACT:
+				cri /= 2;
+				break;
 		}
 		if(tsd && tsd->bonus.critical_def)
 			cri = cri * ( 100 - tsd->bonus.critical_def ) / 100;
@@ -2577,13 +2605,12 @@ static int is_attack_piercing(struct Damage* wd, struct block_list *src, struct
 	if(src != NULL) {
 		struct map_session_data *sd = BL_CAST(BL_PC, src);
 		struct status_data *tstatus = status_get_status_data(target);
-#ifdef RENEWAL
-		if( skill_id != PA_SACRIFICE && skill_id != CR_GRANDCROSS && skill_id != NPC_GRANDDARKNESS
-			&& skill_id != PA_SHIELDCHAIN && skill_id != KO_HAPPOKUNAI && skill_id != ASC_BREAKER ) // Renewal: Soul Breaker no longer gains ice pick effect and ice pick effect gets crit benefit [helvetica]
-#else
-		if( skill_id != PA_SACRIFICE && skill_id != CR_GRANDCROSS && skill_id != NPC_GRANDDARKNESS
-			&& skill_id != PA_SHIELDCHAIN && skill_id != KO_HAPPOKUNAI && !is_attack_critical(wd, src, target, skill_id, skill_lv, false) )
+
+		if( skill_id != PA_SACRIFICE && skill_id != CR_GRANDCROSS && skill_id != NPC_GRANDDARKNESS && skill_id != PA_SHIELDCHAIN && skill_id != KO_HAPPOKUNAI
+#ifndef RENEWAL
+			&& !is_attack_critical(wd, src, target, skill_id, skill_lv, false)
 #endif
+		)
 		{ //Elemental/Racial adjustments
 			if( sd && (sd->right_weapon.def_ratio_atk_ele & (1<<tstatus->def_ele) || sd->right_weapon.def_ratio_atk_ele & (1<<ELE_ALL) ||
 				sd->right_weapon.def_ratio_atk_race & (1<<tstatus->race) || sd->right_weapon.def_ratio_atk_race & (1<<RC_ALL) ||
@@ -2823,11 +2850,7 @@ static bool attack_ignores_def(struct Damage* wd, struct block_list *src, struct
 #endif
 	if (sc && sc->data[SC_FUSION])
 		return true;
-#ifdef RENEWAL
-	else if (skill_id != CR_GRANDCROSS && skill_id != NPC_GRANDDARKNESS && skill_id != ASC_BREAKER) // Renewal: Soul Breaker no longer gains ignore DEF from weapon [helvetica]
-#else
 	else if (skill_id != CR_GRANDCROSS && skill_id != NPC_GRANDDARKNESS)
-#endif
 	{	//Ignore Defense?
 		if (sd && (sd->right_weapon.ignore_def_ele & (1<<tstatus->def_ele) || sd->right_weapon.ignore_def_ele & (1<<ELE_ALL) ||
 			sd->right_weapon.ignore_def_race & (1<<tstatus->race) || sd->right_weapon.ignore_def_race & (1<<RC_ALL) ||
@@ -2845,7 +2868,8 @@ static bool attack_ignores_def(struct Damage* wd, struct block_list *src, struct
 			} else if (weapon_position == EQI_HAND_L)
 				return true;
 		}
-	}
+	} else if (skill_id == RK_WINDCUTTER && sd && sd->status.weapon == W_2HSWORD)
+		return true;
 
 	return nk[NK_IGNOREDEFENSE] != 0;
 }
@@ -2937,6 +2961,22 @@ static int battle_get_weapon_element(struct Damage* wd, struct block_list *src,
 			if (!sd)
 				element = ELE_NEUTRAL; //forced neutral for monsters
 			break;
+		case RK_DRAGONBREATH:
+			if (sc) {
+				if (sc->data[SC_LUXANIMA]) // Lux Anima has priority over Giant Growth
+					element = ELE_DARK;
+				else if (sc->data[SC_GIANTGROWTH])
+					element = ELE_HOLY;
+			}
+			break;
+		case RK_DRAGONBREATH_WATER:
+			if (sc) {
+				if (sc->data[SC_LUXANIMA]) // Lux Anima has priority over Fighting Spirit
+					element = ELE_NEUTRAL;
+				else if (sc->data[SC_FIGHTINGSPIRIT])
+					element = ELE_GHOST;
+			}
+			break;
 		case LG_HESPERUSLIT:
 			if (sc && sc->data[SC_BANDING] && sc->data[SC_BANDING]->val2 > 4)
 				element = ELE_HOLY;
@@ -3103,6 +3143,13 @@ static void battle_calc_attack_masteries(struct Damage* wd, struct block_list *s
 #endif
 		}
 
+		if (skill_id == NV_BREAKTHROUGH) {
+			ATK_ADD(wd->damage, wd->damage2, 15 * skill_lv + (skill_lv > 4 ? 25 : 0));
+#ifdef RENEWAL
+			ATK_ADD(wd->masteryAtk, wd->masteryAtk2, 15 * skill_lv + (skill_lv > 4 ? 25 : 0));
+#endif
+		}
+
 		switch(skill_id) {
 			case RA_WUGDASH:
 			case RA_WUGSTRIKE:
@@ -3337,6 +3384,8 @@ static void battle_calc_skill_base_damage(struct Damage* wd, struct block_list *
 #endif
 					sstatus->batk + sstatus->rhw.atk + (index >= 0 && sd->inventory_data[index] ?
 						sd->inventory_data[index]->atk : 0)) * (skill_lv + 5) / 5;
+				if (sc && sc->data[SC_KAGEMUSYA])
+					damagevalue += damagevalue * sc->data[SC_KAGEMUSYA]->val2 / 100;
 				ATK_ADD(wd->damage, wd->damage2, damagevalue);
 #ifdef RENEWAL
 				ATK_ADD(wd->weaponAtk, wd->weaponAtk2, damagevalue);
@@ -3470,7 +3519,11 @@ static void battle_calc_multi_attack(struct Damage* wd, struct block_list *src,s
 			if (sc && sc->data[SC_KAGEMUSYA])
 				max_rate = sc->data[SC_KAGEMUSYA]->val1 * 10; // Same rate as even levels of TF_DOUBLE
 			else
+#ifdef RENEWAL
+				max_rate = max(7 * skill_lv, sd->bonus.double_rate);
+#else
 				max_rate = max(5 * skill_lv, sd->bonus.double_rate);
+#endif
 
 			if( rnd()%100 < max_rate ) {
 				wd->div_ = skill_get_num(TF_DOUBLE,skill_lv?skill_lv:1);
@@ -3483,6 +3536,7 @@ static void battle_calc_multi_attack(struct Damage* wd, struct block_list *src,s
 		{
 			wd->div_ = skill_get_num(GS_CHAINACTION,skill_lv);
 			wd->type = DMG_MULTI_HIT;
+
 			sc_start(src,src,SC_QD_SHOT_READY,100,target->id,skill_get_time(RL_QD_SHOT,1));
 		}
 		else if(sc && sc->data[SC_FEARBREEZE] && sd->weapontype1==W_BOW
@@ -3504,6 +3558,10 @@ static void battle_calc_multi_attack(struct Damage* wd, struct block_list *src,s
 	}
 
 	switch (skill_id) {
+		case RK_WINDCUTTER:
+			if (sd && sd->weapontype1 == W_2HSWORD)
+				wd->div_ = 2;
+			break;
 		case RA_AIMEDBOLT:
 			wd->div_ = 2 + tstatus->size + rnd()%2;
 			break;
@@ -3768,7 +3826,7 @@ static int battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list *
 			break;
 		case MO_FINGEROFFENSIVE:
 #ifdef RENEWAL
-			skillratio += 500 + skill_lv * 2;
+			skillratio += 500 + skill_lv * 200;
 			if (tsc && tsc->data[SC_BLADESTOP])
 				skillratio += skillratio / 2;
 #else
@@ -3785,11 +3843,11 @@ static int battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list *
 #endif
 			break;
 		case MO_EXTREMITYFIST:
+			skillratio += 100 * (7 + sstatus->sp / 10);			
 #ifdef RENEWAL
 			if (wd->miscflag&1)
-				skillratio += 100; // More than 5 spirit balls active
+				skillratio *= 2; // More than 5 spirit balls active
 #endif
-			skillratio += 100 * (7 + sstatus->sp / 10);
 			skillratio = min(500000,skillratio); //We stop at roughly 50k SP for overflow protection
 			break;
 		case MO_TRIPLEATTACK:
@@ -3880,9 +3938,10 @@ static int battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list *
 			skillratio += 100 + 50 * skill_lv;
 #endif
 			break;
+		case GN_FIRE_EXPANSION_ACID:
 #ifdef RENEWAL
 		case CR_ACIDDEMONSTRATION:
-			skillratio += -100 + 200 * skill_lv + sstatus->int_ + sstatus->vit; // !TODO: Confirm status bonus
+			skillratio += -100 + 200 * skill_lv + sstatus->int_ + tstatus->vit; // !TODO: Confirm status bonus
 			if (target->type == BL_PC)
 				skillratio /= 2;
 			break;
@@ -3904,12 +3963,15 @@ static int battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list *
 			if(sd)
 				skillratio += 20 * pc_checkskill(sd,AS_POISONREACT);
 			break;
-#ifndef RENEWAL
-		// Pre-Renewal: skill ratio for weapon part of damage [helvetica]
 		case ASC_BREAKER:
+#ifdef RENEWAL
+			skillratio += -100 + 140 * skill_lv + sstatus->str + sstatus->int_; // !TODO: Confirm stat modifier
+			RE_LVL_DMOD(100);
+#else
+			// Pre-Renewal: skill ratio for weapon part of damage [helvetica]
 			skillratio += -100 + 100 * skill_lv;
-			break;
 #endif
+			break;
 		case PA_SACRIFICE:
 			skillratio += -10 + 10 * skill_lv;
 			break;
@@ -4025,6 +4087,9 @@ static int battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list *
 #endif
 			break;
 #ifdef RENEWAL
+		case NJ_SYURIKEN:
+			skillratio += 5 * skill_lv;
+			break;
 		case NJ_KUNAI:
 			skillratio += -100 + 100 * skill_lv;
 			break;
@@ -4054,50 +4119,42 @@ static int battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list *
 			skillratio += ((skill_lv - 1) % 5 + 1) * 100;
 			break;
 		case RK_SONICWAVE:
-			skillratio += -100 + (skill_lv + 7) * 100; // ATK = {((Skill Level + 7) x 100) x (1 + [(Caster's Base Level - 100) / 200])} %
-			skillratio = skillratio * (100 + (status_get_lv(src) - 100) / 2) / 100;
+			skillratio += -100 + 500 + 100 * skill_lv;
+			RE_LVL_DMOD(100);
 			break;
 		case RK_HUNDREDSPEAR:
-			skillratio += 500 + (80 * skill_lv);
-			if (sd) {
-				short index = sd->equip_index[EQI_HAND_R];
-
-				if (index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == IT_WEAPON)
-					skillratio += max(10000 - sd->inventory_data[index]->weight, 0) / 10;
+			skillratio += -100 + 600 + 200 * skill_lv;
+			if (sd)
 				skillratio += 50 * pc_checkskill(sd,LK_SPIRALPIERCE);
-			} // (1 + [(Casters Base Level - 100) / 200])
-			skillratio = skillratio * (100 + (status_get_lv(src) - 100) / 2) / 100;
+			RE_LVL_DMOD(100);
 			break;
 		case RK_WINDCUTTER:
-			skillratio += -100 + (skill_lv + 2) * 50;
+			if (sd) {
+				if (sd->weapontype1 == W_2HSWORD)
+					skillratio += -100 + 250 * skill_lv;
+				else if (sd->weapontype1 == W_1HSPEAR || sd->weapontype1 == W_2HSPEAR)
+					skillratio += -100 + 400 * skill_lv;
+				else
+					skillratio += -100 + 300 * skill_lv;
+			} else
+				skillratio += -100 + 300 * skill_lv;
 			RE_LVL_DMOD(100);
 			break;
 		case RK_IGNITIONBREAK:
-			// 3x3 cell Damage = ATK [{(Skill Level x 300) x (1 + [(Caster's Base Level - 100) / 100])}] %
-			// 7x7 cell Damage = ATK [{(Skill Level x 250) x (1 + [(Caster's Base Level - 100) / 100])}] %
-			// 11x11 cell Damage = ATK [{(Skill Level x 200) x (1 + [(Caster's Base Level - 100) / 100])}] %
-			i = distance_bl(src,target);
-			if (i < 2)
-				skillratio += -100 + 300 * skill_lv;
-			else if (i < 4)
-				skillratio += -100 + 250 * skill_lv;
-			else
-				skillratio += -100 + 200 * skill_lv;
-			skillratio = skillratio * status_get_lv(src) / 100;
-			// Elemental check, 1.5x damage if your weapon element is fire.
-			if (sstatus->rhw.ele == ELE_FIRE)
-				skillratio += 100 * skill_lv;
+			skillratio += -100 + 400 * skill_lv;
+			RE_LVL_DMOD(100);
 			break;
 		case RK_STORMBLAST:
 			skillratio += -100 + (((sd) ? pc_checkskill(sd,RK_RUNEMASTERY) : 0) + status_get_str(src) / 8) * 100; // ATK = [{Rune Mastery Skill Level + (Caster's STR / 8)} x 100] %
+			RE_LVL_DMOD(100);
 			break;
 		case RK_PHANTOMTHRUST: // ATK = [{(Skill Level x 50) + (Spear Master Level x 10)} x Caster's Base Level / 150] %
 			skillratio += -100 + 50 * skill_lv + 10 * (sd ? pc_checkskill(sd,KN_SPEARMASTERY) : 5);
 			RE_LVL_DMOD(150); // Base level bonus.
 			break;
 		case GC_CROSSIMPACT:
-			skillratio += 900 + 100 * skill_lv;
-			RE_LVL_DMOD(120);
+			skillratio += -100 + 1000 + 150 * skill_lv;
+			RE_LVL_DMOD(100);
 			break;
 		case GC_COUNTERSLASH:
 			//ATK [{(Skill Level x 150) + 300} x Caster's Base Level / 120]% + ATK [(AGI x 2) + (Caster's Job Level x 4)]%
@@ -4111,14 +4168,14 @@ static int battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list *
 			skillratio += 200;
 			break;
 		case GC_ROLLINGCUTTER:
-			skillratio += -50 + 50 * skill_lv;
+			skillratio += -100 + 50 + 80 * skill_lv;
 			RE_LVL_DMOD(100);
 			break;
 		case GC_CROSSRIPPERSLASHER:
-			skillratio += 300 + 80 * skill_lv;
+			skillratio += -100 + 80 * skill_lv + (sstatus->agi * 3);
 			RE_LVL_DMOD(100);
 			if (sc && sc->data[SC_ROLLINGCUTTER])
-				skillratio += sc->data[SC_ROLLINGCUTTER]->val1 * status_get_agi(src);
+				skillratio += sc->data[SC_ROLLINGCUTTER]->val1 * 200;
 			break;
 		case GC_DARKCROW:
 			skillratio += 100 * (skill_lv - 1);
@@ -4386,11 +4443,6 @@ static int battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list *
 				skillratio += skillratio * 25 / 100;
 			RE_LVL_DMOD(100);
 			break;
-		case WM_REVERBERATION_MELEE:
-			// ATK [{(Skill Level x 100) + 300} x Caster Base Level / 100]
-			skillratio += 200 + 100 * ((sd) ? pc_checkskill(sd, WM_REVERBERATION) : 1);
-			RE_LVL_DMOD(100);
-			break;
 		case WM_SEVERE_RAINSTORM_MELEE:
 			//ATK [{(Caster DEX + AGI) x (Skill Level / 5)} x Caster Base Level / 100] %
 			skillratio = (status_get_dex(src) + status_get_agi(src)) * skill_lv / 5;
@@ -4399,13 +4451,11 @@ static int battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list *
 			RE_LVL_DMOD(100);
 			break;
 		case WM_GREAT_ECHO:
-			skillratio += 300 + 200 * skill_lv;
+			skillratio += -100 + 250 + 500 * skill_lv;
 			if (sd) {
-				int chorusbonus = battle_calc_chorusbonus(sd);
-
-				// Chorus bonus don't count the first 2 Minstrels/Wanderers and only increases when their are 3 or more. [Rytech]
-				if (chorusbonus >= 1 && chorusbonus <= 5)
-					skillratio += 100<<(chorusbonus-1); // 1->100; 2->200; 3->400; 4->800; 5->1600
+				skillratio += pc_checkskill(sd, WM_LESSON) * 50; // !TODO: Confirm bonus
+				if (skill_check_pc_partner(sd, skill_id, &skill_lv, AREA_SIZE, 0) > 0)
+					skillratio <<= 1;
 			}
 			RE_LVL_DMOD(100);
 			break;
@@ -4421,9 +4471,9 @@ static int battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list *
 			RE_LVL_DMOD(100);
 			break;
 		case GN_SPORE_EXPLOSION:
-			if (wd->miscflag & 2048)
-				skillratio += 200; // Target
-			skillratio += -100 + 180 * skill_lv + sstatus->int_;
+			skillratio += -100 + 180 * skill_lv;
+			if (wd->miscflag & 8)
+				skillratio += 200 + sstatus->int_; // Target receives extra damage
 			RE_LVL_DMOD(100);
 			break;
 		case GN_WALLOFTHORN:
@@ -4433,8 +4483,37 @@ static int battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list *
 			skillratio += -100 + 700 + 100 * skill_lv;
 			RE_LVL_DMOD(100);
 			break;
+		case GN_SLINGITEM_RANGEMELEEATK:
+			if( sd ) {
+				switch( sd->itemid ) {
+					case ITEMID_APPLE_BOMB:
+						skillratio += 200 + status_get_str(src) + status_get_dex(src);
+						break;
+					case ITEMID_COCONUT_BOMB:
+					case ITEMID_PINEAPPLE_BOMB:
+						skillratio += 700 + status_get_str(src) + status_get_dex(src);
+						break;
+					case ITEMID_MELON_BOMB:
+						skillratio += 400 + status_get_str(src) + status_get_dex(src);
+						break;
+					case ITEMID_BANANA_BOMB:
+						skillratio += 777 + status_get_str(src) + status_get_dex(src);
+						break;
+					case ITEMID_BLACK_LUMP:
+						skillratio += -100 + (status_get_str(src) + status_get_agi(src) + status_get_dex(src)) / 3;
+						break;
+					case ITEMID_BLACK_HARD_LUMP:
+						skillratio += -100 + (status_get_str(src) + status_get_agi(src) + status_get_dex(src)) / 2;
+						break;
+					case ITEMID_VERY_HARD_LUMP:
+						skillratio += -100 + status_get_str(src) + status_get_agi(src) + status_get_dex(src);
+						break;
+				}
+				RE_LVL_DMOD(100);
+			}
+			break;
 		case GN_HELLS_PLANT_ATK:
-			skillratio += -100 + 500 * skill_lv + sstatus->int_ * (10 - (sd ? pc_checkskill(sd, AM_CANNIBALIZE) : 0)); // !TODO: Confirm INT and Cannibalize bonus
+			skillratio += -100 + 100 * skill_lv + sstatus->int_ * (sd ? pc_checkskill(sd, AM_CANNIBALIZE) : 5); // !TODO: Confirm INT and Cannibalize bonus
 			RE_LVL_DMOD(100);
 			break;
 		// Physical Elemantal Spirits Attack Skills
@@ -4466,13 +4545,18 @@ static int battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list *
 			skillratio += 700;
 			break;
 		case KO_JYUMONJIKIRI:
-			skillratio += -100 + 150 * skill_lv;
+			skillratio += -100 + 200 * skill_lv;
 			RE_LVL_DMOD(120);
 			if(tsc && tsc->data[SC_JYUMONJIKIRI])
 				skillratio += skill_lv * status_get_lv(src);
+			if (sc && sc->data[SC_KAGEMUSYA])
+				skillratio += skillratio * sc->data[SC_KAGEMUSYA]->val2 / 100;
 			break;
 		case KO_HUUMARANKA:
-			skillratio += -100 + 150 * skill_lv + sstatus->agi + sstatus->dex + (sd ? pc_checkskill(sd,NJ_HUUMA) * 100 : 0);
+			skillratio += -100 + 150 * skill_lv + sstatus->str + (sd ? pc_checkskill(sd,NJ_HUUMA) * 100 : 0);
+			RE_LVL_DMOD(100);
+			if (sc && sc->data[SC_KAGEMUSYA])
+				skillratio += skillratio * sc->data[SC_KAGEMUSYA]->val2 / 100;
 			break;
 		case KO_SETSUDAN:
 			skillratio += 100 * (skill_lv - 1);
@@ -4488,6 +4572,8 @@ static int battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list *
 			skillratio += -100 + (sd ? pc_checkskill(sd,NJ_TOBIDOUGU) : 1) * (50 + sstatus->dex / 4) * skill_lv * 4 / 10;
 			RE_LVL_DMOD(120);
 			skillratio += 10 * (sd ? sd->status.job_level : 1);
+			if (sc && sc->data[SC_KAGEMUSYA])
+				skillratio += skillratio * sc->data[SC_KAGEMUSYA]->val2 / 100;
 			break;
 		case KO_MAKIBISHI:
 			skillratio += -100 + 20 * skill_lv;
@@ -4658,10 +4744,10 @@ static int64 battle_calc_skill_constant_addition(struct Damage* wd, struct block
 			else
 				atk = sstatus->matk_min;
 			break;
-#endif
 		case NJ_SYURIKEN:
 			atk = 4 * skill_lv;
 			break;
+#endif
 #ifdef RENEWAL
 		case HT_FREEZINGTRAP:
 			if(sd)
@@ -4782,10 +4868,6 @@ static void battle_attack_sc_bonus(struct Damage* wd, struct block_list *src, st
 #endif
 			}
 		}
-		if (sc->data[SC_GLOOMYDAY_SK] && skill_get_inf2(skill_id, INF2_INCREASEGLOOMYDAYDAMAGE)) {
-			ATK_ADDRATE(wd->damage, wd->damage2, sc->data[SC_GLOOMYDAY_SK]->val2);
-			RE_ALLATK_ADDRATE(wd, sc->data[SC_GLOOMYDAY_SK]->val2);
-		}
 		if (sc->data[SC_DANCEWITHWUG]) {
 			if (skill_get_inf2(skill_id, INF2_INCREASEDANCEWITHWUGDAMAGE)) {
 				ATK_ADDRATE(wd->damage, wd->damage2, sc->data[SC_DANCEWITHWUG]->val1 * 10 * battle_calc_chorusbonus(sd));
@@ -4852,17 +4934,19 @@ static void battle_attack_sc_bonus(struct Damage* wd, struct block_list *src, st
 			RE_ALLATK_ADDRATE(wd, sc->data[SC_GVG_GIANT]->val3);
 		}
 
+		if (sc->data[SC_PYREXIA] && sc->data[SC_PYREXIA]->val3 == 0) {
+			ATK_ADDRATE(wd->damage, wd->damage2, sc->data[SC_PYREXIA]->val2);
+			RE_ALLATK_ADDRATE(wd, sc->data[SC_PYREXIA]->val2);
+		}
+
 		if (sc->data[SC_MIRACLE])
 			anger_id = 2; // Always treat all monsters as star flagged monster when in miracle state
 	}
 
 	if ((wd->flag&(BF_LONG|BF_MAGIC)) == BF_LONG) {
-		if (sd && pc_checkskill(sd, SU_POWEROFLIFE) > 0) {
-			if ((pc_checkskill(sd, SU_SCAROFTAROU) + pc_checkskill(sd, SU_PICKYPECK) + pc_checkskill(sd, SU_ARCLOUSEDASH) + pc_checkskill(sd, SU_LUNATICCARROTBEAT) +
-				pc_checkskill(sd, SU_HISS) + pc_checkskill(sd, SU_POWEROFFLOCK) + pc_checkskill(sd, SU_SVG_SPIRIT)) > 19) {
-					ATK_ADDRATE(wd->damage, wd->damage2, 20);
-					RE_ALLATK_ADDRATE(wd, 20);
-			}
+		if (sd && pc_checkskill(sd, SU_POWEROFLIFE) > 0 && pc_checkskill_summoner(sd, SUMMONER_POWER_LIFE) >= 20) {
+			ATK_ADDRATE(wd->damage, wd->damage2, 20);
+			RE_ALLATK_ADDRATE(wd, 20);
 		}
 	}
 
@@ -5452,8 +5536,12 @@ static struct Damage initialize_weapon_data(struct block_list *src, struct block
 			}
 				break;
 			case MO_FINGEROFFENSIVE:
-				if (sd)
-					wd.div_ = (battle_config.finger_offensive_type)?1:sd->spiritball_old;
+				if (sd) {
+					if (battle_config.finger_offensive_type)
+						wd.div_ = 1;
+					else if ((sd->spiritball + sd->spiritball_old) < wd.div_)
+						wd.div_ = sd->spiritball + sd->spiritball_old;
+				}
 				break;
 
 			case KN_PIERCE:
@@ -5492,6 +5580,9 @@ static struct Damage initialize_weapon_data(struct block_list *src, struct block
 			case LK_SPIRALPIERCE:
 				if (!sd) wd.flag = (wd.flag&~(BF_RANGEMASK|BF_WEAPONMASK))|BF_LONG|BF_MISC;
 				break;
+			case RK_WINDCUTTER:
+				if (sd && (sd->status.weapon == W_1HSPEAR || sd->status.weapon == W_2HSPEAR))
+					wd.flag |= BF_LONG;
 
 			// The number of hits is set to 3 by default for use in Inspiration status.
 			// When in Banding, the number of hits is equal to the number of Royal Guards in Banding.
@@ -5537,7 +5628,10 @@ void battle_do_reflect(int attack_type, struct Damage *wd, struct block_list* sr
 			rdamage = battle_calc_return_damage(target, src, &damage, wd->flag, skill_id,true);
 		if( rdamage > 0 ) {
 			struct block_list *d_bl = battle_check_devotion(src);
+			status_change *sc = status_get_sc(src);
 
+			if (sc && sc->data[SC_VITALITYACTIVATION])
+				rdamage /= 2;
 			if (tsc->data[SC_MAXPAIN]) {
 				tsc->data[SC_MAXPAIN]->val2 = (int)rdamage;
 				skill_castend_damage_id(target, src, NPC_MAXPAIN_ATK, tsc->data[SC_MAXPAIN]->val1, tick, wd->flag);
@@ -5673,6 +5767,8 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src, struct bl
 		if (sd) { //monsters, homuns and pets have their damage computed directly
 			wd.damage = wd.statusAtk + wd.weaponAtk + wd.equipAtk + wd.masteryAtk;
 			wd.damage2 = wd.statusAtk2 + wd.weaponAtk2 + wd.equipAtk2 + wd.masteryAtk2;
+			if (wd.flag & BF_SHORT)
+				ATK_ADDRATE(wd.damage, wd.damage2, sd->bonus.short_attack_atk_rate);
 			if(wd.flag&BF_LONG && (skill_id != RA_WUGBITE && skill_id != RA_WUGSTRIKE)) //Long damage rate addition doesn't use weapon + equip attack
 				ATK_ADDRATE(wd.damage, wd.damage2, sd->bonus.long_attack_atk_rate);
 		}
@@ -5798,8 +5894,6 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src, struct bl
 #ifdef RENEWAL
 		switch(skill_id) {
 			case NJ_ISSEN:
-			case ASC_BREAKER:
-			case GN_FIRE_EXPANSION_ACID:
 				break; //These skills will do a card fix later
 			default:
 #endif
@@ -5820,7 +5914,6 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src, struct bl
 		case MC_CARTREVOLUTION:
 		case MO_INVESTIGATE:
 		case SR_GATEOFHELL:
-		case GN_FIRE_EXPANSION_ACID:
 		case KO_BAKURETSU:
 		//case NC_MAGMA_ERUPTION:
 			// Forced to neutral element
@@ -5879,8 +5972,6 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src, struct bl
 #ifdef RENEWAL
 	switch (skill_id) {
 		case NJ_ISSEN:
-		case ASC_BREAKER:
-		case GN_FIRE_EXPANSION_ACID:
 			return wd; //These skills will do a GVG fix later
 		default:
 #endif
@@ -5972,6 +6063,10 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list
 			if (mflag&ELE_DARK)
 				s_ele = ELE_DARK;
 			break;
+		case WM_REVERBERATION:
+			if (sd)
+				s_ele = sd->bonus.arrow_ele;
+			break;
 		case SO_PSYCHIC_WAVE:
 			if( sc && sc->count ) {
 				if( sc->data[SC_HEATER_OPTION] )
@@ -6063,6 +6158,9 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list
 #endif
 				}
 				break;
+			case NPC_DARKBREATH:
+				ad.damage = tstatus->hp * (skill_lv <= 5 ? 100 / (2 * 6 - skill_lv) : 50) / 100;
+				break;
 			case PF_SOULBURN:
 				ad.damage = tstatus->sp * 2;
 				break;
@@ -6185,17 +6283,17 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list
 					case NJ_KOUENKA:
 						skillratio -= 10;
 						if(sd && sd->spiritcharm_type == CHARM_TYPE_FIRE && sd->spiritcharm > 0)
-							skillratio += 20 * sd->spiritcharm;
+							skillratio += 10 * sd->spiritcharm;
 						break;
 					case NJ_KAENSIN:
 						skillratio -= 50;
 						if(sd && sd->spiritcharm_type == CHARM_TYPE_FIRE && sd->spiritcharm > 0)
-							skillratio += 10 * sd->spiritcharm;
+							skillratio += 20 * sd->spiritcharm;
 						break;
 					case NJ_BAKUENRYU:
 						skillratio += 50 + 150 * skill_lv;
 						if(sd && sd->spiritcharm_type == CHARM_TYPE_FIRE && sd->spiritcharm > 0)
-							skillratio += 15 * sd->spiritcharm;
+							skillratio += 100 * sd->spiritcharm;
 						break;
 					case NJ_HYOUSENSOU:
 #ifdef RENEWAL
@@ -6204,12 +6302,12 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list
 							skillratio += 2 * skill_lv;
 #endif
 						if(sd && sd->spiritcharm_type == CHARM_TYPE_WATER && sd->spiritcharm > 0)
-							skillratio += 5 * sd->spiritcharm;
+							skillratio += 20 * sd->spiritcharm;
 						break;
 					case NJ_HYOUSYOURAKU:
 						skillratio += 50 * skill_lv;
 						if(sd && sd->spiritcharm_type == CHARM_TYPE_WATER && sd->spiritcharm > 0)
-							skillratio += 25 * sd->spiritcharm;
+							skillratio += 100 * sd->spiritcharm;
 						break;
 					case NJ_RAIGEKISAI:
 #ifdef RENEWAL
@@ -6218,12 +6316,12 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list
 						skillratio += 60 + 40 * skill_lv;
 #endif
 						if(sd && sd->spiritcharm_type == CHARM_TYPE_WIND && sd->spiritcharm > 0)
-							skillratio += 15 * sd->spiritcharm;
+							skillratio += 20 * sd->spiritcharm;
 						break;
 					case NJ_KAMAITACHI:
 						skillratio += 100 * skill_lv;
 						if(sd && sd->spiritcharm_type == CHARM_TYPE_WIND && sd->spiritcharm > 0)
-							skillratio += 10 * sd->spiritcharm;
+							skillratio += 100 * sd->spiritcharm;
 						break;
 					case NJ_HUUJIN:
 #ifdef RENEWAL
@@ -6387,11 +6485,13 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list
 						break;
 					case WM_METALICSOUND:
 						skillratio += -100 + 120 * skill_lv + 60 * ((sd) ? pc_checkskill(sd, WM_LESSON) : 1);
+						if (tsc && tsc->data[SC_SLEEP])
+							skillratio += 100; // !TODO: Confirm target sleeping bonus
 						RE_LVL_DMOD(100);
 						break;
-					case WM_REVERBERATION_MAGIC:
-						// MATK [{(Skill Level x 100) + 100} x Casters Base Level / 100] %
-						skillratio += 100 * skill_lv;
+					case WM_REVERBERATION:
+						// MATK [{(Skill Level x 300) + 400} x Casters Base Level / 100] %
+						skillratio += -100 + 700 + 300 * skill_lv;
 						RE_LVL_DMOD(100);
 						break;
 					case SO_FIREWALK:
@@ -6538,13 +6638,7 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list
 			}
 		}
 #ifdef RENEWAL
-		switch(skill_id) { // These skills will do a card fix later
-			case ASC_BREAKER:
-				break;
-			default:
-				ad.damage += battle_calc_cardfix(BF_MAGIC, src, target, nk, s_ele, 0, ad.damage, 0, ad.flag);
-				break;
-		}
+		ad.damage += battle_calc_cardfix(BF_MAGIC, src, target, nk, s_ele, 0, ad.damage, 0, ad.flag);
 #endif
 
 		if(sd) {
@@ -6640,7 +6734,7 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list
 			}
 		}
 
-		if (!nk[NK_IGNOREELEMENT] && skill_id != ASC_BREAKER) // Soul Breaker's magic portion is non-elemental. [Secret]
+		if (!nk[NK_IGNOREELEMENT])
 			ad.damage = battle_attr_fix(src, target, ad.damage, s_ele, tstatus->def_ele, tstatus->ele_lv);
 
 		//Apply the physical part of the skill's damage. [Skotlex]
@@ -6673,13 +6767,6 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list
 	//Apply DAMAGE_DIV_FIX and check for min damage
 	battle_apply_div_fix(&ad, skill_id);
 
-#ifdef RENEWAL
-	switch(skill_id) {
-		case ASC_BREAKER:
-			return ad; //These skills will do a GVG fix later
-	}
-#endif
-
 	struct map_data *mapdata = map_getmapdata(target->m);
 
 	ad.damage = battle_calc_damage(src,target,&ad,ad.damage,skill_id,skill_lv);
@@ -6817,41 +6904,15 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list *
 		case NPC_SMOKING:
 			md.damage = 3;
 			break;
-		case NPC_DARKBREATH:
-			md.damage = tstatus->max_hp * skill_lv * 10 / 100;
-			break;
 		case NPC_EVILLAND:
 			md.damage = skill_calc_heal(src,target,skill_id,skill_lv,false);
 			break;
+#ifndef RENEWAL
 		case ASC_BREAKER:
-#ifdef RENEWAL
-			// Official Renewal formula [helvetica]
-			// damage = ((atk + matk) * (3 + (.5 * skill level))) - (edef + sdef + emdef + smdef)
-			// atk part takes weapon element, matk part is non-elemental
-			// modified def formula
-			{
-				short totaldef, totalmdef;
-				struct Damage atk, matk;
-
-				atk = battle_calc_weapon_attack(src, target, skill_id, skill_lv, 0);
-				nk.set(NK_IGNOREELEMENT); // atk part takes on weapon element, matk part is non-elemental
-				matk = battle_calc_magic_attack(src, target, skill_id, skill_lv, 0);
-
-				// (atk + matk) * (3 + (.5 * skill level))
-				md.damage = ((30 + (5 * skill_lv)) * (atk.damage + matk.damage)) / 10;
-
-				// modified def reduction, final damage = base damage - (edef + sdef + emdef + smdef)
-				totaldef = tstatus->def2 + (short)status_get_def(target);
-				totalmdef = tstatus->mdef + tstatus->mdef2;
-				md.damage -= totaldef + totalmdef;
-			}
-#else
 			md.damage = 500 + rnd()%500 + 5 * skill_lv * sstatus->int_;
 			nk.set(NK_IGNOREFLEE);
 			nk.set(NK_IGNOREELEMENT); //These two are not properties of the weapon based part.
-#endif
 			break;
-#ifndef RENEWAL
 		case HW_GRAVITATION:
 			md.damage = 200 + 200 * skill_lv;
 			md.dmotion = 0; //No flinch animation
@@ -6875,30 +6936,15 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list *
 					md.damage = 0;
 			}
 			break;
-		case GN_FIRE_EXPANSION_ACID:
-#ifdef RENEWAL
-			// Official Renewal formula [helvetica]
-			// damage = 7 * ((atk + matk)/skill level) * (target vit/100)
-			// skill is a "forced neutral" type skill, it benefits from weapon element but final damage
-			// 	is considered "neutral" for purposes of resistances
-			{
-				struct Damage atk = battle_calc_weapon_attack(src, target, skill_id, skill_lv, 0);
-				struct Damage matk = battle_calc_magic_attack(src, target, skill_id, skill_lv, 0);
-				md.damage = 7 * ((atk.damage/skill_lv + matk.damage/skill_lv) * tstatus->vit / 100 );
-
-				// AD benefits from endow/element but damage is forced back to neutral
-				md.damage = battle_attr_fix(src, target, md.damage, ELE_NEUTRAL, tstatus->def_ele, tstatus->ele_lv);
-			}
-			// Fall through
-#else
+#ifndef RENEWAL
 		case CR_ACIDDEMONSTRATION:
 			if(tstatus->vit+sstatus->int_) //crash fix
 				md.damage = (int)((int64)7*tstatus->vit*sstatus->int_*sstatus->int_ / (10*(tstatus->vit+sstatus->int_)));
 			else
 				md.damage = 0;
 			if (tsd) md.damage>>=1;
-#endif
 			break;
+#endif
 		case NJ_ZENYNAGE:
 		case KO_MUCHANAGE:
 				md.damage = skill_get_zeny(skill_id, skill_lv);
@@ -6962,10 +7008,6 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list *
 		case NC_MAGMA_ERUPTION_DOTDAMAGE: // 'Eruption' damage
 			md.damage = 800 + 200 * skill_lv;
 			break;
-		case WM_SOUND_OF_DESTRUCTION:
-			md.damage = 1000 * skill_lv + sstatus->int_ * ((sd) ? pc_checkskill(sd,WM_LESSON) : 1);
-			md.damage += md.damage * 10 * ((sd) ? battle_calc_chorusbonus(sd) / 100 : 0);
-			break;
 		case GN_THORNS_TRAP:
 			md.damage = 100 + 200 * skill_lv + status_get_int(src);
 			break;
@@ -7206,8 +7248,14 @@ int64 battle_calc_return_damage(struct block_list* bl, struct block_list *src, i
 	sc = status_get_sc(bl);
 	ssc = status_get_sc(src);
 
-	if (sc && sc->data[SC_WHITEIMPRISON])
-		return 0; // White Imprison does not reflect any damage
+	if (sc) { // These statuses do not reflect any damage (off the target)
+		if (sc->data[SC_WHITEIMPRISON] || sc->data[SC_DARKCROW] ||
+			(sc->data[SC_KYOMU] && (!ssc || !ssc->data[SC_SHIELDSPELL_DEF]))) // Nullify reflecting ability except for Shield Spell - Def
+				return 0;
+	}
+
+	if (ssc && (ssc->data[SC_REF_T_POTION] || ssc->data[SC_HELLS_PLANT]))
+		return 0;
 
 	if (flag & BF_SHORT) {//Bounces back part of the damage.
 		if ( (skill_get_inf2(skill_id, INF2_ISTRAP) || !status_reflect) && sd && sd->bonus.short_weapon_damage_return ) {
@@ -7272,20 +7320,22 @@ int64 battle_calc_return_damage(struct block_list* bl, struct block_list *src, i
 		}
 	}
 
-	if (ssc && ssc->data[SC_INSPIRATION]) {
-		rdamage += damage / 100;
+	if (ssc) {
+		if (ssc->data[SC_INSPIRATION]) {
+			rdamage += damage / 100;
 #ifdef RENEWAL
-		rdamage = cap_value(rdamage, 1, max_damage);
+			rdamage = cap_value(rdamage, 1, max_damage);
 #else
-		rdamage = i64max(rdamage,1);
+			rdamage = i64max(rdamage, 1);
 #endif
+		}
+		if (ssc->data[SC_VENOMBLEED] && ssc->data[SC_VENOMBLEED]->val3 == 0)
+			rdamage -= damage * ssc->data[SC_VENOMBLEED]->val2 / 100;
 	}
 
-	if (sc && sc->data[SC_KYOMU] && (!ssc || !ssc->data[SC_SHIELDSPELL_DEF])) // Nullify reflecting ability except for Shield Spell - Def
-		rdamage = 0;
-
-	if (sc && sc->data[SC_MAXPAIN]) {
-		rdamage = damage * sc->data[SC_MAXPAIN]->val1 * 10 / 100;
+	if (sc) {
+		if (sc->data[SC_MAXPAIN])
+			rdamage = damage * sc->data[SC_MAXPAIN]->val1 * 10 / 100;
 	}
 
 	return cap_value(min(rdamage,max_damage),INT_MIN,INT_MAX);
@@ -7659,10 +7709,8 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t
 			} else
 				status_change_end(src,SC_SPELLFIST,INVALID_TIMER);
 		}
-		if (sc->data[SC_GIANTGROWTH] && (wd.flag&BF_SHORT) && rnd()%100 < sc->data[SC_GIANTGROWTH]->val2 && !is_infinite_defense(target, wd.flag) && !vellum_damage) {
-			wd.damage <<= 1; // Double Damage
-			skill_break_equip(src, src, EQP_WEAPON, 10, BCT_SELF); // Break chance happens on successful damage increase
-		}
+		if (sc->data[SC_GIANTGROWTH] && (wd.flag&BF_SHORT) && rnd()%100 < sc->data[SC_GIANTGROWTH]->val2 && !is_infinite_defense(target, wd.flag) && !vellum_damage)
+			wd.damage += wd.damage * 150 / 100; // 2.5 times damage
 
 		if( sd && battle_config.arrow_decrement && sc->data[SC_FEARBREEZE] && sc->data[SC_FEARBREEZE]->val4 > 0) {
 			short idx = sd->equip_index[EQI_AMMO];
@@ -8049,7 +8097,7 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f
 			if( !su || !su->group)
 				return 0;
 			if( skill_get_inf2(su->group->skill_id, INF2_ISTRAP) && su->group->unit_id != UNT_USED_TRAPS) {
-				if (!skill_id || su->group->skill_id == WM_REVERBERATION || su->group->skill_id == NPC_REVERBERATION || su->group->skill_id == WM_POEMOFNETHERWORLD) {
+				if (!skill_id || su->group->skill_id == NPC_REVERBERATION || su->group->skill_id == WM_POEMOFNETHERWORLD) {
 					;
 				}
 				else if (skill_get_inf2(skill_id, INF2_TARGETTRAP)) { // Only a few skills can target traps
@@ -8897,7 +8945,14 @@ static const struct _battle_data {
 	{ "idletime_hom_option",                &battle_config.idletime_hom_option,             0x1F,   0x1,    0xFFF,          },
 	{ "devotion_standup_fix",               &battle_config.devotion_standup_fix,            1,      0,      1,              },
 	{ "feature.bgqueue",                    &battle_config.feature_bgqueue,                 1,      0,      1,              },
+	{ "bgqueue_nowarp_mapflag",             &battle_config.bgqueue_nowarp_mapflag,          0,      0,      1,              },
 	{ "homunculus_exp_gain",                &battle_config.homunculus_exp_gain,             10,     0,      100,            },
+	{ "rental_item_novalue",                &battle_config.rental_item_novalue,             1,      0,      1,              },
+	{ "ping_timer_inverval",                &battle_config.ping_timer_interval,             30,     0,      99999999,       },
+	{ "ping_time",                          &battle_config.ping_time,                       20,     0,      99999999,       },
+	{ "show_skill_scale",                   &battle_config.show_skill_scale,                1,      0,      1,              },
+	{ "achievement_mob_share",              &battle_config.achievement_mob_share,           0,      0,      1,              },
+	{ "slave_stick_with_master",            &battle_config.slave_stick_with_master,         0,      0,      1,              },
 	{ "blocking_play_delay",                &battle_config.blocking_play_delay,             20000,  0,      INT_MAX,        },
 
 #include "../custom/battle_config_init.inc"

+ 7 - 0
src/map/battle.hpp

@@ -675,7 +675,14 @@ struct Battle_Config
 	int idletime_hom_option;
 	int devotion_standup_fix;
 	int feature_bgqueue;
+	int bgqueue_nowarp_mapflag;
 	int homunculus_exp_gain;
+	int rental_item_novalue;
+	int ping_timer_interval;
+	int ping_time;
+	int show_skill_scale;
+	int achievement_mob_share;
+	int slave_stick_with_master;
 	int blocking_play_delay;
 
 #include "../custom/battle_config_struct.inc"

+ 463 - 126
src/map/battleground.cpp

@@ -32,6 +32,7 @@ using namespace rathena;
 BattlegroundDatabase battleground_db;
 std::unordered_map<int, std::shared_ptr<s_battleground_data>> bg_team_db;
 std::vector<std::shared_ptr<s_battleground_queue>> bg_queues;
+int bg_queue_count = 1;
 
 const std::string BattlegroundDatabase::getDefaultLocation() {
 	return std::string(db_path) + "/battleground_db.yml";
@@ -75,6 +76,11 @@ uint64 BattlegroundDatabase::parseBodyNode(const YAML::Node &node) {
 		if (!this->asInt32(node, "MinPlayers", min))
 			return 0;
 
+		if (min < 1) {
+			this->invalidWarning(node["MinPlayers"], "Minimum players %d cannot be less than 1, capping to 1.\n", min);
+			min = 1;
+		}
+
 		if (min * 2 > MAX_BG_MEMBERS) {
 			this->invalidWarning(node["MinPlayers"], "Minimum players %d exceeds MAX_BG_MEMBERS, capping to %d.\n", min, MAX_BG_MEMBERS / 2);
 			min = MAX_BG_MEMBERS / 2;
@@ -92,6 +98,11 @@ uint64 BattlegroundDatabase::parseBodyNode(const YAML::Node &node) {
 		if (!this->asInt32(node, "MaxPlayers", max))
 			return 0;
 
+		if (max < 1) {
+			this->invalidWarning(node["MaxPlayers"], "Maximum players %d cannot be less than 1, capping to 1.\n", max);
+			max = 1;
+		}
+
 		if (max * 2 > MAX_BG_MEMBERS) {
 			this->invalidWarning(node["MaxPlayers"], "Maximum players %d exceeds MAX_BG_MEMBERS, capping to %d.\n", max, MAX_BG_MEMBERS / 2);
 			max = MAX_BG_MEMBERS / 2;
@@ -158,7 +169,77 @@ uint64 BattlegroundDatabase::parseBodyNode(const YAML::Node &node) {
 		bg->start_delay = delay;
 	} else {
 		if (!exists)
-			bg->start_delay = 30;
+			bg->start_delay = 0;
+	}
+
+	if (this->nodeExists(node, "Join")) {
+		const YAML::Node &joinNode = node["Join"];
+
+		if (this->nodeExists(joinNode, "Solo")) {
+			bool active;
+
+			if (!this->asBool(joinNode, "Solo", active))
+				return 0;
+
+			bg->solo = active;
+		} else {
+			if (!exists)
+				bg->solo = true;
+		}
+
+		if (this->nodeExists(joinNode, "Party")) {
+			bool active;
+
+			if (!this->asBool(joinNode, "Party", active))
+				return 0;
+
+			bg->party = active;
+		} else {
+			if (!exists)
+				bg->party = true;
+		}
+
+		if (this->nodeExists(joinNode, "Guild")) {
+			bool active;
+
+			if (!this->asBool(joinNode, "Guild", active))
+				return 0;
+
+			bg->guild = active;
+		} else {
+			if (!exists)
+				bg->guild = true;
+		}
+	} else {
+		if (!exists) {
+			bg->solo = true;
+			bg->party = true;
+			bg->guild = true;
+		}
+	}
+
+	if (this->nodeExists(node, "JobRestrictions")) {
+		const YAML::Node &jobsNode = node["JobRestrictions"];
+
+		for (const auto &jobit : jobsNode) {
+			std::string job_name = jobit.first.as<std::string>(), job_name_constant = "JOB_" + job_name;
+			int64 constant;
+
+			if (!script_get_constant(job_name_constant.c_str(), &constant)) {
+				this->invalidWarning(node["JobRestrictions"], "Job %s does not exist.\n", job_name.c_str());
+				continue;
+			}
+
+			bool active;
+
+			if (!this->asBool(jobsNode, job_name, active))
+				return 0;
+
+			if (active)
+				bg->job_restrictions.push_back(static_cast<int32>(constant));
+			else
+				util::vector_erase_if_exists(bg->job_restrictions, static_cast<int32>(constant));
+		}
 	}
 
 	if (this->nodeExists(node, "Locations")) {
@@ -174,9 +255,9 @@ uint64 BattlegroundDatabase::parseBodyNode(const YAML::Node &node) {
 				if (!this->asString(location, "Map", map_name))
 					return 0;
 
-				map_entry.mapid = map_mapname2mapid(map_name.c_str());
+				map_entry.mapindex = mapindex_name2id(map_name.c_str());
 
-				if (map_entry.mapid == -1) {
+				if (map_entry.mapindex == 0) {
 					this->invalidWarning(location["Map"], "Invalid battleground map name %s, skipping.\n", map_name.c_str());
 					return 0;
 				}
@@ -245,6 +326,18 @@ uint64 BattlegroundDatabase::parseBodyNode(const YAML::Node &node) {
 						}
 					}
 
+					if (this->nodeExists(team[it], "ActiveEvent")) {
+						if (!this->asString(team[it], "ActiveEvent", team_ptr->active_event))
+							return 0;
+
+						team_ptr->active_event.resize(EVENT_NAME_LENGTH);
+
+						if (team_ptr->active_event.find("::On") == std::string::npos) {
+							this->invalidWarning(team["ActiveEvent"], "Battleground ActiveEvent label %s should begin with '::On', skipping.\n", team_ptr->active_event.c_str());
+							return 0;
+						}
+					}
+
 					if (this->nodeExists(team[it], "Variable")) {
 						if (!this->asString(team[it], "Variable", team_ptr->bg_id_var))
 							return 0;
@@ -284,6 +377,21 @@ std::shared_ptr<s_battleground_type> bg_search_name(const char *name)
 	return nullptr;
 }
 
+/**
+ * Search for a Battleground queue based on the given queue ID
+ * @param queue_id: Queue ID
+ * @return s_battleground_queue on success or nullptr on failure
+ */
+std::shared_ptr<s_battleground_queue> bg_search_queue(int queue_id)
+{
+	for (const auto &queue : bg_queues) {
+		if (queue_id == queue->queue_id)
+			return queue;
+	}
+
+	return nullptr;
+}
+
 /**
  * Search for an available player in Battleground
  * @param bg: Battleground data
@@ -293,7 +401,12 @@ struct map_session_data* bg_getavailablesd(s_battleground_data *bg)
 {
 	nullpo_retr(nullptr, bg);
 
-	return (bg->members.size() != 0) ? bg->members[0].sd : nullptr;
+	for (const auto &member : bg->members) {
+		if (member.sd != nullptr)
+			return member.sd;
+	}
+
+	return nullptr;
 }
 
 /**
@@ -514,7 +627,7 @@ int bg_create(uint16 mapindex, s_battleground_team* team)
 	bg->cemetery.y = team->warp_y;
 	bg->logout_event = team->quit_event.c_str();
 	bg->die_event = team->death_event.c_str();
-	bg->members.clear();
+	bg->active_event = team->active_event.c_str();
 
 	return bg->id;
 }
@@ -569,7 +682,7 @@ void bg_send_message(struct map_session_data *sd, const char *mes, int len)
 {
 	nullpo_retv(sd);
 
-	if (!sd->bg_id)
+	if (sd->bg_id == 0)
 		return;
 	
 	std::shared_ptr<s_battleground_data> bgteam = util::umap_find(bg_team_db, sd->bg_id);
@@ -617,7 +730,7 @@ TIMER_FUNC(bg_send_xy_timer)
 }
 
 /**
- * Mark a Battleground as ready to begin queuing
+ * Mark a Battleground as ready to begin queuing for a free map
  * @param tid: Timer ID
  * @param tick: Timer
  * @param id: ID
@@ -625,14 +738,18 @@ TIMER_FUNC(bg_send_xy_timer)
  */
 static TIMER_FUNC(bg_on_ready_loopback)
 {
-	s_battleground_queue *queue = (s_battleground_queue*)data;
+	int queue_id = (int)data;
+	std::shared_ptr<s_battleground_queue> queue = bg_search_queue(queue_id);
 
-	nullpo_retr(1, queue);
+	if (queue == nullptr) {
+		ShowError("bg_on_ready_loopback: Invalid battleground queue %d.\n", queue_id);
+		return 1;
+	}
 
 	std::shared_ptr<s_battleground_type> bg = battleground_db.find(queue->id);
 
 	if (bg) {
-		bg_queue_on_ready(bg->name.c_str(), std::shared_ptr<s_battleground_queue>(queue));
+		bg_queue_on_ready(bg->name.c_str(), queue);
 		return 0;
 	} else {
 		ShowError("bg_on_ready_loopback: Can't find battleground %d in the battlegrounds database.\n", queue->id);
@@ -641,7 +758,7 @@ static TIMER_FUNC(bg_on_ready_loopback)
 }
 
 /**
- * Reset Battleground queue data
+ * Reset Battleground queue data if players don't accept in time
  * @param tid: Timer ID
  * @param tick: Timer
  * @param id: ID
@@ -649,31 +766,32 @@ static TIMER_FUNC(bg_on_ready_loopback)
  */
 static TIMER_FUNC(bg_on_ready_expire)
 {
-	s_battleground_queue *queue = (s_battleground_queue*)data;
-
-	nullpo_retr(1, queue);
+	int queue_id = (int)data;
+	std::shared_ptr<s_battleground_queue> queue = bg_search_queue(queue_id);
 
-	queue->in_ready_state = false;
-	queue->map->isReserved = false; // Remove reservation to free up for future queue
-	queue->map = nullptr;
-	queue->accepted_players = 0; // Reset the queue count
+	if (queue == nullptr) {
+		ShowError("bg_on_ready_expire: Invalid battleground queue %d.\n", queue_id);
+		return 1;
+	}
 
 	std::string bg_name = battleground_db.find(queue->id)->name;
 
 	for (const auto &sd : queue->teama_members) {
-		sd->bg_queue_accept_state = false;
 		clif_bg_queue_apply_result(BG_APPLY_QUEUE_FINISHED, bg_name.c_str(), sd);
+		clif_bg_queue_entry_init(sd);
 	}
 
 	for (const auto &sd : queue->teamb_members) {
-		sd->bg_queue_accept_state = false;
 		clif_bg_queue_apply_result(BG_APPLY_QUEUE_FINISHED, bg_name.c_str(), sd);
+		clif_bg_queue_entry_init(sd);
 	}
+
+	bg_queue_clear(queue, true);
 	return 0;
 }
 
 /**
- * Start a Battleground
+ * Start a Battleground when all players have accepted
  * @param tid: Timer ID
  * @param tick: Timer
  * @param id: ID
@@ -681,9 +799,13 @@ static TIMER_FUNC(bg_on_ready_expire)
  */
 static TIMER_FUNC(bg_on_ready_start)
 {
-	s_battleground_queue *queue = (s_battleground_queue*)data;
+	int queue_id = (int)data;
+	std::shared_ptr<s_battleground_queue> queue = bg_search_queue(queue_id);
 
-	nullpo_retr(1, queue);
+	if (queue == nullptr) {
+		ShowError("bg_on_ready_start: Invalid battleground queue %d.\n", queue_id);
+		return 1;
+	}
 
 	queue->tid_start = INVALID_TIMER;
 	bg_queue_start_battleground(queue);
@@ -702,7 +824,7 @@ bool bg_player_is_in_bg_map(struct map_session_data *sd)
 
 	for (const auto &pair : battleground_db) {
 		for (const auto &it : pair.second->maps) {
-			if (it.mapid == sd->bl.m)
+			if (it.mapindex == sd->mapindex)
 				return true;
 		}
 	}
@@ -724,7 +846,7 @@ static bool bg_queue_check_status(struct map_session_data* sd, const char *name)
 		if (sd->sc.data[SC_ENTRY_QUEUE_APPLY_DELAY]) { // Exclude any player who's recently left a battleground queue
 			char buf[CHAT_SIZE_MAX];
 
-			sprintf(buf, msg_txt(sd, 339), (get_timer(sd->sc.data[SC_ENTRY_QUEUE_APPLY_DELAY]->timer)->tick - gettick()) / 1000); // You can't apply to a battleground queue for %d seconds due to recently leaving one.
+			sprintf(buf, msg_txt(sd, 339), static_cast<int32>((get_timer(sd->sc.data[SC_ENTRY_QUEUE_APPLY_DELAY]->timer)->tick - gettick()) / 1000)); // You can't apply to a battleground queue for %d seconds due to recently leaving one.
 			clif_bg_queue_apply_result(BG_APPLY_NONE, name, sd);
 			clif_messagecolor(&sd->bl, color_table[COLOR_LIGHT_GREEN], buf, false, SELF);
 			return false;
@@ -732,9 +854,9 @@ static bool bg_queue_check_status(struct map_session_data* sd, const char *name)
 
 		if (sd->sc.data[SC_ENTRY_QUEUE_NOTIFY_ADMISSION_TIME_OUT]) { // Exclude any player who's recently deserted a battleground
 			char buf[CHAT_SIZE_MAX];
-			t_tick status_tick = get_timer(sd->sc.data[SC_ENTRY_QUEUE_NOTIFY_ADMISSION_TIME_OUT]->timer)->tick, tick = gettick();
+			int32 status_tick = static_cast<int32>(DIFF_TICK(get_timer(sd->sc.data[SC_ENTRY_QUEUE_NOTIFY_ADMISSION_TIME_OUT]->timer)->tick, gettick()) / 1000);
 
-			sprintf(buf, msg_txt(sd, 338), ((status_tick - tick) / 1000) / 60, ((status_tick - tick) / 1000) % 60); // You can't apply to a battleground queue due to recently deserting a battleground. Time remaining: %d minutes and %d seconds.
+			sprintf(buf, msg_txt(sd, 338), status_tick / 60, status_tick % 60); // You can't apply to a battleground queue due to recently deserting a battleground. Time remaining: %d minutes and %d seconds.
 			clif_bg_queue_apply_result(BG_APPLY_NONE, name, sd);
 			clif_messagecolor(&sd->bl, color_table[COLOR_LIGHT_GREEN], buf, false, SELF);
 			return false;
@@ -755,43 +877,64 @@ bool bg_queue_check_joinable(std::shared_ptr<s_battleground_type> bg, struct map
 {
 	nullpo_retr(false, sd);
 
-	if (bg->min_lvl && sd->status.base_level < bg->min_lvl) { // Check min level if min_lvl isn't 0
+	for (const auto &job : bg->job_restrictions) { // Check class requirement
+		if (sd->class_ == job) {
+			clif_bg_queue_apply_result(BG_APPLY_PLAYER_CLASS, name, sd);
+			return false;
+		}
+	}
+
+	if (bg->min_lvl > 0 && sd->status.base_level < bg->min_lvl) { // Check minimum level requirement
 		clif_bg_queue_apply_result(BG_APPLY_PLAYER_LEVEL, name, sd);
 		return false;
 	}
 
-	if (bg->max_lvl && sd->status.base_level > bg->max_lvl) { // Check max level if max_lvl isn't 0
+	if (bg->max_lvl > 0 && sd->status.base_level > bg->max_lvl) { // Check maximum level requirement
 		clif_bg_queue_apply_result(BG_APPLY_PLAYER_LEVEL, name, sd);
 		return false;
 	}
 
-	if (!bg_queue_check_status(sd, name))
+	if (!bg_queue_check_status(sd, name)) // Check status blocks
 		return false;
 
 	if (bg_player_is_in_bg_map(sd)) { // Is the player currently in a battleground map? Reject them.
 		clif_bg_queue_apply_result(BG_APPLY_NONE, name, sd);
-		clif_messagecolor(&sd->bl, color_table[COLOR_LIGHT_GREEN], msg_txt(sd, 337), false, SELF); // You may not join a battleground queue when you're in a battleground map.
+		clif_messagecolor(&sd->bl, color_table[COLOR_LIGHT_GREEN], msg_txt(sd, 337), false, SELF); // You can't apply to a battleground queue from this map.
+		return false;
+	}
+
+	if (battle_config.bgqueue_nowarp_mapflag > 0 && map_getmapflag(sd->bl.m, MF_NOWARP)) { // Check player's current position for mapflag check
+		clif_bg_queue_apply_result(BG_APPLY_NONE, name, sd);
+		clif_messagecolor(&sd->bl, color_table[COLOR_LIGHT_GREEN], msg_txt(sd, 337), false, SELF); // You can't apply to a battleground queue from this map.
 		return false;
 	}
 
-	return true; // Return true if all conditions are met.
+	return true;
 }
 
 /**
- * Sub function for reserving a slot in the Battleground if it's joinable
+ * Mark a map as reserved for a Battleground
  * @param name: Battleground map name
  * @param state: Whether to mark reserved or not
+ * @param ended: Whether the Battleground event is complete; players getting prize
  * @return True on success or false otherwise
  */
-bool bg_queue_reservation(const char *name, bool state)
+bool bg_queue_reservation(const char *name, bool state, bool ended)
 {
-	int16 mapid = map_mapname2mapid(name);
+	uint16 mapindex = mapindex_name2id(name);
 
-	for (const auto &pair : battleground_db) {
-		// Bound checking isn't needed since we iterate within battleground_db's bound.
-		for (auto &it : pair.second->maps) {
-			if (it.mapid == mapid) {
-				it.isReserved = state;
+	for (auto &pair : battleground_db) {
+		for (auto &map : pair.second->maps) {
+			if (map.mapindex == mapindex) {
+				map.isReserved = state;
+				for (auto &queue : bg_queues) {
+					if (queue->map == &map) {
+						if (ended) // The ended flag is applied from bg_reserve (bg_unbook clears it for the next queue)
+							queue->state = QUEUE_STATE_ENDED;
+						if (!state)
+							bg_queue_clear(queue, true);
+					}
+				}
 				return true;
 			}
 		}
@@ -800,6 +943,33 @@ bool bg_queue_reservation(const char *name, bool state)
 	return false;
 }
 
+/**
+ * Join as an individual into a Battleground
+ * @param name: Battleground name
+ * @param sd: Player who requested to join the battlegrounds
+ */
+void bg_queue_join_solo(const char *name, struct map_session_data *sd)
+{
+	if (!sd) {
+		ShowError("bg_queue_join_solo: Tried to join non-existent player\n.");
+		return;
+	}
+
+	std::shared_ptr<s_battleground_type> bg = bg_search_name(name);
+
+	if (!bg) {
+		ShowWarning("bq_queue_join_solo: Could not find battleground \"%s\" requested by %s (AID: %d / CID: %d)\n", name, sd->status.name, sd->status.account_id, sd->status.char_id);
+		return;
+	}
+
+	if (!bg->solo) {
+		clif_bg_queue_apply_result(BG_APPLY_INVALID_APP, name, sd);
+		return;
+	}
+
+	bg_queue_join_multi(name, sd, { sd }); // Join as solo
+}
+
 /**
  * Join a party onto the same side of a Battleground
  * @param name: Battleground name
@@ -807,6 +977,11 @@ bool bg_queue_reservation(const char *name, bool state)
  */
 void bg_queue_join_party(const char *name, struct map_session_data *sd)
 {
+	if (!sd) {
+		ShowError("bg_queue_join_party: Tried to join non-existent player\n.");
+		return;
+	}
+
 	struct party_data *p = party_search(sd->status.party_id);
 
 	if (!p) {
@@ -824,6 +999,11 @@ void bg_queue_join_party(const char *name, struct map_session_data *sd)
 	std::shared_ptr<s_battleground_type> bg = bg_search_name(name);
 
 	if (bg) {
+		if (!bg->party) {
+			clif_bg_queue_apply_result(BG_APPLY_INVALID_APP, name, sd);
+			return;
+		}
+
 		int p_online = 0;
 
 		for (const auto &it : p->party.member) {
@@ -835,7 +1015,7 @@ void bg_queue_join_party(const char *name, struct map_session_data *sd)
 			clif_bg_queue_apply_result(BG_APPLY_PLAYER_COUNT, name, sd);
 			return; // Too many party members online
 		}
-		
+
 		std::vector<struct map_session_data *> list;
 
 		for (const auto &it : p->party.member) {
@@ -865,6 +1045,11 @@ void bg_queue_join_party(const char *name, struct map_session_data *sd)
  */
 void bg_queue_join_guild(const char *name, struct map_session_data *sd)
 {
+	if (!sd) {
+		ShowError("bg_queue_join_guild: Tried to join non-existent player\n.");
+		return;
+	}
+
 	if (!sd->guild) {
 		clif_bg_queue_apply_result(BG_APPLY_INVALID_APP, name, sd);
 		return; // Someone has bypassed the client check for being in a guild
@@ -878,6 +1063,11 @@ void bg_queue_join_guild(const char *name, struct map_session_data *sd)
 	std::shared_ptr<s_battleground_type> bg = bg_search_name(name);
 
 	if (bg) {
+		if (!bg->guild) {
+			clif_bg_queue_apply_result(BG_APPLY_INVALID_APP, name, sd);
+			return;
+		}
+
 		struct guild* g = sd->guild;
 
 		if (g->connect_member > bg->max_players) {
@@ -932,43 +1122,55 @@ void bg_queue_join_multi(const char *name, struct map_session_data *sd, std::vec
 	}
 
 	for (const auto &queue : bg_queues) {
-		if (queue->id != bg->id)
-			continue;
-		if (queue->in_ready_state)
+		if (queue->id != bg->id || queue->state == QUEUE_STATE_SETUP_DELAY || queue->state == QUEUE_STATE_ENDED)
 			continue;
 
 		// Make sure there's enough space on one side to join as a party/guild in this queue
-		if (queue->teama_members.size() + list.size() > bg->required_players && queue->teamb_members.size() + list.size() > bg->required_players) {
+		if (queue->teama_members.size() + list.size() > bg->max_players && queue->teamb_members.size() + list.size() > bg->max_players) {
 			break;
 		}
 
 		bool r = rnd() % 2 != 0;
-		std::vector<map_session_data *>* team = r ? &queue->teamb_members : &queue->teama_members;
-
-		// If the designated team is full, put the player into the other team
-		if (team->size() + list.size() > bg->required_players) {
-			team = r ? &queue->teama_members : &queue->teamb_members;
+		std::vector<map_session_data *> *team = r ? &queue->teamb_members : &queue->teama_members;
+
+		if (queue->state == QUEUE_STATE_ACTIVE) {
+			// If one team has lesser members try to balance (on an active BG)
+			if (r && queue->teama_members.size() < queue->teamb_members.size())
+				team = &queue->teama_members;
+			else if (!r && queue->teamb_members.size() < queue->teama_members.size())
+				team = &queue->teamb_members;
+		} else {
+			// If the designated team is full, put the player into the other team
+			if (team->size() + list.size() > bg->required_players)
+				team = r ? &queue->teama_members : &queue->teamb_members;
 		}
 
-		while (!list.empty() && team->size() < bg->required_players) {
+		while (!list.empty() && team->size() < bg->max_players) {
 			struct map_session_data *sd2 = list.back();
 
 			list.pop_back();
 
-			if (!sd2 || sd2->bg_queue)
+			if (!sd2 || sd2->bg_queue_id > 0)
 				continue;
 
 			if (!bg_queue_check_joinable(bg, sd2, name))
 				continue;
 
-			sd2->bg_queue = queue;
+			sd2->bg_queue_id = queue->queue_id;
 			team->push_back(sd2);
 			clif_bg_queue_apply_result(BG_APPLY_ACCEPT, name, sd2);
 			clif_bg_queue_apply_notify(name, sd2);
 		}
 
-		// Enough players have joined
-		if (queue->teamb_members.size() == bg->required_players && queue->teama_members.size() == bg->required_players)
+		if (queue->state == QUEUE_STATE_ACTIVE) { // Battleground is already active
+			for (auto &pl_sd : *team) {
+				if (queue->map->mapindex == pl_sd->mapindex)
+					continue;
+
+				pc_set_bg_queue_timer(pl_sd);
+				clif_bg_queue_lobby_notify(name, pl_sd);
+			}
+		} else if (queue->state == QUEUE_STATE_SETUP && queue->teamb_members.size() >= bg->required_players && queue->teama_members.size() >= bg->required_players) // Enough players have joined
 			bg_queue_on_ready(name, queue);
 
 		return;
@@ -981,10 +1183,11 @@ void bg_queue_join_multi(const char *name, struct map_session_data *sd, std::vec
 /**
  * Clear Battleground queue for next one
  * @param queue: Queue to clean up
+ * @param ended: If a Battleground has ended through normal means (by script command bg_unbook)
  */
-static void bg_queue_clear(s_battleground_queue *queue)
+void bg_queue_clear(std::shared_ptr<s_battleground_queue> queue, bool ended)
 {
-	if (!queue)
+	if (queue == nullptr)
 		return;
 
 	if (queue->tid_requeue != INVALID_TIMER) {
@@ -1002,49 +1205,47 @@ static void bg_queue_clear(s_battleground_queue *queue)
 		queue->tid_start = INVALID_TIMER;
 	}
 
-	if (queue->map != nullptr) {
-		queue->map->isReserved = false; // Remove reservation to free up for future queue
-		queue->map = nullptr;
+	if (ended) {
+		if (queue->map != nullptr) {
+			queue->map->isReserved = false; // Remove reservation to free up for future queue
+			queue->map = nullptr;
+		}
+
+		for (const auto &sd : queue->teama_members)
+			sd->bg_queue_id = 0;
+
+		for (const auto &sd : queue->teamb_members)
+			sd->bg_queue_id = 0;
+
+		queue->teama_members.clear();
+		queue->teamb_members.clear();
+		queue->teama_members.shrink_to_fit();
+		queue->teamb_members.shrink_to_fit();
+		queue->accepted_players = 0;
+		queue->state = QUEUE_STATE_SETUP;
 	}
-	queue->in_ready_state = false;
-	queue->accepted_players = 0; // Reset the queue count
 }
 
 /**
  * Sub function for leaving a Battleground queue
  * @param sd: Player leaving
- * @param lista: List of players in queue data
- * @param listb: List of players in second queue data
+ * @param members: List of players in queue data
  * @return True on success or false otherwise
  */
-static bool bg_queue_leave_sub(struct map_session_data *sd, std::vector<map_session_data *> lista, std::vector<map_session_data *> listb)
+static bool bg_queue_leave_sub(struct map_session_data *sd, std::vector<map_session_data *> &members)
 {
 	if (!sd)
 		return false;
 
-	auto list_it = lista.begin();
-
-	while (list_it != lista.end()) {
-		struct map_session_data *player = *list_it;
-
-		if (player == sd) {
-			if (sd->bg_queue->in_ready_state) {
-				sd->bg_queue->accepted_players = 0;
-				sd->bg_queue->in_ready_state = false;
-				sd->bg_queue_accept_state = false;
-			}
+	auto list_it = members.begin();
 
-			lista.erase(list_it);
-
-			if (lista.empty() && listb.empty()) { // If there are no players left in the queue, discard it
-				for (auto &queue : bg_queues) {
-					if (sd->bg_queue == queue)
-						bg_queue_clear(queue.get());
-				}
-			}
+	while (list_it != members.end()) {
+		if (*list_it == sd) {
+			members.erase(list_it);
 
 			sc_start(nullptr, &sd->bl, SC_ENTRY_QUEUE_APPLY_DELAY, 100, 1, 60000);
-			sd->bg_queue = nullptr;
+			sd->bg_queue_id = 0;
+			pc_delete_bg_queue_timer(sd);
 			return true;
 		} else {
 			list_it++;
@@ -1061,14 +1262,26 @@ static bool bg_queue_leave_sub(struct map_session_data *sd, std::vector<map_sess
  */
 bool bg_queue_leave(struct map_session_data *sd)
 {
-	if (!sd || !sd->bg_queue)
+	if (!sd || sd->bg_queue_id == 0)
 		return false;
 
-	if (!bg_queue_leave_sub(sd, sd->bg_queue->teama_members, sd->bg_queue->teamb_members) && !bg_queue_leave_sub(sd, sd->bg_queue->teamb_members, sd->bg_queue->teama_members)) {
-		ShowError("bg_queue_leave: Couldn't find player %s in battlegrounds queue.\n", sd->status.name);
-		return false;
-	} else
-		return true;
+	pc_delete_bg_queue_timer(sd);
+
+	for (auto &queue : bg_queues) {
+		if (sd->bg_queue_id == queue->queue_id) {
+			if (!bg_queue_leave_sub(sd, queue->teama_members) && !bg_queue_leave_sub(sd, queue->teamb_members)) {
+				ShowError("bg_queue_leave: Couldn't find player %s in battlegrounds queue.\n", sd->status.name);
+				return false;
+			} else {
+				if ((queue->state == QUEUE_STATE_SETUP || queue->state == QUEUE_STATE_SETUP_DELAY) && queue->teama_members.empty() && queue->teamb_members.empty()) // If there are no players left in the queue (that hasn't started), discard it
+					bg_queue_clear(queue, true);
+
+				return true;
+			}
+		}
+	}
+
+	return false;
 }
 
 /**
@@ -1086,29 +1299,27 @@ bool bg_queue_on_ready(const char *name, std::shared_ptr<s_battleground_queue> q
 		return false;
 	}
 
-	queue->accepted_players = 0; // Reset the counter just in case.
-
-	if (queue->teama_members.size() != queue->required_players || queue->teamb_members.size() != queue->required_players)
+	if (queue->teama_members.size() < queue->required_players || queue->teamb_members.size() < queue->required_players)
 		return false; // Return players to the queue and stop reapplying the timer
 
-	s_battleground_map *bgmap = nullptr;
+	bool map_reserved = false;
 
-	for (auto &it : bg->maps) {
-		if (!it.isReserved) {
-			it.isReserved = true;
-			bgmap = &it;
-			queue->map = &it;
+	for (auto &map : bg->maps) {
+		if (!map.isReserved) {
+			map.isReserved = true;
+			map_reserved = true;
+			queue->map = &map;
 			break;
 		}
 	}
 
-	if (!bgmap) { // All the battleground maps are reserved. Set a timer to check for an open battleground every 10 seconds.
-		queue->tid_requeue = add_timer(gettick() + 10000, bg_on_ready_loopback, 0, (intptr_t)queue.get());
+	if (!map_reserved) { // All the battleground maps are reserved. Set a timer to check for an open battleground every 10 seconds.
+		queue->tid_requeue = add_timer(gettick() + 10000, bg_on_ready_loopback, 0, (intptr_t)queue->queue_id);
 		return false;
 	}
 
-	queue->in_ready_state = true;
-	queue->tid_expire = add_timer(gettick() + 20000, bg_on_ready_expire, 0, (intptr_t)queue.get());
+	queue->state = QUEUE_STATE_SETUP_DELAY;
+	queue->tid_expire = add_timer(gettick() + 20000, bg_on_ready_expire, 0, (intptr_t)queue->queue_id);
 
 	for (const auto &sd : queue->teama_members)
 		clif_bg_queue_lobby_notify(name, sd);
@@ -1119,25 +1330,150 @@ bool bg_queue_on_ready(const char *name, std::shared_ptr<s_battleground_queue> q
 	return true;
 }
 
+/**
+ * Send a player into an active Battleground
+ * @param sd: Player to send in
+ * @param queue: Queue data
+ */
+void bg_join_active(map_session_data *sd, std::shared_ptr<s_battleground_queue> queue)
+{
+	if (sd == nullptr || queue == nullptr)
+		return;
+
+	// Check player's current position for mapflag check
+	if (battle_config.bgqueue_nowarp_mapflag > 0 && map_getmapflag(sd->bl.m, MF_NOWARP)) {
+		clif_messagecolor(&sd->bl, color_table[COLOR_LIGHT_GREEN], msg_txt(sd, 337), false, SELF); // You can't apply to a battleground queue from this map.
+		bg_queue_leave(sd);
+		clif_bg_queue_entry_init(sd);
+		return;
+	}
+
+	int bg_id_team_1 = static_cast<int>(mapreg_readreg(add_str(queue->map->team1.bg_id_var.c_str())));
+	std::shared_ptr<s_battleground_data> bgteam_1 = util::umap_find(bg_team_db, bg_id_team_1);
+
+	for (auto &pl_sd : queue->teama_members) {
+		if (sd != pl_sd)
+			continue;
+
+		if (bgteam_1 == nullptr) {
+			bg_queue_leave(sd);
+			clif_bg_queue_apply_result(BG_APPLY_RECONNECT, battleground_db.find(queue->id)->name.c_str(), sd);
+			clif_bg_queue_entry_init(sd);
+			return;
+		}
+
+		clif_bg_queue_entry_init(pl_sd);
+		bg_team_join(bg_id_team_1, pl_sd, true);
+		npc_event(pl_sd, bgteam_1->active_event.c_str(), 0);
+		return;
+	}
+
+	int bg_id_team_2 = static_cast<int>(mapreg_readreg(add_str(queue->map->team2.bg_id_var.c_str())));
+	std::shared_ptr<s_battleground_data> bgteam_2 = util::umap_find(bg_team_db, bg_id_team_2);
+
+	for (auto &pl_sd : queue->teamb_members) {
+		if (sd != pl_sd)
+			continue;
+
+		if (bgteam_2 == nullptr) {
+			bg_queue_leave(sd);
+			clif_bg_queue_apply_result(BG_APPLY_RECONNECT, battleground_db.find(queue->id)->name.c_str(), sd);
+			clif_bg_queue_entry_init(sd);
+			return;
+		}
+
+		clif_bg_queue_entry_init(pl_sd);
+		bg_team_join(bg_id_team_2, pl_sd, true);
+		npc_event(pl_sd, bgteam_2->active_event.c_str(), 0);
+		return;
+	}
+
+	return;
+}
+
+/**
+ * Check to see if any players in the queue are on a map with MF_NOWARP and remove them from the queue
+ * @param queue: Queue data
+ * @return True if the player is on a map with MF_NOWARP or false otherwise
+ */
+bool bg_mapflag_check(std::shared_ptr<s_battleground_queue> queue) {
+	if (queue == nullptr || battle_config.bgqueue_nowarp_mapflag == 0)
+		return false;
+
+	bool found = false;
+
+	for (const auto &sd : queue->teama_members) {
+		if (map_getmapflag(sd->bl.m, MF_NOWARP)) {
+			clif_messagecolor(&sd->bl, color_table[COLOR_LIGHT_GREEN], msg_txt(sd, 337), false, SELF); // You can't apply to a battleground queue from this map.
+			bg_queue_leave(sd);
+			clif_bg_queue_entry_init(sd);
+			found = true;
+		}
+	}
+
+	for (const auto &sd : queue->teamb_members) {
+		if (map_getmapflag(sd->bl.m, MF_NOWARP)) {
+			clif_messagecolor(&sd->bl, color_table[COLOR_LIGHT_GREEN], msg_txt(sd, 337), false, SELF); // You can't apply to a battleground queue from this map.
+			bg_queue_leave(sd);
+			clif_bg_queue_entry_init(sd);
+			found = true;
+		}
+	}
+
+	if (found) {
+		queue->state = QUEUE_STATE_SETUP; // Set back to queueing state
+		queue->accepted_players = 0; // Reset acceptance count
+
+		// Free map to avoid creating a reservation delay
+		if (queue->map != nullptr) {
+			queue->map->isReserved = false;
+			queue->map = nullptr;
+		}
+
+		// Announce failure to remaining players
+		for (const auto &sd : queue->teama_members)
+			clif_messagecolor(&sd->bl, color_table[COLOR_LIGHT_GREEN], msg_txt(sd, 340), false, SELF); // Participants were unable to join. Delaying entry for more participants.
+
+		for (const auto &sd : queue->teamb_members)
+			clif_messagecolor(&sd->bl, color_table[COLOR_LIGHT_GREEN], msg_txt(sd, 340), false, SELF); // Participants were unable to join. Delaying entry for more participants.
+	}
+
+	return found;
+}
+
 /**
  * Update the Battleground queue when the player accepts the invite
  * @param queue: Battleground queue
  * @param sd: Player data
  */
-void bg_queue_on_accept_invite(std::shared_ptr<s_battleground_queue> queue, struct map_session_data *sd)
+void bg_queue_on_accept_invite(struct map_session_data *sd)
 {
 	nullpo_retv(sd);
 
-	sd->bg_queue_accept_state = true;
+	std::shared_ptr<s_battleground_queue> queue = bg_search_queue(sd->bg_queue_id);
+
+	if (queue == nullptr) {
+		ShowError("bg_queue_on_accept_invite: Couldn't find player %s in battlegrounds queue.\n", sd->status.name);
+		return;
+	}
+
 	queue->accepted_players++;
-	clig_bg_queue_ack_lobby(true, map_mapid2mapname(queue->map->mapid), map_mapid2mapname(queue->map->mapid), sd);
+	clif_bg_queue_ack_lobby(true, mapindex_id2name(queue->map->mapindex), mapindex_id2name(queue->map->mapindex), sd);
+
+	if (queue->state == QUEUE_STATE_ACTIVE) // Battleground is already active
+		bg_join_active(sd, queue);
+	else if (queue->state == QUEUE_STATE_SETUP_DELAY) {
+		if (queue->accepted_players == queue->required_players * 2) {
+			if (queue->tid_expire != INVALID_TIMER) {
+				delete_timer(queue->tid_expire, bg_on_ready_expire);
+				queue->tid_expire = INVALID_TIMER;
+			}
 
-	if (queue->accepted_players == queue->required_players * 2) {
-		queue->tid_start = add_timer(gettick() + battleground_db.find(queue->id)->start_delay * 1000, bg_on_ready_start, 0, (intptr_t)queue.get());
+			// Check player's current position for mapflag check
+			if (battle_config.bgqueue_nowarp_mapflag > 0 && bg_mapflag_check(queue))
+				return;
 
-		if (queue->tid_expire != INVALID_TIMER) {
-			delete_timer(queue->tid_expire, bg_on_ready_expire);
-			queue->tid_expire = INVALID_TIMER;
+			queue->tid_start = add_timer(gettick() + battleground_db.find(queue->id)->start_delay * 1000, bg_on_ready_start, 0, (intptr_t)queue->queue_id);
 		}
 	}
 }
@@ -1146,31 +1482,33 @@ void bg_queue_on_accept_invite(std::shared_ptr<s_battleground_queue> queue, stru
  * Begin the Battleground from the given queue
  * @param queue: Battleground queue
  */
-void bg_queue_start_battleground(s_battleground_queue *queue)
+void bg_queue_start_battleground(std::shared_ptr<s_battleground_queue> queue)
 {
+	if (queue == nullptr)
+		return;
+
 	std::shared_ptr<s_battleground_type> bg = battleground_db.find(queue->id);
 
 	if (!bg) {
-		queue->map->isReserved = false; // Remove reservation to free up for future queue
-		queue->map = nullptr;
+		bg_queue_clear(queue, true);
 		ShowError("bg_queue_start_battleground: Could not find battleground ID %d in battlegrounds database.\n", queue->id);
 		return;
 	}
 
-	uint16 map_idx = map_id2index(queue->map->mapid);
+	// Check player's current position for mapflag check
+	if (battle_config.bgqueue_nowarp_mapflag > 0 && bg_mapflag_check(queue))
+		return;
+
+	uint16 map_idx = queue->map->mapindex;
 	int bg_team_1 = bg_create(map_idx, &queue->map->team1);
 	int bg_team_2 = bg_create(map_idx, &queue->map->team2);
 
 	for (const auto &sd : queue->teama_members) {
-		sd->bg_queue = nullptr;
-		sd->bg_queue_accept_state = false;
 		clif_bg_queue_entry_init(sd);
 		bg_team_join(bg_team_1, sd, true);
 	}
 
 	for (const auto &sd : queue->teamb_members) {
-		sd->bg_queue = nullptr;
-		sd->bg_queue_accept_state = false;
 		clif_bg_queue_entry_init(sd);
 		bg_team_join(bg_team_2, sd, true);
 	}
@@ -1178,11 +1516,9 @@ void bg_queue_start_battleground(s_battleground_queue *queue)
 	mapreg_setreg(add_str(queue->map->team1.bg_id_var.c_str()), bg_team_1);
 	mapreg_setreg(add_str(queue->map->team2.bg_id_var.c_str()), bg_team_2);
 	npc_event_do(queue->map->bgcallscript.c_str());
-	queue->teama_members.clear();
-	queue->teamb_members.clear();
-	queue->teama_members.shrink_to_fit();
-	queue->teamb_members.shrink_to_fit();
-	bg_queue_clear(queue);
+	queue->state = QUEUE_STATE_ACTIVE;
+
+	bg_queue_clear(queue, false);
 }
 
 /**
@@ -1195,13 +1531,14 @@ static void bg_queue_create(int bg_id, int req_players)
 {
 	auto queue = std::make_shared<s_battleground_queue>();
 
+	queue->queue_id = bg_queue_count++;
 	queue->id = bg_id;
 	queue->required_players = req_players;
 	queue->accepted_players = 0;
 	queue->tid_expire = INVALID_TIMER;
 	queue->tid_start = INVALID_TIMER;
 	queue->tid_requeue = INVALID_TIMER;
-	queue->in_ready_state = false;
+	queue->state = QUEUE_STATE_SETUP;
 
 	bg_queues.push_back(queue);
 }

+ 26 - 7
src/map/battleground.hpp

@@ -27,32 +27,43 @@ struct s_battleground_data {
 	struct point cemetery; ///< Respawn point for players who die
 	std::string logout_event; ///< NPC Event to call on log out events
 	std::string die_event; ///< NPC Event to call on death events
+	std::string active_event; ///< NPC Event to call on players joining an active battleground
 };
 
 struct s_battleground_team {
 	int16 warp_x, warp_y; ///< Team respawn coordinates
 	std::string quit_event, ///< Team NPC Event to call on log out events
 		death_event, ///< Team NPC Event to call on death events
+		active_event, ///< Team NPC Event to call on players joining an active battleground
 		bg_id_var; ///< Team NPC variable name
 };
 
 struct s_battleground_map {
 	int id; ///< Battleground ID
-	int16 mapid; ///< ID of the map
+	uint16 mapindex; ///< Index of the map
 	s_battleground_team team1, team2; ///< Team data
 	std::string bgcallscript; ///< Script to be called when players join the battleground
 	bool isReserved; ///< Reserve BG maps that are used so that the system won't create multiple BG instances on the same map
 };
 
+/// Enum for queue state tracking
+enum e_queue_state : uint16 {
+	QUEUE_STATE_SETUP = 0, ///< The initial setup of a queue (a required amount of players hasn't been met)
+	QUEUE_STATE_SETUP_DELAY, ///< The initial setup of a queue but a required amount of players have accepted and the delay timer is active
+	QUEUE_STATE_ACTIVE, ///< The queue is active script side and more players can join (players may or may not be on the field)
+	QUEUE_STATE_ENDED, ///< The queue is no longer joinable (players are getting prizes)
+};
+
 /// Battlegrounds client interface queue system [MasterOfMuppets]
 struct s_battleground_queue {
+	int queue_id; ///< Battlegrounds Queue ID
 	int id; ///< Battlegrounds database ID
 	std::vector<map_session_data *> teama_members; ///< List of members on team A
 	std::vector<map_session_data *> teamb_members; ///< List of members on team B
 	int required_players; ///< Amount of players required on each side to start
 	int max_players; ///< Maximum amount of players on each side
 	int accepted_players; ///< Amount of players who accepted the offer to enter the battleground
-	bool in_ready_state; ///< Is this BG queue waiting for players to enter the BG?
+	e_queue_state state; ///< See @e_queue_state
 	int tid_expire; ///< Timer ID associated with the time out at the ready to enter window
 	int tid_start; ///< Timer ID associated with the start delay
 	int tid_requeue; ///< Timer ID associated with requeuing this group if all BG maps are reserved
@@ -69,6 +80,10 @@ struct s_battleground_type {
 	std::vector<s_battleground_map> maps; ///< List of battleground locations
 	uint32 deserter_time; ///< Amount of time a player is marked deserter (seconds)
 	uint32 start_delay; ///< Amount of time before the start message is sent to players (seconds)
+	bool solo; ///< Ability to join a queue as an individual.
+	bool party; ///< Ability to join a queue as a party.
+	bool guild; ///< Ability to join a queue as a guild.
+	std::vector<int32> job_restrictions; ///< List of jobs that are unable to join.
 };
 
 /// Enum of responses when applying for a Battleground
@@ -109,15 +124,17 @@ public:
 
 extern BattlegroundDatabase battleground_db;
 extern std::unordered_map<int, std::shared_ptr<s_battleground_data>> bg_team_db;
+extern std::vector<std::shared_ptr<s_battleground_queue>> bg_queues;
 
 std::shared_ptr<s_battleground_type> bg_search_name(const char *name);
+std::shared_ptr<s_battleground_queue> bg_search_queue(int queue_id);
 void bg_send_dot_remove(struct map_session_data *sd);
 int bg_team_get_id(struct block_list *bl);
 struct map_session_data *bg_getavailablesd(s_battleground_data *bg);
 
-bool bg_queue_reservation(const char *name, bool state);
-#define bg_queue_reserve(name) (bg_queue_reservation(name, true))
-#define bg_queue_unbook(name) (bg_queue_reservation(name, false))
+bool bg_queue_reservation(const char *name, bool state, bool ended);
+#define bg_queue_reserve(name, end) (bg_queue_reservation(name, true, end))
+#define bg_queue_unbook(name) (bg_queue_reservation(name, false, false))
 
 int bg_create(uint16 mapindex, s_battleground_team* team);
 bool bg_team_join(int bg_id, struct map_session_data *sd, bool is_queue);
@@ -126,13 +143,15 @@ int bg_team_leave(struct map_session_data *sd, bool quit, bool deserter);
 bool bg_team_warp(int bg_id, unsigned short mapindex, short x, short y);
 bool bg_player_is_in_bg_map(struct map_session_data *sd);
 bool bg_queue_check_joinable(std::shared_ptr<s_battleground_type> bg, struct map_session_data *sd, const char *name);
+void bg_queue_join_solo(const char *name, struct map_session_data *sd);
 void bg_queue_join_party(const char *name, struct map_session_data *sd);
 void bg_queue_join_guild(const char *name, struct map_session_data *sd);
 void bg_queue_join_multi(const char *name, struct map_session_data *sd, std::vector<map_session_data *> list);
+void bg_queue_clear(std::shared_ptr<s_battleground_queue> queue, bool ended);
 bool bg_queue_leave(struct map_session_data *sd);
 bool bg_queue_on_ready(const char *name, std::shared_ptr<s_battleground_queue> queue);
-void bg_queue_on_accept_invite(std::shared_ptr<s_battleground_queue> queue, struct map_session_data *sd);
-void bg_queue_start_battleground(s_battleground_queue *queue);
+void bg_queue_on_accept_invite(struct map_session_data *sd);
+void bg_queue_start_battleground(std::shared_ptr<s_battleground_queue> queue);
 bool bg_member_respawn(struct map_session_data *sd);
 void bg_send_message(struct map_session_data *sd, const char *mes, int len);
 

+ 97 - 107
src/map/buyingstore.cpp

@@ -113,8 +113,7 @@ int8 buyingstore_setup(struct map_session_data* sd, unsigned char slots){
 * @param at Autotrader info, or NULL if requetsed not from autotrade persistance
 * @return 0 If success, 1 - Cannot open, 2 - Manner penalty, 3 - Mapflag restiction, 4 - Cell restriction, 5 - Invalid count/result, 6 - Cannot give item, 7 - Will be overweight
 */
-int8 buyingstore_create(struct map_session_data* sd, int zenylimit, unsigned char result, const char* storename, const uint8* itemlist, unsigned int count, struct s_autotrader *at)
-{
+int8 buyingstore_create( struct map_session_data* sd, int zenylimit, unsigned char result, const char* storename, const struct PACKET_CZ_REQ_OPEN_BUYING_STORE_sub* itemlist, unsigned int count, struct s_autotrader *at ){
 	unsigned int i, weight, listidx;
 	char message_sql[MESSAGE_SIZE*2];
 	StringBuf buf;
@@ -161,50 +160,53 @@ int8 buyingstore_create(struct map_session_data* sd, int zenylimit, unsigned cha
 	weight = sd->weight;
 
 	// check item list
-	for( i = 0; i < count; i++ )
-	{// itemlist: <name id>.W <amount>.W <price>.L
-		unsigned short nameid, amount;
-		int price, idx;
-		struct item_data* id;
-
-		nameid = RBUFW(itemlist,i*8+0);
-		amount = RBUFW(itemlist,i*8+2);
-		price  = RBUFL(itemlist,i*8+4);
-
-		if( ( id = itemdb_exists(nameid) ) == NULL || amount == 0 )
-		{// invalid input
+	for( i = 0; i < count; i++ ){
+		const struct PACKET_CZ_REQ_OPEN_BUYING_STORE_sub *item = &itemlist[i];
+
+		struct item_data* id = itemdb_exists( item->itemId );
+
+		// invalid input
+		if( id == NULL || item->amount == 0 ){	
+			break;
+		}
+
+		// invalid price: unlike vending, items cannot be bought at 0 Zeny
+		if( item->price <= 0 || item->price > BUYINGSTORE_MAX_PRICE ){
 			break;
 		}
 
-		if( price <= 0 || price > BUYINGSTORE_MAX_PRICE )
-		{// invalid price: unlike vending, items cannot be bought at 0 Zeny
+		// restrictions: allowed and no character-bound items
+		if( !id->flag.buyingstore || !itemdb_cantrade_sub( id, pc_get_group_level( sd ), pc_get_group_level( sd ) ) ){ 
 			break;
 		}
 
-		if( !id->flag.buyingstore || !itemdb_cantrade_sub(id, pc_get_group_level(sd), pc_get_group_level(sd)) || ( idx = pc_search_inventory(sd, nameid) ) == -1 )
-		{// restrictions: allowed, no character-bound items and at least one must be owned
+		int idx = pc_search_inventory( sd, item->itemId );
+
+		// At least one must be owned
+		if( idx < 0 ){
 			break;
 		}
 
-		if( sd->inventory.u.items_inventory[idx].amount + amount > BUYINGSTORE_MAX_AMOUNT )
-		{// too many items of same kind
+		// too many items of same kind
+		if( sd->inventory.u.items_inventory[idx].amount + item->amount > BUYINGSTORE_MAX_AMOUNT ){
 			break;
 		}
 
-		if( i )
-		{// duplicate check. as the client does this too, only malicious intent should be caught here
-			ARR_FIND( 0, i, listidx, sd->buyingstore.items[listidx].nameid == nameid );
-			if( listidx != i )
-			{// duplicate
-				ShowWarning("buyingstore_create: Found duplicate item on buying list (nameid=%hu, amount=%hu, account_id=%d, char_id=%d).\n", nameid, amount, sd->status.account_id, sd->status.char_id);
+		// duplicate check. as the client does this too, only malicious intent should be caught here
+		if( i ){
+			ARR_FIND( 0, i, listidx, sd->buyingstore.items[listidx].nameid == item->itemId );
+
+			// duplicate
+			if( listidx != i ){
+				ShowWarning( "buyingstore_create: Found duplicate item on buying list (nameid=%hu, amount=%hu, account_id=%d, char_id=%d).\n", item->itemId, item->amount, sd->status.account_id, sd->status.char_id );
 				break;
 			}
 		}
 
-		weight+= id->weight*amount;
-		sd->buyingstore.items[i].nameid = nameid;
-		sd->buyingstore.items[i].amount = amount;
-		sd->buyingstore.items[i].price  = price;
+		weight+= id->weight*item->amount;
+		sd->buyingstore.items[i].nameid = item->itemId;
+		sd->buyingstore.items[i].amount = item->amount;
+		sd->buyingstore.items[i].price  = item->price;
 	}
 
 	if( i != count )
@@ -322,10 +324,9 @@ void buyingstore_open(struct map_session_data* sd, uint32 account_id)
 * @param *itemlist List of sold items { <index>.W, <nameid>.W, <amount>.W }*
 * @param count Number of item on the itemlist
 */
-void buyingstore_trade(struct map_session_data* sd, uint32 account_id, unsigned int buyer_id, const uint8* itemlist, unsigned int count)
-{
+void buyingstore_trade( struct map_session_data* sd, uint32 account_id, unsigned int buyer_id, const struct PACKET_CZ_REQ_TRADE_BUYING_STORE_sub* itemlist, unsigned int count ){
 	int zeny = 0;
-	unsigned int i, weight, listidx, k;
+	unsigned int weight;
 	struct map_session_data* pl_sd;
 
 	nullpo_retv(sd);
@@ -362,98 +363,94 @@ void buyingstore_trade(struct map_session_data* sd, uint32 account_id, unsigned
 
 	searchstore_clearremote(sd);
 
-	if( pl_sd->status.zeny < pl_sd->buyingstore.zenylimit )
-	{// buyer lost zeny in the mean time? fix the limit
+	// buyer lost zeny in the mean time? fix the limit
+	if( pl_sd->status.zeny < pl_sd->buyingstore.zenylimit ){
 		pl_sd->buyingstore.zenylimit = pl_sd->status.zeny;
 	}
 	weight = pl_sd->weight;
 
 	// check item list
-	for( i = 0; i < count; i++ )
-	{// itemlist: <index>.W <name id>.W <amount>.W
-		unsigned short nameid, amount;
-		int index;
-
-		index  = RBUFW(itemlist,i*6+0)-2;
-		nameid = RBUFW(itemlist,i*6+2);
-		amount = RBUFW(itemlist,i*6+4);
-
-		if( i )
-		{// duplicate check. as the client does this too, only malicious intent should be caught here
-			ARR_FIND( 0, i, k, RBUFW(itemlist,k*6+0)-2 == index );
-			if( k != i )
-			{// duplicate
-				ShowWarning("buyingstore_trade: Found duplicate item on selling list (prevnameid=%hu, prevamount=%hu, nameid=%hu, amount=%hu, account_id=%d, char_id=%d).\n",
-					RBUFW(itemlist,k*6+2), RBUFW(itemlist,k*6+4), nameid, amount, sd->status.account_id, sd->status.char_id);
-				clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, nameid);
+	for( int i = 0; i < count; i++ ){
+		const struct PACKET_CZ_REQ_TRADE_BUYING_STORE_sub* item = &itemlist[i];
+
+		// duplicate check. as the client does this too, only malicious intent should be caught here
+		for( int k = 0; k < i; k++ ){
+			// duplicate
+			if( itemlist[k].index == item->index && k != i ){
+				ShowWarning( "buyingstore_trade: Found duplicate item on selling list (prevnameid=%hu, prevamount=%hu, nameid=%hu, amount=%hu, account_id=%d, char_id=%d).\n", itemlist[k].itemId, itemlist[k].amount, item->itemId, item->amount, sd->status.account_id, sd->status.char_id );
+				clif_buyingstore_trade_failed_seller( sd, BUYINGSTORE_TRADE_SELLER_FAILED, item->itemId );
 				return;
 			}
 		}
 
-		if( index < 0 || index >= ARRAYLENGTH(sd->inventory.u.items_inventory) || sd->inventory_data[index] == NULL || sd->inventory.u.items_inventory[index].nameid != nameid || sd->inventory.u.items_inventory[index].amount < amount )
-		{// invalid input
-			clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, nameid);
+		int index = item->index - 2; // TODO: clif::server_index
+
+		// invalid input
+		if( index < 0 || index >= ARRAYLENGTH( sd->inventory.u.items_inventory ) || sd->inventory_data[index] == NULL || sd->inventory.u.items_inventory[index].nameid != item->itemId || sd->inventory.u.items_inventory[index].amount < item->amount ){
+			clif_buyingstore_trade_failed_seller( sd, BUYINGSTORE_TRADE_SELLER_FAILED, item->itemId );
 			return;
 		}
 
-		if( sd->inventory.u.items_inventory[index].expire_time || (sd->inventory.u.items_inventory[index].bound && !pc_can_give_bounded_items(sd)) || !itemdb_cantrade(&sd->inventory.u.items_inventory[index], pc_get_group_level(sd), pc_get_group_level(pl_sd)) || memcmp(sd->inventory.u.items_inventory[index].card, buyingstore_blankslots, sizeof(buyingstore_blankslots)) )
-		{// non-tradable item
-			clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, nameid);
+		// non-tradable item
+		if( sd->inventory.u.items_inventory[index].expire_time || ( sd->inventory.u.items_inventory[index].bound && !pc_can_give_bounded_items( sd ) ) || !itemdb_cantrade( &sd->inventory.u.items_inventory[index], pc_get_group_level( sd ), pc_get_group_level( pl_sd ) ) || memcmp( sd->inventory.u.items_inventory[index].card, buyingstore_blankslots, sizeof( buyingstore_blankslots ) ) ){
+			clif_buyingstore_trade_failed_seller( sd, BUYINGSTORE_TRADE_SELLER_FAILED, item->itemId );
 			return;
 		}
 
-		ARR_FIND( 0, pl_sd->buyingstore.slots, listidx, pl_sd->buyingstore.items[listidx].nameid == nameid );
-		if( listidx == pl_sd->buyingstore.slots || pl_sd->buyingstore.items[listidx].amount == 0 )
-		{// there is no such item or the buyer has already bought all of them
-			clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, nameid);
+		int listidx;
+
+		ARR_FIND( 0, pl_sd->buyingstore.slots, listidx, pl_sd->buyingstore.items[listidx].nameid == item->itemId );
+
+		// there is no such item or the buyer has already bought all of them
+		if( listidx == pl_sd->buyingstore.slots || pl_sd->buyingstore.items[listidx].amount == 0 ){
+			clif_buyingstore_trade_failed_seller( sd, BUYINGSTORE_TRADE_SELLER_FAILED, item->itemId );
 			return;
 		}
 
-		if( pl_sd->buyingstore.items[listidx].amount < amount )
-		{// buyer does not need that much of the item
-			clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_COUNT, nameid);
+		// buyer does not need that much of the item
+		if( pl_sd->buyingstore.items[listidx].amount < item->amount ){
+			clif_buyingstore_trade_failed_seller( sd, BUYINGSTORE_TRADE_SELLER_COUNT, item->itemId );
 			return;
 		}
 
-		if( pc_checkadditem(pl_sd, nameid, amount) == CHKADDITEM_OVERAMOUNT )
-		{// buyer does not have enough space for this item
-			clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, nameid);
+		// buyer does not have enough space for this item
+		if( pc_checkadditem( pl_sd, item->itemId, item->amount ) == CHKADDITEM_OVERAMOUNT ){
+			clif_buyingstore_trade_failed_seller( sd, BUYINGSTORE_TRADE_SELLER_FAILED, item->itemId );
 			return;
 		}
 
-		if( amount*(unsigned int)sd->inventory_data[index]->weight > pl_sd->max_weight-weight )
-		{// normally this is not supposed to happen, as the total weight is
-		 // checked upon creation, but the buyer could have gained items
-			clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, nameid);
+		// normally this is not supposed to happen, as the total weight is
+		// checked upon creation, but the buyer could have gained items
+		if( item->amount * (unsigned int)sd->inventory_data[index]->weight > pl_sd->max_weight - weight ){
+			clif_buyingstore_trade_failed_seller( sd, BUYINGSTORE_TRADE_SELLER_FAILED, item->itemId );
 			return;
 		}
-		weight+= amount*sd->inventory_data[index]->weight;
 
-		if( amount*pl_sd->buyingstore.items[listidx].price > pl_sd->buyingstore.zenylimit-zeny )
-		{// buyer does not have enough zeny
-			clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_ZENY, nameid);
+		weight += item->amount * sd->inventory_data[index]->weight;
+
+		// buyer does not have enough zeny
+		if( item->amount * pl_sd->buyingstore.items[listidx].price > pl_sd->buyingstore.zenylimit - zeny ){
+			clif_buyingstore_trade_failed_seller( sd, BUYINGSTORE_TRADE_SELLER_ZENY, item->itemId );
 			return;
 		}
-		zeny+= amount*pl_sd->buyingstore.items[listidx].price;
+
+		zeny += item->amount * pl_sd->buyingstore.items[listidx].price;
 	}
 
 	// process item list
-	for( i = 0; i < count; i++ )
-	{// itemlist: <index>.W <name id>.W <amount>.W
-		unsigned short nameid, amount;
-		int index;
+	for( int i = 0; i < count; i++ ){
+		const struct PACKET_CZ_REQ_TRADE_BUYING_STORE_sub* item = &itemlist[i];
+		int listidx;
 
-		index  = RBUFW(itemlist,i*6+0)-2;
-		nameid = RBUFW(itemlist,i*6+2);
-		amount = RBUFW(itemlist,i*6+4);
+		ARR_FIND( 0, pl_sd->buyingstore.slots, listidx, pl_sd->buyingstore.items[listidx].nameid == item->itemId );
+		zeny = item->amount * pl_sd->buyingstore.items[listidx].price;
 
-		ARR_FIND( 0, pl_sd->buyingstore.slots, listidx, pl_sd->buyingstore.items[listidx].nameid == nameid );
-		zeny = amount*pl_sd->buyingstore.items[listidx].price;
+		int index = item->index - 2; // TODO: clif::server_index
 
 		// move item
-		pc_additem(pl_sd, &sd->inventory.u.items_inventory[index], amount, LOG_TYPE_BUYING_STORE);
-		pc_delitem(sd, index, amount, 1, 0, LOG_TYPE_BUYING_STORE);
-		pl_sd->buyingstore.items[listidx].amount-= amount;
+		pc_additem(pl_sd, &sd->inventory.u.items_inventory[index], item->amount, LOG_TYPE_BUYING_STORE);
+		pc_delitem(sd, index, item->amount, 1, 0, LOG_TYPE_BUYING_STORE);
+		pl_sd->buyingstore.items[listidx].amount -= item->amount;
 
 		if( pl_sd->buyingstore.items[listidx].amount > 0 ){
 			if( Sql_Query( mmysql_handle, "UPDATE `%s` SET `amount` = %d WHERE `buyingstore_id` = %d AND `index` = %d;", buyingstore_items_table, pl_sd->buyingstore.items[listidx].amount, pl_sd->buyer_id, listidx ) != SQL_SUCCESS ){
@@ -471,8 +468,8 @@ void buyingstore_trade(struct map_session_data* sd, uint32 account_id, unsigned
 		pl_sd->buyingstore.zenylimit-= zeny;
 
 		// notify clients
-		clif_buyingstore_delete_item(sd, index, amount, pl_sd->buyingstore.items[listidx].price);
-		clif_buyingstore_update_item(pl_sd, nameid, amount, sd->status.char_id, zeny);
+		clif_buyingstore_delete_item(sd, index, item->amount, pl_sd->buyingstore.items[listidx].price);
+		clif_buyingstore_update_item(pl_sd, item->itemId, item->amount, sd->status.char_id, zeny);
 	}
 
 	if( save_settings&CHARSAVE_VENDING ) {
@@ -481,6 +478,7 @@ void buyingstore_trade(struct map_session_data* sd, uint32 account_id, unsigned
 	}
 	
 	// check whether or not there is still something to buy
+	int i;
 	ARR_FIND( 0, pl_sd->buyingstore.slots, i, pl_sd->buyingstore.items[i].amount != 0 );
 	if( i == pl_sd->buyingstore.slots )
 	{// everything was bought
@@ -548,7 +546,7 @@ bool buyingstore_searchall(struct map_session_data* sd, const struct s_search_st
 
 	for( idx = 0; idx < s->item_count; idx++ )
 	{
-		ARR_FIND( 0, sd->buyingstore.slots, i, sd->buyingstore.items[i].nameid == s->itemlist[idx] && sd->buyingstore.items[i].amount );
+		ARR_FIND( 0, sd->buyingstore.slots, i, sd->buyingstore.items[i].nameid == s->itemlist[idx].itemId && sd->buyingstore.items[i].amount );
 		if( i == sd->buyingstore.slots )
 		{// not found
 			continue;
@@ -591,23 +589,15 @@ void buyingstore_reopen( struct map_session_data* sd ){
 
 	// Ready to open buyingstore for this char
 	if ((at = (struct s_autotrader *)uidb_get(buyingstore_autotrader_db, sd->status.char_id)) && at->count && at->entries) {
-		uint8 *data, *p;
-		uint16 j, count;
+		struct PACKET_CZ_REQ_OPEN_BUYING_STORE_sub* data;
 
 		// Init buyingstore data for autotrader
-		CREATE(data, uint8, at->count * 8);
-
-		for (j = 0, p = data, count = at->count; j < at->count; j++) {
-			struct s_autotrade_entry *entry = at->entries[j];
-			unsigned short *item_id = (uint16*)(p + 0);
-			uint16 *amount = (uint16*)(p + 2);
-			uint32 *price = (uint32*)(p + 4);
-
-			*item_id = entry->item_id;
-			*amount = entry->amount;
-			*price = entry->price;
+		CREATE(data, struct PACKET_CZ_REQ_OPEN_BUYING_STORE_sub, at->count );
 
-			p += 8;
+		for( int j = 0; j < at->count; j++) {
+			data[j].itemId = at->entries[j]->item_id;
+			data[j].amount = at->entries[j]->amount;
+			data[j].price = at->entries[j]->price;
 		}
 
 		sd->state.autotrade = 1;
@@ -633,7 +623,7 @@ void buyingstore_reopen( struct map_session_data* sd ){
 			chrif_save(sd, CSAVE_AUTOTRADE);
 
 			ShowInfo("Buyingstore loaded for '" CL_WHITE "%s" CL_RESET "' with '" CL_WHITE "%d" CL_RESET "' items at " CL_WHITE "%s (%d,%d)" CL_RESET "\n",
-				sd->status.name, count, mapindex_id2name(sd->mapindex), sd->bl.x, sd->bl.y);
+				sd->status.name, at->count, mapindex_id2name(sd->mapindex), sd->bl.x, sd->bl.y);
 		}
 		aFree(data);
 	}

+ 2 - 2
src/map/buyingstore.hpp

@@ -56,10 +56,10 @@ struct s_autotrader {
 };
 
 int8 buyingstore_setup(struct map_session_data* sd, unsigned char slots);
-int8 buyingstore_create(struct map_session_data* sd, int zenylimit, unsigned char result, const char* storename, const uint8* itemlist, unsigned int count, struct s_autotrader *at);
+int8 buyingstore_create(struct map_session_data* sd, int zenylimit, unsigned char result, const char* storename, const struct PACKET_CZ_REQ_OPEN_BUYING_STORE_sub* itemlist, unsigned int count, struct s_autotrader *at);
 void buyingstore_close(struct map_session_data* sd);
 void buyingstore_open(struct map_session_data* sd, uint32 account_id);
-void buyingstore_trade(struct map_session_data* sd, uint32 account_id, unsigned int buyer_id, const uint8* itemlist, unsigned int count);
+void buyingstore_trade(struct map_session_data* sd, uint32 account_id, unsigned int buyer_id, const struct PACKET_CZ_REQ_TRADE_BUYING_STORE_sub* itemlist, unsigned int count);
 bool buyingstore_search(struct map_session_data* sd, unsigned short nameid);
 bool buyingstore_searchall(struct map_session_data* sd, const struct s_search_store_search* s);
 DBMap *buyingstore_getdb(void);

+ 12 - 11
src/map/cashshop.cpp

@@ -467,7 +467,7 @@ static void cashshop_read_db( void ){
  * @param item_list Array of item ID
  * @return true: success, false: fail
  */
-bool cashshop_buylist( struct map_session_data* sd, uint32 kafrapoints, int n, uint16* item_list ){
+bool cashshop_buylist( struct map_session_data* sd, uint32 kafrapoints, int n, struct PACKET_CZ_SE_PC_BUY_CASHITEM_LIST_sub* item_list ){
 	uint32 totalcash = 0;
 	uint32 totalweight = 0;
 	int i,new_;
@@ -487,9 +487,9 @@ bool cashshop_buylist( struct map_session_data* sd, uint32 kafrapoints, int n, u
 	new_ = 0;
 
 	for( i = 0; i < n; ++i ){
-		unsigned short nameid = *( item_list + i * 5 );
-		uint32 quantity = *( item_list + i * 5 + 2 );
-		uint8 tab = (uint8)*( item_list + i * 5 + 4 );
+		unsigned short nameid = item_list[i].itemId;
+		uint32 quantity = item_list[i].amount;
+		uint16 tab = item_list[i].tab;
 		int j;
 
 		if( tab >= CASHSHOP_TAB_MAX ){
@@ -504,7 +504,7 @@ bool cashshop_buylist( struct map_session_data* sd, uint32 kafrapoints, int n, u
 			return false;
 		}
 
-		nameid = *( item_list + i * 5 ) = cash_shop_items[tab].item[j]->nameid; //item_avail replacement
+		nameid = item_list[i].itemId = cash_shop_items[tab].item[j]->nameid; //item_avail replacement
 		id = itemdb_exists(nameid);
 
 		if( !id ){
@@ -569,10 +569,10 @@ bool cashshop_buylist( struct map_session_data* sd, uint32 kafrapoints, int n, u
 	}
 
 	for( i = 0; i < n; ++i ){
-		unsigned short nameid = *( item_list + i * 5 );
-		uint32 quantity = *( item_list + i * 5 + 2 );
+		unsigned short nameid = item_list[i].itemId;
+		uint32 quantity = item_list[i].amount;
 #if PACKETVER_SUPPORTS_SALES
-		uint16 tab = *(item_list + i * 5 + 4);
+		uint16 tab = item_list[i].tab;
 #endif
 		struct item_data *id = itemdb_search(nameid);
 
@@ -580,12 +580,12 @@ bool cashshop_buylist( struct map_session_data* sd, uint32 kafrapoints, int n, u
 			continue;
 
 		if (!pet_create_egg(sd, nameid)) {
-			unsigned short get_amt = quantity, j;
+			unsigned short get_amt = quantity;
 
 			if (id->flag.guid || !itemdb_isstackable2(id))
 				get_amt = 1;
 
-			for (j = 0; j < quantity; j += get_amt) {
+			for (uint32 j = 0; j < quantity; j += get_amt) {
 				struct item item_tmp = { 0 };
 
 				item_tmp.nameid = nameid;
@@ -606,6 +606,8 @@ bool cashshop_buylist( struct map_session_data* sd, uint32 kafrapoints, int n, u
 						return false;
 				}
 
+				clif_cashshop_result( sd, nameid, CASHSHOP_RESULT_SUCCESS );
+
 #if PACKETVER_SUPPORTS_SALES
 				if( tab == CASHSHOP_TAB_SALE ){
 					uint32 new_amount = sale->amount - get_amt;
@@ -627,7 +629,6 @@ bool cashshop_buylist( struct map_session_data* sd, uint32 kafrapoints, int n, u
 		}
 	}
 
-	clif_cashshop_result( sd, 0, CASHSHOP_RESULT_SUCCESS ); //Doesn't show any message?
 	return true;
 }
 

+ 1 - 1
src/map/cashshop.hpp

@@ -13,7 +13,7 @@ struct map_session_data;
 void do_init_cashshop( void );
 void do_final_cashshop( void );
 void cashshop_reloaddb( void );
-bool cashshop_buylist( struct map_session_data* sd, uint32 kafrapoints, int n, uint16* item_list );
+bool cashshop_buylist( struct map_session_data* sd, uint32 kafrapoints, int n, struct PACKET_CZ_SE_PC_BUY_CASHITEM_LIST_sub* item_list );
 
 // Taken from AEGIS
 enum CASH_SHOP_TAB_CODE

+ 4 - 0
src/map/clan.cpp

@@ -12,6 +12,7 @@
 #include "../common/showmsg.hpp"
 
 #include "clif.hpp"
+#include "instance.hpp"
 #include "intif.hpp"
 #include "log.hpp"
 #include "pc.hpp"
@@ -128,6 +129,9 @@ void clan_member_joined( struct map_session_data* sd ){
 
 		intif_clan_member_joined(clan->id);
 		clif_clan_onlinecount(clan);
+
+		if (clan->instance_id > 0)
+			instance_reqinfo(sd, clan->instance_id);
 	}
 }
 

Some files were not shown because too many files changed in this diff