Bladeren bron

Merge branch 'master' into refactor/cmake

Vincent Stumpf 1 jaar geleden
bovenliggende
commit
b01e7da68d
68 gewijzigde bestanden met toevoegingen van 4041 en 1912 verwijderingen
  1. 0 4
      conf/inter_athena.conf
  2. 20 0
      db/pre-re/statpoint.yml
  3. 2 17
      db/re/item_combos.yml
  4. 77 38
      db/re/item_db_equip.yml
  5. 40 10
      db/re/item_db_etc.yml
  6. 0 1
      db/re/item_db_usable.yml
  7. 760 0
      db/re/job_basepoints.yml
  8. 418 418
      db/re/job_exp.yml
  9. 184 0
      db/re/job_stats.yml
  10. 205 243
      db/re/skill_db.yml
  11. 86 0
      db/re/skill_tree.yml
  12. 30 0
      db/re/statpoint.yml
  13. 33 3
      db/re/status.yml
  14. 11 4
      doc/script_commands.txt
  15. 69 68
      npc/re/instances/HiddenGarden.txt
  16. 14 0
      npc/re/merchants/barters/enchan_illusion_dungeons.yml
  17. 38 0
      npc/re/merchants/enchan_illusion_dungeons.txt
  18. 51 24
      npc/re/mobs/dungeons/lhz_dun_n.txt
  19. 0 4
      src/char/char_clif.cpp
  20. 1 1
      src/char/int_mail.cpp
  21. 0 12
      src/common/cbasetypes.hpp
  22. 1 0
      src/common/common.vcxproj
  23. 3 0
      src/common/common.vcxproj.filters
  24. 1 0
      src/common/db.cpp
  25. 22 28
      src/common/db.hpp
  26. 1 0
      src/common/mapindex.cpp
  27. 4 6
      src/common/md5calc.cpp
  28. 3 1
      src/common/md5calc.hpp
  29. 3 0
      src/common/mmo.hpp
  30. 212 0
      src/common/packets.hpp
  31. 3 0
      src/common/random.hpp
  32. 4 0
      src/common/socket.cpp
  33. 30 0
      src/common/socket.hpp
  34. 55 23
      src/common/sql.cpp
  35. 6 4
      src/common/timer.cpp
  36. 25 42
      src/login/account.cpp
  37. 1 5
      src/login/account.hpp
  38. 25 41
      src/login/ipban.cpp
  39. 43 28
      src/login/login.cpp
  40. 259 207
      src/login/loginclif.cpp
  41. 22 82
      src/login/loginlog.cpp
  42. 259 63
      src/map/battle.cpp
  43. 1 0
      src/map/channel.cpp
  44. 1 0
      src/map/chrif.cpp
  45. 69 75
      src/map/clif.cpp
  46. 1 1
      src/map/clif.hpp
  47. 16 5
      src/map/clif_packetdb.hpp
  48. 10 17
      src/map/elemental.cpp
  49. 4 4
      src/map/itemdb.cpp
  50. 20 14
      src/map/map.cpp
  51. 1 1
      src/map/map.hpp
  52. 34 34
      src/map/mob.cpp
  53. 3 5
      src/map/navi.cpp
  54. 1 4
      src/map/npc.cpp
  55. 19 100
      src/map/packets.hpp
  56. 321 65
      src/map/packets_struct.hpp
  57. 5 7
      src/map/path.cpp
  58. 24 18
      src/map/pc.cpp
  59. 97 41
      src/map/script.cpp
  60. 3 1
      src/map/script.hpp
  61. 17 2
      src/map/script_constants.hpp
  62. 1 1
      src/map/searchstore.cpp
  63. 208 67
      src/map/skill.cpp
  64. 3 0
      src/map/skill.hpp
  65. 139 60
      src/map/status.cpp
  66. 9 0
      src/map/status.hpp
  67. 1 1
      src/map/unit.cpp
  68. 12 12
      src/web/web.cpp

+ 0 - 4
conf/inter_athena.conf

@@ -30,10 +30,6 @@ emblem_transparency_limit: 80
 // "Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)"
 // and you have localhost, switch it to 127.0.0.1
 
-// Global SQL settings
-// overridden by local settings when the hostname is defined there
-// (currently only the login-server reads/obeys these settings)
-
 // MySQL Login server
 login_server_ip: 127.0.0.1
 login_server_port: 3306

+ 20 - 0
db/pre-re/statpoint.yml

@@ -532,3 +532,23 @@ Body:
     Points: 4545
   - Level: 250
     Points: 4545
+  - Level: 251
+    Points: 4545
+  - Level: 252
+    Points: 4545
+  - Level: 253
+    Points: 4545
+  - Level: 254
+    Points: 4545
+  - Level: 255
+    Points: 4545
+  - Level: 256
+    Points: 4545
+  - Level: 257
+    Points: 4545
+  - Level: 258
+    Points: 4545
+  - Level: 259
+    Points: 4545
+  - Level: 260
+    Points: 4545

+ 2 - 17
db/re/item_combos.yml

@@ -10518,7 +10518,7 @@ Body:
           - Shoes_Of_Punishment     # 22120
           - Holy_Stick     # 1631
       - Combo:
-          - Shoes_Of_Punishment     # 22225
+          - Shoes_Of_Punishment_     # 22225
           - Holy_Stick     # 1631
     Script: |
       .@r = getequiprefinerycnt(EQI_HAND_R);
@@ -47267,7 +47267,7 @@ Body:
   - Combos:
       - Combo:
           - Hero    # 29509
-          - aegis_312300    # 312300
+          - aegis_312301    # 312301
     Script: |
       bonus2 bSkillCooldown,"BO_ACIDIFIED_ZONE_FIRE",-200;
       bonus2 bSkillCooldown,"BO_ACIDIFIED_ZONE_WATER",-200;
@@ -47454,21 +47454,6 @@ Body:
       bonus bMaxHPrate,10;
       bonus bMaxSPrate,10;
       bonus2 bSubEle,Ele_Earth,15;
-  - Combos:
-      - Combo:
-          - Goddess_of_Abundance    # 311073
-          - aegis_450286    # 450286
-    Script: |
-      bonus2 bAddSize,Size_All,30;
-      bonus2 bMagicAddSize,Size_All,30;
-  - Combos:
-      - Combo:
-          - Goddess_of_Abundance    # 311073
-          - aegis_420223    # 420223
-    Script: |
-      bonus2 bSubRace,RC_Player_Human,3;
-      bonus2 bSubRace,RC_Player_Doram,3;
-      bonus bNoCastCancel;
   - Combos:
       - Combo:
           - Bakonawa_Tattoo    # 2910

+ 77 - 38
db/re/item_db_equip.yml

@@ -40827,7 +40827,7 @@ Body:
       Assassin: true
       Priest: true
     Locations:
-      Head_Low: true
+      Head_Top: true
     ArmorLevel: 1
     EquipLevelMin: 70
     View: 180
@@ -48957,6 +48957,7 @@ Body:
     Weight: 500
     Defense: 5
     Locations:
+      Head_Low: true
       Head_Mid: true
       Head_Top: true
     ArmorLevel: 1
@@ -49901,7 +49902,6 @@ Body:
     Weight: 500
     Defense: 5
     Locations:
-      Head_Low: true
       Head_Mid: true
       Head_Top: true
     ArmorLevel: 1
@@ -49959,6 +49959,7 @@ Body:
     Type: Armor
     Defense: 5
     Locations:
+      Head_Mid: true
       Head_Top: true
     ArmorLevel: 1
     Refineable: true
@@ -64053,7 +64054,7 @@ Body:
       KagerouOboro: true
       Ninja: true
     Locations:
-      Right_Hand: true
+      Both_Hand: true
     WeaponLevel: 3
     EquipLevelMin: 40
     Refineable: true
@@ -78196,7 +78197,7 @@ Body:
       .@d = readparam(bInt)/18;
       .@e = readparam(bDex)/18;
       .@f = readparam(bLuk)/18;
-      skill "MC_IDENTIFY",1,0;
+      skill "MC_IDENTIFY",1;
       bonus bHit,2*.@a;
       bonus bMaxHPrate,2*.@a;
       bonus bFlee,2*.@b;
@@ -84118,6 +84119,7 @@ Body:
     Defense: 10
     Slots: 1
     Locations:
+      Head_Mid: true
       Head_Top: true
     ArmorLevel: 1
     EquipLevelMin: 70
@@ -96939,7 +96941,7 @@ Body:
     EquipLevelMin: 100
     View: 1093
     Script: |
-      skill "MC_IDENTIFY",1,0;
+      skill "MC_IDENTIFY",1;
       .@a = readparam(bStr);
       .@b = readparam(bAgi);
       .@c = readparam(bVit);
@@ -96971,7 +96973,7 @@ Body:
     ArmorLevel: 1
     EquipLevelMin: 100
     Script: |
-      skill "MC_IDENTIFY",1,0;
+      skill "MC_IDENTIFY",1;
       .@a = readparam(bStr);
       .@b = readparam(bAgi);
       .@c = readparam(bVit);
@@ -98820,6 +98822,7 @@ Body:
     Type: Armor
     Locations:
       Costume_Head_Top: true
+      Costume_Head_Mid: true
     ArmorLevel: 1
     EquipLevelMin: 1
     View: 528
@@ -100887,6 +100890,14 @@ Body:
       NoAuction: true
     Script: |
       bonus2 bExpAddRace,RC_All,10;
+  - Id: 19766
+    AegisName: C_Yggdrasil_Hat
+    Name: Costume Yggdrasil Hat
+    Type: Armor
+    Locations:
+      Costume_Head_Top: true
+    ArmorLevel: 1
+    View: 997
   - Id: 19767
     AegisName: C_Home_Cherry_Blossom
     Name: Costume Home Cherry Blossom
@@ -100896,14 +100907,6 @@ Body:
     ArmorLevel: 1
     EquipLevelMin: 1
     View: 602
-  - Id: 19766
-    AegisName: C_Yggdrasil_Hat
-    Name: Costume Yggdrasil Hat
-    Type: Armor
-    Locations:
-      Costume_Head_Top: true
-    ArmorLevel: 1
-    View: 997
   - Id: 19768
     AegisName: C_Sakura_Coronet
     Name: Costume Sakura Coronet
@@ -102407,8 +102410,6 @@ Body:
     Type: Armor
     Locations:
       Costume_Head_Top: true
-      Costume_Head_Mid: true
-      Costume_Head_Low: true
     ArmorLevel: 1
     EquipLevelMin: 1
     View: 636
@@ -103236,6 +103237,7 @@ Body:
     Type: Armor
     Locations:
       Costume_Head_Top: true
+      Costume_Head_Mid: true
     ArmorLevel: 1
     EquipLevelMin: 1
     View: 175
@@ -103669,7 +103671,7 @@ Body:
     Name: Costume Prayer Cherry Blossom
     Type: Armor
     Locations:
-      Costume_Head_Top: true
+      Costume_Head_Mid: true
     ArmorLevel: 1
     EquipLevelMin: 1
     View: 1223
@@ -107006,6 +107008,7 @@ Body:
     Type: Armor
     Locations:
       Costume_Head_Top: true
+      Costume_Head_Mid: true
     ArmorLevel: 1
     EquipLevelMin: 1
     View: 634
@@ -107903,7 +107906,7 @@ Body:
     Name: Costume Unidentified Flying Poring
     Type: Armor
     Locations:
-      Costume_Head_Top: true
+      Costume_Head_Low: true
     ArmorLevel: 1
     EquipLevelMin: 1
     View: 1017
@@ -108180,7 +108183,7 @@ Body:
     Name: Costume Blessings Of Soul
     Type: Armor
     Locations:
-      Costume_Head_Low: true
+      Costume_Garment: true
     ArmorLevel: 1
     EquipLevelMin: 1
     Script: |
@@ -147592,7 +147595,6 @@ Body:
     Type: Armor
     Locations:
       Costume_Head_Top: true
-      Costume_Head_Mid: true
       Costume_Head_Low: true
     ArmorLevel: 1
     EquipLevelMin: 1
@@ -148489,6 +148491,7 @@ Body:
     Type: Armor
     Locations:
       Costume_Head_Top: true
+      Costume_Head_Mid: true
     ArmorLevel: 1
     EquipLevelMin: 1
     View: 223
@@ -149039,7 +149042,7 @@ Body:
     Name: Costume War Princess Ribbon
     Type: Armor
     Locations:
-      Costume_Head_Top: true
+      Costume_Head_Mid: true
     ArmorLevel: 1
     EquipLevelMin: 1
     View: 1583
@@ -154559,7 +154562,7 @@ Body:
     Name: Costume Savage Shoulder Bebe
     Type: Armor
     Locations:
-      Costume_Head_Top: true
+      Costume_Head_Mid: true
     ArmorLevel: 1
     EquipLevelMin: 1
     View: 1915
@@ -169223,6 +169226,14 @@ Body:
       Costume_Head_Top: true
     ArmorLevel: 1
     View: 1001
+  - Id: 400558
+    AegisName: aegis_400558
+    Name: Costume Snowman Experience    # !todo check english name
+    Type: Armor
+    Locations:
+      Costume_Head_Top: true
+    ArmorLevel: 1
+    View: 2486
   - Id: 400574
     AegisName: ROZ_Bijou_Hat_Str
     Name: Bijou's Hat (Strength)
@@ -169397,6 +169408,14 @@ Body:
              }
          }
       }
+  - Id: 400585
+    AegisName: aegis_400585
+    Name: Costume Snowman Hat    # !todo check english name
+    Type: Armor
+    Locations:
+      Costume_Head_Top: true
+    ArmorLevel: 1
+    View: 2488
   - Id: 410000
     AegisName: Resonate_Taego_J
     Name: Ancient Resonance
@@ -169741,8 +169760,7 @@ Body:
     View: 876
     Slots: 1
     Locations:
-      Head_Top: true
-      Head_Low: true
+      Head_Mid: true
     ArmorLevel: 1
     EquipLevelMin: 130
     Trade:
@@ -169762,8 +169780,7 @@ Body:
     View: 917
     Slots: 1
     Locations:
-      Head_Top: true
-      Head_Low: true
+      Head_Mid: true
     ArmorLevel: 1
     EquipLevelMin: 130
     Trade:
@@ -169783,8 +169800,7 @@ Body:
     View: 906
     Slots: 1
     Locations:
-      Head_Top: true
-      Head_Low: true
+      Head_Mid: true
     ArmorLevel: 1
     EquipLevelMin: 130
     Trade:
@@ -172200,8 +172216,8 @@ Body:
     Trade:
       NoDrop: true
       NoTrade: true
+      NoSell: true
       NoCart: true
-      NoStorage: true
       NoGuildStorage: true
       NoMail: true
       NoAuction: true
@@ -172216,8 +172232,8 @@ Body:
     Trade:
       NoDrop: true
       NoTrade: true
+      NoSell: true
       NoCart: true
-      NoStorage: true
       NoGuildStorage: true
       NoMail: true
       NoAuction: true
@@ -172422,6 +172438,13 @@ Body:
       Costume_Head_Top: true
     ArmorLevel: 1
     View: 1463
+  - Id: 410295
+    AegisName: aegis_410295
+    Name: Costume Bells on a Winter Night    # !todo check english name
+    Type: Armor
+    Locations:
+      Costume_Head_Mid: true
+    ArmorLevel: 1
   - Id: 420000
     AegisName: Isabella_Carrot
     Name: Isabella Carrot
@@ -174724,6 +174747,13 @@ Body:
     ArmorLevel: 1
     EquipLevelMin: 150
     View: 2448
+  - Id: 420304
+    AegisName: aegis_420304
+    Name: Costume Routier’s Night Sky    # !todo check english name
+    Type: Armor
+    Locations:
+      Costume_Head_Low: true
+    ArmorLevel: 1
   - Id: 430001
     AegisName: C_Helm_Of_Ra
     Name: Costume Hat of the Sun God
@@ -174902,7 +174932,7 @@ Body:
     View: 666
     Weight: 100
     Locations:
-      Head_Top: true
+      Head_Low: true
       Head_Mid: true
     ArmorLevel: 1
     EquipLevelMin: 99
@@ -174917,7 +174947,7 @@ Body:
     View: 693
     Weight: 100
     Locations:
-      Head_Top: true
+      Head_Low: true
       Head_Mid: true
     ArmorLevel: 1
     EquipLevelMin: 99
@@ -174933,7 +174963,7 @@ Body:
     Weight: 100
     Defense: 3
     Locations:
-      Head_Top: true
+      Head_Low: true
       Head_Mid: true
     ArmorLevel: 1
     EquipLevelMin: 99
@@ -174950,7 +174980,7 @@ Body:
     Defense: 3
     Slots: 1
     Locations:
-      Head_Top: true
+      Head_Low: true
       Head_Mid: true
     ArmorLevel: 1
     EquipLevelMin: 99
@@ -174966,7 +174996,7 @@ Body:
     Weight: 100
     Slots: 1
     Locations:
-      Head_Top: true
+      Head_Low: true
       Head_Mid: true
     ArmorLevel: 1
     EquipLevelMin: 99
@@ -174982,7 +175012,7 @@ Body:
     Weight: 100
     Slots: 1
     Locations:
-      Head_Top: true
+      Head_Low: true
       Head_Mid: true
     ArmorLevel: 1
     EquipLevelMin: 99
@@ -188348,6 +188378,7 @@ Body:
          bonus bAtkRate,7;
          if (.@r>=9) {
             bonus bShortAtkRate,10;
+            bonus bLongAtkRate,10;
             if (.@r>=11) {
                bonus bFixedCast,-500;
             }
@@ -195089,6 +195120,14 @@ Body:
              }
          }
       }
+  - Id: 480405
+    AegisName: aegis_480405
+    Name: Costume Santa Teddy Bear Doll Bag    # !todo check english name
+    Type: Armor
+    Locations:
+      Costume_Garment: true
+    ArmorLevel: 1
+    View: 202
   - Id: 490004
     AegisName: Atker_Ring
     Name: Attacker Booster Ring
@@ -203309,7 +203348,7 @@ Body:
          }
       }
       if (.@g>=ENCHANTGRADE_D) {
-         bonus bShortAtkRate,5;
+         bonus bShortAtkRate,10;
          if (.@g>=ENCHANTGRADE_C) {
             bonus2 bAddSize,Size_All,10;
             if (.@g>=ENCHANTGRADE_B) {
@@ -225854,7 +225893,7 @@ Body:
       All_Third: true
       Fourth: true
     Locations:
-      Right_Hand: true
+      Both_Hand: true
     WeaponLevel: 4
     EquipLevelMin: 150
     Refineable: true

+ 40 - 10
db/re/item_db_etc.yml

@@ -41749,6 +41749,7 @@ Body:
     Buy: 20
     Weight: 10
     Locations:
+      Head_Low: true
       Head_Mid: true
       Head_Top: true
     Flags:
@@ -41763,6 +41764,7 @@ Body:
     Buy: 20
     Weight: 10
     Locations:
+      Head_Low: true
       Head_Mid: true
       Head_Top: true
     Flags:
@@ -51300,6 +51302,8 @@ Body:
     Type: Card
     Weight: 10
     Locations:
+      Head_Low: true
+      Head_Mid: true
       Head_Top: true
     Flags:
       BuyingStore: true
@@ -63337,42 +63341,42 @@ Body:
     Type: Card
     SubType: Enchant
     Script: |
-      autobonus "{ bonus bAtkRate,25; bonus bVit,50; }",30,10000,BF_WEAPON;
+      autobonus "{ bonus bAtkRate,25; bonus bVit,50; }",30,10000,BF_WEAPON,"{ specialeffect2 EF_POTION_BERSERK; }";
   - Id: 311121
     AegisName: Ice_F_Orb_Sp_Int
     Name: Ice Magic Orb (Spell Buster)
     Type: Card
     SubType: Enchant
     Script: |
-      autobonus "{ bonus bMatkRate,25; bonus bInt,50; }",30,10000,BF_MAGIC;
+      autobonus "{ bonus bMatkRate,25; bonus bInt,50; }",30,10000,BF_MAGIC,"{ specialeffect2 EF_POTION_BERSERK; }";
   - Id: 311122
     AegisName: Ice_F_Orb_Fi_Dex
     Name: Ice Magic Orb (Firing Shot)
     Type: Card
     SubType: Enchant
     Script: |
-      autobonus "{ bonus bLongAtkRate,15; bonus bDex,50; }",30,10000,BF_WEAPON;
+      autobonus "{ bonus bLongAtkRate,15; bonus bDex,50; }",30,10000,BF_WEAPON,"{ specialeffect2 EF_POTION_BERSERK; }";
   - Id: 311123
     AegisName: Ice_F_Orb_Ov_Str
     Name: Ice Magic Orb (Overpower)
     Type: Card
     SubType: Enchant
     Script: |
-      autobonus "{ bonus bShortAtkRate,15; bonus bStr,50; }",30,10000,BF_WEAPON;
+      autobonus "{ bonus bShortAtkRate,15; bonus bStr,50; }",30,10000,BF_WEAPON,"{ specialeffect2 EF_POTION_BERSERK; }";
   - Id: 311124
     AegisName: Ice_F_Orb_Fa_Agi
     Name: Ice Magic Orb (Fatal Flash)
     Type: Card
     SubType: Enchant
     Script: |
-      autobonus "{ bonus bCritAtkRate,25; bonus bAgi,50; }",30,10000,BF_WEAPON;
+      autobonus "{ bonus bCritAtkRate,25; bonus bAgi,50; }",30,10000,BF_WEAPON,"{ specialeffect2 EF_POTION_BERSERK; }";
   - Id: 311125
     AegisName: Ice_F_Orb_Lu_Luk
     Name: Ice Magic Orb (Lucky Strike)
     Type: Card
     SubType: Enchant
     Script: |
-      autobonus "{ bonus2 bMagicAtkEle,Ele_All,15; bonus bLuk,50; }",30,10000,BF_MAGIC;
+      autobonus "{ bonus2 bMagicAtkEle,Ele_All,15; bonus bLuk,50; }",30,10000,BF_MAGIC,"{ specialeffect2 EF_POTION_BERSERK; }";
   - Id: 311126
     AegisName: Ice_F_Orb_A_Delay
     Name: Ice Magic Orb (Delay After Attack)
@@ -70933,9 +70937,9 @@ Body:
     SubType: Enchant
     Script: |
       .@g = getenchantgrade();
-      bonus bMaxHPrate,-5;
+      bonus bMaxHPrate,-5; 
       bonus bMaxSPrate,-5;
-      autobonus "{ bonus bStr,50; bonus bPow,15; bonus bSta,15; }",30,10000,BF_WEAPON;
+      autobonus "{ bonus bStr,50; bonus bPow,15; bonus bSta,15; }",30,10000,BF_WEAPON,"{ specialeffect2 EF_POTION_BERSERK; }";
       if (.@g>=ENCHANTGRADE_D) {
          bonus bLongAtkRate,5;
          bonus bShortAtkRate,5;
@@ -70953,7 +70957,7 @@ Body:
       .@g = getenchantgrade();
       bonus bMaxHPrate,-5;
       bonus bMaxSPrate,-5;
-      autobonus "{ bonus bInt,50; bonus bWis,15; bonus bSpl,15; }",30,10000,BF_MAGIC;
+      autobonus "{ bonus bInt,50; bonus bWis,15; bonus bSpl,15; }",30,10000,BF_MAGIC,"{ specialeffect2 EF_POTION_BERSERK; }";
       if (.@g>=ENCHANTGRADE_D) {
          bonus2 bMagicAtkEle,Ele_All,5;
          if (.@g>=ENCHANTGRADE_C) {
@@ -70969,7 +70973,7 @@ Body:
       .@g = getenchantgrade();
       bonus bMaxHPrate,-5;
       bonus bMaxSPrate,-5;
-      autobonus "{ bonus bDex,50; bonus bCon,15; bonus bCrt,15; }",30,10000,BF_WEAPON;
+      autobonus "{ bonus bDex,50; bonus bCon,15; bonus bCrt,15; }",30,10000,BF_WEAPON,"{ specialeffect2 EF_POTION_BERSERK; }";
       if (.@g>=ENCHANTGRADE_D) {
          bonus bLongAtkRate,5;
          bonus bShortAtkRate,5;
@@ -78734,6 +78738,7 @@ Body:
     Trade:
       NoDrop: true
       NoTrade: true
+      NoSell: true
       NoCart: true
       NoStorage: true
       NoGuildStorage: true
@@ -78746,6 +78751,7 @@ Body:
     Trade:
       NoDrop: true
       NoTrade: true
+      NoSell: true
       NoCart: true
       NoStorage: true
       NoGuildStorage: true
@@ -84763,6 +84769,30 @@ Body:
     Flags:
       BuyingStore: true
       DropEffect: CLIENT
+  - Id: 1001581
+    AegisName: aegis_1001581
+    Name: Coffin of Good and Evil Coupon    # !todo check english name
+    Type: Etc
+    Flags:
+      BuyingStore: true
+  - Id: 1001583
+    AegisName: aegis_1001583
+    Name: Good and Evil Boots Coupon    # !todo check english name
+    Type: Etc
+    Flags:
+      BuyingStore: true
+  - Id: 1001584
+    AegisName: aegis_1001584
+    Name: Good Weapon Coupon    # !todo check english name
+    Type: Etc
+    Flags:
+      BuyingStore: true
+  - Id: 1001588
+    AegisName: aegis_1001588
+    Name: Weapon of Evil Coupon    # !todo check english name
+    Type: Etc
+    Flags:
+      BuyingStore: true
   - Id: 1220001
     AegisName: Kunai
     Name: Kunai

+ 0 - 1
db/re/item_db_usable.yml

@@ -62882,7 +62882,6 @@ Body:
       NoDrop: true
       NoTrade: true
       NoCart: true
-      NoStorage: true
       NoGuildStorage: true
       NoMail: true
       NoAuction: true

File diff suppressed because it is too large
+ 760 - 0
db/re/job_basepoints.yml


File diff suppressed because it is too large
+ 418 - 418
db/re/job_exp.yml


+ 184 - 0
db/re/job_stats.yml

@@ -8884,6 +8884,15 @@ Body:
       - Level: 50
         Vit: 1
         Pow: 1
+      - Level: 51
+        Crt: 1
+      - Level: 52
+        Pow: 1
+      - Level: 54
+        Pow: 1
+        Crt: 1
+      - Level: 55
+        Sta: 1
   - Jobs:
       Meister: true
       Meister2: true
@@ -9017,6 +9026,15 @@ Body:
       - Level: 50
         Pow: 1
         Wis: 1
+      - Level: 51
+        Pow: 1
+      - Level: 52
+        Con: 1
+      - Level: 53
+        Sta: 1
+        Wis: 1
+      - Level: 55
+        Pow: 1
   - Jobs:
       Shadow_Cross: true
     MaxWeight: 32000
@@ -9149,6 +9167,15 @@ Body:
       - Level: 50
         Pow: 1
         Crt: 1
+      - Level: 51
+        Pow: 1
+      - Level: 53
+        Con: 1
+      - Level: 54
+        Sta: 1
+        Crt: 1
+      - Level: 55
+        Crt: 1
   - Jobs:
       Arch_Mage: true
     MaxWeight: 30000
@@ -9281,6 +9308,15 @@ Body:
       - Level: 50
         Sta: 1
         Wis: 1
+      - Level: 52
+        Spl: 1
+      - Level: 53
+        Con: 1
+      - Level: 54
+        Sta: 1
+        Wis: 1
+      - Level: 55
+        Spl: 1
   - Jobs:
       Cardinal: true
     MaxWeight: 30000
@@ -9413,6 +9449,16 @@ Body:
       - Level: 50
         Spl: 1
         Crt: 1
+      - Level: 51
+        Spl: 1
+      - Level: 52
+        Pow: 1
+      - Level: 53
+        Sta: 1
+      - Level: 54
+        Wis: 1
+      - Level: 55
+        Crt: 1
   - Jobs:
       Windhawk: true
       Windhawk2: true
@@ -9546,6 +9592,15 @@ Body:
       - Level: 50
         Dex: 1
         Con: 1
+      - Level: 51
+        Con: 1
+      - Level: 52
+        Pow: 1
+        Con: 1
+      - Level: 53
+        Sta: 1
+      - Level: 55
+        Pow: 1
   - Jobs:
       Imperial_Guard: true
       Imperial_Guard2: true
@@ -9680,6 +9735,15 @@ Body:
       - Level: 50
         Pow: 1
         Sta: 1
+      - Level: 51
+        Pow: 1
+      - Level: 52
+        Sta: 1
+      - Level: 53
+        Sta: 1
+      - Level: 55
+        Wis: 1
+        Con: 1
   - Jobs:
       Biolo: true
     MaxWeight: 32000
@@ -9812,6 +9876,15 @@ Body:
       - Level: 50
         Str: 1
         Crt: 1
+      - Level: 51
+        Crt: 1
+      - Level: 52
+        Sta: 1
+      - Level: 53
+        Pow: 1
+        Crt: 1
+      - Level: 55
+        Con: 1
   - Jobs:
       Abyss_Chaser: true
     MaxWeight: 28000
@@ -9944,6 +10017,15 @@ Body:
       - Level: 50
         Pow: 1
         Spl: 1
+      - Level: 51
+        Pow: 1
+      - Level: 52
+        Crt: 1
+      - Level: 54
+        Sta: 1
+      - Level: 55
+        Sta: 1
+        Con: 1
   - Jobs:
       Elemental_Master: true
     MaxWeight: 30000
@@ -10076,6 +10158,16 @@ Body:
       - Level: 50
         Wis: 1
         Spl: 1
+      - Level: 51
+        Spl: 1
+      - Level: 52
+        Sta: 1
+      - Level: 53
+        Sta: 1
+      - Level: 54
+        Wis: 1
+      - Level: 55
+        Spl: 1
   - Jobs:
       Inquisitor: true
     MaxWeight: 30000
@@ -10208,6 +10300,15 @@ Body:
       - Level: 50
         Pow: 1
         Wis: 1
+      - Level: 51
+        Pow: 1
+      - Level: 52
+        Sta: 1
+      - Level: 53
+        Sta: 1
+      - Level: 55
+        Pow: 1
+        Wis: 1
   - Jobs:
       Troubadour: true
     MaxWeight: 32000
@@ -10340,6 +10441,15 @@ Body:
         Con: 1
       - Level: 50
         Dex: 1
+      - Level: 51
+        Con: 1
+      - Level: 52
+        Spl: 1
+      - Level: 53
+        Sta: 1
+      - Level: 55
+        Pow: 1
+        Con: 1
   - Jobs:
       Trouvere: true
     MaxWeight: 32000
@@ -10473,6 +10583,15 @@ Body:
         Con: 1
       - Level: 50
         Agi: 1
+      - Level: 51
+        Con: 1
+      - Level: 52
+        Sta: 1
+      - Level: 53
+        Spl: 1
+      - Level: 55
+        Pow: 1
+        Con: 1
   - Jobs:
       Sky_Emperor: true
     MaxWeight: 42000
@@ -10607,6 +10726,14 @@ Body:
       - Level: 50
         Pow: 1
         Crt: 1
+      - Level: 51
+        Sta: 1
+        Con: 1
+      - Level: 53
+        Sta: 1
+      - Level: 55
+        Pow: 1
+        Con: 1
   - Jobs:
       Soul_Ascetic: true
     MaxWeight: 42000
@@ -10730,6 +10857,16 @@ Body:
       - Level: 50
         Wis: 1
         Spl: 1
+      - Level: 51
+        Spl: 1
+      - Level: 52
+        Con: 1
+      - Level: 53
+        Wis: 1
+      - Level: 54
+        Sta: 1
+      - Level: 55
+        Spl: 1
   - Jobs:
       Shinkiro: true
     MaxWeight: 45000
@@ -10863,6 +11000,16 @@ Body:
       - Level: 50
         Pow: 1
         Crt: 1
+      - Level: 51
+        Crt: 1
+      - Level: 52
+        Con: 1
+      - Level: 53
+        Wis: 1
+      - Level: 54
+        Sta: 1
+      - Level: 55
+        Sta: 1
   - Jobs:
       Shiranui: true
     MaxWeight: 45000
@@ -10985,6 +11132,15 @@ Body:
       - Level: 50
         Wis: 1
         Spl: 1
+      - Level: 51
+        Pow: 1
+      - Level: 52
+        Spl: 1
+      - Level: 54
+        Spl: 1
+      - Level: 55
+        Spl: 1
+        Con: 1
   - Jobs:
       Night_Watch: true
     MaxWeight: 48000
@@ -11112,6 +11268,15 @@ Body:
         Con: 1
       - Level: 50
         Pow: 1
+      - Level: 51
+        Con: 1
+      - Level: 53
+        Pow: 1
+        Con: 1
+      - Level: 54
+        Wis: 1
+      - Level: 55
+        Pow: 1
   - Jobs:
       Hyper_Novice: true
     MaxWeight: 40000
@@ -11248,6 +11413,15 @@ Body:
       - Level: 50
         Agi: 1
         Dex: 1
+      - Level: 51
+        Con: 1
+      - Level: 52
+        Pow: 1
+        Con: 1
+      - Level: 53
+        Sta: 1
+      - Level: 55
+        Spl: 1
   - Jobs:
       Spirit_Handler: true
     MaxWeight: 42000
@@ -11379,3 +11553,13 @@ Body:
         Crt: 1
       - Level: 50
         Pow: 1
+      - Level: 51
+        Con: 1
+      - Level: 52
+        Pow: 1
+      - Level: 53
+        Spl: 1
+      - Level: 54
+        Wis: 1
+      - Level: 55
+        Sta: 1

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


+ 86 - 0
db/re/skill_tree.yml

@@ -7864,3 +7864,89 @@ Body:
       Royal_Guard: true
       Royal_Guard_T: true
       Imperial_Guard: true
+  - Job: Hyper_Novice
+    Inherit:
+      Novice: true
+      Supernovice: true
+      Super_Novice_E: true
+    Tree:
+      - Name: HN_SELFSTUDY_TATICS
+        MaxLevel: 10
+      - Name: HN_SELFSTUDY_SOCERY
+        MaxLevel: 10
+      - Name: HN_DOUBLEBOWLINGBASH
+        MaxLevel: 10
+        Requires:
+          - Name: HN_SELFSTUDY_TATICS
+            Level: 5
+      - Name: HN_SHIELD_CHAIN_RUSH
+        MaxLevel: 10
+        Requires:
+          - Name: HN_SELFSTUDY_TATICS
+            Level: 5
+      - Name: HN_METEOR_STORM_BUSTER
+        MaxLevel: 10
+        Requires:
+          - Name: HN_SELFSTUDY_SOCERY
+            Level: 5
+      - Name: HN_JUPITEL_THUNDER_STORM
+        MaxLevel: 10
+        Requires:
+          - Name: HN_SELFSTUDY_SOCERY
+            Level: 5
+      - Name: HN_JACK_FROST_NOVA
+        MaxLevel: 10
+        Requires:
+          - Name: HN_SELFSTUDY_SOCERY
+            Level: 5
+      - Name: HN_HELLS_DRIVE
+        MaxLevel: 10
+        Requires:
+          - Name: HN_SELFSTUDY_SOCERY
+            Level: 5
+      - Name: HN_MEGA_SONIC_BLOW
+        MaxLevel: 10
+        Requires:
+          - Name: HN_DOUBLEBOWLINGBASH
+            Level: 7
+      - Name: HN_SPIRAL_PIERCE_MAX
+        MaxLevel: 10
+        Requires:
+          - Name: HN_SHIELD_CHAIN_RUSH
+            Level: 7
+      - Name: HN_GROUND_GRAVITATION
+        MaxLevel: 10
+        Requires:
+          - Name: HN_SELFSTUDY_SOCERY
+            Level: 5
+      - Name: HN_NAPALM_VULCAN_STRIKE
+        MaxLevel: 10
+        Requires:
+          - Name: HN_SELFSTUDY_SOCERY
+            Level: 5
+      - Name: HN_BREAKINGLIMIT
+        MaxLevel: 1
+        Requires:
+          - Name: HN_DOUBLEBOWLINGBASH
+            Level: 7
+          - Name: HN_MEGA_SONIC_BLOW
+            Level: 7
+          - Name: HN_SHIELD_CHAIN_RUSH
+            Level: 7
+          - Name: HN_SPIRAL_PIERCE_MAX
+            Level: 7
+      - Name: HN_RULEBREAK
+        MaxLevel: 1
+        Requires:
+          - Name: HN_METEOR_STORM_BUSTER
+            Level: 5
+          - Name: HN_JUPITEL_THUNDER_STORM
+            Level: 5
+          - Name: HN_JACK_FROST_NOVA
+            Level: 5
+          - Name: HN_HELLS_DRIVE
+            Level: 5
+          - Name: HN_GROUND_GRAVITATION
+            Level: 5
+          - Name: HN_NAPALM_VULCAN_STRIKE
+            Level: 5

+ 30 - 0
db/re/statpoint.yml

@@ -582,3 +582,33 @@ Body:
   - Level: 250
     Points: 4099
     TraitPoints: 190
+  - Level: 251
+    Points: 4099
+    TraitPoints: 193
+  - Level: 252
+    Points: 4099
+    TraitPoints: 196
+  - Level: 253
+    Points: 4099
+    TraitPoints: 199
+  - Level: 254
+    Points: 4099
+    TraitPoints: 202
+  - Level: 255
+    Points: 4099
+    TraitPoints: 209
+  - Level: 256
+    Points: 4099
+    TraitPoints: 212
+  - Level: 257
+    Points: 4099
+    TraitPoints: 215
+  - Level: 258
+    Points: 4099
+    TraitPoints: 218
+  - Level: 259
+    Points: 4099
+    TraitPoints: 221
+  - Level: 260
+    Points: 4099
+    TraitPoints: 228

+ 33 - 3
db/re/status.yml

@@ -5732,6 +5732,8 @@ Body:
     DurationLookup: RA_UNLIMIT
     Flags:
       DisplayPc: true
+      NoDispell: true
+      NoClearance: true
   - Status: Kings_Grace
     Icon: EFST_KINGS_GRACE
     DurationLookup: LG_KINGS_GRACE
@@ -7633,7 +7635,7 @@ Body:
       RemoveOnDamaged: true
   - Status: Handicapstate_Lightningstrike
     Icon: EFST_HANDICAPSTATE_LIGHTNINGSTRIKE
-    DurationLookup: WH_SWIFTTRAP
+    DurationLookup: EM_LIGHTNING_LAND
     States:
       #NoMove: true
       #NoCast: true
@@ -7646,7 +7648,7 @@ Body:
       RemoveOnDamaged: true
   - Status: Handicapstate_Crystallization
     Icon: EFST_HANDICAPSTATE_CRYSTALLIZATION
-    DurationLookup: WH_SOLIDTRAP
+    DurationLookup: EM_TERRA_DRIVE
     States:
       #NoMove: true
       #NoCast: true
@@ -7660,7 +7662,7 @@ Body:
       RemoveOnDamaged: true
   - Status: Handicapstate_Conflagration
     Icon: EFST_HANDICAPSTATE_CONFLAGRATION
-    DurationLookup: WH_FLAMETRAP
+    DurationLookup: EM_CONFLAGRATION
     Flags:
       BlEffect: true
       DisplayPc: true
@@ -8751,3 +8753,31 @@ Body:
       NoDispell: true
       NoBanishingBuster: true
       NoClearance: true
+  - Status: Hnnoweapon
+    Icon: EFST_NOEQUIPWEAPON
+    DurationLookup: HN_DOUBLEBOWLINGBASH
+  - Status: Shieldchainrush
+    Icon: EFST_SHIELDCHAINRUSH
+    DurationLookup: HN_SHIELD_CHAIN_RUSH
+    CalcFlags:
+      Speed: true
+    Flags:
+      BossResist: true
+  - Status: Mistyfrost
+    Icon: EFST_MISTYFROST
+    DurationLookup: HN_JACK_FROST_NOVA
+    Flags:
+      BossResist: true
+  - Status: Groundgravity
+    Icon: EFST_GROUNDGRAVITY
+    DurationLookup: HN_GROUND_GRAVITATION
+    CalcFlags:
+      Speed: true
+    Flags:
+      BossResist: true
+  - Status: Breakinglimit
+    Icon: EFST_BREAKINGLIMIT
+    DurationLookup: HN_BREAKINGLIMIT
+  - Status: Rulebreak
+    Icon: EFST_RULEBREAK
+    DurationLookup: HN_RULEBREAK

+ 11 - 4
doc/script_commands.txt

@@ -7481,10 +7481,10 @@ This command lets you override the contents of an existing NPC shop or cashshop.
 current sell list will be wiped, and only the items specified with the price
 specified will be for sale.
 
-The function returns 1 if shop was updated successfully, or 0 if not found.
+The function returns 1 if shop was updated successfully, or 0 on failure.
 
 NOTES:
- - That you cannot use -1 to specify default selling price!
+ - That you cannot use -1 to specify default selling price for cashshops, pointshops, or itemshops.
  - If the attached shop type is a market shop, notice that there is an extra parameter after price, <stock>. Make sure to not add duplicate items! For unlimited stock use -1.
 
 ---------------------------------------
@@ -7496,10 +7496,10 @@ This command will add more items at the end of the selling list for the
 specified NPC shop or cashshop. If you specify an item already for sell, that item will
 appear twice on the sell list.
 
-The function returns 1 if shop was updated successfully, or 0 if not found.
+The function returns 1 if shop was updated successfully, or 0 on failure.
 
 NOTES:
- - That you cannot use -1 to specify default selling price!
+ - That you cannot use -1 to specify default selling price for cashshops, pointshops, or itemshops.
  - If attached shop type is market shop, need an extra param after price, it's <stock>
    and make sure don't add duplication item! For unlimited stock use -1.
 
@@ -7543,6 +7543,13 @@ Update an entry from a shop. If the price is 0 it won't be changed. May also be
 marketshop to update the stock quantity. For unlimited stock, use -1.
 For other shop types, the stock value has no effect.
 
+If the price is -1, it sets it to the default buy price.
+
+The function returns 1 if shop was updated successfully, or 0 on failure.
+
+NOTES:
+ - That you cannot use -1 to specify default selling price for cashshops, pointshops, or itemshops.
+
 ---------------------------------------
 
 *waitingroom "<chatroom name>",<limit>{,"<event label>"{,<trigger>{,<required zeny>{,<min lvl>{,<max lvl>}}}}};

+ 69 - 68
npc/re/instances/HiddenGarden.txt

@@ -10,6 +10,7 @@
 //= 1.0 Initial release [crazyarashi]
 //= 1.1 Optimizations and cleanup [Everade]
 //= 1.2 Cleanup [Capuche]
+//= 1.3 Updated monsters spawn times (significantly reduced). [Atemo]
 //============================================================
 
 ba_maison,120,320,0	script	#herbs_chk	HIDDEN_WARP_NPC,3,3,{
@@ -1623,36 +1624,36 @@ OnSummon:
 			'total_mobs = 16;
 			monster 'map_herbs$,77,197,"Flower Garden Watcher",20622,1, .@event$;
 			monster 'map_herbs$,51,196,"Flower Garden Watcher",20622,1, .@event$;
-			sleep 6000;
+			sleep 100;
 			monster 'map_herbs$,63,217,"Flower Garden Watcher",20622,1, .@event$;
-			sleep 3000;
+			sleep 100;
 			monster 'map_herbs$,81,195,"Flower Garden Watcher",20624,1, .@event$;
 			monster 'map_herbs$,61,217,"Flower Garden Watcher",20622,1, .@event$;
-			sleep 3000;
+			sleep 100;
 			monster 'map_herbs$,57,193,"Flower Garden Watcher",20622,1, .@event$;
-			sleep 6000;
+			sleep 100;
 			monster 'map_herbs$,56,191,"Flower Garden Watcher",20626,1, .@event$;
-			sleep 3000;
+			sleep 100;
 			monster 'map_herbs$,59,193,"Flower Garden Watcher",20626,1, .@event$;
-			sleep 6000;
+			sleep 100;
 			monster 'map_herbs$,59,192,"Flower Garden Watcher",20622,1, .@event$;
 			monster 'map_herbs$,60,222,"Flower Garden Watcher",20622,1, .@event$;
 			monster 'map_herbs$,58,191,"Flower Garden Watcher",20622,1, .@event$;
-			sleep 6000;
+			sleep 100;
 			monster 'map_herbs$,78,199,"Flower Garden Watcher",20622,1, .@event$;
-			sleep 3000;
+			sleep 100;
 			monster 'map_herbs$,54,192,"Flower Garden Watcher",20626,1, .@event$;
 			monster 'map_herbs$,79,195,"Flower Garden Watcher",20622,1, .@event$;
-			sleep 9000;
+			sleep 100;
 			monster 'map_herbs$,76,192,"Flower Garden Watcher",20626,1, .@event$;
 			monster 'map_herbs$,51,196,"Flower Garden Watcher",20624,1, .@event$;
 		}
 		else {
 			'total_mobs = 16;
 			monster 'map_herbs$,53,197,"Flower Garden Watcher",20623,1, .@event$;
-			sleep 3000;
+			sleep 100;
 			monster 'map_herbs$,62,217,"Flower Garden Watcher",20623,1, .@event$;
-			sleep 3000;
+			sleep 100;
 			monster 'map_herbs$,57,219,"Flower Garden Watcher",20627,1, .@event$;
 			monster 'map_herbs$,62,222,"Flower Garden Watcher",20623,1, .@event$;
 			monster 'map_herbs$,79,200,"Flower Garden Watcher",20623,1, .@event$;
@@ -1660,14 +1661,14 @@ OnSummon:
 			monster 'map_herbs$,80,199,"Flower Garden Watcher",20623,1, .@event$;
 			monster 'map_herbs$,58,193,"Flower Garden Watcher",20623,1, .@event$;
 			monster 'map_herbs$,56,192,"Flower Garden Watcher",20625,1, .@event$;
-			sleep 3000;
+			sleep 100;
 			monster 'map_herbs$,51,191,"Flower Garden Watcher",20623,1, .@event$;
 			monster 'map_herbs$,51,192,"Flower Garden Watcher",20623,1, .@event$;
 			monster 'map_herbs$,83,199,"Flower Garden Watcher",20625,1, .@event$;
 			monster 'map_herbs$,83,191,"Flower Garden Watcher",20623,1, .@event$;
-			sleep 3000;
+			sleep 100;
 			monster 'map_herbs$,83,196,"Flower Garden Watcher",20623,1, .@event$;
-			sleep 6000;
+			sleep 100;
 			monster 'map_herbs$,57,193,"Flower Garden Watcher",20623,1, .@event$;
 			monster 'map_herbs$,62,222,"Flower Garden Watcher",20623,1, .@event$;
 		}
@@ -1678,15 +1679,15 @@ OnSummon:
 			monster 'map_herbs$,114,226,"Flower Garden Watcher",20622,1, .@event$;
 			monster 'map_herbs$,114,227,"Flower Garden Watcher",20622,1, .@event$;
 			monster 'map_herbs$,119,217,"Flower Garden Watcher",20624,1, .@event$;
-			sleep 6000;
+			sleep 100;
 			monster 'map_herbs$,118,227,"Flower Garden Watcher",20622,1, .@event$;
-			sleep 3000;
+			sleep 100;
 			monster 'map_herbs$,116,216,"Flower Garden Watcher",20626,1, .@event$;
-			sleep 6000;
+			sleep 100;
 			monster 'map_herbs$,114,215,"Flower Garden Watcher",20626,1, .@event$;
-			sleep 3000;
+			sleep 100;
 			monster 'map_herbs$,114,225,"Flower Garden Watcher",20622,1, .@event$;
-			sleep 6000;
+			sleep 100;
 			monster 'map_herbs$,114,224,"Flower Garden Watcher",20622,1, .@event$;
 			monster 'map_herbs$,139,205,"Flower Garden Watcher",20622,1, .@event$;
 			monster 'map_herbs$,140,202,"Flower Garden Watcher",20622,1, .@event$;
@@ -1708,30 +1709,30 @@ OnSummon:
 			monster 'map_herbs$,142,205,"Flower Garden Watcher",20627,1, .@event$;
 			monster 'map_herbs$,145,200,"Flower Garden Watcher",20623,1, .@event$;
 			monster 'map_herbs$,146,201,"Flower Garden Watcher",20625,1, .@event$;
-			sleep 6000;
+			sleep 100;
 			monster 'map_herbs$,147,201,"Flower Garden Watcher",20623,1, .@event$;
-			sleep 3000;
+			sleep 100;
 			monster 'map_herbs$,141,208,"Flower Garden Watcher",20627,1, .@event$;
 			monster 'map_herbs$,166,224,"Flower Garden Watcher",20625,1, .@event$;
-			sleep 6000;
+			sleep 100;
 			monster 'map_herbs$,171,217,"Flower Garden Watcher",20627,1, .@event$;
-			sleep 3000;
+			sleep 100;
 			monster 'map_herbs$,172,225,"Flower Garden Watcher",20627,1, .@event$;
 			monster 'map_herbs$,173,214,"Flower Garden Watcher",20623,1, .@event$;
 			monster 'map_herbs$,174,225,"Flower Garden Watcher",20627,1, .@event$;
 			monster 'map_herbs$,174,223,"Flower Garden Watcher",20627,1, .@event$;
-			sleep 6000;
+			sleep 100;
 			monster 'map_herbs$,170,213,"Flower Garden Watcher",20623,1, .@event$;
-			sleep 3000;
+			sleep 100;
 			monster 'map_herbs$,169,219,"Flower Garden Watcher",20623,1, .@event$;
-			sleep 6000;
+			sleep 100;
 			monster 'map_herbs$,136,205,"Flower Garden Watcher",20623,1, .@event$;
 			monster 'map_herbs$,136,210,"Flower Garden Watcher",20623,1, .@event$;
 			monster 'map_herbs$,120,224,"Flower Garden Watcher",20623,1, .@event$;
 			monster 'map_herbs$,118,223,"Flower Garden Watcher",20623,1, .@event$;
 			monster 'map_herbs$,117,219,"Flower Garden Watcher",20623,1, .@event$;
 			monster 'map_herbs$,115,214,"Flower Garden Watcher",20623,1, .@event$;
-			sleep 3000;
+			sleep 100;
 			monster 'map_herbs$,115,233,"Flower Garden Watcher",20623,1, .@event$;
 		}
 		break;
@@ -1740,45 +1741,45 @@ OnSummon:
 			'total_mobs = 28;
 			monster 'map_herbs$,213,205,"Flower Garden Watcher",20622,1, .@event$;
 			monster 'map_herbs$,202,214,"Flower Garden Watcher",20626,1, .@event$;
-			sleep 3000;
+			sleep 100;
 			monster 'map_herbs$,202,213,"Flower Garden Watcher",20626,1, .@event$;
-			sleep 3000;
+			sleep 100;
 			monster 'map_herbs$,210,212,"Flower Garden Watcher",20626,1, .@event$;
-			sleep 6000;
+			sleep 100;
 			monster 'map_herbs$,211,207,"Flower Garden Watcher",20624,1, .@event$;
-			sleep 3000;
+			sleep 100;
 			monster 'map_herbs$,209,214,"Flower Garden Watcher",20624,1, .@event$;
-			sleep 3000;
+			sleep 100;
 			monster 'map_herbs$,203,212,"Flower Garden Watcher",20622,1, .@event$;
 			monster 'map_herbs$,218,194,"Flower Garden Watcher",20622,1, .@event$;
-			sleep 6000;
+			sleep 100;
 			monster 'map_herbs$,203,196,"Flower Garden Watcher",20622,1, .@event$;
-			sleep 3000;
+			sleep 100;
 			monster 'map_herbs$,204,193,"Flower Garden Watcher",20626,1, .@event$;
-			sleep 3000;
+			sleep 100;
 			monster 'map_herbs$,215,201,"Flower Garden Watcher",20624,1, .@event$;
 			monster 'map_herbs$,204,193,"Flower Garden Watcher",20626,1, .@event$;
-			sleep 3000;
+			sleep 100;
 			monster 'map_herbs$,205,213,"Flower Garden Watcher",20626,1, .@event$;
-			sleep 3000;
+			sleep 100;
 			monster 'map_herbs$,218,208,"Flower Garden Watcher",20622,1, .@event$;
-			sleep 6000;
+			sleep 100;
 			monster 'map_herbs$,210,210,"Flower Garden Watcher",20622,1, .@event$;
 			monster 'map_herbs$,245,214,"Flower Garden Watcher",20626,1, .@event$;
-			sleep 6000;
+			sleep 100;
 			monster 'map_herbs$,220,192,"Flower Garden Watcher",20622,1, .@event$;
 			monster 'map_herbs$,248,208,"Flower Garden Watcher",20622,1, .@event$;
 			monster 'map_herbs$,253,208,"Flower Garden Watcher",20622,1, .@event$;
 			monster 'map_herbs$,253,208,"Flower Garden Watcher",20626,1, .@event$;
-			sleep 6000;
+			sleep 100;
 			monster 'map_herbs$,246,212,"Flower Garden Watcher",20624,1, .@event$;
-			sleep 6000;
+			sleep 100;
 			monster 'map_herbs$,251,210,"Flower Garden Watcher",20622,1, .@event$;
-			sleep 3000;
+			sleep 100;
 			monster 'map_herbs$,245,209,"Flower Garden Watcher",20626,1, .@event$;
 			monster 'map_herbs$,222,195,"Flower Garden Watcher",20624,1, .@event$;
 			monster 'map_herbs$,203,212,"Flower Garden Watcher",20624,1, .@event$;
-			sleep 6000;
+			sleep 100;
 			monster 'map_herbs$,208,213,"Flower Garden Watcher",20622,1, .@event$;
 			monster 'map_herbs$,219,192,"Flower Garden Watcher",20622,1, .@event$;
 			monster 'map_herbs$,245,209,"Flower Garden Watcher",20626,1, .@event$;
@@ -1787,35 +1788,35 @@ OnSummon:
 			'total_mobs = 27;
 			monster 'map_herbs$,207,194,"Flower Garden Watcher",20625,1, .@event$;
 			monster 'map_herbs$,217,204,"Flower Garden Watcher",20623,1, .@event$;
-			sleep 3000;
+			sleep 100;
 			monster 'map_herbs$,210,210,"Flower Garden Watcher",20627,1, .@event$;
-			sleep 3000;
+			sleep 100;
 			monster 'map_herbs$,218,195,"Flower Garden Watcher",20623,1, .@event$;
-			sleep 3000;
+			sleep 100;
 			monster 'map_herbs$,211,209,"Flower Garden Watcher",20627,1, .@event$;
-			sleep 3000;
+			sleep 100;
 			monster 'map_herbs$,210,211,"Flower Garden Watcher",20625,1, .@event$;
-			sleep 3000;
+			sleep 100;
 			monster 'map_herbs$,207,194,"Flower Garden Watcher",20625,1, .@event$;
-			sleep 3000;
+			sleep 100;
 			monster 'map_herbs$,209,214,"Flower Garden Watcher",20623,1, .@event$;
-			sleep 3000;
+			sleep 100;
 			monster 'map_herbs$,216,192,"Flower Garden Watcher",20623,1, .@event$;
-			sleep 3000;
+			sleep 100;
 			monster 'map_herbs$,208,211,"Flower Garden Watcher",20623,1, .@event$;
-			sleep 3000;
+			sleep 100;
 			monster 'map_herbs$,214,208,"Flower Garden Watcher",20623,1, .@event$;
-			sleep 6000;
+			sleep 100;
 			monster 'map_herbs$,209,214,"Flower Garden Watcher",20623,1, .@event$;
 			monster 'map_herbs$,215,201,"Flower Garden Watcher",20627,1, .@event$;
 			monster 'map_herbs$,205,214,"Flower Garden Watcher",20623,1, .@event$;
 			monster 'map_herbs$,205,214,"Flower Garden Watcher",20625,1, .@event$;
-			sleep 6000;
+			sleep 100;
 			monster 'map_herbs$,220,207,"Flower Garden Watcher",20625,1, .@event$;
-			sleep 3000;
+			sleep 100;
 			monster 'map_herbs$,208,213,"Flower Garden Watcher",20623,1, .@event$;
 			monster 'map_herbs$,202,212,"Flower Garden Watcher",20623,1, .@event$;
-			sleep 3000;
+			sleep 100;
 			monster 'map_herbs$,202,193,"Flower Garden Watcher",20623,1, .@event$;
 			monster 'map_herbs$,206,214,"Flower Garden Watcher",20623,1, .@event$;
 			monster 'map_herbs$,245,212,"Flower Garden Watcher",20627,1, .@event$;
@@ -1849,15 +1850,15 @@ OnSummon:
 			monster 'map_herbs$,285,210,"Flower Garden Watcher",20624,1, .@event$;
 			monster 'map_herbs$,283,228,"Flower Garden Watcher",20624,1, .@event$;
 			monster 'map_herbs$,294,252,"Flower Garden Watcher",20624,1, .@event$;
-			sleep 3000;
+			sleep 100;
 			monster 'map_herbs$,295,247,"Flower Garden Watcher",20626,1, .@event$;
-			sleep 6000;
+			sleep 100;
 			monster 'map_herbs$,294,245,"Flower Garden Watcher",20624,1, .@event$;
-			sleep 3000;
+			sleep 100;
 			monster 'map_herbs$,281,232,"Flower Garden Watcher",20622,1, .@event$;
 			monster 'map_herbs$,287,219,"Flower Garden Watcher",20626,1, .@event$;
 			monster 'map_herbs$,302,239,"Flower Garden Watcher",20626,1, .@event$;
-			sleep 3000;
+			sleep 100;
 			monster 'map_herbs$,307,217,"Flower Garden Watcher",20622,1, .@event$;
 			monster 'map_herbs$,300,235,"Flower Garden Watcher",20624,1, .@event$;
 			monster 'map_herbs$,295,249,"Flower Garden Watcher",20624,1, .@event$;
@@ -1873,18 +1874,18 @@ OnSummon:
 			monster 'map_herbs$,284,236,"Flower Garden Watcher",20625,1, .@event$;
 			monster 'map_herbs$,283,235,"Flower Garden Watcher",20625,1, .@event$;
 			monster 'map_herbs$,304,240,"Flower Garden Watcher",20627,1, .@event$;
-			sleep 3000;
+			sleep 100;
 			monster 'map_herbs$,298,246,"Flower Garden Watcher",20625,1, .@event$;
 			monster 'map_herbs$,305,224,"Flower Garden Watcher",20627,1, .@event$;
 			monster 'map_herbs$,310,225,"Flower Garden Watcher",20627,1, .@event$;
-			sleep 9000;
+			sleep 100;
 			monster 'map_herbs$,284,218,"Flower Garden Watcher",20623,1, .@event$;
 			monster 'map_herbs$,298,213,"Flower Garden Watcher",20625,1, .@event$;
-			sleep 3000;
+			sleep 100;
 			monster 'map_herbs$,308,224,"Flower Garden Watcher",20625,1, .@event$;
 			monster 'map_herbs$,290,210,"Flower Garden Watcher",20625,1, .@event$;
 			monster 'map_herbs$,310,224,"Flower Garden Watcher",20627,1, .@event$;
-			sleep 3000;
+			sleep 100;
 			monster 'map_herbs$,308,220,"Flower Garden Watcher",20627,1, .@event$;
 			monster 'map_herbs$,284,211,"Flower Garden Watcher",20625,1, .@event$;
 			monster 'map_herbs$,284,218,"Flower Garden Watcher",20623,1, .@event$;
@@ -1892,22 +1893,22 @@ OnSummon:
 			monster 'map_herbs$,281,231,"Flower Garden Watcher",20625,1, .@event$;
 			monster 'map_herbs$,280,226,"Flower Garden Watcher",20625,1, .@event$;
 			monster 'map_herbs$,285,210,"Flower Garden Watcher",20625,1, .@event$;
-			sleep 6000;
+			sleep 100;
 			monster 'map_herbs$,280,227,"Flower Garden Watcher",20623,1, .@event$;
 			monster 'map_herbs$,285,234,"Flower Garden Watcher",20627,1, .@event$;
 			monster 'map_herbs$,283,236,"Flower Garden Watcher",20627,1, .@event$;
 			monster 'map_herbs$,284,233,"Flower Garden Watcher",20625,1, .@event$;
-			sleep 3000;
+			sleep 100;
 			monster 'map_herbs$,284,237,"Flower Garden Watcher",20625,1, .@event$;
 			monster 'map_herbs$,284,239,"Flower Garden Watcher",20627,1, .@event$;
 			monster 'map_herbs$,293,246,"Flower Garden Watcher",20627,1, .@event$;
 			monster 'map_herbs$,300,247,"Flower Garden Watcher",20627,1, .@event$;
-			sleep 3000;
+			sleep 100;
 			monster 'map_herbs$,294,253,"Flower Garden Watcher",20627,1, .@event$;
 			monster 'map_herbs$,302,240,"Flower Garden Watcher",20625,1, .@event$;
 			monster 'map_herbs$,299,255,"Flower Garden Watcher",20625,1, .@event$;
 			monster 'map_herbs$,295,256,"Flower Garden Watcher",20625,1, .@event$;
-			sleep 3000;
+			sleep 100;
 			monster 'map_herbs$,310,218,"Flower Garden Watcher",20623,1, .@event$;
 		}
 		break;

+ 14 - 0
npc/re/merchants/barters/enchan_illusion_dungeons.yml

@@ -412,6 +412,20 @@ Body:
           - Index: 3
             Item: IllusionStone
             Amount: 120
+  - Name: resonance_stone_barter
+    Items:
+      - Index: 0
+        Item: ILL_Piece_A
+        RequiredItems:
+          - Index: 0
+            Item: IllusionStone
+            Amount: 10
+      - Index: 1
+        Item: ILL_Piece_B
+        RequiredItems:
+          - Index: 0
+            Item: IllusionStone
+            Amount: 10
   - Name: barter_ill_moonlight
     Items:
       - Index: 0

+ 38 - 0
npc/re/merchants/enchan_illusion_dungeons.txt

@@ -14,6 +14,7 @@
 //= 1.5 Added Illusion of Luanda enchanter [Capuche]
 //= 1.6 Added Illusion of Underwater exchange [Capuche]
 //= 1.7 Added Illusion of Twins enchanter [Capuche]
+//= 1.8 Added Illusion Merchant [Haydrich]
 //============================================================
 
 //============================================================
@@ -846,3 +847,40 @@ OnInit:
 	setunitdata .@npc_id, UNPC_HAIRCOLOR, 6;
 	end;
 }
+
+//============================================================
+//= Illusion Merchant
+//============================================================
+-	marketshop	market_resonance_stone	-1,100003:2000000:99999,100004:2000000:99999
+prontera,88,113,5	script	Illusion Merchant#0829	HIDDEN_NPC,{
+	mes "[Illusion Merchant]";
+	mes "I'm selling two random optional weapon grant scrolls that I made myself. You can choose the payment method you like.";
+	next;
+	switch( select( "Purchase with Zeny.", "Purchase with Illusion Stones" )) {
+		case 1:
+			mes "[Illusion Merchant]";
+			mes "I hope you like it.";
+			close2;
+			callshop "market_resonance_stone";
+			end;
+		case 2:
+			mes "[Illusion Merchant]";
+			mes "I hope you like it.";
+			close2;
+			callshop "resonance_stone_barter";
+			end;
+	}
+OnInit:
+	.@npc_id = getnpcid(0);
+	setunitdata .@npc_id,UNPC_CLASS, JOB_MAGE_HIGH;
+	setunitdata .@npc_id,UNPC_SEX,SEX_FEMALE;
+	setunitdata .@npc_id,UNPC_HEADTOP,142;
+	setunitdata .@npc_id,UNPC_HEADMIDDLE,92;
+	setunitdata .@npc_id,UNPC_HAIRSTYLE,2;
+	setunitdata .@npc_id,UNPC_HAIRCOLOR,2;
+
+	// Restock
+	npcshopupdate "market_resonance_stone",100003,2000000,99999;
+	npcshopupdate "market_resonance_stone",100004,2000000,99999;
+	end;
+}

+ 51 - 24
npc/re/mobs/dungeons/lhz_dun_n.txt

@@ -9,35 +9,66 @@
 //		monsters killed. [Capuche]
 //============================================================
 
-lhz_dun_n,0,0	monster	Eremes Guille	3208,20,5000,0,"lhz_dun_n::OnRegularDead"
-lhz_dun_n,0,0	monster	Magaleta Sorin	3209,10,5000,0,"lhz_dun_n::OnRegularDead"
-lhz_dun_n,0,0	monster	Catherine Cheiron	3210,15,5000,0,"lhz_dun_n::OnRegularDead"
-lhz_dun_n,0,0	monster	Shecil Damon	3211,20,5000,0,"lhz_dun_n::OnRegularDead"
-lhz_dun_n,0,0	monster	Harword Alt-Eisen	3212,10,5000,0,"lhz_dun_n::OnRegularDead"
-lhz_dun_n,0,0	monster	Seyren Windsor	3213,10,5000,0,"lhz_dun_n::OnRegularDead"
+lhz_dun_n,0,0	monster	Eremes Guille	3208,20,5000,0,"lhz_dun_n::OnRegularDead3208"
+lhz_dun_n,0,0	monster	Magaleta Sorin	3209,10,5000,0,"lhz_dun_n::OnRegularDead3209"
+lhz_dun_n,0,0	monster	Catherine Cheiron	3210,15,5000,0,"lhz_dun_n::OnRegularDead3210"
+lhz_dun_n,0,0	monster	Shecil Damon	3211,20,5000,0,"lhz_dun_n::OnRegularDead3211"
+lhz_dun_n,0,0	monster	Harword Alt-Eisen	3212,10,5000,0,"lhz_dun_n::OnRegularDead3212"
+lhz_dun_n,0,0	monster	Seyren Windsor	3213,10,5000,0,"lhz_dun_n::OnRegularDead3213"
 
-lhz_dun_n,0,0	monster	Randel Lawrence	3226,10,5000,0,"lhz_dun_n::OnRegularDead"
-lhz_dun_n,0,0	monster	Flamel Emule	3227,10,5000,0,"lhz_dun_n::OnRegularDead"
-lhz_dun_n,0,0	monster	Celia Alde	3228,15,5000,0,"lhz_dun_n::OnRegularDead"
-lhz_dun_n,0,0	monster	Chen Liu	3229,15,5000,0,"lhz_dun_n::OnRegularDead"
-lhz_dun_n,0,0	monster	Gertie Wie	3230,15,5000,0,"lhz_dun_n::OnRegularDead"
-lhz_dun_n,0,0	monster	Alphoccio Basil	3231,10,5000,0,"lhz_dun_n::OnRegularDead"
-lhz_dun_n,0,0	monster	Trentini	3232,10,5000,0,"lhz_dun_n::OnRegularDead"
+lhz_dun_n,0,0	monster	Randel Lawrence	3226,10,5000,0,"lhz_dun_n::OnRegularDead3226"
+lhz_dun_n,0,0	monster	Flamel Emule	3227,10,5000,0,"lhz_dun_n::OnRegularDead3227"
+lhz_dun_n,0,0	monster	Celia Alde	3228,15,5000,0,"lhz_dun_n::OnRegularDead3228"
+lhz_dun_n,0,0	monster	Chen Liu	3229,15,5000,0,"lhz_dun_n::OnRegularDead3229"
+lhz_dun_n,0,0	monster	Gertie Wie	3230,15,5000,0,"lhz_dun_n::OnRegularDead3230"
+lhz_dun_n,0,0	monster	Alphoccio Basil	3231,10,5000,0,"lhz_dun_n::OnRegularDead3231"
+lhz_dun_n,0,0	monster	Trentini	3232,10,5000,0,"lhz_dun_n::OnRegularDead3232"
 
 lhz_dun_n,0,0,0	script	lhz_dun_n	-1,{
 	end;
-OnRegularDead:
-	.@mob_id = killedrid;
+OnRegularDead3208: callsub( S_Regular, 3208 );
+OnRegularDead3209: callsub( S_Regular, 3209 );
+OnRegularDead3210: callsub( S_Regular, 3210 );
+OnRegularDead3211: callsub( S_Regular, 3211 );
+OnRegularDead3212: callsub( S_Regular, 3212 );
+OnRegularDead3213: callsub( S_Regular, 3213 );
+
+OnRegularDead3226: callsub( S_Regular, 3226 );
+OnRegularDead3227: callsub( S_Regular, 3227 );
+OnRegularDead3228: callsub( S_Regular, 3228 );
+OnRegularDead3229: callsub( S_Regular, 3229 );
+OnRegularDead3230: callsub( S_Regular, 3230 );
+OnRegularDead3231: callsub( S_Regular, 3231 );
+OnRegularDead3232: callsub( S_Regular, 3232 );
+
+S_Regular:
+	.@mob_id = getarg(0);
 	if (.lhz_dun_n[.@mob_id] < 110 && .lhz_dun_n_boss == 0) {
 		.lhz_dun_n[.@mob_id]++;
 		if (.lhz_dun_n[.@mob_id] == 110) {
-			.@mini_boss = .@mob_id + 6 + (.@mob_id > 3213);	// mini boss version ID: regular ID +6 for non-transcendent, +7 for others
-			monster "lhz_dun_n",0,0,"--en--",.@mini_boss,1, "lhz_dun_n::OnMiniDead";
+			.@mini_boss = .@mob_id + 6 + (.@mob_id > 3219);	// mini boss version ID: regular ID +6 for non-transcendent, +7 for others
+			monster "lhz_dun_n",0,0,"--en--",.@mini_boss,1, "lhz_dun_n::OnMiniDead" + .@mini_boss;
 		}
 	}
 	end;
-OnMiniDead:
-	.@mob_id = killedrid;
+
+OnMiniDead3214: callsub( S_Mini, 3214 );
+OnMiniDead3215: callsub( S_Mini, 3215 );
+OnMiniDead3216: callsub( S_Mini, 3216 );
+OnMiniDead3217: callsub( S_Mini, 3217 );
+OnMiniDead3218: callsub( S_Mini, 3218 );
+OnMiniDead3219: callsub( S_Mini, 3219 );
+
+OnMiniDead3233: callsub( S_Mini, 3233 );
+OnMiniDead3234: callsub( S_Mini, 3234 );
+OnMiniDead3235: callsub( S_Mini, 3235 );
+OnMiniDead3236: callsub( S_Mini, 3236 );
+OnMiniDead3237: callsub( S_Mini, 3237 );
+OnMiniDead3238: callsub( S_Mini, 3238 );
+OnMiniDead3239: callsub( S_Mini, 3239 );
+
+S_Mini:
+	.@mob_id = getarg(0);
 	if (.lhz_dun_n[.@mob_id] < 4 && .lhz_dun_n_boss == 0) {
 		.lhz_dun_n[.@mob_id]++;
 		.@regular = .@mob_id - 6 - (.@mob_id > 3219);
@@ -53,11 +84,7 @@ OnMiniDead:
 			monster "lhz_dun_n",140,230,"--en--", F_Rand(3220,3221,3222,3223,3224,3225,3240,3241,3242,3243,3244,3245,3246),1, "lhz_dun_n::OnMyMVPDead";
 			mapannounce "lhz_dun_n", "Voice of Reaper: It's been a while.", bc_map;	// unknown message
 			.lhz_dun_n_boss = 1;
-			for ( .@i = 0; .@i < 13; ++.@i ) {	
-				.@regular = .@mini_boss_list[.@i] - 6 - (.@mini_boss_list[.@i] > 3219);
-				.lhz_dun_n[.@regular] = 0;
-				.lhz_dun_n[.@mini_boss_list[.@i]] = 0;
-			}
+			deletearray .lhz_dun_n;
 		}
 	}
 	end;

+ 0 - 4
src/char/char_clif.cpp

@@ -30,10 +30,6 @@
 
 using namespace rathena;
 
-// Reuseable global packet buffer to prevent too many allocations
-// Take socket.cpp::socket_max_client_packet into consideration
-static int8 packet_buffer[UINT16_MAX];
-
 std::vector<struct s_point_str> accessible_maps{
 	s_point_str{ MAP_PRONTERA, 273, 354 },
 	s_point_str{ MAP_GEFFEN, 120, 100 },

+ 1 - 1
src/char/int_mail.cpp

@@ -548,7 +548,7 @@ void mapif_Mail_return( int fd, uint32 char_id, int mail_id, uint32 account_id_r
 	char temp_[MAIL_TITLE_LENGTH + 3];
 
 	// swap sender and receiver
-	SWAP( msg.send_id, msg.dest_id );
+	std::swap( msg.send_id, msg.dest_id );
 	safestrncpy( temp_, msg.send_name, NAME_LENGTH );
 	safestrncpy( msg.send_name, msg.dest_name, NAME_LENGTH );
 	safestrncpy( msg.dest_name, temp_, NAME_LENGTH );

+ 0 - 12
src/common/cbasetypes.hpp

@@ -266,18 +266,6 @@ typedef char bool;
 //////////////////////////////////////////////////////////////////////////
 // macro tools
 
-#ifdef SWAP // just to be sure
-#undef SWAP
-#endif
-// hmm only ints?
-//#define SWAP(a,b) { int temp=a; a=b; b=temp;}
-// if using macros then something that is type independent
-//#define SWAP(a,b) ((a == b) || ((a ^= b), (b ^= a), (a ^= b)))
-// Avoid "value computed is not used" warning and generates the same assembly code
-#define SWAP(a,b) if (a != b) ((a ^= b), (b ^= a), (a ^= b))
-#define swap_ptrcast(c,a,b) if ((a) != (b)) ((a) = static_cast<c>((void*)((intptr_t)(a) ^ (intptr_t)(b))), (b) = static_cast<c>((void*)((intptr_t)(a) ^ (intptr_t)(b))), (a) = static_cast<c>((void*)((intptr_t)(a) ^ (intptr_t)(b))) )
-#define swap_ptr(a,b) swap_ptrcast(void*,a,b)
-
 //////////////////////////////////////////////////////////////////////////
 // should not happen
 #ifndef NULL

+ 1 - 0
src/common/common.vcxproj

@@ -34,6 +34,7 @@
     <ClInclude Include="mmo.hpp" />
     <ClInclude Include="msg_conf.hpp" />
     <ClInclude Include="nullpo.hpp" />
+    <ClInclude Include="packets.hpp" />
     <ClInclude Include="random.hpp" />
     <ClInclude Include="showmsg.hpp" />
     <ClInclude Include="socket.hpp" />

+ 3 - 0
src/common/common.vcxproj.filters

@@ -56,6 +56,9 @@
     <ClInclude Include="nullpo.hpp">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="packets.hpp">
+      <Filter>Header Files</Filter>
+    </ClInclude>
     <ClInclude Include="random.hpp">
       <Filter>Header Files</Filter>
     </ClInclude>

+ 1 - 0
src/common/db.cpp

@@ -2386,6 +2386,7 @@ DBOptions db_fix_options(DBType type, DBOptions options)
 
 		default:
 			ShowError("db_fix_options: Unknown database type %u with options %x\n", type, options);
+		[[fallthrough]];
 		case DB_STRING:
 		case DB_ISTRING: // String databases, no fix required
 			return options;

+ 22 - 28
src/common/db.hpp

@@ -42,6 +42,8 @@
 #ifndef DB_HPP
 #define DB_HPP
 
+#include <utility>
+
 #include <stdarg.h>
 
 #include "cbasetypes.hpp"
@@ -1483,8 +1485,7 @@ void  linkdb_foreach (struct linkdb_node** head, LinkDBFunc func, ...);
 /// @param __heap Binary heap
 /// @param __val Value
 /// @param __topcmp Comparator
-/// @param __swp Swapper
-#define BHEAP_PUSH(__heap,__val,__topcmp,__swp) \
+#define BHEAP_PUSH(__heap,__val,__topcmp) \
 	do{ \
 		size_t _i_ = VECTOR_LENGTH(__heap); \
 		VECTOR_PUSH(__heap,__val); /* insert at end */ \
@@ -1493,7 +1494,7 @@ void  linkdb_foreach (struct linkdb_node** head, LinkDBFunc func, ...);
 			size_t _parent_ = (_i_-1)/2; \
 			if( __topcmp(VECTOR_INDEX(__heap,_parent_),VECTOR_INDEX(__heap,_i_)) < 0 ) \
 				break; /* done */ \
-			__swp(VECTOR_INDEX(__heap,_parent_),VECTOR_INDEX(__heap,_i_)); \
+			std::swap(VECTOR_INDEX(__heap,_parent_),VECTOR_INDEX(__heap,_i_)); \
 			_i_ = _parent_; \
 		} \
 	}while(0)
@@ -1505,12 +1506,11 @@ void  linkdb_foreach (struct linkdb_node** head, LinkDBFunc func, ...);
 /// @param __heap Binary heap
 /// @param __val Value
 /// @param __topcmp Comparator
-/// @param __swp Swapper
-#define BHEAP_PUSH2(__heap,__val,__topcmp,__swp) \
+#define BHEAP_PUSH2(__heap,__val,__topcmp) \
 	do{ \
 		size_t _i_ = VECTOR_LENGTH(__heap); \
 		VECTOR_PUSH(__heap,__val); /* insert at end */ \
-		BHEAP_SIFTDOWN(__heap,0,_i_,__topcmp,__swp); \
+		BHEAP_SIFTDOWN(__heap,0,_i_,__topcmp); \
 	}while(0)
 
 
@@ -1525,8 +1525,7 @@ void  linkdb_foreach (struct linkdb_node** head, LinkDBFunc func, ...);
 ///
 /// @param __heap Binary heap
 /// @param __topcmp Comparator
-/// @param __swp Swapper
-#define BHEAP_POP(__heap,__topcmp,__swp) BHEAP_POPINDEX(__heap,0,__topcmp,__swp)
+#define BHEAP_POP(__heap,__topcmp) BHEAP_POPINDEX(__heap,0,__topcmp)
 
 
 
@@ -1534,13 +1533,12 @@ void  linkdb_foreach (struct linkdb_node** head, LinkDBFunc func, ...);
 ///
 /// @param __heap Binary heap
 /// @param __topcmp Comparator
-/// @param __swp Swapper
-#define BHEAP_POP2(__heap,__topcmp,__swp) \
+#define BHEAP_POP2(__heap,__topcmp) \
 	do{ \
 		VECTOR_INDEX(__heap,0) = VECTOR_POP(__heap); /* put last at index */ \
 		if( !VECTOR_LENGTH(__heap) ) /* removed last, nothing to do */ \
 			break; \
-		BHEAP_SIFTUP(__heap,0,__topcmp,__swp); \
+		BHEAP_SIFTUP(__heap,0,__topcmp); \
 	}while(0)
 
 
@@ -1556,8 +1554,7 @@ void  linkdb_foreach (struct linkdb_node** head, LinkDBFunc func, ...);
 /// @param __heap Binary heap
 /// @param __idx Index
 /// @param __topcmp Comparator
-/// @param __swp Swapper
-#define BHEAP_POPINDEX(__heap,__idx,__topcmp,__swp) \
+#define BHEAP_POPINDEX(__heap,__idx,__topcmp) \
 	do{ \
 		size_t _i_ = __idx; \
 		VECTOR_INDEX(__heap,__idx) = VECTOR_POP(__heap); /* put last at index */ \
@@ -1568,7 +1565,7 @@ void  linkdb_foreach (struct linkdb_node** head, LinkDBFunc func, ...);
 			size_t _parent_ = (_i_-1)/2; \
 			if( __topcmp(VECTOR_INDEX(__heap,_parent_),VECTOR_INDEX(__heap,_i_)) < 0 ) \
 				break; /* done */ \
-			__swp(VECTOR_INDEX(__heap,_parent_),VECTOR_INDEX(__heap,_i_)); \
+			std::swap(VECTOR_INDEX(__heap,_parent_),VECTOR_INDEX(__heap,_i_)); \
 			_i_ = _parent_; \
 		} \
 		while( _i_ < VECTOR_LENGTH(__heap) ) \
@@ -1580,12 +1577,12 @@ void  linkdb_foreach (struct linkdb_node** head, LinkDBFunc func, ...);
 				break; /* done */ \
 			else if( _rchild_ >= VECTOR_LENGTH(__heap) || __topcmp(VECTOR_INDEX(__heap,_lchild_),VECTOR_INDEX(__heap,_rchild_)) <= 0 ) \
 			{ /* left child */ \
-				__swp(VECTOR_INDEX(__heap,_i_),VECTOR_INDEX(__heap,_lchild_)); \
+				std::swap(VECTOR_INDEX(__heap,_i_),VECTOR_INDEX(__heap,_lchild_)); \
 				_i_ = _lchild_; \
 			} \
 			else \
 			{ /* right child */ \
-				__swp(VECTOR_INDEX(__heap,_i_),VECTOR_INDEX(__heap,_rchild_)); \
+				std::swap(VECTOR_INDEX(__heap,_i_),VECTOR_INDEX(__heap,_rchild_)); \
 				_i_ = _rchild_; \
 			} \
 		} \
@@ -1601,8 +1598,7 @@ void  linkdb_foreach (struct linkdb_node** head, LinkDBFunc func, ...);
 /// @param __startidx Index of an ancestor of __idx
 /// @param __idx Index of an inserted element
 /// @param __topcmp Comparator
-/// @param __swp Swapper
-#define BHEAP_SIFTDOWN(__heap,__startidx,__idx,__topcmp,__swp) \
+#define BHEAP_SIFTDOWN(__heap,__startidx,__idx,__topcmp) \
 	do{ \
 		size_t _i2_ = __idx; \
 		while( _i2_ > __startidx ) \
@@ -1610,7 +1606,7 @@ void  linkdb_foreach (struct linkdb_node** head, LinkDBFunc func, ...);
 			size_t _parent_ = (_i2_-1)/2; \
 			if( __topcmp(VECTOR_INDEX(__heap,_parent_),VECTOR_INDEX(__heap,_i2_)) <= 0 ) \
 				break; /* done */ \
-			__swp(VECTOR_INDEX(__heap,_parent_),VECTOR_INDEX(__heap,_i2_)); \
+			std::swap(VECTOR_INDEX(__heap,_parent_),VECTOR_INDEX(__heap,_i2_)); \
 			_i2_ = _parent_; \
 		} \
 	}while(0)
@@ -1622,8 +1618,7 @@ void  linkdb_foreach (struct linkdb_node** head, LinkDBFunc func, ...);
 /// @param __heap Binary heap
 /// @param __idx Index of an inserted element
 /// @param __topcmp Comparator
-/// @param __swp Swapper
-#define BHEAP_SIFTUP(__heap,__idx,__topcmp,__swp) \
+#define BHEAP_SIFTUP(__heap,__idx,__topcmp) \
 	do{ \
 		size_t _i_ = __idx; \
 		size_t _lchild_ = _i_*2 + 1; \
@@ -1632,17 +1627,17 @@ void  linkdb_foreach (struct linkdb_node** head, LinkDBFunc func, ...);
 			size_t _rchild_ = _i_*2 + 2; \
 			if( _rchild_ >= VECTOR_LENGTH(__heap) || __topcmp(VECTOR_INDEX(__heap,_lchild_),VECTOR_INDEX(__heap,_rchild_)) < 0 ) \
 			{ /* left child */ \
-				__swp(VECTOR_INDEX(__heap,_i_),VECTOR_INDEX(__heap,_lchild_)); \
+				std::swap(VECTOR_INDEX(__heap,_i_),VECTOR_INDEX(__heap,_lchild_)); \
 				_i_ = _lchild_; \
 			} \
 			else \
 			{ /* right child */ \
-				__swp(VECTOR_INDEX(__heap,_i_),VECTOR_INDEX(__heap,_rchild_)); \
+				std::swap(VECTOR_INDEX(__heap,_i_),VECTOR_INDEX(__heap,_rchild_)); \
 				_i_ = _rchild_; \
 			} \
 			_lchild_ = _i_*2 + 1; \
 		} \
-		BHEAP_SIFTDOWN(__heap,__idx,_i_,__topcmp,__swp); \
+		BHEAP_SIFTDOWN(__heap,__idx,_i_,__topcmp); \
 	}while(0)
 
 
@@ -1652,11 +1647,10 @@ void  linkdb_foreach (struct linkdb_node** head, LinkDBFunc func, ...);
 /// @param __heap Binary heap
 /// @param __idx Index
 /// @param __topcmp Comparator
-/// @param __swp Swapper
-#define BHEAP_UPDATE(__heap,__idx,__topcmp,__swp) \
+#define BHEAP_UPDATE(__heap,__idx,__topcmp) \
 	do{ \
-		BHEAP_SIFTDOWN(__heap,0,__idx,__topcmp,__swp); \
-		BHEAP_SIFTUP(__heap,__idx,__topcmp,__swp); \
+		BHEAP_SIFTDOWN(__heap,0,__idx,__topcmp); \
+		BHEAP_SIFTUP(__heap,__idx,__topcmp); \
 	}while(0)
 
 

+ 1 - 0
src/common/mapindex.cpp

@@ -164,6 +164,7 @@ void mapindex_init(void) {
 			switch (sscanf(line, "%11s\t%d", map_name, &index)) {
 				case 1: //Map with no ID given, auto-assign
 					index = last_index+1;
+					[[fallthrough]];
 				case 2: //Map with ID given
 					mapindex_addmap(index,map_name);
 					break;

+ 4 - 6
src/common/md5calc.cpp

@@ -235,10 +235,8 @@ void MD5_String(const char * string, char * output)
 }
 
 /** output is a sequence of non-zero characters to be used as password salt. */
-void MD5_Salt(unsigned int len, char * output)
-{
-	unsigned int i;
-	for( i = 0; i < len; ++i )
-		output[i] = (char)(1 + rnd() % 255);
-
+void MD5_Salt( size_t len, char* output ){
+	for( size_t i = 0; i < len; ++i ){
+		output[i] = static_cast<char>( rnd_value( 1, 255 ) );
+	}
 }

+ 3 - 1
src/common/md5calc.hpp

@@ -4,8 +4,10 @@
 #ifndef MD5CALC_HPP
 #define MD5CALC_HPP
 
+#include "cbasetypes.hpp"
+
 void MD5_String(const char * string, char * output);
 void MD5_Binary(const char * string, unsigned char * output);
-void MD5_Salt(unsigned int len, char * output);
+void MD5_Salt(size_t len, char * output);
 
 #endif /* MD5CALC_HPP */

+ 3 - 0
src/common/mmo.hpp

@@ -116,6 +116,9 @@ typedef uint32 t_itemid;
 #ifndef MAX_BARTER_REQUIREMENTS
 	#define MAX_BARTER_REQUIREMENTS 5
 #endif
+#ifndef WEB_AUTH_TOKEN_LENGTH
+	#define WEB_AUTH_TOKEN_LENGTH 16+1
+#endif
 
 enum e_enchantgrade : uint16{
 	ENCHANTGRADE_NONE = 0,

+ 212 - 0
src/common/packets.hpp

@@ -0,0 +1,212 @@
+// Copyright (c) rAthena Dev Teams - Licensed under GNU GPL
+// For more information, see LICENCE in the main folder
+
+#ifndef PACKETS_HPP
+#define PACKETS_HPP
+
+#include <common/cbasetypes.hpp>
+#include <common/mmo.hpp>
+
+#pragma warning( push )
+#pragma warning( disable : 4200 )
+
+#define DEFINE_PACKET_HEADER( name, id ) const int16 HEADER_##name = id
+#define DEFINE_PACKET_ID( name, id ) DEFINE_PACKET_HEADER( name, id )
+
+// NetBSD 5 and Solaris don't like pragma pack but accept the packed attribute
+#if !defined( sun ) && ( !defined( __NETBSD__ ) || __NetBSD_Version__ >= 600000000 )
+	#pragma pack( push, 1 )
+#endif
+
+struct PACKET_CA_LOGIN{
+	int16 packetType;
+	uint32 version;
+	char username[NAME_LENGTH];
+	char password[NAME_LENGTH];
+	uint8 clienttype;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER( CA_LOGIN, 0x64 );
+
+#if PACKETVER >= 20170315
+struct PACKET_AC_ACCEPT_LOGIN_sub{
+	uint32 ip;
+	uint16 port;
+	char name[20];
+	uint16 users;
+	uint16 type;
+	uint16 new_;
+	uint8 unknown[128];
+} __attribute__((packed));
+
+struct PACKET_AC_ACCEPT_LOGIN{
+	int16 packetType;
+	int16 packetLength;
+	uint32 login_id1;
+	uint32 AID;
+	uint32 login_id2;
+	uint32 last_ip;
+	char last_login[26];
+	uint8 sex;
+	char token[WEB_AUTH_TOKEN_LENGTH];
+	PACKET_AC_ACCEPT_LOGIN_sub char_servers[];
+} __attribute__((packed));
+DEFINE_PACKET_HEADER( AC_ACCEPT_LOGIN, 0xac4 );
+#else
+struct PACKET_AC_ACCEPT_LOGIN_sub{
+	uint32 ip;
+	uint16 port;
+	char name[20];
+	uint16 users;
+	uint16 type;
+	uint16 new_;
+} __attribute__((packed));
+
+struct PACKET_AC_ACCEPT_LOGIN{
+	int16 packetType;
+	int16 packetLength;
+	uint32 login_id1;
+	uint32 AID;
+	uint32 login_id2;
+	uint32 last_ip;
+	char last_login[26];
+	uint8 sex;
+	PACKET_AC_ACCEPT_LOGIN_sub char_servers[];
+} __attribute__((packed));
+DEFINE_PACKET_HEADER( AC_ACCEPT_LOGIN, 0x69 );
+#endif
+
+// not sure when this started
+#if PACKETVER >= 20120000
+struct PACKET_AC_REFUSE_LOGIN{
+	int16 packetType;
+	uint32 error;
+	char unblock_time[20];
+} __attribute__((packed));
+DEFINE_PACKET_HEADER( AC_REFUSE_LOGIN, 0x83e );
+#else
+struct PACKET_AC_REFUSE_LOGIN{
+	int16 packetType;
+	uint8 error;
+	char unblock_time[20];
+} __attribute__((packed));
+DEFINE_PACKET_HEADER( AC_REFUSE_LOGIN, 0x6a );
+#endif
+
+struct PACKET_SC_NOTIFY_BAN{
+	int16 packetType;
+	uint8 result;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER( SC_NOTIFY_BAN, 0x81 );
+
+struct PACKET_CA_REQ_HASH{
+	int16 packetType;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER( CA_REQ_HASH, 0x1db );
+
+struct PACKET_AC_ACK_HASH{
+	int16 packetType;
+	int16 packetLength;
+	char salt[];
+} __attribute__((packed));
+DEFINE_PACKET_HEADER( AC_ACK_HASH, 0x1dc );
+
+struct PACKET_CA_LOGIN2{
+	int16 packetType;
+	uint32 version;
+	char username[NAME_LENGTH];
+	uint8 passwordMD5[16];
+	uint8 clienttype;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER( CA_LOGIN2, 0x1dd );
+
+struct PACKET_CA_LOGIN3{
+	int16 packetType;
+	uint32 version;
+	char username[NAME_LENGTH];
+	uint8 passwordMD5[16];
+	uint8 clienttype;
+	uint8 clientinfo;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER( CA_LOGIN3, 0x1fa );
+
+struct PACKET_CA_CONNECT_INFO_CHANGED{
+	int16 packetType;
+	char name[NAME_LENGTH];
+} __attribute__((packed));
+DEFINE_PACKET_HEADER( CA_CONNECT_INFO_CHANGED, 0x200 );
+
+struct PACKET_CA_EXE_HASHCHECK{
+	int16 packetType;
+	char hash[16];
+} __attribute__((packed));
+DEFINE_PACKET_HEADER( CA_EXE_HASHCHECK, 0x204 );
+
+struct PACKET_CA_LOGIN_PCBANG{
+	int16 packetType;
+	uint32 version;
+	char username[NAME_LENGTH];
+	char password[NAME_LENGTH];
+	uint8 clienttype;
+	char ip[16];
+	char mac[13];
+} __attribute__((packed));
+DEFINE_PACKET_HEADER( CA_LOGIN_PCBANG, 0x277 );
+
+struct PACKET_CA_LOGIN4{
+	int16 packetType;
+	uint32 version;
+	char username[NAME_LENGTH];
+	uint8 passwordMD5[16];
+	uint8 clienttype;
+	char mac[13];
+} __attribute__((packed));
+DEFINE_PACKET_HEADER( CA_LOGIN4, 0x27c );
+
+struct PACKET_CA_LOGIN_CHANNEL{
+	int16 packetType;
+	uint32 version;
+	char username[NAME_LENGTH];
+	char password[NAME_LENGTH];
+	uint8 clienttype;
+	char ip[16];
+	char mac[13];
+	uint8 is_gravity;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER( CA_LOGIN_CHANNEL, 0x2b0 );
+
+struct PACKET_CA_SSO_LOGIN_REQ{
+	int16 packetType;
+	int16 packetLength;
+	uint32 version;
+	uint8 clienttype;
+	char username[NAME_LENGTH];
+	char password[27];
+	char mac[17];
+	char ip[15];
+	char token[];
+} __attribute__((packed));
+DEFINE_PACKET_HEADER( CA_SSO_LOGIN_REQ, 0x825 );
+
+struct PACKET_CT_AUTH{
+	int16 packetType;
+	uint8 unknown[66];
+} __attribute__((packed));
+DEFINE_PACKET_HEADER( CT_AUTH, 0xacf );
+
+struct PACKET_TC_RESULT{
+	int16 packetType;
+	int16 packetLength;
+	uint32 type;
+	char unknown1[20];
+	char unknown2[6];
+} __attribute__((packed));
+DEFINE_PACKET_HEADER( TC_RESULT, 0xae3 );
+
+// NetBSD 5 and Solaris don't like pragma pack but accept the packed attribute
+#if !defined( sun ) && ( !defined( __NETBSD__ ) || __NetBSD_Version__ >= 600000000 )
+	#pragma pack( pop )
+#endif
+
+#pragma warning( pop )
+
+#endif /* PACKETS_HPP */

+ 3 - 0
src/common/random.hpp

@@ -20,6 +20,9 @@ int32 rnd(void);// [0, SINT32_MAX]
  */
 template <typename T>
 typename std::enable_if<std::is_integral<T>::value, T>::type rnd_value(T min, T max) {
+	if (min > max) {
+		std::swap(min, max);
+	}
 	std::uniform_int_distribution<T> dist(min, max);
 	return dist(generator);
 }

+ 4 - 0
src/common/socket.cpp

@@ -47,6 +47,10 @@
 #include "strlib.hpp"
 #include "timer.hpp"
 
+// Reuseable global packet buffer to prevent too many allocations
+// Take socket.cpp::socket_max_client_packet into consideration
+int8 packet_buffer[UINT16_MAX];
+
 /////////////////////////////////////////////////////////////////////
 #if defined(WIN32)
 /////////////////////////////////////////////////////////////////////

+ 30 - 0
src/common/socket.hpp

@@ -199,4 +199,34 @@ void send_shortlist_add_fd(int fd);
 void send_shortlist_do_sends();
 #endif
 
+// Reuseable global packet buffer to prevent too many allocations
+// Take socket.cpp::socket_max_client_packet into consideration
+extern int8 packet_buffer[UINT16_MAX];
+
+template <typename P>
+bool socket_send( int fd, P& packet ){
+	if( !session_isActive( fd ) ){
+		return false;
+	}
+
+	WFIFOHEAD( fd, sizeof( P ) );
+	memcpy( WFIFOP( fd, 0 ), &packet, sizeof( P ) );
+	WFIFOSET( fd, sizeof( P ) );
+
+	return true;
+}
+
+template <typename P>
+bool socket_send( int fd, P* packet ){
+	if( !session_isActive( fd ) ){
+		return false;
+	}
+
+	WFIFOHEAD( fd, packet->packetLength );
+	memcpy( WFIFOP( fd, 0 ), packet, packet->packetLength );
+	WFIFOSET( fd, packet->packetLength );
+
+	return true;
+}
+
 #endif /* SOCKET_HPP */

+ 55 - 23
src/common/sql.cpp

@@ -511,59 +511,91 @@ static int Sql_P_BindSqlDataType(MYSQL_BIND* bind, enum SqlDataType buffer_type,
 	memset(bind, 0, sizeof(MYSQL_BIND));
 	switch( buffer_type )
 	{
-	case SQLDT_NULL: bind->buffer_type = MYSQL_TYPE_NULL;
+	case SQLDT_NULL:
+		bind->buffer_type = MYSQL_TYPE_NULL;
 		buffer_len = 0;// FIXME length = ? [FlavioJS]
 		break;
 	// fixed size
-	case SQLDT_UINT8: bind->is_unsigned = 1;
-	case SQLDT_INT8: bind->buffer_type = MYSQL_TYPE_TINY;
+	case SQLDT_UINT8:
+		bind->is_unsigned = 1;
+		[[fallthrough]];
+	case SQLDT_INT8:
+		bind->buffer_type = MYSQL_TYPE_TINY;
 		buffer_len = 1;
 		break;
-	case SQLDT_UINT16: bind->is_unsigned = 1;
-	case SQLDT_INT16: bind->buffer_type = MYSQL_TYPE_SHORT;
+	case SQLDT_UINT16:
+		bind->is_unsigned = 1;
+		[[fallthrough]];
+	case SQLDT_INT16:
+		bind->buffer_type = MYSQL_TYPE_SHORT;
 		buffer_len = 2;
 		break;
-	case SQLDT_UINT32: bind->is_unsigned = 1;
-	case SQLDT_INT32: bind->buffer_type = MYSQL_TYPE_LONG;
+	case SQLDT_UINT32:
+		bind->is_unsigned = 1;
+		[[fallthrough]];
+	case SQLDT_INT32:
+		bind->buffer_type = MYSQL_TYPE_LONG;
 		buffer_len = 4;
 		break;
-	case SQLDT_UINT64: bind->is_unsigned = 1;
-	case SQLDT_INT64: bind->buffer_type = MYSQL_TYPE_LONGLONG;
+	case SQLDT_UINT64:
+		bind->is_unsigned = 1;
+		[[fallthrough]];
+	case SQLDT_INT64:
+		bind->buffer_type = MYSQL_TYPE_LONGLONG;
 		buffer_len = 8;
 		break;
 	// platform dependent size
-	case SQLDT_UCHAR: bind->is_unsigned = 1;
-	case SQLDT_CHAR: bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(char));
+	case SQLDT_UCHAR:
+		bind->is_unsigned = 1;
+		[[fallthrough]];
+	case SQLDT_CHAR:
+		bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(char));
 		buffer_len = sizeof(char);
 		break;
-	case SQLDT_USHORT: bind->is_unsigned = 1;
-	case SQLDT_SHORT: bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(short));
+	case SQLDT_USHORT:
+		bind->is_unsigned = 1;
+		[[fallthrough]];
+	case SQLDT_SHORT:
+		bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(short));
 		buffer_len = sizeof(short);
 		break;
-	case SQLDT_UINT: bind->is_unsigned = 1;
-	case SQLDT_INT: bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(int));
+	case SQLDT_UINT:
+		bind->is_unsigned = 1;
+		[[fallthrough]];
+	case SQLDT_INT:
+		bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(int));
 		buffer_len = sizeof(int);
 		break;
-	case SQLDT_ULONG: bind->is_unsigned = 1;
-	case SQLDT_LONG: bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(long));
+	case SQLDT_ULONG:
+		bind->is_unsigned = 1;
+		[[fallthrough]];
+	case SQLDT_LONG:
+		bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(long));
 		buffer_len = sizeof(long);
 		break;
-	case SQLDT_ULONGLONG: bind->is_unsigned = 1;
-	case SQLDT_LONGLONG: bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(int64));
+	case SQLDT_ULONGLONG:
+		bind->is_unsigned = 1;
+		[[fallthrough]];
+	case SQLDT_LONGLONG:
+		bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(int64));
 		buffer_len = sizeof(int64);
 		break;
 	// floating point
-	case SQLDT_FLOAT: bind->buffer_type = MYSQL_TYPE_FLOAT;
+	case SQLDT_FLOAT:
+		bind->buffer_type = MYSQL_TYPE_FLOAT;
 		buffer_len = 4;
 		break;
-	case SQLDT_DOUBLE: bind->buffer_type = MYSQL_TYPE_DOUBLE;
+	case SQLDT_DOUBLE:
+		bind->buffer_type = MYSQL_TYPE_DOUBLE;
 		buffer_len = 8;
 		break;
 	// other
 	case SQLDT_STRING:
-	case SQLDT_ENUM: bind->buffer_type = MYSQL_TYPE_STRING;
+	case SQLDT_ENUM:
+		bind->buffer_type = MYSQL_TYPE_STRING;
 		break;
-	case SQLDT_BLOB: bind->buffer_type = MYSQL_TYPE_BLOB;
+	case SQLDT_BLOB:
+		bind->buffer_type = MYSQL_TYPE_BLOB;
 		break;
 	default:
 		ShowDebug("Sql_P_BindSqlDataType: unsupported buffer type (%d)\n", buffer_type);

+ 6 - 4
src/common/timer.cpp

@@ -3,6 +3,8 @@
 
 #include "timer.hpp"
 
+#include <utility>
+
 #include <stdlib.h>
 #include <string.h>
 
@@ -203,7 +205,7 @@ t_tick gettick(void)
 static void push_timer_heap(int tid)
 {
 	BHEAP_ENSURE(timer_heap, 1, 256);
-	BHEAP_PUSH(timer_heap, tid, DIFFTICK_MINTOPCMP, SWAP);
+	BHEAP_PUSH(timer_heap, tid, DIFFTICK_MINTOPCMP);
 }
 
 /*==========================
@@ -340,9 +342,9 @@ t_tick settick_timer(int tid, t_tick tick)
 		return tick;// nothing to do, already in propper position
 
 	// pop and push adjusted timer
-	BHEAP_POPINDEX(timer_heap, i, DIFFTICK_MINTOPCMP, SWAP);
+	BHEAP_POPINDEX(timer_heap, i, DIFFTICK_MINTOPCMP);
 	timer_data[tid].tick = tick;
-	BHEAP_PUSH(timer_heap, tid, DIFFTICK_MINTOPCMP, SWAP);
+	BHEAP_PUSH(timer_heap, tid, DIFFTICK_MINTOPCMP);
 	return tick;
 }
 
@@ -362,7 +364,7 @@ t_tick do_timer(t_tick tick)
 			break; // no more expired timers to process
 
 		// remove timer
-		BHEAP_POP(timer_heap, DIFFTICK_MINTOPCMP, SWAP);
+		BHEAP_POP(timer_heap, DIFFTICK_MINTOPCMP);
 		timer_data[tid].type |= TIMER_REMOVE_HEAP;
 
 		if( timer_data[tid].func )

+ 25 - 42
src/login/account.cpp

@@ -22,12 +22,12 @@
 typedef struct AccountDB_SQL {
 	AccountDB vtable;    // public interface
 	Sql* accounts;       // SQL handle accounts storage
-	char   db_hostname[1024]; // Doubled for long hostnames (bugreport:8003)
-	uint16 db_port;
-	char   db_username[1024];
-	char   db_password[1024];
-	char   db_database[1024];
-	char   codepage[1024];
+	std::string db_hostname = "127.0.0.1";
+	uint16 db_port = 3306;
+	std::string db_username = "ragnarok";
+	std::string db_password = "";
+	std::string db_database = "ragnarok";
+	std::string codepage = "";
 	// other settings
 	bool case_sensitive;
 	//table name
@@ -67,6 +67,7 @@ static bool mmo_auth_tosql(AccountDB_SQL* db, const struct mmo_account* acc, boo
 /// public constructor
 AccountDB* account_db_sql(void) {
 	AccountDB_SQL* db = (AccountDB_SQL*)aCalloc(1, sizeof(AccountDB_SQL));
+	new(db) AccountDB_SQL();
 
 	// set up the vtable
 	db->vtable.init         = &account_db_sql_init;
@@ -85,13 +86,6 @@ AccountDB* account_db_sql(void) {
 
 	// initialize to default values
 	db->accounts = NULL;
-	// local sql settings
-	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, "", sizeof(db->db_password));
-	safestrncpy(db->db_database, "ragnarok", sizeof(db->db_database));
-	safestrncpy(db->codepage, "", sizeof(db->codepage));
 	// other settings
 	db->case_sensitive = false;
 	safestrncpy(db->account_db, "login", sizeof(db->account_db));
@@ -112,34 +106,21 @@ AccountDB* account_db_sql(void) {
 static bool account_db_sql_init(AccountDB* self) {
 	AccountDB_SQL* db = (AccountDB_SQL*)self;
 	Sql* sql_handle;
-	const char* username = "ragnarok";
-	const char* password = "";
-	const char* hostname = "127.0.0.1";
-	uint16      port     = 3306;
-	const char* database = "ragnarok";
-	const char* codepage = "";
 
 	db->accounts = Sql_Malloc();
 	sql_handle = db->accounts;
 
-	username = db->db_username;
-	password = db->db_password;
-	hostname = db->db_hostname;
-	port     = db->db_port;
-	database = db->db_database;
-	codepage = db->codepage;
-
-	if( SQL_ERROR == Sql_Connect(sql_handle, username, password, hostname, port, database) )
+	if( SQL_ERROR == Sql_Connect(sql_handle, db->db_username.c_str(), db->db_password.c_str(), db->db_hostname.c_str(), db->db_port, db->db_database.c_str()) )
 	{
-                ShowError("Couldn't connect with uname='%s',host='%s',port='%d',database='%s'\n",
-                        username, hostname, port, database);
+		ShowError("Couldn't connect with uname='%s',host='%s',port='%hu',database='%s'\n",
+			db->db_username.c_str(), db->db_hostname.c_str(), db->db_port, db->db_database.c_str());
 		Sql_ShowDebug(sql_handle);
 		Sql_Free(db->accounts);
 		db->accounts = NULL;
 		return false;
 	}
 
-	if( codepage[0] != '\0' && SQL_ERROR == Sql_SetEncoding(sql_handle, codepage) )
+	if( !db->codepage.empty() && SQL_ERROR == Sql_SetEncoding(sql_handle, db->codepage.c_str()) )
 		Sql_ShowDebug(sql_handle);
 
 	self->remove_webtokens( self );
@@ -160,6 +141,8 @@ static void account_db_sql_destroy(AccountDB* self){
 
 	Sql_Free(db->accounts);
 	db->accounts = NULL;
+
+	db->~AccountDB_SQL();
 	aFree(db);
 }
 
@@ -181,19 +164,19 @@ static bool account_db_sql_get_property(AccountDB* self, const char* key, char*
 	if( strncmpi(key, signature, strlen(signature)) == 0 ) {
 		key += strlen(signature);
 		if( strcmpi(key, "ip") == 0 )
-			safesnprintf(buf, buflen, "%s", db->db_hostname);
+			safesnprintf(buf, buflen, "%s", db->db_hostname.c_str());
 		else
 		if( strcmpi(key, "port") == 0 )
-			safesnprintf(buf, buflen, "%d", db->db_port);
+			safesnprintf(buf, buflen, "%hu", db->db_port);
 		else
 		if( strcmpi(key, "id") == 0 )
-			safesnprintf(buf, buflen, "%s", db->db_username);
+			safesnprintf(buf, buflen, "%s", db->db_username.c_str());
 		else
 		if(	strcmpi(key, "pw") == 0 )
-			safesnprintf(buf, buflen, "%s", db->db_password);
+			safesnprintf(buf, buflen, "%s", db->db_password.c_str());
 		else
 		if( strcmpi(key, "db") == 0 )
-			safesnprintf(buf, buflen, "%s", db->db_database);
+			safesnprintf(buf, buflen, "%s", db->db_database.c_str());
 		else
 		if( strcmpi(key, "account_db") == 0 )
 			safesnprintf(buf, buflen, "%s", db->account_db);
@@ -212,7 +195,7 @@ static bool account_db_sql_get_property(AccountDB* self, const char* key, char*
 	if( strncmpi(key, signature, strlen(signature)) == 0 ) {
 		key += strlen(signature);
 		if( strcmpi(key, "codepage") == 0 )
-			safesnprintf(buf, buflen, "%s", db->codepage);
+			safesnprintf(buf, buflen, "%s", db->codepage.c_str());
 		else
 		if( strcmpi(key, "case_sensitive") == 0 )
 			safesnprintf(buf, buflen, "%d", (db->case_sensitive ? 1 : 0));
@@ -240,19 +223,19 @@ static bool account_db_sql_set_property(AccountDB* self, const char* key, const
 	if( strncmp(key, signature, strlen(signature)) == 0 ) {
 		key += strlen(signature);
 		if( strcmpi(key, "ip") == 0 )
-			safestrncpy(db->db_hostname, value, sizeof(db->db_hostname));
+			db->db_hostname = value;
 		else
 		if( strcmpi(key, "port") == 0 )
-			db->db_port = (uint16)strtoul(value, NULL, 10);
+			db->db_port = (uint16)strtoul( value, nullptr, 10 );
 		else
 		if( strcmpi(key, "id") == 0 )
-			safestrncpy(db->db_username, value, sizeof(db->db_username));
+			db->db_username = value;
 		else
 		if( strcmpi(key, "pw") == 0 )
-			safestrncpy(db->db_password, value, sizeof(db->db_password));
+			db->db_password = value;
 		else
 		if( strcmpi(key, "db") == 0 )
-			safestrncpy(db->db_database, value, sizeof(db->db_database));
+			db->db_database = value;
 		else
 		if( strcmpi(key, "account_db") == 0 )
 			safestrncpy(db->account_db, value, sizeof(db->account_db));
@@ -271,7 +254,7 @@ static bool account_db_sql_set_property(AccountDB* self, const char* key, const
 	if( strncmpi(key, signature, strlen(signature)) == 0 ) {
 		key += strlen(signature);
 		if( strcmpi(key, "codepage") == 0 )
-			safestrncpy(db->codepage, value, sizeof(db->codepage));
+			db->codepage = value;
 		else
 		if( strcmpi(key, "case_sensitive") == 0 )
 			db->case_sensitive = (config_switch(value)==1);

+ 1 - 5
src/login/account.hpp

@@ -5,13 +5,9 @@
 #define ACCOUNT_HPP
 
 #include <common/cbasetypes.hpp>
-#include <common/mmo.hpp> // ACCOUNT_REG2_NUM
+#include <common/mmo.hpp> // ACCOUNT_REG2_NUM, WEB_AUTH_TOKEN_LENGTH
 #include <config/core.hpp>
 
-#ifndef WEB_AUTH_TOKEN_LENGTH
-#define WEB_AUTH_TOKEN_LENGTH 16+1
-#endif
-
 typedef struct AccountDB AccountDB;
 typedef struct AccountDBIterator AccountDBIterator;
 

+ 25 - 41
src/login/ipban.cpp

@@ -15,14 +15,14 @@
 #include "login.hpp"
 #include "loginlog.hpp"
 
-// login sql settings
-static char   ipban_db_hostname[64] = "127.0.0.1";
-static uint16 ipban_db_port = 3306;
-static char   ipban_db_username[32] = "ragnarok";
-static char   ipban_db_password[32] = "";
-static char   ipban_db_database[32] = "ragnarok";
-static char   ipban_codepage[32] = "";
-static char   ipban_table[32] = "ipbanlist";
+
+std::string ipban_db_hostname = "127.0.0.1";
+uint16 ipban_db_port = 3306;
+std::string ipban_db_username = "ragnarok";
+std::string ipban_db_password = "";
+std::string ipban_db_database = "ragnarok";
+std::string ipban_codepage = "";
+std::string ipban_table = "ipbanlist";
 
 // globals
 static Sql* sql_handle = NULL;
@@ -46,7 +46,7 @@ bool ipban_check(uint32 ip) {
 		return false;// ipban disabled
 
 	if( SQL_ERROR == Sql_Query(sql_handle, "SELECT count(*) FROM `%s` WHERE `rtime` > NOW() AND (`list` = '%u.*.*.*' OR `list` = '%u.%u.*.*' OR `list` = '%u.%u.%u.*' OR `list` = '%u.%u.%u.%u')",
-		ipban_table, p[3], p[3], p[2], p[3], p[2], p[1], p[3], p[2], p[1], p[0]) )
+		ipban_table.c_str(), p[3], p[3], p[2], p[3], p[2], p[1], p[3], p[2], p[1], p[0]) )
 	{
 		Sql_ShowDebug(sql_handle);
 		// close connection because we can't verify their connectivity.
@@ -81,7 +81,7 @@ void ipban_log(uint32 ip) {
 	{
 		uint8* p = (uint8*)&ip;
 		if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s`(`list`,`btime`,`rtime`,`reason`) VALUES ('%u.%u.%u.*', NOW() , NOW() +  INTERVAL %d MINUTE ,'Password error ban')",
-			ipban_table, p[3], p[2], p[1], login_config.dynamic_pass_failure_ban_duration) )
+			ipban_table.c_str(), p[3], p[2], p[1], login_config.dynamic_pass_failure_ban_duration) )
 			Sql_ShowDebug(sql_handle);
 	}
 }
@@ -100,7 +100,7 @@ TIMER_FUNC(ipban_cleanup){
 	if( !login_config.ipban )
 		return 0;// ipban disabled
 
-	if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `rtime` <= NOW()", ipban_table) )
+	if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `rtime` <= NOW()", ipban_table.c_str()) )
 		Sql_ShowDebug(sql_handle);
 
 	return 0;
@@ -123,19 +123,19 @@ bool ipban_config_read(const char* key, const char* value) {
 	{
 		key += strlen(signature);
 		if( strcmpi(key, "ip") == 0 )
-			safestrncpy(ipban_db_hostname, value, sizeof(ipban_db_hostname));
+			ipban_db_hostname = value;
 		else
 		if( strcmpi(key, "port") == 0 )
-			ipban_db_port = (uint16)strtoul(value, NULL, 10);
+			ipban_db_port = (uint16)strtoul( value, nullptr, 10 );
 		else
 		if( strcmpi(key, "id") == 0 )
-			safestrncpy(ipban_db_username, value, sizeof(ipban_db_username));
+			ipban_db_username = value;
 		else
 		if( strcmpi(key, "pw") == 0 )
-			safestrncpy(ipban_db_password, value, sizeof(ipban_db_password));
+			ipban_db_password = value;
 		else
 		if( strcmpi(key, "db") == 0 )
-			safestrncpy(ipban_db_database, value, sizeof(ipban_db_database));
+			ipban_db_database = value;
 		else
 			return false;// not found
 		return true;
@@ -146,10 +146,10 @@ bool ipban_config_read(const char* key, const char* value) {
 	{
 		key += strlen(signature);
 		if( strcmpi(key, "codepage") == 0 )
-			safestrncpy(ipban_codepage, value, sizeof(ipban_codepage));
+			ipban_codepage = value;
 		else
 		if( strcmpi(key, "ipban_table") == 0 )
-			safestrncpy(ipban_table, value, sizeof(ipban_table));
+			ipban_table = value;
 		else
 		if( strcmpi(key, "enable") == 0 )
 			login_config.ipban = (config_switch(value) != 0);
@@ -181,41 +181,25 @@ bool ipban_config_read(const char* key, const char* value) {
  * Launched at login-serv start, create db or other long scope variable here.
  */
 void ipban_init(void) {
-	const char* username = ipban_db_username;
-	const char* password = ipban_db_password;
-	const char* hostname = ipban_db_hostname;
-	uint16      port     = ipban_db_port;
-	const char* database = ipban_db_database;
-	const char* codepage = ipban_codepage;
-
 	ipban_inited = true;
 
 	if( !login_config.ipban )
 		return;// ipban disabled
 
-	if( ipban_db_hostname[0] != '\0' )
-	{// local settings
-		username = ipban_db_username;
-		password = ipban_db_password;
-		hostname = ipban_db_hostname;
-		port     = ipban_db_port;
-		database = ipban_db_database;
-		codepage = ipban_codepage;
-	}
-
 	// establish connections
 	sql_handle = Sql_Malloc();
-	if( SQL_ERROR == Sql_Connect(sql_handle, username, password, hostname, port, database) )
+	if( SQL_ERROR == Sql_Connect(sql_handle, ipban_db_username.c_str(), ipban_db_password.c_str(), ipban_db_hostname.c_str(), ipban_db_port, ipban_db_database.c_str()) )
 	{
-                ShowError("Couldn't connect with uname='%s',passwd='%s',host='%s',port='%d',database='%s'\n",
-                        username, password, hostname, port, database);
+		ShowError("Couldn't connect with uname='%s',host='%s',port='%hu',database='%s'\n",
+			ipban_db_username.c_str(), ipban_db_hostname.c_str(), ipban_db_port, ipban_db_database.c_str());
 		Sql_ShowDebug(sql_handle);
 		Sql_Free(sql_handle);
 		exit(EXIT_FAILURE);
 	}
-        ShowInfo("Ipban connection made.\n");
-        
-	if( codepage[0] != '\0' && SQL_ERROR == Sql_SetEncoding(sql_handle, codepage) )
+
+	ShowInfo("Ipban connection made.\n");
+
+	if( !ipban_codepage.empty() && SQL_ERROR == Sql_SetEncoding(sql_handle, ipban_codepage.c_str()) )
 		Sql_ShowDebug(sql_handle);
 
 	if( login_config.ipban_cleanup_interval > 0 )

+ 43 - 28
src/login/login.cpp

@@ -56,7 +56,7 @@ int subnet_count = 0; //number of subnet config
 int login_fd; // login server file descriptor socket
 
 //early declaration
-bool login_check_password(const char* md5key, int passwdenc, const char* passwd, const char* refpass);
+bool login_check_password( struct login_session_data& sd, struct mmo_account& acc );
 
 ///Accessors
 AccountDB* login_get_accounts_db(void){
@@ -345,7 +345,12 @@ int login_mmo_auth(struct login_session_data* sd, bool isServer) {
 		return 0; // 0 = Unregistered ID
 	}
 
-	if( !login_check_password(sd->md5key, sd->passwdenc, sd->passwd, acc.pass) ) {
+	if( !isServer && sex_str2num( acc.sex ) == SEX_SERVER ){
+		ShowWarning( "Connection refused: ip %s tried to log into server account '%s'\n", ip, sd->userid );
+		return 0; // 0 = Unregistered ID
+	}
+
+	if( !login_check_password( *sd, acc ) ) {
 		ShowNotice("Invalid password (account: '%s', ip: %s)\n", sd->userid, ip);
 		return 1; // 1 = Incorrect Password
 	}
@@ -426,24 +431,6 @@ int login_mmo_auth(struct login_session_data* sd, bool isServer) {
 	return -1; // account OK
 }
 
-/**
- * Sub function of login_check_password.
- *  Checking if password matches the one in db hashed with client md5key.
- *  Test if(md5(str1+str2)==passwd).
- * @param str1: string (atm:md5key or dbpass)
- * @param str2: string (atm:md5key or dbpass)
- * @param passwd: pass to check
- * @return true if matching else false
- */
-bool login_check_encrypted(const char* str1, const char* str2, const char* passwd) {
-	char tmpstr[64+1], md5str[32+1];
-
-	safesnprintf(tmpstr, sizeof(tmpstr), "%s%s", str1, str2);
-	MD5_String(tmpstr, md5str);
-
-	return (0==strcmp(passwd, md5str));
-}
-
 /**
  * Verify if a password is correct.
  * @param md5key: md5key of client
@@ -452,16 +439,44 @@ bool login_check_encrypted(const char* str1, const char* str2, const char* passw
  * @param refpass: pass register in db
  * @return true if matching else false
  */
-bool login_check_password(const char* md5key, int passwdenc, const char* passwd, const char* refpass) {
-	if(passwdenc == 0){
-		return (0==strcmp(passwd, refpass));
+bool login_check_password( struct login_session_data& sd, struct mmo_account& acc ){
+	if( sd.passwdenc == 0 ){
+		return 0 == strcmp( sd.passwd, acc.pass );
 	}
-	else {
-		// password mode set to 1 -> md5(md5key, refpass) enable with <passwordencrypt></passwordencrypt>
-		// password mode set to 2 -> md5(refpass, md5key) enable with <passwordencrypt2></passwordencrypt2>
-		return ((passwdenc&0x01) && login_check_encrypted(md5key, refpass, passwd)) ||
-		       ((passwdenc&0x02) && login_check_encrypted(refpass, md5key, passwd));
+
+	// password mode set to 1 -> md5(md5key, refpass) enable with <passwordencrypt></passwordencrypt>
+	if( sd.passwdenc & 0x01 ){
+		std::string pwd;
+
+		pwd.append( sd.md5key, sd.md5keylen );
+		pwd.append( acc.pass );
+
+		char md5str[32 + 1];
+
+		MD5_String( pwd.c_str(), md5str );
+
+		if( 0 == strcmp( sd.passwd, md5str ) ){
+			return true;
+		}
+	}
+
+	// password mode set to 2 -> md5(refpass, md5key) enable with <passwordencrypt2></passwordencrypt2>
+	if( sd.passwdenc & 0x02 ){
+		std::string pwd;
+
+		pwd.append( acc.pass );
+		pwd.append( sd.md5key, sd.md5keylen );
+
+		char md5str[32 + 1];
+
+		MD5_String( pwd.c_str(), md5str );
+
+		if( 0 == strcmp( sd.passwd, md5str ) ){
+			return true;
+		}
 	}
+
+	return false;
 }
 
 int login_get_usercount( int users ){

+ 259 - 207
src/login/loginclif.cpp

@@ -8,6 +8,7 @@
 
 #include <common/malloc.hpp>
 #include <common/md5calc.hpp>
+#include <common/packets.hpp>
 #include <common/random.hpp>
 #include <common/showmsg.hpp> //show notice
 #include <common/socket.hpp> //wfifo session
@@ -31,10 +32,12 @@
  * <result>.B (SC_NOTIFY_BAN)
  */
 static void logclif_sent_auth_result(int fd,char result){
-	WFIFOHEAD(fd,3);
-	WFIFOW(fd,0) = 0x81;
-	WFIFOB(fd,2) = result;
-	WFIFOSET(fd,3);
+	PACKET_SC_NOTIFY_BAN p = {};
+
+	p.packetType = HEADER_SC_NOTIFY_BAN;
+	p.result = result;
+
+	socket_send( fd, p );
 }
 
 /**
@@ -49,16 +52,6 @@ static void logclif_auth_ok(struct login_session_data* sd) {
 	uint32 subnet_char_ip;
 	int i;
 
-#if PACKETVER < 20170315
-	int cmd = 0x69; // AC_ACCEPT_LOGIN
-	int header = 47;
-	int size = 32;
-#else
-	int cmd = 0xac4; // AC_ACCEPT_LOGIN3
-	int header = 64;
-	int size = 160;
-#endif
-
 	if( !global_core->is_running() ){
 		// players can only login while running
 		logclif_sent_auth_result(fd,1); // server closed
@@ -118,33 +111,39 @@ static void logclif_auth_ok(struct login_session_data* sd) {
 	login_log(ip, sd->userid, 100, "login ok");
 	ShowStatus("Connection of the account '%s' accepted.\n", sd->userid);
 
-	WFIFOHEAD(fd,header+size*server_num);
-	WFIFOW(fd,0) = cmd;
-	WFIFOW(fd,2) = header+size*server_num;
-	WFIFOL(fd,4) = sd->login_id1;
-	WFIFOL(fd,8) = sd->account_id;
-	WFIFOL(fd,12) = sd->login_id2;
-	WFIFOL(fd,16) = 0; // in old version, that was for ip (not more used)
-	//memcpy(WFIFOP(fd,20), sd->lastlogin, 24); // in old version, that was for name (not more used)
-	memset(WFIFOP(fd,20), 0, 24);
-	WFIFOW(fd,44) = 0; // unknown
-	WFIFOB(fd,46) = sex_str2num(sd->sex);
+	PACKET_AC_ACCEPT_LOGIN* p = (PACKET_AC_ACCEPT_LOGIN*)packet_buffer;
+
+	p->packetType = HEADER_AC_ACCEPT_LOGIN;
+	p->packetLength = sizeof( *p );
+	p->login_id1 = sd->login_id1;
+	p->AID = sd->account_id;
+	p->login_id2 = sd->login_id2;
+	// in old version, that was for ip (not more used)
+	p->last_ip = 0;
+	// in old version, that was for last login time (not more used)
+	safestrncpy( p->last_login, "", sizeof( p->last_login ) );
+	p->sex = sex_str2num( sd->sex );
 #if PACKETVER >= 20170315
-	safestrncpy( WFIFOCP( fd, 47 ), sd->web_auth_token, WEB_AUTH_TOKEN_LENGTH ); // web authentication token
+	safestrncpy( p->token, sd->web_auth_token, WEB_AUTH_TOKEN_LENGTH ); // web authentication token
 #endif
+
 	for( i = 0, n = 0; i < ARRAYLENGTH(ch_server); ++i ) {
 		if( !session_isValid(ch_server[i].fd) )
 			continue;
 		subnet_char_ip = lan_subnetcheck(ip); // Advanced subnet check [LuzZza]
-		WFIFOL(fd,header+n*size) = htonl((subnet_char_ip) ? subnet_char_ip : ch_server[i].ip);
-		WFIFOW(fd,header+n*size+4) = ntows(htons(ch_server[i].port)); // [!] LE byte order here [!]
-		memcpy(WFIFOP(fd,header+n*size+6), ch_server[i].name, 20);
-		WFIFOW(fd,header+n*size+26) = login_get_usercount( ch_server[i].users );
-		WFIFOW(fd,header+n*size+28) = ch_server[i].type;
-		WFIFOW(fd,header+n*size+30) = ch_server[i].new_;
+
+		PACKET_AC_ACCEPT_LOGIN_sub& char_server = p->char_servers[n];
+
+		char_server.ip = htonl( ( subnet_char_ip ) ? subnet_char_ip : ch_server[i].ip );
+		char_server.port = ntows( htons( ch_server[i].port ) ); // [!] LE byte order here [!]
+		safestrncpy( char_server.name, ch_server[i].name, sizeof( char_server.name ) );
+		char_server.users = login_get_usercount( ch_server[i].users );
+		char_server.type = ch_server[i].type;
+		char_server.new_ = ch_server[i].new_;
 #if PACKETVER >= 20170315
-		memset(WFIFOP(fd, header+n*size+32), 0, 128); // Unknown
+		memset( &char_server.unknown, 0, sizeof( char_server.unknown ) );
 #endif
+
 #ifdef DEBUG
 		ShowDebug(
 			"Sending the client (%d %d.%d.%d.%d) to char-server %s with ip %d.%d.%d.%d and port "
@@ -152,9 +151,12 @@ static void logclif_auth_ok(struct login_session_data* sd) {
 			sd->account_id, CONVIP(ip), ch_server[i].name,
 			CONVIP((subnet_char_ip) ? subnet_char_ip : ch_server[i].ip), ch_server[i].port);
 #endif
+
 		n++;
+		p->packetLength += sizeof( char_server );
 	}
-	WFIFOSET(fd,header+size*server_num);
+
+	socket_send( fd, p );
 
 	// create temporary auth entry
 	login_add_auth_node( sd, ip );
@@ -165,6 +167,16 @@ static void logclif_auth_ok(struct login_session_data* sd) {
 	data->waiting_disconnect = add_timer(gettick()+AUTH_TIMEOUT, login_waiting_disconnect_timer, sd->account_id, 0);
 }
 
+static void logclif_auth_failed( int fd, int result, const char* unblock_time = "" ){
+	PACKET_AC_REFUSE_LOGIN p = {};
+
+	p.packetType = HEADER_AC_REFUSE_LOGIN;
+	p.error = result;
+	safestrncpy( p.unblock_time, "", sizeof( p.unblock_time ) );
+
+	socket_send( fd, p );
+}
+
 /**
  * Inform client that auth has failed.
  * @param sd: player session
@@ -210,33 +222,18 @@ static void logclif_auth_failed(struct login_session_data* sd, int result) {
 	if( (result == 0 || result == 1) && login_config.dynamic_pass_failure_ban )
 		ipban_log(ip); // log failed password attempt
 
-#if PACKETVER >= 20120000 /* not sure when this started */
-	WFIFOHEAD(fd,26);
-	WFIFOW(fd,0) = 0x83e;
-	WFIFOL(fd,2) = result;
-	if( result != 6 )
-		memset(WFIFOP(fd,6), '\0', 20);
-	else { // 6 = You are prohibited to log in until %s
-		struct mmo_account acc;
-		AccountDB* accounts = login_get_accounts_db();
-		time_t unban_time = ( accounts->load_str(accounts, &acc, sd->userid) ) ? acc.unban_time : 0;
-		timestamp2string(WFIFOCP(fd,6), 20, unban_time, login_config.date_format);
-	}
-	WFIFOSET(fd,26);
-#else
-	WFIFOHEAD(fd,23);
-	WFIFOW(fd,0) = 0x6a;
-	WFIFOB(fd,2) = (uint8)result;
-	if( result != 6 )
-		memset(WFIFOP(fd,3), '\0', 20);
-	else { // 6 = You are prohibited to log in until %s
+	// 6 = You are prohibited to log in until %s
+	if( result == 6 ){
+		char unblock_time[20];
 		struct mmo_account acc;
 		AccountDB* accounts = login_get_accounts_db();
-		time_t unban_time = ( accounts->load_str(accounts, &acc, sd->userid) ) ? acc.unban_time : 0;
-		timestamp2string(WFIFOCP(fd,3), 20, unban_time, login_config.date_format);
+		time_t unban_time = ( accounts->load_str( accounts, &acc, sd->userid ) ) ? acc.unban_time : 0;
+		timestamp2string( unblock_time, sizeof( unblock_time ), unban_time, login_config.date_format );
+
+		logclif_auth_failed( fd, result, unblock_time );
+	}else{
+		logclif_auth_failed( fd, result );
 	}
-	WFIFOSET(fd,23);
-#endif	
 }
 
 /**
@@ -246,9 +243,14 @@ static void logclif_auth_failed(struct login_session_data* sd, int result) {
  * @return 0 not enough info transmitted, 1 success
  */
 static int logclif_parse_keepalive(int fd){
-	if (RFIFOREST(fd) < 26)
+	PACKET_CA_CONNECT_INFO_CHANGED* p = (PACKET_CA_CONNECT_INFO_CHANGED*)RFIFOP( fd, 0 );
+
+	if( RFIFOREST( fd ) < sizeof( *p ) ){
 		return 0;
-	RFIFOSKIP(fd,26);
+	}
+
+	RFIFOSKIP( fd,  sizeof( *p ) );
+
 	return 1;
 }
 
@@ -259,112 +261,124 @@ static int logclif_parse_keepalive(int fd){
  * @return 0 not enough info transmitted, 1 success
  */
 static int logclif_parse_updclhash(int fd, struct login_session_data *sd){
-	if (RFIFOREST(fd) < 18)
+	PACKET_CA_EXE_HASHCHECK* p = (PACKET_CA_EXE_HASHCHECK*)RFIFOP( fd, 0 );
+
+	if( RFIFOREST( fd ) < sizeof( *p ) ){
 		return 0;
+	}
+
 	sd->has_client_hash = 1;
-	memcpy(sd->client_hash, RFIFOP(fd, 2), 16);
-	RFIFOSKIP(fd,18);
+	memcpy( sd->client_hash, p->hash, sizeof( sd->client_hash ) );
+
+	RFIFOSKIP( fd,  sizeof( *p ) );
+
 	return 1;
 }
 
-/**
- * Received a connection request.
- * @param fd: file descriptor to parse from (client)
- * @param sd: client session
- * @param command: packet type sent
- * @param ip: ipv4 address (client)
- *  S 0064 <version>.L <username>.24B <password>.24B <clienttype>.B
- *  S 0277 <version>.L <username>.24B <password>.24B <clienttype>.B <ip address>.16B <adapter address>.13B
- *  S 02b0 <version>.L <username>.24B <password>.24B <clienttype>.B <ip address>.16B <adapter address>.13B <g_isGravityID>.B
- *  S 01dd <version>.L <username>.24B <password hash>.16B <clienttype>.B
- *  S 01fa <version>.L <username>.24B <password hash>.16B <clienttype>.B <?>.B(index of the connection in the clientinfo file (+10 if the command-line contains "pc"))
- *  S 027c <version>.L <username>.24B <password hash>.16B <clienttype>.B <?>.13B(junk)
- *  S 0825 <packetsize>.W <version>.L <clienttype>.B <userid>.24B <password>.27B <mac>.17B <ip>.15B <token>.(packetsize - 0x5C)B
- * @param fd: fd to parse from (client fd)
- * @return 0 failure, 1 success
- */
-static int logclif_parse_reqauth(int fd, struct login_session_data *sd, int command, char* ip){
-	size_t packet_len = RFIFOREST(fd);
-
-	if( (command == 0x0064 && packet_len < 55)
-	||  (command == 0x0277 && packet_len < 84)
-	||  (command == 0x02b0 && packet_len < 85)
-	||  (command == 0x01dd && packet_len < 47)
-	||  (command == 0x01fa && packet_len < 48)
-	||  (command == 0x027c && packet_len < 60)
-	||  (command == 0x0825 && (packet_len < 4 || packet_len < RFIFOW(fd, 2))) )
+template <typename P>
+int logclif_parse_reqauth_raw( int fd, login_session_data& sd, char* ip ){
+	P* p = (P*)RFIFOP( fd, 0 );
+
+	if( RFIFOREST( fd ) < sizeof( *p ) ){
 		return 0;
-	else {
-		int result;
-		char username[NAME_LENGTH];
-		char password[PASSWD_LENGTH];
-		unsigned char passhash[16];
-		uint8 clienttype;
-		bool israwpass = (command==0x0064 || command==0x0277 || command==0x02b0 || command == 0x0825);
-
-		// Shinryo: For the time being, just use token as password.
-		if(command == 0x0825) {
-			char *accname = RFIFOCP(fd, 9);
-			char *token = RFIFOCP(fd, 0x5C);
-			size_t uAccLen = strlen(accname);
-			size_t uTokenLen = RFIFOREST(fd) - 0x5C;
-
-			if(uAccLen > NAME_LENGTH - 1 || uAccLen == 0 || uTokenLen > NAME_LENGTH - 1  || uTokenLen == 0)
-			{
-				logclif_auth_failed(sd, 3);
-				return 0;
-			}
+	}
 
-			safestrncpy(username, accname, uAccLen + 1);
-			safestrncpy(password, token, uTokenLen + 1);
-			clienttype = RFIFOB(fd, 8);
-		}
-		else
-		{
-			safestrncpy(username, RFIFOCP(fd,6), NAME_LENGTH);
-			if( israwpass )
-			{
-				safestrncpy(password, RFIFOCP(fd,30), PASSWD_LENGTH);
-				clienttype = RFIFOB(fd,54);
-			}
-			else
-			{
-				memcpy(passhash, RFIFOP(fd,30), 16);
-				clienttype = RFIFOB(fd,46);
-			}
-		}
-		RFIFOSKIP(fd,RFIFOREST(fd)); // assume no other packet was sent
+	safestrncpy( sd.userid, p->username, sizeof( sd.userid ) );
+	sd.clienttype = p->clienttype;
 
-		sd->clienttype = clienttype;
-		safestrncpy(sd->userid, username, NAME_LENGTH);
-		if( israwpass )
-		{
-			ShowStatus("Request for connection of %s (ip: %s)\n", sd->userid, ip);
-			safestrncpy(sd->passwd, password, PASSWD_LENGTH);
-			if( login_config.use_md5_passwds )
-				MD5_String(sd->passwd, sd->passwd);
-			sd->passwdenc = 0;
-		}
-		else
-		{
-			ShowStatus("Request for connection (passwdenc mode) of %s (ip: %s)\n", sd->userid, ip);
-			bin2hex(sd->passwd, passhash, 16); // raw binary data here!
-			sd->passwdenc = PASSWORDENC;
-		}
+	ShowStatus( "Request for connection of %s (ip: %s)\n", sd.userid, ip );
+	safestrncpy( sd.passwd, p->password, PASSWD_LENGTH );
 
-		if( sd->passwdenc != 0 && login_config.use_md5_passwds )
-		{
-			logclif_auth_failed(sd, 3); // send "rejected from server"
-			return 0;
-		}
+	if( login_config.use_md5_passwds ){
+		MD5_String( sd.passwd, sd.passwd );
+	}
 
-		result = login_mmo_auth(sd, false);
+	sd.passwdenc = 0;
 
-		if( result == -1 )
-			logclif_auth_ok(sd);
-		else
-			logclif_auth_failed(sd, result);
+	RFIFOSKIP( fd, sizeof( *p ) );
+
+	int result = login_mmo_auth( &sd, false );
+
+	if( result == -1 ){
+		logclif_auth_ok( &sd );
+	}else{
+		logclif_auth_failed( &sd, result );
+	}
+
+	return 1;
+}
+
+template <typename P>
+int logclif_parse_reqauth_md5( int fd, login_session_data& sd, char* ip ){
+	P* p = (P*)RFIFOP( fd, 0 );
+
+	if( RFIFOREST( fd ) < sizeof( *p ) ){
+		return 0;
+	}
+
+	safestrncpy( sd.userid, p->username, sizeof( sd.userid ) );
+	sd.clienttype = p->clienttype;
+
+	ShowStatus( "Request for connection (passwdenc mode) of %s (ip: %s)\n", sd.userid, ip );
+	bin2hex( sd.passwd, p->passwordMD5, sizeof( p->passwordMD5 ) ); // raw binary data here!
+
+	sd.passwdenc = PASSWORDENC;
+
+	RFIFOSKIP( fd, sizeof( *p ) );
+
+	if( login_config.use_md5_passwds ){
+		logclif_auth_failed( &sd, 3 ); // send "rejected from server"
+		return 0;
+	}
+
+	int result = login_mmo_auth( &sd, false );
+
+	if( result == -1 ){
+		logclif_auth_ok( &sd );
+	}else{
+		logclif_auth_failed( &sd, result );
 	}
+
+	return 1;
+}
+
+template <typename P>
+int logclif_parse_reqauth_sso( int fd, login_session_data& sd, char* ip ){
+	P* p = (P*)RFIFOP( fd, 0 );
+
+	if( RFIFOREST( fd ) < sizeof( *p ) ){
+		return 0;
+	}
+
+	if( RFIFOREST( fd ) < p->packetLength ){
+		return 0;
+	}
+
+	size_t token_length = p->packetLength - sizeof( *p );
+
+	safestrncpy( sd.userid, p->username, sizeof( sd.userid ) );
+	sd.clienttype = p->clienttype;
+
+	ShowStatus( "Request for connection (SSO mode) of %s (ip: %s)\n", sd.userid, ip );
+	// Shinryo: For the time being, just use token as password.
+	safestrncpy( sd.passwd, p->token, token_length + 1 );
+
+	if( login_config.use_md5_passwds ){
+		MD5_String( sd.passwd, sd.passwd );
+	}
+
+	sd.passwdenc = 0;
+
+	RFIFOSKIP( fd, p->packetLength );
+
+	int result = login_mmo_auth( &sd, false );
+
+	if( result == -1 ){
+		logclif_auth_ok( &sd );
+	}else{
+		logclif_auth_failed( &sd, result );
+	}
+
 	return 1;
 }
 
@@ -375,17 +389,25 @@ static int logclif_parse_reqauth(int fd, struct login_session_data *sd, int comm
  * @return 1 success
  */
 static int logclif_parse_reqkey(int fd, struct login_session_data *sd){
-	RFIFOSKIP(fd,2);
-	{
-		sd->md5keylen = sizeof( sd->md5key );
-		MD5_Salt(sd->md5keylen, sd->md5key);
-
-		WFIFOHEAD(fd,4 + sd->md5keylen);
-		WFIFOW(fd,0) = 0x01dc;
-		WFIFOW(fd,2) = 4 + sd->md5keylen;
-		memcpy(WFIFOP(fd,4), sd->md5key, sd->md5keylen);
-		WFIFOSET(fd,WFIFOW(fd,2));
+	PACKET_CA_REQ_HASH* p_in = (PACKET_CA_REQ_HASH*)RFIFOP( fd, 0 );
+
+	if( RFIFOREST( fd ) < sizeof( *p_in ) ){
+		return 0;
 	}
+
+	RFIFOSKIP( fd,  sizeof( *p_in ) );
+
+	sd->md5keylen = sizeof( sd->md5key );
+	MD5_Salt( sd->md5keylen, sd->md5key );
+
+	PACKET_AC_ACK_HASH* p_out = (PACKET_AC_ACK_HASH*)packet_buffer;
+
+	p_out->packetType = HEADER_AC_ACK_HASH;
+	p_out->packetLength = sizeof( *p_out ) + sd->md5keylen;
+	strncpy( p_out->salt, sd->md5key, sd->md5keylen );
+
+	socket_send( fd, p_out );
+
 	return 1;
 }
 
@@ -464,15 +486,23 @@ static int logclif_parse_reqcharconnec(int fd, struct login_session_data *sd, ch
 }
 
 int logclif_parse_otp_login( int fd, struct login_session_data* sd ){
-	RFIFOSKIP( fd, 68 );
+	PACKET_CT_AUTH* p_in = (PACKET_CT_AUTH*)RFIFOP( fd, 0 );
+
+	if( RFIFOREST( fd ) < sizeof( *p_in ) ){
+		return 0;
+	}
+
+	RFIFOSKIP( fd,  sizeof( *p_in ) );
+
+	PACKET_TC_RESULT p_out = {};
+
+	p_out.packetType = HEADER_TC_RESULT;
+	p_out.packetLength = sizeof( p_out );
+	p_out.type = 0; // normal login
+	safestrncpy( p_out.unknown1, "S1000", sizeof( p_out.unknown1 ) );
+	safestrncpy( p_out.unknown2, "token", sizeof( p_out.unknown2 ) );
 
-	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 );
+	socket_send( fd, p_out );
 
 	return 1;
 }
@@ -497,17 +527,15 @@ int logclif_parse(int fd) {
 		return 0;
 	}
 
-	if( sd == NULL )
-	{
+	if( sd == nullptr ){
 		// Perform ip-ban check
 		if( login_config.ipban && ipban_check(ipl) )
 		{
 			ShowStatus("Connection refused: IP isn't authorised (deny/allow, ip: %s).\n", ip);
 			login_log(ipl, "unknown", -3, "ip banned");
-			WFIFOHEAD(fd,23);
-			WFIFOW(fd,0) = 0x6a;
-			WFIFOB(fd,2) = 3; // 3 = Rejected from Server
-			WFIFOSET(fd,23);
+
+			logclif_auth_failed( fd, 3 ); // 3 = Rejected from Server
+
 			set_eof(fd);
 			return 0;
 		}
@@ -522,35 +550,59 @@ int logclif_parse(int fd) {
 		uint16 command = RFIFOW(fd,0);
 		int next=1;
 
-		switch( command )
-		{
-		// New alive packet: used to verify if client is always alive.
-		case 0x0200: next = logclif_parse_keepalive(fd); break;
-		// client md5 hash (binary)
-		case 0x0204: next = logclif_parse_updclhash(fd,sd); break;
-		// request client login (raw password)
-		case 0x0064: // S 0064 <version>.L <username>.24B <password>.24B <clienttype>.B
-		case 0x0277: // S 0277 <version>.L <username>.24B <password>.24B <clienttype>.B <ip address>.16B <adapter address>.13B
-		case 0x02b0: // S 02b0 <version>.L <username>.24B <password>.24B <clienttype>.B <ip address>.16B <adapter address>.13B <g_isGravityID>.B
-		// request client login (md5-hashed password)
-		case 0x01dd: // S 01dd <version>.L <username>.24B <password hash>.16B <clienttype>.B
-		case 0x01fa: // S 01fa <version>.L <username>.24B <password hash>.16B <clienttype>.B <?>.B(index of the connection in the clientinfo file (+10 if the command-line contains "pc"))
-		case 0x027c: // S 027c <version>.L <username>.24B <password hash>.16B <clienttype>.B <?>.13B(junk)
-		case 0x0825: // S 0825 <packetsize>.W <version>.L <clienttype>.B <userid>.24B <password>.27B <mac>.17B <ip>.15B <token>.(packetsize - 0x5C)B
-			next = logclif_parse_reqauth(fd,  sd, command, ip); 
-			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:
-			ShowNotice("Abnormal end of connection (ip: %s): Unknown packet 0x%x\n", ip, command);
-			set_eof(fd);
-			return 0;
+		switch( command ){
+			// New alive packet: used to verify if client is always alive.
+			case HEADER_CA_CONNECT_INFO_CHANGED:
+				next = logclif_parse_keepalive( fd );
+				break;
+			// client md5 hash (binary)
+			case HEADER_CA_EXE_HASHCHECK:
+				next = logclif_parse_updclhash( fd, sd );
+				break;
+			// request client login (raw password)
+			case HEADER_CA_LOGIN:
+				// S 0064 <version>.L <username>.24B <password>.24B <clienttype>.B
+				next = logclif_parse_reqauth_raw<PACKET_CA_LOGIN>( fd, *sd, ip );
+				break;
+			case HEADER_CA_LOGIN_PCBANG:
+				// S 0277 <version>.L <username>.24B <password>.24B <clienttype>.B <ip address>.16B <adapter address>.13B
+				next = logclif_parse_reqauth_raw<PACKET_CA_LOGIN_PCBANG>( fd, *sd, ip );
+				break;
+			case HEADER_CA_LOGIN_CHANNEL:
+				// S 02b0 <version>.L <username>.24B <password>.24B <clienttype>.B <ip address>.16B <adapter address>.13B <g_isGravityID>.B
+				next = logclif_parse_reqauth_raw<PACKET_CA_LOGIN_CHANNEL>( fd, *sd, ip );
+				break;
+			// request client login (md5-hashed password)
+			case HEADER_CA_LOGIN2:
+				// S 01dd <version>.L <username>.24B <password hash>.16B <clienttype>.B
+				next = logclif_parse_reqauth_md5<PACKET_CA_LOGIN2>( fd, *sd, ip );
+				break;
+			case HEADER_CA_LOGIN3:
+				// S 01fa <version>.L <username>.24B <password hash>.16B <clienttype>.B <?>.B(index of the connection in the clientinfo file (+10 if the command-line contains "pc"))
+				next = logclif_parse_reqauth_md5<PACKET_CA_LOGIN3>( fd, *sd, ip );
+				break;
+			case HEADER_CA_LOGIN4:
+				// S 027c <version>.L <username>.24B <password hash>.16B <clienttype>.B <adapter address>.13B
+				next = logclif_parse_reqauth_md5<PACKET_CA_LOGIN4>( fd, *sd, ip );
+				break;
+			case HEADER_CA_SSO_LOGIN_REQ:
+				// S 0825 <packetsize>.W <version>.L <clienttype>.B <userid>.24B <password>.27B <mac>.17B <ip>.15B <token>.?B
+				next = logclif_parse_reqauth_sso<PACKET_CA_SSO_LOGIN_REQ>( fd, *sd, ip );
+				break;
+			// Sending request of the coding key
+			case HEADER_CA_REQ_HASH:
+				next = logclif_parse_reqkey( fd, sd );
+				break;
+			// OTP token login
+			case HEADER_CT_AUTH:
+				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:
+				ShowNotice("Abnormal end of connection (ip: %s): Unknown packet 0x%x\n", ip, command);
+				set_eof(fd);
+				return 0;
 		}
 		if(next==0) return 0; // avoid processing of followup packets (prev was probably incomplete)
 	}

+ 22 - 82
src/login/loginlog.cpp

@@ -3,8 +3,9 @@
 
 #include "loginlog.hpp"
 
+#include <string>
+
 #include <stdlib.h> // exit
-#include <string.h>
 
 #include <common/cbasetypes.hpp>
 #include <common/mmo.hpp>
@@ -13,21 +14,14 @@
 #include <common/sql.hpp>
 #include <common/strlib.hpp>
 
-// global sql settings (in ipban_sql.cpp)
-static char   global_db_hostname[64] = "127.0.0.1"; // Doubled to reflect the change on commit #0f2dd7f
-static uint16 global_db_port = 3306;
-static char   global_db_username[32] = "ragnarok";
-static char   global_db_password[32] = ""; //empty by default since mysql is empty by default as well
-static char   global_db_database[32] = "ragnarok";
-static char   global_codepage[32] = "";
-// local sql settings
-static char   log_db_hostname[64] = ""; // Doubled to reflect the change on commit #0f2dd7f
-static uint16 log_db_port = 0;
-static char   log_db_username[32] = "";
-static char   log_db_password[32] = "";
-static char   log_db_database[32] = "";
-static char   log_codepage[32] = "";
-static char   log_login_db[256] = "loginlog";
+
+std::string log_db_hostname = "127.0.0.1";
+uint16 log_db_port = 3306;
+std::string log_db_username = "ragnarok";
+std::string log_db_password = "";
+std::string log_db_database = "ragnarok";
+std::string log_login_db = "loginlog";
+std::string log_codepage = "";
 
 static Sql* sql_handle = NULL;
 static bool enabled = false;
@@ -46,7 +40,7 @@ unsigned long loginlog_failedattempts(uint32 ip, unsigned int minutes) {
 		return 0;
 
 	if( SQL_ERROR == Sql_Query(sql_handle, "SELECT count(*) FROM `%s` WHERE `ip` = '%s' AND (`rcode` = '0' OR `rcode` = '1') AND `time` > NOW() - INTERVAL %d MINUTE",
-		log_login_db, ip2str(ip,NULL), minutes) )// how many times failed account? in one ip.
+		log_login_db.c_str(), ip2str(ip,NULL), minutes) )// how many times failed account? in one ip.
 		Sql_ShowDebug(sql_handle);
 
 	if( SQL_SUCCESS == Sql_NextRow(sql_handle) )
@@ -80,7 +74,7 @@ void login_log(uint32 ip, const char* username, int rcode, const char* message)
 
 	retcode = Sql_Query(sql_handle,
 		"INSERT INTO `%s`(`time`,`ip`,`user`,`rcode`,`log`) VALUES (NOW(), '%s', '%s', '%d', '%s')",
-		log_login_db, ip2str(ip,NULL), esc_username, rcode, esc_message);
+		log_login_db.c_str(), ip2str(ip,NULL), esc_username, rcode, esc_message);
 
 	if( retcode != SQL_SUCCESS )
 		Sql_ShowDebug(sql_handle);
@@ -93,54 +87,26 @@ void login_log(uint32 ip, const char* username, int rcode, const char* message)
  * @return true if successful, false if config not complete or server already running
  */
 bool loginlog_config_read(const char* key, const char* value) {
-	const char* signature;
-
-	signature = "sql.";
-	if( strncmpi(key, signature, strlen(signature)) == 0 )
-	{
-		key += strlen(signature);
-		if( strcmpi(key, "db_hostname") == 0 )
-			safestrncpy(global_db_hostname, value, sizeof(global_db_hostname));
-		else
-		if( strcmpi(key, "db_port") == 0 )
-			global_db_port = (uint16)strtoul(value, NULL, 10);
-		else
-		if( strcmpi(key, "db_username") == 0 )
-			safestrncpy(global_db_username, value, sizeof(global_db_username));
-		else
-		if( strcmpi(key, "db_password") == 0 )
-			safestrncpy(global_db_password, value, sizeof(global_db_password));
-		else
-		if( strcmpi(key, "db_database") == 0 )
-			safestrncpy(global_db_database, value, sizeof(global_db_database));
-		else
-		if( strcmpi(key, "codepage") == 0 )
-			safestrncpy(global_codepage, value, sizeof(global_codepage));
-		else
-			return false;// not found
-		return true;
-	}
-
 	if( strcmpi(key, "log_db_ip") == 0 )
-		safestrncpy(log_db_hostname, value, sizeof(log_db_hostname));
+		log_db_hostname = value;
 	else
 	if( strcmpi(key, "log_db_port") == 0 )
 		log_db_port = (uint16)strtoul(value, NULL, 10);
 	else
 	if( strcmpi(key, "log_db_id") == 0 )
-		safestrncpy(log_db_username, value, sizeof(log_db_username));
+		log_db_username = value;
 	else
 	if( strcmpi(key, "log_db_pw") == 0 )
-		safestrncpy(log_db_password, value, sizeof(log_db_password));
+		log_db_password = value;
 	else
 	if( strcmpi(key, "log_db_db") == 0 )
-		safestrncpy(log_db_database, value, sizeof(log_db_database));
+		log_db_database = value;
 	else
 	if( strcmpi(key, "log_codepage") == 0 )
-		safestrncpy(log_codepage, value, sizeof(log_codepage));
+		log_codepage = value;
 	else
 	if( strcmpi(key, "log_login_db") == 0 )
-		safestrncpy(log_login_db, value, sizeof(log_login_db));
+		log_login_db = value;
 	else
 		return false;
 
@@ -156,44 +122,18 @@ bool loginlog_config_read(const char* key, const char* value) {
  * @return true if success else exit execution
  */
 bool loginlog_init(void) {
-	const char* username;
-	const char* password;
-	const char* hostname;
-	uint16      port;
-	const char* database;
-	const char* codepage;
-
-	if( log_db_hostname[0] != '\0' )
-	{// local settings
-		username = log_db_username;
-		password = log_db_password;
-		hostname = log_db_hostname;
-		port     = log_db_port;
-		database = log_db_database;
-		codepage = log_codepage;
-	}
-	else
-	{// global settings
-		username = global_db_username;
-		password = global_db_password;
-		hostname = global_db_hostname;
-		port     = global_db_port;
-		database = global_db_database;
-		codepage = global_codepage;
-	}
-
 	sql_handle = Sql_Malloc();
 
-	if( SQL_ERROR == Sql_Connect(sql_handle, username, password, hostname, port, database) )
+	if( SQL_ERROR == Sql_Connect(sql_handle, log_db_username.c_str(), log_db_password.c_str(), log_db_hostname.c_str(), log_db_port, log_db_database.c_str()) )
 	{
-        ShowError("Couldn't connect with uname='%s',passwd='%s',host='%s',port='%d',database='%s'\n",
-                        username, password, hostname, port, database);
+		ShowError("Couldn't connect with uname='%s',host='%s',port='%hu',database='%s'\n",
+			log_db_username.c_str(), log_db_hostname.c_str(), log_db_port, log_db_database.c_str());
 		Sql_ShowDebug(sql_handle);
 		Sql_Free(sql_handle);
 		exit(EXIT_FAILURE);
 	}
 
-	if( codepage[0] != '\0' && SQL_ERROR == Sql_SetEncoding(sql_handle, codepage) )
+	if( !log_codepage.empty() && SQL_ERROR == Sql_SetEncoding(sql_handle, log_codepage.c_str()) )
 		Sql_ShowDebug(sql_handle);
 
 	enabled = true;

+ 259 - 63
src/map/battle.cpp

@@ -580,6 +580,12 @@ int64 battle_attr_fix(struct block_list *src, struct block_list *target, int64 d
 					ratio += 50;
 #else
 					damage += (int64)(damage * 50 / 100);
+#endif
+				if (tsc->getSCE(SC_MISTYFROST))
+#ifdef RENEWAL
+					ratio += 15;
+#else
+					damage += (int64)(damage * 15 / 100);
 #endif
 				break;
 			case ELE_EARTH:
@@ -1377,7 +1383,7 @@ bool battle_status_block_damage(struct block_list *src, struct block_list *targe
 			unit_set_walkdelay(target, gettick(), delay, 1);
 #ifdef RENEWAL
 			if (sc->getSCE(SC_SHRINK))
-				sc_start(src, target, SC_STUN, 50, skill_lv, skill_get_time2(skill_id, skill_lv));
+				sc_start(target, src, SC_STUN, 50, skill_lv, skill_get_time2(skill_id, skill_lv));
 #else
 			if (sc->getSCE(SC_SHRINK) && rnd() % 100 < 5 * sce->val1)
 				skill_blown(target, src, skill_get_blewcount(CR_SHRINK, 1), -1, BLOWN_NONE);
@@ -1569,6 +1575,11 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam
 			damage *= 4;
 #endif
 
+		if (tsc->getSCE(SC_GROUNDGRAVITY) && flag&(BF_MAGIC|BF_WEAPON))
+			damage += damage * 15 / 100;
+		if (tsc->getSCE(SC_SHIELDCHAINRUSH))
+			damage += damage / 10;
+
 		if (tsc->getSCE(SC_AETERNA) && skill_id != PF_SOULBURN) {
 			if (src->type != BL_MER || !skill_id)
 				damage *= 2; // Lex Aeterna only doubles damage of regular attacks from mercenaries
@@ -1605,6 +1616,7 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam
 					case W_WHIP:
 						if(!tsd->state.arrow_atk)
 							break;
+						[[fallthrough]];
 					case W_BOW:
 					case W_REVOLVER:
 					case W_RIFLE:
@@ -1830,6 +1842,36 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam
 	status_change* sc = status_get_sc(src);
 
 	if (sc && sc->count) {
+		if (sc->getSCE(SC_BREAKINGLIMIT)) {
+			switch (skill_id) {
+				case HN_SHIELD_CHAIN_RUSH:
+				case HN_DOUBLEBOWLINGBASH:
+					damage += damage * 70 / 100; 
+					break;
+				case HN_MEGA_SONIC_BLOW:
+				case HN_SPIRAL_PIERCE_MAX:
+					damage *= 2;
+					break;
+			}
+		}
+
+		if (sc->getSCE(SC_RULEBREAK)) {
+			switch (skill_id) {
+				case HN_METEOR_STORM_BUSTER:
+				case HN_GROUND_GRAVITATION:
+					damage += damage / 2;
+					break;
+				case HN_JUPITEL_THUNDER_STORM:
+				case HN_JACK_FROST_NOVA:
+				case HN_HELLS_DRIVE:
+					damage += damage * 70 / 100;
+					break;
+				case HN_NAPALM_VULCAN_STRIKE:
+					damage += damage * 40 / 100;
+					break;
+			}
+		}
+
 		if( sc->getSCE(SC_INVINCIBLE) && !sc->getSCE(SC_INVINCIBLEOFF) )
 			damage += damage * 75 / 100;
 
@@ -2263,7 +2305,7 @@ int64 battle_addmastery(map_session_data *sd,struct block_list *target,int64 dmg
 		case W_FIST:
 			if((skill = pc_checkskill(sd,TK_RUN)) > 0)
 				damage += (skill * 10);
-			// No break, fallthrough to Knuckles
+			[[fallthrough]];
 		case W_KNUCKLE:
 			if((skill = pc_checkskill(sd,MO_IRONHAND)) > 0)
 				damage += (skill * 3);
@@ -2924,6 +2966,7 @@ static bool is_attack_critical(struct Damage* wd, struct block_list *src, struct
 					break;
 				clif_specialeffect(src, EF_AUTOCOUNTER, AREA);
 				status_change_end(src, SC_AUTOCOUNTER);
+				[[fallthrough]];
 			case KN_AUTOCOUNTER:
 				if(battle_config.auto_counter_type &&
 					(battle_config.auto_counter_type&src->type))
@@ -3238,7 +3281,11 @@ static bool attack_ignores_def(struct Damage* wd, struct block_list *src, struct
 #endif
 	if (sc && sc->getSCE(SC_FUSION))
 		return true;
-	else if (skill_id != CR_GRANDCROSS && skill_id != NPC_GRANDDARKNESS)
+
+	if (skill_id == RK_WINDCUTTER && sd && sd->status.weapon == W_2HSWORD)
+		return true;
+
+	if (skill_id != CR_GRANDCROSS && skill_id != NPC_GRANDDARKNESS)
 	{	//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) ||
@@ -3256,8 +3303,7 @@ 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;
 }
@@ -4036,11 +4082,30 @@ static void battle_calc_multi_attack(struct Damage* wd, struct block_list *src,s
 		{
 			int chance = rnd()%100;
 			switch(sc->getSCE(SC_FEARBREEZE)->val1) {
-				case 5: if( chance < 4) { wd->div_ = 5; break; } // 3 % chance to attack 5 times.
-				case 4: if( chance < 7) { wd->div_ = 4; break; } // 6 % chance to attack 4 times.
-				case 3: if( chance < 10) { wd->div_ = 3; break; } // 9 % chance to attack 3 times.
+				case 5:
+					if (chance < 4) {
+						wd->div_ = 5;
+						break;
+					} // 3 % chance to attack 5 times.
+					[[fallthrough]];
+				case 4:
+					if (chance < 7) {
+						wd->div_ = 4;
+						break;
+					} // 6 % chance to attack 4 times.
+					[[fallthrough]];
+				case 3:
+					if (chance < 10) {
+						wd->div_ = 3;
+						break;
+					} // 9 % chance to attack 3 times.
+					[[fallthrough]];
 				case 2:
-				case 1: if( chance < 13) { wd->div_ = 2; break; } // 12 % chance to attack 2 times.
+				case 1:
+					if (chance < 13) {
+						wd->div_ = 2;
+						break;
+					} // 12 % chance to attack 2 times.
 			}
 			wd->div_ = min(wd->div_,sd->inventory.u.items_inventory[i].amount);
 			sc->getSCE(SC_FEARBREEZE)->val4 = wd->div_-1;
@@ -4491,7 +4556,7 @@ static int battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list *
 					skillratio += 100 + 50 * skill_lv;
 				break;
 			}
-			// Fall through
+			[[fallthrough]];
 		case MA_SHARPSHOOTING:
 #ifdef RENEWAL
 			skillratio += -100 + 300 + 300 * skill_lv;
@@ -5380,7 +5445,7 @@ static int battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list *
 			break;
 		case DK_HACKANDSLASHER:
 		case DK_HACKANDSLASHER_ATK:
-			skillratio += -100 + 300 + 700 * skill_lv;
+			skillratio += -100 + 200 + 750 * skill_lv;
 			skillratio += 7 * sstatus->pow;
 			RE_LVL_DMOD(100);
 			break;
@@ -5391,7 +5456,7 @@ static int battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list *
 			RE_LVL_DMOD(100);
 			break;
 		case DK_MADNESS_CRUSHER:
-			skillratio += -100 + 400 + 800 * skill_lv + 7 * sstatus->pow;
+			skillratio += -100 + 350 + 1600 * skill_lv + 10 * sstatus->pow;
 			if( sd != nullptr ){
 				int16 index = sd->equip_index[EQI_HAND_R];
 
@@ -5404,9 +5469,9 @@ static int battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list *
 				skillratio *= 2;
 			break;
 		case DK_STORMSLASH:
-			skillratio += -100 + 100 + 170 * skill_lv + 5 * sstatus->pow;
+			skillratio += -100 + 200 + 400 * skill_lv + 5 * sstatus->pow;
 			RE_LVL_DMOD(100);
-			if (sc && sc->getSCE(SC_GIANTGROWTH) && rnd()%100 < 30)
+			if (sc && sc->getSCE(SC_GIANTGROWTH) && rnd_chance(60, 100))
 				skillratio *= 2;
 			break;
 		case DK_DRAGONIC_BREATH:
@@ -5423,16 +5488,16 @@ static int battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list *
 			RE_LVL_DMOD(100);
 			break;
 		case IQ_MASSIVE_F_BLASTER:
-			skillratio += -100 + 2150 * skill_lv + 15 * sstatus->pow;
+			skillratio += -100 + 2300 * skill_lv + 15 * sstatus->pow;
 			if (tstatus->race == RC_BRUTE || tstatus->race == RC_DEMON)
 				skillratio += 150 * skill_lv;
 			RE_LVL_DMOD(100);
 			break;
 		case IQ_EXPOSION_BLASTER:
-			skillratio += -100 + 2800 * skill_lv + 15 * sstatus->pow;
+			skillratio += -100 + 2400 * skill_lv + 10 * sstatus->pow;
 
 			if( tsc != nullptr && tsc->getSCE( SC_HOLY_OIL ) ){
-				skillratio += 400 * skill_lv;
+				skillratio += 350 + 1050 * skill_lv;
 			}
 
 			RE_LVL_DMOD(100);
@@ -5475,20 +5540,23 @@ static int battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list *
 				skillratio += skillratio * i / 100;
 			break;
 		case IG_SHIELD_SHOOTING:
-			skillratio += -100 + 1400 + 2100 * skill_lv + 5 * sstatus->pow;
-			skillratio += skill_lv * 15 * pc_checkskill( sd, IG_SHIELD_MASTERY );
+			skillratio += -100 + 650 + 2850 * skill_lv;
+			skillratio += 7 * sstatus->pow;
+			skillratio += skill_lv * 50 * pc_checkskill( sd, IG_SHIELD_MASTERY );
 			if (sd) { // Damage affected by the shield's weight and refine. Need official formula. [Rytech]
 				short index = sd->equip_index[EQI_HAND_L];
 
 				if (index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == IT_ARMOR) {
 					skillratio += (sd->inventory_data[index]->weight * 7 / 6) / 10;
-					skillratio += sd->inventory.u.items_inventory[index].refine * 4;
+					skillratio += sd->inventory.u.items_inventory[index].refine * 25;
 				}
 			}
 			RE_LVL_DMOD(100);
 			break;
 		case IG_OVERSLASH:
-			skillratio += -100 + (120 + pc_checkskill(sd, IG_SPEAR_SWORD_M) * 10) * skill_lv + 5 * sstatus->pow;
+			skillratio += -100 + 160 * skill_lv;
+			skillratio += pc_checkskill(sd, IG_SPEAR_SWORD_M) * 25 * skill_lv;
+			skillratio += 7 * sstatus->pow;
 			RE_LVL_DMOD(100);
 			if ((i = pc_checkskill_imperial_guard(sd, 3)) > 0)
 				skillratio += skillratio * i / 100;
@@ -5503,7 +5571,7 @@ static int battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list *
 			RE_LVL_DMOD(100);
 			break;
 		case CD_PETITIO:
-			skillratio += -100 + (1050 + pc_checkskill(sd,CD_MACE_BOOK_M) * 10) * skill_lv + 5 * sstatus->pow;
+			skillratio += -100 + (1050 + pc_checkskill(sd,CD_MACE_BOOK_M) * 50) * skill_lv + 5 * sstatus->pow;
 			RE_LVL_DMOD(100);
 			break;
 		case SHC_DANCING_KNIFE:
@@ -5529,7 +5597,12 @@ static int battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list *
 			RE_LVL_DMOD(100);
 			break;
 		case SHC_SHADOW_STAB:
-			skillratio += -100 + 300 * skill_lv + 5 * sstatus->pow;
+			skillratio += -100 + 350 * skill_lv + 5 * sstatus->pow;
+
+			if( sc && sc->getSCE( SC_CLOAKINGEXCEED ) ){
+				skillratio += 50 * skill_lv + 2 * sstatus->pow;
+			}
+
 			RE_LVL_DMOD(100);
 			break;
 		case SHC_IMPACT_CRATER:
@@ -5543,7 +5616,7 @@ static int battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list *
 			RE_LVL_DMOD(100);
 			break;
 		case MT_AXE_STOMP:
-			skillratio += -100 + 350 + 850 * skill_lv + 5 * sstatus->pow;
+			skillratio += -100 + 400 + 950 * skill_lv + 5 * sstatus->pow;
 			RE_LVL_DMOD(100);
 			break;
 		case MT_MIGHTY_SMASH:
@@ -5576,7 +5649,8 @@ static int battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list *
 			RE_LVL_DMOD(100);
 			break;
 		case ABC_ABYSS_DAGGER:
-			skillratio += -100 + 100 + 500 * skill_lv + 5 * sstatus->pow;
+			skillratio += -100 + 100 + 900 * skill_lv;
+			skillratio += 5 * sstatus->pow;
 			RE_LVL_DMOD(100);
 			break;
 		case ABC_UNLUCKY_RUSH:
@@ -5592,31 +5666,37 @@ static int battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list *
 			RE_LVL_DMOD(100);
 			break;
 		case ABC_DEFT_STAB:
-			skillratio += -100 + 350 + 550 * skill_lv + 5 * sstatus->pow;
+			skillratio += -100 + 250 + 350 * skill_lv;
+			skillratio += 5 * sstatus->pow;
 			RE_LVL_DMOD(100);
 			break;
 		case ABC_FRENZY_SHOT:
-			skillratio += -100 + 400 * skill_lv + 5 * sstatus->con;
+			skillratio += -100 + 150 + 600 * skill_lv;
+			skillratio += 15 * sstatus->con;
 			RE_LVL_DMOD(100);
 			break;
 		case WH_HAWKRUSH:
 			skillratio += -100 + 500 * skill_lv + 5 * sstatus->con;
+			if (sd)
+				skillratio += skillratio * pc_checkskill(sd, WH_NATUREFRIENDLY) / 10;
 			RE_LVL_DMOD(100);
 			break;
-		case WH_HAWKBOOMERANG:// Affected by trait stats??? CON for sure but the other one unknown. Likely POW. [Rytech]
-			skillratio += -100 + 600 * skill_lv + 10 * sstatus->pow + 10 * sstatus->con;
+		case WH_HAWKBOOMERANG:
+			skillratio += -100 + 600 * skill_lv + 10 * sstatus->con;
+			if (sd)
+				skillratio += skillratio * pc_checkskill(sd, WH_NATUREFRIENDLY) / 10;
 			if (tstatus->race == RC_BRUTE || tstatus->race == RC_FISH)
 				skillratio += skillratio * 50 / 100;
 			RE_LVL_DMOD(100);
 			break;
 		case WH_GALESTORM:
-			skillratio += -100 + 950 * skill_lv + 10 * sstatus->con;
+			skillratio += -100 + 1000 * skill_lv + 10 * sstatus->con;
 			RE_LVL_DMOD(100);
 			if (sc && sc->getSCE(SC_CALAMITYGALE) && (tstatus->race == RC_BRUTE || tstatus->race == RC_FISH))
 				skillratio += skillratio * 50 / 100;
 			break;
 		case WH_CRESCIVE_BOLT:
-			skillratio += -100 + 340 * skill_lv + 5 * sstatus->con;
+			skillratio += -100 + 400 + 900 * skill_lv + 5 * sstatus->con;
 			RE_LVL_DMOD(100);
 			if (sc) {
 				if (sc->getSCE(SC_CRESCIVEBOLT))
@@ -5708,13 +5788,18 @@ static int battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list *
 			}
 			break;
 		case TR_RHYTHMSHOOTING:
-			skillratio += -100 + 200 + 120 * skill_lv;
+			skillratio += -100 + 450 + 650 * skill_lv;
 
 			if (sd && pc_checkskill(sd, TR_STAGE_MANNER) > 0)
-				skillratio += 3 * sstatus->con;
+				skillratio += 5 * sstatus->con;
 
-			if (tsc && tsc->getSCE(SC_SOUNDBLEND))
-				skillratio += 100 + 100 * skill_lv;
+			if (tsc && tsc->getSCE(SC_SOUNDBLEND)) {
+				if (skill_lv == 4)
+					skillratio += 830;	// Typo in skill description ?
+				else
+					skillratio += 350 + 100 * skill_lv;
+				skillratio += 2 * sstatus->con;
+			}
 
 			RE_LVL_DMOD(100);
 			if (sc && sc->getSCE(SC_MYSTIC_SYMPHONY)) {
@@ -5731,6 +5816,43 @@ static int battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list *
 		case ABR_INFINITY_BUSTER:// Need official formula.
 			skillratio += -100 + 50000;
 			break;
+		case HN_SPIRAL_PIERCE_MAX:
+			skillratio += -100 + 700 + 800 * skill_lv;
+			skillratio += pc_checkskill(sd, HN_SELFSTUDY_TATICS) * 3 * skill_lv;
+			skillratio += 5 * sstatus->pow;
+			switch (status_get_size(target)){
+				case SZ_SMALL:
+					skillratio = skillratio * 150 / 100;
+					break;
+				case SZ_MEDIUM:
+					skillratio = skillratio * 130 / 100;
+					break;
+				case SZ_BIG:
+					skillratio = skillratio * 120 / 100;
+					break;
+			}
+			RE_LVL_DMOD(100);
+			break;
+		case HN_SHIELD_CHAIN_RUSH:
+			skillratio += -100 + 700 + 500 * skill_lv;
+			skillratio += pc_checkskill(sd, HN_SELFSTUDY_TATICS) * 3 * skill_lv;
+			skillratio += 5 * sstatus->pow;
+			RE_LVL_DMOD(100);
+			break;
+		case HN_MEGA_SONIC_BLOW:
+			skillratio += -100 + 900 + 750 * skill_lv;
+			skillratio += pc_checkskill(sd, HN_SELFSTUDY_TATICS) * 5 * skill_lv;
+			skillratio += 5 * sstatus->pow;
+			if (status_get_hp(target) < status_get_max_hp(target) / 2)
+				skillratio *= 2;
+			RE_LVL_DMOD(100);
+			break;
+		case HN_DOUBLEBOWLINGBASH:
+			skillratio += -100 + 200 + 300 * skill_lv;
+			skillratio += pc_checkskill(sd, HN_SELFSTUDY_TATICS) * 3 * skill_lv;
+			skillratio += 5 * sstatus->pow;
+			RE_LVL_DMOD(100);
+			break;
 	}
 	return skillratio;
 }
@@ -6608,7 +6730,7 @@ static struct Damage initialize_weapon_data(struct block_list *src, struct block
 
 			case GS_GROUNDDRIFT:
 				wd.amotion = sstatus->amotion;
-				//Fall through
+				[[fallthrough]];
 			case KN_SPEARSTAB:
 #ifndef RENEWAL
 			case KN_BOWLINGBASH:
@@ -6673,7 +6795,7 @@ static struct Damage initialize_weapon_data(struct block_list *src, struct block
 				break;
 			case SHC_SHADOW_STAB:
 				if (wd.miscflag == 2)
-					wd.div_ = 2;
+					wd.div_ = 3;
 				break;
 			case SHC_IMPACT_CRATER:
 				if (sc && sc->getSCE(SC_ROLLINGCUTTER))
@@ -6698,6 +6820,10 @@ static struct Damage initialize_weapon_data(struct block_list *src, struct block
 				if (sc && sc->getSCE(SC_RESEARCHREPORT))
 					wd.div_ = 4;
 				break;
+			case HN_DOUBLEBOWLINGBASH:
+				if (wd.miscflag > 1)
+					wd.div_ += min(4, wd.miscflag);
+				break;
 		}
 	} else {
 		bool is_long = false;
@@ -6903,11 +7029,27 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src, struct bl
 		battle_attack_sc_bonus(&wd, src, target, skill_id, skill_lv);
 
 		if (sd) { //monsters, homuns and pets have their damage computed directly
-			//PATK mod applies to Dragonbreaths if Dragonic Aura is skilled only - [munkrej]
-			if (!((skill_id == RK_DRAGONBREATH || skill_id == RK_DRAGONBREATH_WATER) && pc_checkskill( sd, DK_DRAGONIC_AURA ) == 0)) {
-				wd.damage = (int64)floor((float)((wd.statusAtk + wd.weaponAtk + wd.equipAtk + wd.percentAtk) * (100 + sstatus->patk) / 100 + wd.masteryAtk + bonus_damage));
-				if (is_attack_left_handed(src, skill_id))
-					wd.damage2 = (int64)floor((float)((wd.statusAtk2 + wd.weaponAtk2 + wd.equipAtk2 + wd.percentAtk2) * (100 + sstatus->patk) / 100 + wd.masteryAtk2 + bonus_damage));
+			wd.damage = wd.statusAtk + wd.weaponAtk + wd.equipAtk + wd.percentAtk;
+			if( is_attack_left_handed( src, skill_id ) ){
+				wd.damage2 = wd.statusAtk2 + wd.weaponAtk2 + wd.equipAtk2 + wd.percentAtk2;
+			}
+			// Apply PATK mod
+			// But for Dragonbreaths it only applies if Dragonic Aura is skilled
+			if( ( skill_id != RK_DRAGONBREATH && skill_id != RK_DRAGONBREATH_WATER ) || pc_checkskill( sd, DK_DRAGONIC_AURA ) > 0 ){
+				wd.damage = (int64)floor( (float)( wd.damage * ( 100 + sstatus->patk ) / 100 ) );
+				if( is_attack_left_handed( src, skill_id ) ){
+					wd.damage2 = (int64)floor( (float)( wd.damage2 * ( 100 + sstatus->patk ) / 100 ) );
+				}
+			}
+			// Apply MasteryATK
+			wd.damage += wd.masteryAtk;
+			if( is_attack_left_handed( src, skill_id ) ){
+				wd.damage2 += wd.masteryAtk2;
+			}
+			// Apply bonus damage
+			wd.damage += bonus_damage;
+			if( is_attack_left_handed( src, skill_id ) ){
+				wd.damage2 += bonus_damage;
 			}
 
 			// CritAtkRate modifier
@@ -7267,7 +7409,7 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list
 		case MG_FIREWALL:
 			if ( tstatus->def_ele == ELE_FIRE || battle_check_undead(tstatus->race, tstatus->def_ele) )
 				ad.blewcount = 0; //No knockback
-			//Fall through
+			[[fallthrough]];
 		case NJ_KAENSIN:
 		case PR_SANCTUARY:
 			ad.dmotion = 1; //No flinch animation.
@@ -7833,14 +7975,14 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list
 						RE_LVL_DMOD(100);
 						break;
 					case AG_DESTRUCTIVE_HURRICANE:
-						skillratio += -100 + 250 + 2800 * skill_lv + 5 * sstatus->spl;
+						skillratio += -100 + 600 + 2850 * skill_lv + 5 * sstatus->spl;
 						RE_LVL_DMOD(100);
 						if (sc && sc->getSCE(SC_CLIMAX))
 						{
 							if (sc->getSCE(SC_CLIMAX)->val1 == 3)
-								skillratio *= 3;
+								skillratio += skillratio * 150 / 100;
 							else if (sc->getSCE(SC_CLIMAX)->val1 == 5)
-								skillratio += skillratio * 50 / 100;
+								skillratio -= skillratio * 20 / 100;
 						}
 						break;
 					case AG_RAIN_OF_CRYSTAL:
@@ -7921,7 +8063,7 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list
 						RE_LVL_DMOD(100);
 						break;
 					case AG_ROCK_DOWN:
-						skillratio += -100 + 950 * skill_lv + 5 * sstatus->spl;
+						skillratio += -100 + 1200 * skill_lv + 5 * sstatus->spl;
 
 						if( sc != nullptr && sc->getSCE( SC_CLIMAX ) ){
 							skillratio += 300 * skill_lv;
@@ -7930,7 +8072,7 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list
 						RE_LVL_DMOD(100);
 						break;
 					case AG_STORM_CANNON:
-						skillratio += -100 + 950 * skill_lv + 5 * sstatus->spl;
+						skillratio += -100 + 1200 * skill_lv + 5 * sstatus->spl;
 
 						if( sc != nullptr && sc->getSCE( SC_CLIMAX ) ){
 							skillratio += 300 * skill_lv;
@@ -7939,15 +8081,15 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list
 						RE_LVL_DMOD(100);
 						break;
 					case AG_CRIMSON_ARROW:
-						skillratio += -100 + 300 * skill_lv + 5 * sstatus->spl;
+						skillratio += -100 + 350 * skill_lv + 5 * sstatus->spl;
 						RE_LVL_DMOD(100);
 						break;
 					case AG_CRIMSON_ARROW_ATK:
-						skillratio += -100 + 600 * skill_lv + 5 * sstatus->spl;
+						skillratio += -100 + 700 * skill_lv + 5 * sstatus->spl;
 						RE_LVL_DMOD(100);
 						break;
 					case AG_FROZEN_SLASH:
-						skillratio += -100 + 250 + 900 * skill_lv + 5 * sstatus->spl;
+						skillratio += -100 + 400 + 900 * skill_lv + 5 * sstatus->spl;
 
 						if( sc != nullptr && sc->getSCE( SC_CLIMAX ) ){
 							skillratio += 150 + 350 * skill_lv;
@@ -7965,21 +8107,21 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list
 						break;
 					case IG_CROSS_RAIN:
 						if( sc && sc->getSCE( SC_HOLY_S ) ){
-							skillratio += -100 + ( 450 + 10 * pc_checkskill( sd, IG_SPEAR_SWORD_M ) ) * skill_lv;
+							skillratio += -100 + ( 450 + 15 * pc_checkskill( sd, IG_SPEAR_SWORD_M ) ) * skill_lv;
 						}else{
-							skillratio += -100 + ( 320 + 5 * pc_checkskill( sd, IG_SPEAR_SWORD_M ) ) * skill_lv;
+							skillratio += -100 + ( 320 + 10 * pc_checkskill( sd, IG_SPEAR_SWORD_M ) ) * skill_lv;
 						}
-						skillratio += 5 * sstatus->spl;
+						skillratio += 7 * sstatus->spl;
 						RE_LVL_DMOD(100);
 						break;
 					case CD_ARBITRIUM:
-						skillratio += -100 + 1000 * skill_lv + 7 * sstatus->spl;
+						skillratio += -100 + 1000 * skill_lv + 10 * sstatus->spl;
 						skillratio += 10 * pc_checkskill( sd, CD_FIDUS_ANIMUS ) * skill_lv;
 						RE_LVL_DMOD(100);
 						break;
 					case CD_ARBITRIUM_ATK:
-						skillratio += -100 + 1250 * skill_lv + 7 * sstatus->spl;
-						skillratio += 10 * pc_checkskill( sd, CD_FIDUS_ANIMUS ) * skill_lv;
+						skillratio += -100 + 1750 * skill_lv + 10 * sstatus->spl;
+						skillratio += 50 * pc_checkskill( sd, CD_FIDUS_ANIMUS ) * skill_lv;
 						RE_LVL_DMOD(100);
 						break;
 					case CD_PNEUMATICUS_PROCELLA:
@@ -7992,7 +8134,7 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list
 						RE_LVL_DMOD(100);
 						break;
 					case CD_FRAMEN:
-						skillratio += -100 + (800 + 5 * pc_checkskill(sd,CD_FIDUS_ANIMUS)) * skill_lv + 5 * sstatus->spl;
+						skillratio += -100 + (950 + 5 * pc_checkskill(sd,CD_FIDUS_ANIMUS)) * skill_lv + 5 * sstatus->spl;
 						if (tstatus->race == RC_UNDEAD || tstatus->race == RC_DEMON)
 							skillratio += 100 * skill_lv;
 						RE_LVL_DMOD(100);
@@ -8011,12 +8153,14 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list
 						skillratio += -100 + ( 570 + 20 * pc_checkskill( sd, ABC_MAGIC_SWORD_M ) ) * skill_lv + 5 * sstatus->spl;
 						RE_LVL_DMOD(100);
 						break;
-					case TR_METALIC_FURY: {
-							int area = skill_get_splash(skill_id, skill_lv);
-							int count = map_forcountinarea(skill_check_bl_sc,target->m,target->x - area,target->y - area,target->x + area,target->y + area,5,BL_MOB,SC_SOUNDBLEND);
-							skillratio += -100 + (2200 + 300 * count) * skill_lv + 5 * sstatus->spl;
-							RE_LVL_DMOD(100);
+					case TR_METALIC_FURY:
+						skillratio += -100 + 2600 * skill_lv;
+						// !Todo: skill affected by SPL (without SC_SOUNDBLEND) as well?
+						if (tsc && tsc->getSCE(SC_SOUNDBLEND)) {
+							skillratio += 1000 * skill_lv;
+							skillratio += 2 * pc_checkskill(sd, TR_STAGE_MANNER) * sstatus->spl;
 						}
+						RE_LVL_DMOD(100);
 						break;
 					case TR_SOUNDBLEND:
 						skillratio += -100 + 120 * skill_lv + 5 * sstatus->spl;
@@ -8115,6 +8259,57 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list
 					case NPC_RAINOFMETEOR:
 						skillratio += 350;	// unknown ratio
 						break;
+					case HN_NAPALM_VULCAN_STRIKE:
+						skillratio += -100 + 350 + 650 * skill_lv;
+						skillratio += pc_checkskill(sd, HN_SELFSTUDY_SOCERY) * 4 * skill_lv;
+						skillratio += 5 * sstatus->spl;
+						RE_LVL_DMOD(100);
+						break;
+					case HN_JUPITEL_THUNDER_STORM:
+						skillratio += -100 + 1800 * skill_lv;
+						skillratio += pc_checkskill(sd, HN_SELFSTUDY_SOCERY) * 3 * skill_lv;
+						skillratio += 5 * sstatus->spl;
+						RE_LVL_DMOD(100);
+						break;
+					case HN_HELLS_DRIVE:
+						skillratio += -100 + 1500 + 700 * skill_lv;
+						skillratio += pc_checkskill(sd, HN_SELFSTUDY_SOCERY) * 4 * skill_lv;
+						skillratio += 5 * sstatus->spl;
+						RE_LVL_DMOD(100);
+						break;
+					case HN_GROUND_GRAVITATION:
+						if (mflag & SKILL_ALTDMG_FLAG) {
+							skillratio += -100 + 3000 + 1500 * skill_lv;
+							skillratio += pc_checkskill(sd, HN_SELFSTUDY_SOCERY) * 4 * skill_lv;
+							ad.div_ = -2;
+						} else {
+							skillratio += -100 + 800 + 700 * skill_lv;
+							skillratio += pc_checkskill(sd, HN_SELFSTUDY_SOCERY) * 2 * skill_lv;
+						}
+						skillratio += 5 * sstatus->spl;
+						RE_LVL_DMOD(100);
+						break;
+					case HN_JACK_FROST_NOVA:
+						if (mflag & SKILL_ALTDMG_FLAG) {
+							skillratio += -100 + 200 * skill_lv;
+						} else {
+							skillratio += -100 + 400 + 500 * skill_lv;
+						}
+						skillratio += pc_checkskill(sd, HN_SELFSTUDY_SOCERY) * 3 * skill_lv;
+						skillratio += 5 * sstatus->spl;
+						RE_LVL_DMOD(100);
+						break;
+					case HN_METEOR_STORM_BUSTER:
+						if (mflag & SKILL_ALTDMG_FLAG) {
+							skillratio += -100 + 300 + 160 * skill_lv * 2;
+							ad.div_ = -3;
+						} else {
+							skillratio += -100 + 450 + 160 * skill_lv;
+						}
+						skillratio += pc_checkskill(sd, HN_SELFSTUDY_SOCERY) * 5 * skill_lv;
+						skillratio += 5 * sstatus->spl;
+						RE_LVL_DMOD(100);
+						break;
 				}
 
 				if (sc) {// Insignia's increases the damage of offensive magic by a fixed percentage depending on the element.
@@ -8649,6 +8844,7 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list *
  		case RA_ICEBOUNDTRAP:
 			if (md.damage == 1)
 				break;
+			[[fallthrough]];
 		case RA_CLUSTERBOMB:
 			{
 				struct Damage wd = battle_calc_weapon_attack(src,target,skill_id,skill_lv,mflag);

+ 1 - 0
src/map/channel.cpp

@@ -66,6 +66,7 @@ struct Channel* channel_create(struct Channel *tmp_chan) {
 			break;
 		case CHAN_TYPE_PRIVATE:
 			channel->char_id = tmp_chan->char_id;
+			[[fallthrough]];
 		default:
 			strdb_put(channel_db, channel->name, channel);
 			break;

+ 1 - 0
src/map/chrif.cpp

@@ -915,6 +915,7 @@ static void chrif_ack_login_req(int aid, const char* player_name, uint16 type, u
 		case CHRIF_OP_LOGIN_CHANGESEX:
 		case CHRIF_OP_CHANGECHARSEX:
 			type = CHRIF_OP_LOGIN_CHANGESEX; // So we don't have to create a new msgstring.
+			[[fallthrough]];
 		case CHRIF_OP_LOGIN_BLOCK:
 		case CHRIF_OP_LOGIN_BAN:
 		case CHRIF_OP_LOGIN_UNBLOCK:

+ 69 - 75
src/map/clif.cpp

@@ -81,9 +81,6 @@ static inline int32 client_exp(t_exp exp) {
 static struct eri *delay_clearunit_ers;
 
 struct s_packet_db packet_db[MAX_PACKET_DB + 1];
-// Reuseable global packet buffer to prevent too many allocations
-// Take socket.cpp::socket_max_client_packet into consideration
-static int8 packet_buffer[UINT16_MAX];
 unsigned long color_table[COLOR_MAX];
 
 #include "clif_obfuscation.hpp"
@@ -529,6 +526,7 @@ int clif_send(const void* buf, int len, struct block_list* bl, enum send_target
 	case AREA_WOSC:
 		if (sd && bl->prev == NULL) //Otherwise source misses the packet.[Skotlex]
 			clif_send (buf, len, bl, SELF);
+		[[fallthrough]];
 	case AREA_WOC:
 	case AREA_WOS:
 		map_foreachinallarea(clif_send_sub, bl->m, bl->x-AREA_SIZE, bl->y-AREA_SIZE, bl->x+AREA_SIZE, bl->y+AREA_SIZE,
@@ -568,6 +566,7 @@ int clif_send(const void* buf, int len, struct block_list* bl, enum send_target
 		y0 = bl->y - AREA_SIZE;
 		x1 = bl->x + AREA_SIZE;
 		y1 = bl->y + AREA_SIZE;
+		[[fallthrough]];
 	case PARTY:
 	case PARTY_WOS:
 	case PARTY_SAMEMAP:
@@ -644,6 +643,7 @@ int clif_send(const void* buf, int len, struct block_list* bl, enum send_target
 		y0 = bl->y - AREA_SIZE;
 		x1 = bl->x + AREA_SIZE;
 		y1 = bl->y + AREA_SIZE;
+		[[fallthrough]];
 	case GUILD_SAMEMAP:
 	case GUILD_SAMEMAP_WOS:
 	case GUILD:
@@ -695,6 +695,7 @@ int clif_send(const void* buf, int len, struct block_list* bl, enum send_target
 		y0 = bl->y - AREA_SIZE;
 		x1 = bl->x + AREA_SIZE;
 		y1 = bl->y + AREA_SIZE;
+		[[fallthrough]];
 	case BG_SAMEMAP:
 	case BG_SAMEMAP_WOS:
 	case BG:
@@ -2928,7 +2929,7 @@ static void clif_item_equip( short idx, struct EQUIPITEM_INFO *p, struct item *i
 #endif
 
 #if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200724
-	p->enchantgrade = it->enchantgrade;
+	p->grade = it->enchantgrade;
 #endif
 }
 
@@ -4940,10 +4941,10 @@ void clif_storageitemadded( map_session_data* sd, struct item* i, int index, int
 	p.damaged = i->attribute; // attribute
 	p.refine = i->refine; //refine
 	clif_addcards( &p.slot, i );
-#if PACKETVER >= 20150226
+#if PACKETVER_MAIN_NUM >= 20140813 || PACKETVER_RE_NUM >= 20140402 || defined(PACKETVER_ZERO)
 	clif_add_random_options( p.option_data, *i );
-#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200724
-	p.enchantgrade = i->enchantgrade;
+#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723 || PACKETVER_ZERO_NUM >= 20221024
+	p.grade = i->enchantgrade;
 #endif
 #endif
 
@@ -9156,12 +9157,7 @@ void clif_guild_emblem_area(struct block_list* bl)
 	p.packetType = HEADER_ZC_CHANGE_GUILD;
 	p.guild_id = status_get_guild_id(bl);
 	p.emblem_id = status_get_emblem_id(bl);
-
-#if PACKETVER < 20190724
-	p.aid = bl->id;
-#else
-	p.unknown = 0;
-#endif
+	p.AID = bl->id;
 
 	clif_send(&p, sizeof(p), bl, AREA_WOS);
 }
@@ -15170,6 +15166,7 @@ void clif_parse_NoviceDoriDori(int fd, map_session_data *sd)
 		case MAPID_TAEKWON:
 			if (!sd->state.rest)
 				break;
+			[[fallthrough]];
 		case MAPID_SUPER_NOVICE:
 		case MAPID_SUPER_BABY:
 		case MAPID_SUPER_NOVICE_E:
@@ -17514,40 +17511,31 @@ void clif_parse_Adopt_reply(int fd, map_session_data *sd){
 }
 
 
-/// Convex Mirror (ZC_BOSS_INFO).
-/// 0293 <infoType>.B <x>.L <y>.L <minHours>.W <minMinutes>.W <maxHours>.W <maxMinutes>.W <monster name>.51B
+/// Convex Mirror
+/// 0293 <infoType>.B <x>.L <y>.L <minHours>.W <minMinutes>.W <maxHours>.W <maxMinutes>.W <monster name>.51B (ZC_BOSS_INFO)
 /// infoType:
 ///     BOSS_INFO_NOT = No boss on this map.
 ///     BOSS_INFO_ALIVE = Boss is alive (position update).
 ///     BOSS_INFO_ALIVE_WITHMSG = Boss is alive (initial announce).
 ///     BOSS_INFO_DEAD = Boss is dead.
-void clif_bossmapinfo(map_session_data *sd, struct mob_data *md, enum e_bossmap_info flag)
-{
-	int fd = sd->fd;
+void clif_bossmapinfo( map_session_data& sd, mob_data* md, e_bossmap_info flag ){
+	PACKET_ZC_BOSS_INFO p = {};
 
-	WFIFOHEAD(fd,70);
-	memset(WFIFOP(fd,0),0,70);
-	WFIFOW(fd,0) = 0x293;
+	p.packetType = HEADER_ZC_BOSS_INFO;
+	p.type = flag;
 
 	switch (flag) {
 		case BOSS_INFO_NOT:
-			WFIFOB(fd,2) = BOSS_INFO_NOT;
 			// No data required
-			break; 
-		case BOSS_INFO_ALIVE:
-			WFIFOB(fd,2) = BOSS_INFO_ALIVE;
-			// Update X/Y
-			WFIFOL(fd,3) = md->bl.x;
-			WFIFOL(fd,7) = md->bl.y;
 			break;
 		case BOSS_INFO_ALIVE_WITHMSG:
-			WFIFOB(fd,2) = BOSS_INFO_ALIVE_WITHMSG;
-			// Current X/Y
-			WFIFOL(fd,3) = md->bl.x;
-			WFIFOL(fd,7) = md->bl.y;
+			[[fallthrough]];
+		case BOSS_INFO_ALIVE:
+
+			p.x = md->bl.x;
+			p.y = md->bl.y;
 			break;
-		case BOSS_INFO_DEAD:
-		{
+		case BOSS_INFO_DEAD: {
 			const struct TimerData * timer_data = get_timer(md->spawn_timer);
 			unsigned int seconds;
 			int hours, minutes;
@@ -17557,18 +17545,18 @@ void clif_bossmapinfo(map_session_data *sd, struct mob_data *md, enum e_bossmap_
 			seconds = seconds - (60 * 60 * hours);
 			minutes = seconds / 60;
 
-			WFIFOB(fd,2) = BOSS_INFO_DEAD;
-			// Add respawn info
-			WFIFOW(fd,11) = hours; // Hours
-			WFIFOW(fd,13) = minutes; // Minutes
-		}
+
+			p.minHours = hours;
+			p.minMinutes = minutes;
 			break;
+		}
 	}
 
-	if (md != NULL)
-		safestrncpy(WFIFOCP(fd,19), md->db->jname.c_str(), NAME_LENGTH);
+	if( md != nullptr ){
+		safestrncpy( p.name, md->db->jname.c_str(), sizeof( p.name ) );
+	}
 
-	WFIFOSET(fd,70);
+	clif_send( &p, sizeof( p ), &sd.bl, SELF );
 }
 
 
@@ -17677,7 +17665,7 @@ std::string clif_quest_string( std::shared_ptr<s_quest_objective> objective ){
 		case RC_DRAGON:		race_name = "Dragon"; break;
 		default:
 			ShowWarning( "clif_quest_string: Unsupported race %d - using empty string...\n", objective->race );
-			// Fallthrough
+			[[fallthrough]];
 		case RC_ALL:		race_name = ""; break;
 	}
 
@@ -17689,7 +17677,7 @@ std::string clif_quest_string( std::shared_ptr<s_quest_objective> objective ){
 		case SZ_BIG:	size_name = "Large"; break;
 		default:
 			ShowWarning( "clif_quest_string: Unsupported size %d - using empty string...\n", objective->size );
-			// Fallthrough
+			[[fallthrough]];
 		case SZ_ALL:	size_name = ""; break;
 	}
 
@@ -17708,7 +17696,7 @@ std::string clif_quest_string( std::shared_ptr<s_quest_objective> objective ){
 		case ELE_UNDEAD:	ele_name = "Undead Element"; break;
 		default:
 			ShowWarning( "clif_quest_string: Unsupported element %d - using empty string...\n", objective->element );
-			// Fallthrough
+			[[fallthrough]];
 		case ELE_ALL:		ele_name = ""; break;
 	}
 
@@ -23586,14 +23574,14 @@ void clif_parse_laphine_upgrade( int fd, map_session_data* sd ){
 	}else if( upgrade->resultRefineMaximum > 0 ){
 		// If a minimum is specified it can also downgrade
 		if( upgrade->resultRefineMinimum ){
-			item->refine = rnd_value( upgrade->resultRefineMinimum, upgrade->resultRefineMaximum );
+			item->refine = static_cast<uint8>( rnd_value<uint16>( upgrade->resultRefineMinimum, upgrade->resultRefineMaximum ) );
 		}else{
 			// Otherwise it can only be upgraded until the maximum, but not downgraded
-			item->refine = rnd_value<uint16>( item->refine, upgrade->resultRefineMaximum );
+			item->refine = static_cast<uint8>( rnd_value<uint16>( item->refine, upgrade->resultRefineMaximum ) );
 		}
 	}else if( upgrade->resultRefineMinimum > 0 ){
 		// No maximum has been specified, so it can be anything between minimum and MAX_REFINE
-		item->refine = rnd_value<uint16>( upgrade->resultRefineMinimum, MAX_REFINE );
+		item->refine = static_cast<uint8>( rnd_value<uint16>( upgrade->resultRefineMinimum, MAX_REFINE ) );
 	}
 
 	// Log retrieving the item again -> with the new options
@@ -23987,11 +23975,11 @@ void clif_reputation_list( map_session_data& sd ){
 }
 
 void clif_item_reform_open( map_session_data& sd, t_itemid item ){
-#if PACKETVER_RE_NUM >= 20211103 || PACKETVER_MAIN_NUM >= 20220330
+#if PACKETVER_MAIN_NUM >= 20201118 || PACKETVER_RE_NUM >= 20211103 || PACKETVER_ZERO_NUM >= 20221024
 	struct PACKET_ZC_OPEN_REFORM_UI p = {};
 
-	p.packetType = HEADER_ZC_OPEN_REFORM_UI;
-	p.itemId = item;
+	p.PacketType = HEADER_ZC_OPEN_REFORM_UI;
+	p.ITID = item;
 
 	clif_send( &p, sizeof( p ), &sd.bl, SELF );
 
@@ -24000,16 +23988,16 @@ void clif_item_reform_open( map_session_data& sd, t_itemid item ){
 }
 
 void clif_parse_item_reform_close( int fd, map_session_data* sd ){
-#if PACKETVER_RE_NUM >= 20211103 || PACKETVER_MAIN_NUM >= 20220330
+#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20211103 || PACKETVER_ZERO_NUM >= 20221024
 	sd->state.item_reform = 0;
 #endif
 }
 
 void clif_item_reform_result( map_session_data& sd, uint16 index, uint8 result ){
-#if PACKETVER_RE_NUM >= 20211103 || PACKETVER_MAIN_NUM >= 20220330
+#if PACKETVER_MAIN_NUM >= 20201118 || PACKETVER_RE_NUM >= 20211103 || PACKETVER_ZERO_NUM >= 20221024
 	struct PACKET_ZC_ITEM_REFORM_ACK p = {};
 
-	p.packetType = HEADER_ZC_ITEM_REFORM_ACK;
+	p.PacketType = HEADER_ZC_ITEM_REFORM_ACK;
 	p.index = client_index( index );
 	p.result = result;
 
@@ -24023,7 +24011,7 @@ void clif_item_reform_result( map_session_data& sd, uint16 index, uint8 result )
 }
 
 void clif_parse_item_reform_start( int fd, map_session_data* sd ){
-#if PACKETVER_RE_NUM >= 20211103 || PACKETVER_MAIN_NUM >= 20220330
+#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20211103 || PACKETVER_ZERO_NUM >= 20221024
 	// Not opened
 	if( sd->state.item_reform == 0 ){
 		return;
@@ -24032,7 +24020,7 @@ void clif_parse_item_reform_start( int fd, map_session_data* sd ){
 	struct PACKET_CZ_ITEM_REFORM *p = (struct PACKET_CZ_ITEM_REFORM*)RFIFOP( fd, 0 );
 
 	// Item mismatch
-	if( p->itemId != sd->state.item_reform ){
+	if( p->ITID != sd->state.item_reform ){
 		return;
 	}
 
@@ -24202,13 +24190,13 @@ void clif_enchantwindow_result( map_session_data& sd, bool success, t_itemid enc
 #if PACKETVER_RE_NUM >= 20211103 || PACKETVER_MAIN_NUM >= 20220330
 	struct PACKET_ZC_RESPONSE_ENCHANT p = {};
 
-	p.packetType = HEADER_ZC_RESPONSE_ENCHANT;
+	p.PacketType = HEADER_ZC_RESPONSE_ENCHANT;
 	if( success ){
-		p.messageId = C_ENCHANT_SUCCESS;
+		p.msgId = C_ENCHANT_SUCCESS;
 	}else{
-		p.messageId = C_ENCHANT_FAILURE;
+		p.msgId = C_ENCHANT_FAILURE;
 	}
-	p.enchantItemId = enchant;
+	p.ITID = enchant;
 
 	clif_send( &p, sizeof( p ), &sd.bl, SELF );
 
@@ -24253,10 +24241,10 @@ bool clif_parse_enchant_basecheck( struct item& selected_item, std::shared_ptr<s
 }
 
 void clif_parse_enchantwindow_general( int fd, map_session_data* sd ){
-#if PACKETVER_RE_NUM >= 20211103 || PACKETVER_MAIN_NUM >= 20220330
+#if PACKETVER_MAIN_NUM >= 20201118 || PACKETVER_RE_NUM >= 20211103 || PACKETVER_ZERO_NUM >= 20221024
 	struct PACKET_CZ_REQUEST_RANDOM_ENCHANT *p = (struct PACKET_CZ_REQUEST_RANDOM_ENCHANT*)RFIFOP( fd, 0 );
 
-	if( sd->state.item_enchant_index != p->clientLuaIndex ){
+	if( sd->state.item_enchant_index != p->enchant_group ){
 		return;
 	}
 
@@ -24271,7 +24259,7 @@ void clif_parse_enchantwindow_general( int fd, map_session_data* sd ){
 	}
 
 	struct item& selected_item = sd->inventory.u.items_inventory[index];
-	std::shared_ptr<s_item_enchant> enchant = item_enchant_db.find( p->clientLuaIndex );
+	std::shared_ptr<s_item_enchant> enchant = item_enchant_db.find( p->enchant_group );
 
 	if( enchant == nullptr ){
 		return;
@@ -24382,10 +24370,10 @@ void clif_parse_enchantwindow_general( int fd, map_session_data* sd ){
 }
 
 void clif_parse_enchantwindow_perfect( int fd, map_session_data* sd ){
-#if PACKETVER_RE_NUM >= 20211103 || PACKETVER_MAIN_NUM >= 20220330
+#if PACKETVER_MAIN_NUM >= 20201118 || PACKETVER_RE_NUM >= 20211103 || PACKETVER_ZERO_NUM >= 20221024
 	struct PACKET_CZ_REQUEST_PERFECT_ENCHANT *p = (struct PACKET_CZ_REQUEST_PERFECT_ENCHANT*)RFIFOP( fd, 0 );
 
-	if( sd->state.item_enchant_index != p->clientLuaIndex ){
+	if( sd->state.item_enchant_index != p->enchant_group ){
 		return;
 	}
 
@@ -24400,7 +24388,7 @@ void clif_parse_enchantwindow_perfect( int fd, map_session_data* sd ){
 	}
 
 	struct item& selected_item = sd->inventory.u.items_inventory[index];
-	std::shared_ptr<s_item_enchant> enchant = item_enchant_db.find( p->clientLuaIndex );
+	std::shared_ptr<s_item_enchant> enchant = item_enchant_db.find( p->enchant_group );
 
 	if( enchant == nullptr ){
 		return;
@@ -24433,7 +24421,7 @@ void clif_parse_enchantwindow_perfect( int fd, map_session_data* sd ){
 		return;
 	}
 
-	std::shared_ptr<s_item_enchant_perfect> perfect_enchant = util::umap_find( enchant_slot->perfect.enchants, p->itemId );
+	std::shared_ptr<s_item_enchant_perfect> perfect_enchant = util::umap_find( enchant_slot->perfect.enchants, p->ITID );
 
 	if( perfect_enchant == nullptr ){
 		return;
@@ -24482,10 +24470,10 @@ void clif_parse_enchantwindow_perfect( int fd, map_session_data* sd ){
 }
 
 void clif_parse_enchantwindow_upgrade( int fd, map_session_data* sd ){
-#if PACKETVER_RE_NUM >= 20211103 || PACKETVER_MAIN_NUM >= 20220330
+#if PACKETVER_MAIN_NUM >= 20201118 || PACKETVER_RE_NUM >= 20211103 || PACKETVER_ZERO_NUM >= 20221024
 	struct PACKET_CZ_REQUEST_UPGRADE_ENCHANT *p = (struct PACKET_CZ_REQUEST_UPGRADE_ENCHANT*)RFIFOP( fd, 0 );
 
-	if( sd->state.item_enchant_index != p->clientLuaIndex ){
+	if( sd->state.item_enchant_index != p->enchant_group ){
 		return;
 	}
 
@@ -24500,7 +24488,7 @@ void clif_parse_enchantwindow_upgrade( int fd, map_session_data* sd ){
 	}
 
 	struct item& selected_item = sd->inventory.u.items_inventory[index];
-	std::shared_ptr<s_item_enchant> enchant = item_enchant_db.find( p->clientLuaIndex );
+	std::shared_ptr<s_item_enchant> enchant = item_enchant_db.find( p->enchant_group );
 
 	if( enchant == nullptr ){
 		return;
@@ -24579,10 +24567,10 @@ void clif_parse_enchantwindow_upgrade( int fd, map_session_data* sd ){
 }
 
 void clif_parse_enchantwindow_reset( int fd, map_session_data* sd ){
-#if PACKETVER_RE_NUM >= 20211103 || PACKETVER_MAIN_NUM >= 20220330
+#if PACKETVER_MAIN_NUM >= 20201118 || PACKETVER_RE_NUM >= 20211103 || PACKETVER_ZERO_NUM >= 20221024
 	struct PACKET_CZ_REQUEST_RESET_ENCHANT *p = (struct PACKET_CZ_REQUEST_RESET_ENCHANT*)RFIFOP( fd, 0 );
 
-	if( sd->state.item_enchant_index != p->clientLuaIndex ){
+	if( sd->state.item_enchant_index != p->enchant_group ){
 		return;
 	}
 
@@ -24610,7 +24598,7 @@ void clif_parse_enchantwindow_reset( int fd, map_session_data* sd ){
 		return;
 	}
 
-	std::shared_ptr<s_item_enchant> enchant = item_enchant_db.find( p->clientLuaIndex );
+	std::shared_ptr<s_item_enchant> enchant = item_enchant_db.find( p->enchant_group );
 
 	if( enchant == nullptr ){
 		return;
@@ -24697,7 +24685,7 @@ void clif_parse_enchantwindow_reset( int fd, map_session_data* sd ){
 }
 
 void clif_parse_enchantwindow_close( int fd, map_session_data* sd ){
-#if PACKETVER_RE_NUM >= 20211103 || PACKETVER_MAIN_NUM >= 20220330
+#if PACKETVER_MAIN_NUM >= 20201118 || PACKETVER_RE_NUM >= 20211103 || PACKETVER_ZERO_NUM >= 20221024
 	sd->state.item_enchant_index = 0;
 #endif
 }
@@ -25066,7 +25054,7 @@ void clif_dynamicnpc_result( map_session_data& sd, e_dynamicnpc_result result ){
 #if PACKETVER_MAIN_NUM >= 20140430 || PACKETVER_RE_NUM >= 20140430 || defined(PACKETVER_ZERO)
 	struct PACKET_ZC_DYNAMICNPC_CREATE_RESULT p = {};
 
-	p.packetType = HEADER_ZC_DYNAMICNPC_CREATE_RESULT;
+	p.PacketType = HEADER_ZC_DYNAMICNPC_CREATE_RESULT;
 	p.result = result;
 
 	clif_send( &p, sizeof( p ), &sd.bl, SELF );
@@ -25193,6 +25181,12 @@ void clif_parse_partybooking_reply( int fd, map_session_data* sd ){
 #endif
 }
 
+void clif_parse_reset_skill( int fd, map_session_data* sd ){
+#if PACKETVER_MAIN_NUM >= 20220216 || PACKETVER_ZERO_NUM >= 20220203
+	PACKET_CZ_RESET_SKILL* p = (PACKET_CZ_RESET_SKILL*)RFIFOP( fd, 0 );
+#endif
+}
+
 /*==========================================
  * Main client packet processing function
  *------------------------------------------*/

+ 1 - 1
src/map/clif.hpp

@@ -1015,7 +1015,7 @@ void clif_Auction_message(int fd, unsigned char flag);
 void clif_Auction_close(int fd, unsigned char flag);
 void clif_parse_Auction_cancelreg(int fd, map_session_data *sd);
 
-void clif_bossmapinfo(map_session_data *sd, struct mob_data *md, enum e_bossmap_info flag);
+void clif_bossmapinfo( map_session_data& sd, mob_data* md, e_bossmap_info flag );
 void clif_cashshop_show(map_session_data *sd, struct npc_data *nd);
 
 // ADOPTION

+ 16 - 5
src/map/clif_packetdb.hpp

@@ -2425,18 +2425,25 @@
 	parseable_packet( HEADER_CZ_GRADE_ENCHANT_CLOSE_UI, sizeof( struct PACKET_CZ_GRADE_ENCHANT_CLOSE_UI ), clif_parse_enchantgrade_close, 0 );
 #endif
 
+
+#if PACKETVER_MAIN_NUM >= 20201118 || PACKETVER_RE_NUM >= 20211103 || PACKETVER_ZERO_NUM >= 20221024
+	parseable_packet( HEADER_CZ_REQUEST_RANDOM_ENCHANT, sizeof( struct PACKET_CZ_REQUEST_RANDOM_ENCHANT ), clif_parse_enchantwindow_general, 0 );
+	parseable_packet( HEADER_CZ_REQUEST_PERFECT_ENCHANT, sizeof( struct PACKET_CZ_REQUEST_PERFECT_ENCHANT ), clif_parse_enchantwindow_perfect, 0 );
+	parseable_packet( HEADER_CZ_REQUEST_UPGRADE_ENCHANT, sizeof( struct PACKET_CZ_REQUEST_UPGRADE_ENCHANT ), clif_parse_enchantwindow_upgrade, 0 );
+	parseable_packet( HEADER_CZ_REQUEST_RESET_ENCHANT, sizeof( struct PACKET_CZ_REQUEST_RESET_ENCHANT ), clif_parse_enchantwindow_reset, 0 );
+	parseable_packet( HEADER_CZ_CLOSE_UI_ENCHANT, sizeof( struct PACKET_CZ_CLOSE_UI_ENCHANT ), clif_parse_enchantwindow_close, 0 );
+#endif
+
 #if PACKETVER_RE_NUM >= 20211103 || PACKETVER_ZERO_NUM >= 20210818 || PACKETVER_MAIN_NUM >= 20220330
 	parseable_packet( HEADER_CZ_CHECKNAME2, sizeof( struct PACKET_CZ_CHECKNAME2 ), clif_parse_Mail_Receiver_Check, 0 );
 	parseable_packet( HEADER_CZ_UNCONFIRMED_RODEX_RETURN, sizeof( struct PACKET_CZ_UNCONFIRMED_RODEX_RETURN ), clif_parse_Mail_return, 0 );
 	parseable_packet( HEADER_CZ_REQ_TAKEOFF_EQUIP_ALL, sizeof( struct PACKET_CZ_REQ_TAKEOFF_EQUIP_ALL ), clif_parse_unequipall, 0 );
 	parseable_packet( 0xb93, 12, clif_parse_dull, 0 );
+#endif
+
+#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20211103 || PACKETVER_ZERO_NUM >= 20221024
 	parseable_packet( HEADER_CZ_CLOSE_REFORM_UI, sizeof( struct PACKET_CZ_CLOSE_REFORM_UI ), clif_parse_item_reform_close, 0 );
 	parseable_packet( HEADER_CZ_ITEM_REFORM, sizeof( struct PACKET_CZ_ITEM_REFORM ), clif_parse_item_reform_start, 0 );
-	parseable_packet( HEADER_CZ_REQUEST_RANDOM_ENCHANT, sizeof( struct PACKET_CZ_REQUEST_RANDOM_ENCHANT ), clif_parse_enchantwindow_general, 0 );
-	parseable_packet( HEADER_CZ_REQUEST_PERFECT_ENCHANT, sizeof( struct PACKET_CZ_REQUEST_PERFECT_ENCHANT ), clif_parse_enchantwindow_perfect, 0 );
-	parseable_packet( HEADER_CZ_REQUEST_UPGRADE_ENCHANT, sizeof( struct PACKET_CZ_REQUEST_UPGRADE_ENCHANT ), clif_parse_enchantwindow_upgrade, 0 );
-	parseable_packet( HEADER_CZ_REQUEST_RESET_ENCHANT, sizeof( struct PACKET_CZ_REQUEST_RESET_ENCHANT ), clif_parse_enchantwindow_reset, 0 );
-	parseable_packet( HEADER_CZ_CLOSE_UI_ENCHANT, sizeof( struct PACKET_CZ_CLOSE_UI_ENCHANT ), clif_parse_enchantwindow_close, 0 );
 #endif
 
 #if PACKETVER_MAIN_NUM >= 20220216
@@ -2447,4 +2454,8 @@
 	parseable_packet( HEADER_CZ_USE_PACKAGEITEM, sizeof( struct PACKET_CZ_USE_PACKAGEITEM ), clif_parse_itempackage_select, 0 );
 #endif
 
+#if PACKETVER_MAIN_NUM >= 20220216 || PACKETVER_ZERO_NUM >= 20220203
+	parseable_packet( HEADER_CZ_RESET_SKILL, sizeof( struct PACKET_CZ_RESET_SKILL ), clif_parse_reset_skill, 0 );
+#endif
+
 #endif /* CLIF_PACKETDB_HPP */

+ 10 - 17
src/map/elemental.cpp

@@ -514,23 +514,16 @@ static int elemental_ai_sub_timer_activesearch(block_list *bl, va_list ap) {
 	if( battle_check_target(&ed->bl,bl,BCT_ENEMY) <= 0 )
 		return 0;
 
-	int dist;
-
-	switch( bl->type ) {
-		case BL_PC:
-			if( !map_flag_vs(ed->bl.m) )
-				return 0;
-		default:
-			dist = distance_bl(&ed->bl, bl);
-			if( ((*target) == NULL || !check_distance_bl(&ed->bl, *target, dist)) && battle_check_range(&ed->bl,bl,ed->db->range2) ) { //Pick closest target?
-				(*target) = bl;
-				ed->target_id = bl->id;
-				ed->min_chase = dist + ed->db->range3;
-				if( ed->min_chase > AREA_SIZE )
-					ed->min_chase = AREA_SIZE;
-				return 1;
-			}
-			break;
+	if (bl->type == BL_PC && !map_flag_vs(ed->bl.m))
+		return 0;
+	int dist = distance_bl(&ed->bl, bl);
+	if( ((*target) == nullptr || !check_distance_bl(&ed->bl, *target, dist)) && battle_check_range(&ed->bl,bl,ed->db->range2) ) { //Pick closest target?
+		(*target) = bl;
+		ed->target_id = bl->id;
+		ed->min_chase = dist + ed->db->range3;
+		if( ed->min_chase > AREA_SIZE )
+			ed->min_chase = AREA_SIZE;
+		return 1;
 	}
 	return 0;
 }

+ 4 - 4
src/map/itemdb.cpp

@@ -2954,11 +2954,11 @@ static void itemdb_pc_get_itemgroup_sub(map_session_data *sd, bool identify, std
 
 		if( itemdb_isequip( data->nameid ) ){
 			if( data->refineMinimum > 0 && data->refineMaximum > 0 ){
-				tmp.refine = rnd_value( data->refineMinimum, data->refineMaximum );
+				tmp.refine = static_cast<uint8>( rnd_value<uint16>( data->refineMinimum, data->refineMaximum ) );
 			}else if( data->refineMinimum > 0 ){
-				tmp.refine = rnd_value<uint16>( data->refineMinimum, MAX_REFINE );
+				tmp.refine = static_cast<uint8>( rnd_value<uint16>( data->refineMinimum, MAX_REFINE ) );
 			}else if( data->refineMaximum > 0 ){
-				tmp.refine = rnd_value<uint16>( 1, data->refineMaximum );
+				tmp.refine = static_cast<uint8>( rnd_value<uint16>( 1, data->refineMaximum ) );
 			}else{
 				tmp.refine = 0;
 			}
@@ -4290,7 +4290,7 @@ uint64 RandomOptionDatabase::parseBodyNode(const ryml::NodeRef& node) {
 			return 0;
 
 		if (randopt->script) {
-			aFree(randopt->script);
+			script_free_code( randopt->script );
 			randopt->script = nullptr;
 		}
 

+ 20 - 14
src/map/map.cpp

@@ -95,7 +95,7 @@ char guild_storage_log_table[32] = "guild_storage_log";
 
 // log database
 std::string log_db_ip = "127.0.0.1";
-int log_db_port = 3306;
+uint16 log_db_port = 3306;
 std::string log_db_id = "ragnarok";
 std::string log_db_pw = "";
 std::string log_db_db = "log";
@@ -349,7 +349,7 @@ int map_addblock(struct block_list* bl)
 
 	struct map_data *mapdata = map_getmapdata(m);
 
-	if (mapdata->cell == nullptr) // Player warped to a freed map. Stop them!
+	if (mapdata == nullptr || mapdata->cell == nullptr) // Player warped to a freed map. Stop them!
 		return 1;
 
 	if( x < 0 || x >= mapdata->xs || y < 0 || y >= mapdata->ys )
@@ -402,6 +402,8 @@ int map_delblock(struct block_list* bl)
 
 	struct map_data *mapdata = map_getmapdata(bl->m);
 
+	nullpo_ret(mapdata);
+
 	pos = bl->x/BLOCK_SIZE+(bl->y/BLOCK_SIZE)*mapdata->bxs;
 
 	if (bl->next)
@@ -409,8 +411,10 @@ int map_delblock(struct block_list* bl)
 	if (bl->prev == &bl_head) {
 	//Since the head of the list, update the block_list map of []
 		if (bl->type == BL_MOB) {
+			nullpo_ret(mapdata->block_mob);
 			mapdata->block_mob[pos] = bl->next;
 		} else {
+			nullpo_ret(mapdata->block);
 			mapdata->block[pos] = bl->next;
 		}
 	} else {
@@ -434,6 +438,8 @@ int map_delblock(struct block_list* bl)
  */
 int map_moveblock(struct block_list *bl, int x1, int y1, t_tick tick)
 {
+	nullpo_ret(bl);
+
 	int x0 = bl->x, y0 = bl->y;
 	status_change *sc = NULL;
 	int moveblock = ( x0/BLOCK_SIZE != x1/BLOCK_SIZE || y0/BLOCK_SIZE != y1/BLOCK_SIZE);
@@ -763,9 +769,9 @@ int map_foreachinareaV(int(*func)(struct block_list*, va_list), int16 m, int16 x
 		return 0;
 
 	if (x1 < x0)
-		SWAP(x0, x1);
+		std::swap(x0, x1);
 	if (y1 < y0)
-		SWAP(y0, y1);
+		std::swap(y0, y1);
 
 	struct map_data *mapdata = map_getmapdata(m);
 
@@ -942,9 +948,9 @@ int map_forcountinarea(int (*func)(struct block_list*,va_list), int16 m, int16 x
 		return 0;
 
 	if ( x1 < x0 )
-		SWAP(x0, x1);
+		std::swap(x0, x1);
 	if ( y1 < y0 )
-		SWAP(y0, y1);
+		std::swap(y0, y1);
 
 	struct map_data *mapdata = map_getmapdata(m);
 
@@ -1021,9 +1027,9 @@ int map_foreachinmovearea(int (*func)(struct block_list*,va_list), struct block_
 	y1 = center->y + range;
 
 	if ( x1 < x0 )
-		SWAP(x0, x1);
+		std::swap(x0, x1);
 	if ( y1 < y0 )
-		SWAP(y0, y1);
+		std::swap(y0, y1);
 
 	if( dx == 0 || dy == 0 ) {
 		//Movement along one axis only.
@@ -1254,9 +1260,9 @@ int map_foreachinpath(int (*func)(struct block_list*,va_list),int16 m,int16 x0,i
 
 	//The two fors assume mx0 < mx1 && my0 < my1
 	if ( mx0 > mx1 )
-		SWAP(mx0, mx1);
+		std::swap(mx0, mx1);
 	if ( my0 > my1 )
-		SWAP(my0, my1);
+		std::swap(my0, my1);
 
 	struct map_data *mapdata = map_getmapdata(m);
 
@@ -1416,9 +1422,9 @@ int map_foreachindir(int(*func)(struct block_list*, va_list), int16 m, int16 x0,
 
 	//The following assumes mx0 < mx1 && my0 < my1
 	if (mx0 > mx1)
-		SWAP(mx0, mx1);
+		std::swap(mx0, mx1);
 	if (my0 > my1)
-		SWAP(my0, my1);
+		std::swap(my0, my1);
 
 	//Apply width to the path by turning 90 degrees
 	mx0 -= abs( range * dirx[( dir + 2 ) % DIR_MAX] );
@@ -4189,7 +4195,7 @@ int inter_config_read(const char *cfgName)
 			log_db_pw = w2;
 		else
 		if(strcmpi(w1,"log_db_port")==0)
-			log_db_port = atoi(w2);
+			log_db_port = (uint16)strtoul( w2, nullptr, 10 );
 		else
 		if(strcmpi(w1,"log_db_db")==0)
 			log_db_db = w2;
@@ -4274,7 +4280,7 @@ int log_sql_init(void)
 
 	ShowInfo("" CL_WHITE "[SQL]" CL_RESET ": Connecting to the Log Database " CL_WHITE "%s" CL_RESET " At " CL_WHITE "%s" CL_RESET "...\n",log_db_db.c_str(), log_db_ip.c_str());
 	if ( SQL_ERROR == Sql_Connect(logmysql_handle, log_db_id.c_str(), log_db_pw.c_str(), log_db_ip.c_str(), log_db_port, log_db_db.c_str()) ){
-		ShowError("Couldn't connect with uname='%s',host='%s',port='%d',database='%s'\n",
+		ShowError("Couldn't connect with uname='%s',host='%s',port='%hu',database='%s'\n",
 			log_db_id.c_str(), log_db_ip.c_str(), log_db_port, log_db_db.c_str());
 		Sql_ShowDebug(logmysql_handle);
 		Sql_Free(logmysql_handle);

+ 1 - 1
src/map/map.hpp

@@ -66,7 +66,7 @@ void map_msg_reload(void);
 #define NATURAL_HEAL_INTERVAL 500
 #define MIN_FLOORITEM 2
 #define MAX_FLOORITEM START_ACCOUNT_NUM
-#define MAX_LEVEL 250
+#define MAX_LEVEL 260
 #define MAX_DROP_PER_MAP 48
 #define MAX_IGNORE_LIST 20 	// official is 14
 #define MAX_VENDING 12

+ 34 - 34
src/map/mob.cpp

@@ -726,9 +726,9 @@ int mob_once_spawn_area(map_session_data* sd, int16 m, int16 x0, int16 y0, int16
 
 	// normalize x/y coordinates
 	if (x0 > x1)
-		SWAP(x0, x1);
+		std::swap(x0, x1);
 	if (y0 > y1)
-		SWAP(y0, y1);
+		std::swap(y0, y1);
 
 	// choose a suitable max. number of attempts
 	max = (y1 - y0 + 1)*(x1 - x0 + 1)*3;
@@ -1281,37 +1281,33 @@ static int mob_ai_sub_hard_activesearch(struct block_list *bl,va_list ap)
 	if(battle_check_target(&md->bl,bl,BCT_ENEMY)<=0)
 		return 0;
 
-	switch (bl->type)
-	{
-	case BL_PC:
-		if (((TBL_PC*)bl)->state.gangsterparadise &&
-			!status_has_mode(&md->status,MD_STATUSIMMUNE))
-			return 0; //Gangster paradise protection.
-	default:
-		if (battle_config.hom_setting&HOMSET_FIRST_TARGET &&
-			(*target) && (*target)->type == BL_HOM && bl->type != BL_HOM)
-			return 0; //For some reason Homun targets are never overriden.
-
-		dist = distance_bl(&md->bl, bl);
-		if(
-			((*target) == NULL || !check_distance_bl(&md->bl, *target, dist)) &&
-			battle_check_range(&md->bl,bl,md->db->range2)
-		) { //Pick closest target?
+	if (bl->type == BL_PC && BL_CAST(BL_PC, bl)->state.gangsterparadise &&
+		!status_has_mode(&md->status,MD_STATUSIMMUNE))
+		return 0; //Gangster paradise protection.
+
+	if (battle_config.hom_setting&HOMSET_FIRST_TARGET &&
+		(*target) != nullptr && (*target)->type == BL_HOM && bl->type != BL_HOM)
+		return 0; //For some reason Homun targets are never overriden.
+
+	dist = distance_bl(&md->bl, bl);
+	if(
+		((*target) == nullptr || !check_distance_bl(&md->bl, *target, dist)) &&
+		battle_check_range(&md->bl,bl,md->db->range2)
+	) { //Pick closest target?
 #ifdef ACTIVEPATHSEARCH
-			struct walkpath_data wpd;
-			if (!path_search(&wpd, md->bl.m, md->bl.x, md->bl.y, bl->x, bl->y, 0, CELL_CHKWALL)) // Count walk path cells
-				return 0;
-			//Standing monsters use range2, walking monsters use range3
-			if ((md->ud.walktimer == INVALID_TIMER && wpd.path_len > md->db->range2)
-				|| (md->ud.walktimer != INVALID_TIMER && wpd.path_len > md->db->range3))
-				return 0;
+		struct walkpath_data wpd;
+		if (!path_search(&wpd, md->bl.m, md->bl.x, md->bl.y, bl->x, bl->y, 0, CELL_CHKWALL)) // Count walk path cells
+			return 0;
+		//Standing monsters use range2, walking monsters use range3
+		if ((md->ud.walktimer == INVALID_TIMER && wpd.path_len > md->db->range2)
+			|| (md->ud.walktimer != INVALID_TIMER && wpd.path_len > md->db->range3))
+			return 0;
 #endif
-			(*target) = bl;
-			md->target_id=bl->id;
-			md->min_chase = cap_value(dist + md->db->range3 - md->status.rhw.range, md->db->range3, MAX_MINCHASE);
-			return 1;
-		}
-		break;
+		(*target) = bl;
+		md->target_id=bl->id;
+		md->min_chase = cap_value(dist + md->db->range3 - md->status.rhw.range, md->db->range3, MAX_MINCHASE);
+		return 1;
+
 	}
 	return 0;
 }
@@ -1518,6 +1514,7 @@ int mob_unlocktarget(struct mob_data *md, t_tick tick)
 			break;
 		//Because it is not unset when the mob finishes walking.
 		md->state.skillstate = MSS_IDLE;
+		[[fallthrough]];
 	case MSS_IDLE:
 		if( md->ud.walktimer == INVALID_TIMER && md->idle_event[0] && npc_event_do_id( md->idle_event, md->bl.id ) > 0 ){
 			md->idle_event[0] = 0;
@@ -3857,8 +3854,9 @@ int mobskill_use(struct mob_data *md, t_tick tick, int event, int64 damage)
 					bl = &md->bl;
 					if (md->master_id)
 						bl = map_id2bl(md->master_id);
-					if (bl) //Otherwise, fall through.
+					if (bl)
 						break;
+					[[fallthrough]];
 				case MST_FRIEND:
 					bl = fbl?fbl:(fmd?&fmd->bl:&md->bl);
 					break;
@@ -3907,8 +3905,9 @@ int mobskill_use(struct mob_data *md, t_tick tick, int event, int64 damage)
 					bl = &md->bl;
 					if (md->master_id)
 						bl = map_id2bl(md->master_id);
-					if (bl) //Otherwise, fall through.
+					if (bl)
 						break;
+					[[fallthrough]];
 				case MST_FRIEND:
 					if (fbl) {
 						bl = fbl;
@@ -3916,7 +3915,8 @@ int mobskill_use(struct mob_data *md, t_tick tick, int event, int64 damage)
 					} else if (fmd) {
 						bl = &fmd->bl;
 						break;
-					} // else fall through
+					}
+					[[fallthrough]];
 				default:
 					bl = &md->bl;
 					break;

+ 3 - 5
src/map/navi.cpp

@@ -78,13 +78,11 @@ static enum directions walk_choices [3][3] =
 /// Pushes path_node to the binary node_heap.
 /// Ensures there is enough space in array to store new element.
 
-#define swap_ptrcast_pathnode(a, b) swap_ptrcast(struct path_node *, a, b)
-
 static void heap_push_node(struct node_heap *heap, struct path_node *node)
 {
 #ifndef __clang_analyzer__ // TODO: Figure out why clang's static analyzer doesn't like this
 	BHEAP_ENSURE2(*heap, 1, 256, struct path_node **);
-	BHEAP_PUSH2(*heap, node, NODE_MINTOPCMP, swap_ptrcast_pathnode);
+	BHEAP_PUSH2(*heap, node, NODE_MINTOPCMP);
 #endif // __clang_analyzer__
 }
 
@@ -97,7 +95,7 @@ static int heap_update_node(struct node_heap *heap, struct path_node *node)
 		ShowError("heap_update_node: node not found\n");
 		return 1;
 	}
-	BHEAP_UPDATE(*heap, i, NODE_MINTOPCMP, swap_ptrcast_pathnode);
+	BHEAP_UPDATE(*heap, i, NODE_MINTOPCMP);
 	return 0;
 }
 // end 1:1 copy of definitions from path.cpp
@@ -225,7 +223,7 @@ bool navi_path_search(struct navi_walkpath_data *wpd, const struct navi_pos *fro
 		}
 
 		current = BHEAP_PEEK(g_open_set); // Look for the lowest f_cost node in the 'open' set
-		BHEAP_POP2(g_open_set, NODE_MINTOPCMP, swap_ptrcast_pathnode); // Remove it from 'open' set
+		BHEAP_POP2(g_open_set, NODE_MINTOPCMP); // Remove it from 'open' set
 
 		x = current->x;
 		y = current->y;

+ 1 - 4
src/map/npc.cpp

@@ -5159,10 +5159,7 @@ static const char* npc_parse_function(char* w1, char* w2, char* w3, char* w4, co
 		struct script_code *oldscript = (struct script_code*)db_data2ptr(&old_data);
 
 		ShowInfo("npc_parse_function: Overwriting user function [%s] (%s:%d)\n", w3, filepath, strline(buffer,start-buffer));
-		script_stop_scriptinstances(oldscript);
-		script_free_vars(oldscript->local.vars);
-		aFree(oldscript->script_buf);
-		aFree(oldscript);
+		script_free_code( oldscript );
 	}
 
 	return end;

+ 19 - 100
src/map/packets.hpp

@@ -177,19 +177,6 @@ struct PACKET_CZ_GUILD_EMBLEM_CHANGE2 {
 	uint32 version;
 } __attribute__((packed));
 
-struct PACKET_ZC_CHANGE_GUILD {
-	int16 packetType;
-#if PACKETVER < 20190724
-	uint32 aid;
-	uint32 guild_id;
-	uint16 emblem_id;
-#else
-	uint32 guild_id;
-	uint32 emblem_id;
-	uint32 unknown;
-#endif
-} __attribute__((packed));
-
 struct PACKET_ZC_BROADCAST{
 	int16 packetType;
 	int16 PacketLength;
@@ -252,69 +239,12 @@ struct PACKET_ZC_REPUTE_INFO{
 	struct PACKET_ZC_REPUTE_INFO_sub list[];
 } __attribute__((packed));
 
-struct PACKET_ZC_OPEN_REFORM_UI{
-	int16 packetType;
-	uint32 itemId;
-} __attribute__((packed));
-
-struct PACKET_CZ_CLOSE_REFORM_UI{
-	int16 packetType;
-} __attribute__((packed));
-
-struct PACKET_CZ_ITEM_REFORM{
-	int16 packetType;
-	uint32 itemId;
-	uint16 index;
-} __attribute__((packed));
-
-struct PACKET_ZC_ITEM_REFORM_ACK{
-	int16 packetType;
-	uint16 index;
-	uint8 result;
-} __attribute__((packed));
-
 struct PACKET_ZC_UI_OPEN_V3{
 	int16 packetType;
 	uint8 type;
 	uint64 data;
 } __attribute__((packed));
 
-struct PACKET_CZ_REQUEST_RANDOM_ENCHANT{
-	int16 packetType;
-	uint64 clientLuaIndex;
-	uint16 index;
-} __attribute__((packed));
-
-struct PACKET_CZ_REQUEST_PERFECT_ENCHANT{
-	int16 packetType;
-	uint64 clientLuaIndex;
-	uint16 index;
-	uint32 itemId;
-} __attribute__((packed));
-
-struct PACKET_CZ_REQUEST_UPGRADE_ENCHANT{
-	int16 packetType;
-	uint64 clientLuaIndex;
-	uint16 index;
-	uint16 slot;
-} __attribute__((packed));
-
-struct PACKET_CZ_REQUEST_RESET_ENCHANT{
-	int16 packetType;
-	uint64 clientLuaIndex;
-	uint16 index;
-} __attribute__((packed));
-
-struct PACKET_ZC_RESPONSE_ENCHANT{
-	int16 packetType;
-	uint32 messageId;
-	uint32 enchantItemId;
-} __attribute__((packed));
-
-struct PACKET_CZ_CLOSE_UI_ENCHANT{
-	int16 packetType;
-} __attribute__((packed));
-
 struct PACKET_ZC_TARGET_SPIRITS {
 	int16 packetType;
 	uint32 GID;
@@ -322,14 +252,6 @@ struct PACKET_ZC_TARGET_SPIRITS {
 	uint16 amount;
 } __attribute__((packed));
 
-struct PACKET_CZ_USE_PACKAGEITEM{
-	int16 PacketType;
-	uint16 index;
-	uint32 AID;
-	uint32 itemID;
-	uint32 BoxIndex;
-} __attribute__((packed));
-
 struct PACKET_ZC_FRIENDS_LIST_sub{
 	uint32 AID;
 	uint32 CID;
@@ -418,11 +340,6 @@ struct PACKET_ZC_COUPLENAME {
 	char name[NAME_LENGTH];
 } __attribute__((packed));
 
-struct PACKET_ZC_DYNAMICNPC_CREATE_RESULT{
-	int16 packetType;
-	int32 result;
-} __attribute__((packed));
-
 struct PACKET_CZ_PARTY_REQ_MASTER_TO_JOIN{
 	int16 packetType;
 	uint32 CID;
@@ -481,6 +398,23 @@ struct PACKET_CZ_REQ_MERGE_ITEM{
 	uint16 indices[];
 } __attribute__((packed));
 
+struct PACKET_CZ_RESET_SKILL{
+	int16 packetType;
+	uint8 unknown;
+} __attribute__((packed));
+
+struct PACKET_ZC_BOSS_INFO{
+	int16 packetType;
+	uint8 type;
+	uint32 x;
+	uint32 y;
+	uint16 minHours;
+	uint16 minMinutes;
+	uint16 maxHours;
+	uint16 maxMinutes;
+	char name[51];
+} __attribute__((packed));
+
 // NetBSD 5 and Solaris don't like pragma pack but accept the packed attribute
 #if !defined( sun ) && ( !defined( __NETBSD__ ) || __NetBSD_Version__ >= 600000000 )
 	#pragma pack( pop )
@@ -502,17 +436,13 @@ DEFINE_PACKET_HEADER(ZC_BROADCAST2, 0x1c3)
 #else
 	DEFINE_PACKET_HEADER(CZ_REQ_ITEMREPAIR, 0x1fd)
 #endif
-#if PACKETVER >= 20190724
-	DEFINE_PACKET_HEADER(ZC_CHANGE_GUILD, 0x0b47)
-#else
-	DEFINE_PACKET_HEADER(ZC_CHANGE_GUILD, 0x1b4)
-#endif
 DEFINE_PACKET_HEADER(ZC_COUPLENAME, 0x1e6);
 DEFINE_PACKET_HEADER(ZC_FRIENDS_LIST, 0x201)
 DEFINE_PACKET_HEADER(ZC_NOTIFY_WEAPONITEMLIST, 0x221)
 DEFINE_PACKET_HEADER(ZC_ACK_WEAPONREFINE, 0x223)
 DEFINE_PACKET_HEADER(CZ_REQ_MAKINGITEM, 0x25b)
 DEFINE_PACKET_HEADER(ZC_PC_CASH_POINT_ITEMLIST, 0x287)
+DEFINE_PACKET_HEADER(ZC_BOSS_INFO, 0x293)
 DEFINE_PACKET_HEADER(ZC_CASH_TIME_COUNTER, 0x298)
 DEFINE_PACKET_HEADER(ZC_CASH_ITEM_DELETE, 0x299)
 DEFINE_PACKET_HEADER(ZC_NOTIFY_BIND_ON_EQUIP, 0x2d3)
@@ -537,7 +467,6 @@ DEFINE_PACKET_HEADER(ZC_ACK_OPEN_BANKING, 0x9b7)
 DEFINE_PACKET_HEADER(ZC_ACK_CLOSE_BANKING, 0x9b9)
 DEFINE_PACKET_HEADER(ZC_ACK_COUNT_BARGAIN_SALE_ITEM, 0x9c4)
 DEFINE_PACKET_HEADER(ZC_ACK_GUILDSTORAGE_LOG, 0x9da)
-DEFINE_PACKET_HEADER(ZC_DYNAMICNPC_CREATE_RESULT, 0xa17)
 DEFINE_PACKET_HEADER(CZ_REQ_APPLY_BARGAIN_SALE_ITEM2, 0xa3d)
 DEFINE_PACKET_HEADER(CZ_REQ_STYLE_CHANGE, 0xa46)
 DEFINE_PACKET_HEADER(ZC_STYLE_CHANGE_RES, 0xa47)
@@ -557,18 +486,8 @@ DEFINE_PACKET_HEADER(CZ_UNCONFIRMED_RODEX_RETURN, 0xb98)
 DEFINE_PACKET_HEADER(ZC_SUMMON_HP_INIT, 0xb6b)
 DEFINE_PACKET_HEADER(ZC_SUMMON_HP_UPDATE, 0xb6c)
 DEFINE_PACKET_HEADER(ZC_REPUTE_INFO, 0x0b8d)
-DEFINE_PACKET_HEADER(ZC_OPEN_REFORM_UI, 0x0b8f)
-DEFINE_PACKET_HEADER(CZ_CLOSE_REFORM_UI, 0x0b90)
-DEFINE_PACKET_HEADER(CZ_ITEM_REFORM, 0x0b91)
-DEFINE_PACKET_HEADER(ZC_ITEM_REFORM_ACK, 0x0b92)
 DEFINE_PACKET_HEADER(ZC_UI_OPEN_V3, 0x0b9a)
-DEFINE_PACKET_HEADER(CZ_REQUEST_RANDOM_ENCHANT, 0x0b9b)
-DEFINE_PACKET_HEADER(CZ_REQUEST_PERFECT_ENCHANT, 0x0b9c)
-DEFINE_PACKET_HEADER(CZ_REQUEST_UPGRADE_ENCHANT, 0x0b9d)
-DEFINE_PACKET_HEADER(CZ_REQUEST_RESET_ENCHANT, 0x0b9e)
-DEFINE_PACKET_HEADER(ZC_RESPONSE_ENCHANT, 0x0b9f)
-DEFINE_PACKET_HEADER(CZ_CLOSE_UI_ENCHANT, 0x0ba0)
-DEFINE_PACKET_HEADER(CZ_USE_PACKAGEITEM, 0x0baf)
+DEFINE_PACKET_HEADER(CZ_RESET_SKILL, 0x0bb1)
 DEFINE_PACKET_HEADER(CZ_PC_SELL_ITEMLIST, 0x00c9)
 
 const int16 MAX_INVENTORY_ITEM_PACKET_NORMAL = ( ( INT16_MAX - ( sizeof( struct packet_itemlist_normal ) - ( sizeof( struct NORMALITEM_INFO ) * MAX_ITEMLIST) ) ) / sizeof( struct NORMALITEM_INFO ) );

+ 321 - 65
src/map/packets_struct.hpp

@@ -145,7 +145,7 @@ enum packet_headers {
 #else
 	inventorylistnormalType = 0xa3,
 #endif
-#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723
+#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723 || PACKETVER_ZERO_NUM >= 20221024
 	inventorylistequipType = 0xb39,
 #elif PACKETVER_MAIN_NUM >= 20181002 || PACKETVER_RE_NUM >= 20180912 || PACKETVER_ZERO_NUM >= 20180919
 	inventorylistequipType = 0xb0a,
@@ -171,7 +171,7 @@ enum packet_headers {
 #else
 	storageListNormalType = 0xa5,
 #endif
-#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723
+#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723 || PACKETVER_ZERO_NUM >= 20221024
 	storageListEquipType = 0xb39,
 #elif PACKETVER_MAIN_NUM >= 20181002 || PACKETVER_RE_NUM >= 20180829 || PACKETVER_ZERO_NUM >= 20180919
 	storageListEquipType = 0xb0a,
@@ -197,7 +197,7 @@ enum packet_headers {
 #else
 	cartlistnormalType = 0x123,
 #endif
-#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723
+#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723 || PACKETVER_ZERO_NUM >= 20221024
 	cartlistequipType = 0xb39,
 #elif PACKETVER_MAIN_NUM >= 20181002 || PACKETVER_RE_NUM >= 20180829 || PACKETVER_ZERO_NUM >= 20180919
 	cartlistequipType = 0xb0a,
@@ -211,13 +211,6 @@ enum packet_headers {
 	cartlistequipType = 0x297,
 #else
 	cartlistequipType = 0x122,
-#endif
-#if PACKETVER < 20100105
-	vendinglistType = 0x133,
-#elif !(PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723)
-	vendinglistType = 0x800,
-#else
-	vendinglistType = 0xb3d,
 #endif
 	openvendingType = 0x136,
 #if PACKETVER >= 20120925
@@ -350,9 +343,9 @@ enum packet_headers {
 #endif
 };
 
-#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723
+#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723 || PACKETVER_ZERO_NUM >= 20221024
 DEFINE_PACKET_ID(ZC_PAR_4JOB_CHANGE, 0x0b25);
-#endif  // PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723
+#endif  // PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723 || PACKETVER_ZERO_NUM >= 20221024
 
 #if !defined(sun) && (!defined(__NETBSD__) || __NetBSD_Version__ >= 600000000) // NetBSD 5 and Solaris don't like pragma pack but accept the packed attribute
 #pragma pack(push, 1)
@@ -482,9 +475,9 @@ struct EQUIPITEM_INFO {
 #if PACKETVER < 20120925
 	uint8 IsDamaged;
 #endif
-#if !(PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723)
+#if !(PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723 || PACKETVER_ZERO_NUM >= 20221024)
 	uint8 RefiningLevel;
-#endif  // !(PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723)
+#endif  // !(PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723 || PACKETVER_ZERO_NUM >= 20221024)
 	struct EQUIPSLOTINFO slot;
 #if PACKETVER >= 20071002
 	int32 HireExpireDate;
@@ -499,10 +492,10 @@ struct EQUIPITEM_INFO {
 	uint8 option_count;
 	struct ItemOptions option_data[MAX_ITEM_OPTIONS];
 #endif
-#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723
+#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723 || PACKETVER_ZERO_NUM >= 20221024
 	uint8 RefiningLevel;
-	uint8 enchantgrade;
-#endif  // PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723
+	uint8 grade;
+#endif  // PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723 || PACKETVER_ZERO_NUM >= 20221024
 #if PACKETVER >= 20120925
 	struct {
 		uint8 IsIdentified : 1;
@@ -555,9 +548,9 @@ struct PACKET_ZC_ITEM_PICKUP_ACK {
 #endif
 	uint8 IsIdentified;
 	uint8 IsDamaged;
-#if !(PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723)
+#if !(PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723 || PACKETVER_ZERO_NUM >= 20221024)
 	uint8 refiningLevel;
-#endif  // !(PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723)
+#endif  // !(PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723 || PACKETVER_ZERO_NUM >= 20221024)
 	struct EQUIPSLOTINFO slot;
 #if PACKETVER >= 20120925
 	uint32 location;
@@ -579,13 +572,13 @@ struct PACKET_ZC_ITEM_PICKUP_ACK {
 	uint8 favorite;
 	uint16 look;
 #endif
-#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723
+#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723 || PACKETVER_ZERO_NUM >= 20221024
 	uint8 refiningLevel;
 	uint8 grade;
-#endif  // PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723
+#endif  // PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723 || PACKETVER_ZERO_NUM >= 20221024
 } __attribute__((packed));
 
-#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723
+#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723 || PACKETVER_ZERO_NUM >= 20221024
 DEFINE_PACKET_HEADER(ZC_ITEM_PICKUP_ACK, 0x0b41);
 #elif PACKETVER >= 20160921
 DEFINE_PACKET_HEADER(ZC_ITEM_PICKUP_ACK, 0x0a37);
@@ -1311,7 +1304,7 @@ struct packet_unequipitem_ack {
 	uint8 result;
 } __attribute__((packed));
 
-#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723
+#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723 || PACKETVER_ZERO_NUM >= 20221024
 struct PACKET_ZC_EQUIPWIN_MICROSCOPE {
 	int16 PacketType;
 	int16 PacketLength;
@@ -1524,7 +1517,7 @@ struct PACKET_CZ_NPC_MARKET_PURCHASE {
 DEFINE_PACKET_HEADER(CZ_NPC_MARKET_PURCHASE, 0x09d6)
 #endif
 
-#if PACKETVER_MAIN_NUM >= 20210203 || PACKETVER_RE_NUM >= 20211103
+#if PACKETVER_MAIN_NUM >= 20210203 || PACKETVER_RE_NUM >= 20211103 || PACKETVER_ZERO_NUM >= 20221024
 struct PACKET_ZC_NPC_MARKET_OPEN_sub {
 #if PACKETVER_MAIN_NUM >= 20181121 || PACKETVER_RE_NUM >= 20180704 || PACKETVER_ZERO_NUM >= 20181114
 	uint32 nameid;
@@ -1741,7 +1734,7 @@ struct PACKET_CZ_ADD_ITEM_TO_MAIL {
 // [4144] this packet exists from
 // PACKETVER_MAIN_NUM >= 20141112 || PACKETVER_RE_NUM >= 20140924 || defined(PACKETVER_ZERO)
 // but used only packet versions with known struct
-#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723
+#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723 || PACKETVER_ZERO_NUM >= 20221024
 struct PACKET_ZC_ACK_ADD_ITEM_RODEX {
 	int16 PacketType;
 	int8 result;
@@ -1924,7 +1917,7 @@ struct PACKET_CZ_REQ_READ_MAIL {
 	int64 MailID;
 } __attribute__((packed));
 
-#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723
+#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723 || PACKETVER_ZERO_NUM >= 20221024
 struct PACKET_ZC_ACK_READ_RODEX_SUB {
 	int16 count;
 #if PACKETVER_MAIN_NUM >= 20181121 || PACKETVER_RE_NUM >= 20180704 || PACKETVER_ZERO_NUM >= 20181114
@@ -2259,14 +2252,14 @@ struct PACKET_ZC_UI_OPEN {
 DEFINE_PACKET_HEADER(ZC_UI_OPEN, 0x0a38);
 #endif
 
-#if PACKETVER_MAIN_NUM >= 20210203 || PACKETVER_RE_NUM >= 20211103
+#if PACKETVER_MAIN_NUM >= 20210203 || PACKETVER_RE_NUM >= 20211103 || PACKETVER_ZERO_NUM >= 20221024
 struct PACKET_ZC_UI_OPEN2 {
 	int16 PacketType;
 	int8 UIType;
 	int64 data;
 } __attribute__((packed));
 DEFINE_PACKET_HEADER(ZC_UI_OPEN2, 0x0b9a);
-#endif  // PACKETVER_MAIN_NUM >= 20210203 || PACKETVER_RE_NUM >= 20211103
+#endif  // PACKETVER_MAIN_NUM >= 20210203 || PACKETVER_RE_NUM >= 20211103 || PACKETVER_ZERO_NUM >= 20221024
 
 struct PACKET_ZC_UI_ACTION {
 	int16 PacketType;
@@ -2370,7 +2363,7 @@ struct PACKET_ZC_ITEM_ENTRY {
 	uint8 subY;
 } __attribute__((packed));
 
-#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723
+#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723 || PACKETVER_ZERO_NUM >= 20221024
 struct PACKET_ZC_ADD_ITEM_TO_STORE {
 	int16 packetType;
 	int16 index;
@@ -2386,7 +2379,7 @@ struct PACKET_ZC_ADD_ITEM_TO_STORE {
 	struct EQUIPSLOTINFO slot;
 	struct ItemOptions option_data[MAX_ITEM_OPTIONS];
 	uint8 refine;
-	uint8 enchantgrade;
+	uint8 grade;
 } __attribute__((packed));
 DEFINE_PACKET_HEADER(ZC_ADD_ITEM_TO_STORE, 0x0b44)
 #elif PACKETVER_MAIN_NUM >= 20140813 || PACKETVER_RE_NUM >= 20140402 || defined(PACKETVER_ZERO)
@@ -2467,7 +2460,7 @@ struct PACKET_ZC_ACK_TOUSESKILL {
 } __attribute__((packed));
 DEFINE_PACKET_HEADER(ZC_ACK_TOUSESKILL, 0x0110)
 
-#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723
+#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723 || PACKETVER_ZERO_NUM >= 20221024
 struct PACKET_ZC_ADD_ITEM_TO_CART {
 	int16 packetType;
 	int16 index;
@@ -2628,9 +2621,9 @@ struct PACKET_ZC_ADD_EXCHANGE_ITEM {
 #endif
 	uint8 identified;
 	uint8 damaged;
-#if !(PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723)
+#if !(PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723 || PACKETVER_ZERO_NUM >= 20221024)
 	uint8 refine;
-#endif  // !(PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723)
+#endif  // !(PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723 || PACKETVER_ZERO_NUM >= 20221024)
 	struct EQUIPSLOTINFO slot;
 #if PACKETVER >= 20150226
 	struct ItemOptions option_data[MAX_ITEM_OPTIONS];
@@ -2639,13 +2632,13 @@ struct PACKET_ZC_ADD_EXCHANGE_ITEM {
 	uint32 location;
 	uint16 look;
 #endif  // PACKETVER_MAIN_NUM >= 20161102 || PACKETVER_RE_NUM >= 20161026 || defined(PACKETVER_ZERO)
-#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723
+#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723 || PACKETVER_ZERO_NUM >= 20221024
 	uint8 refine;
 	uint8 grade;
-#endif  // PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723
+#endif  // PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723 || PACKETVER_ZERO_NUM >= 20221024
 } __attribute__((packed));
 
-#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723
+#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723 || PACKETVER_ZERO_NUM >= 20221024
 DEFINE_PACKET_HEADER(ZC_ADD_EXCHANGE_ITEM, 0x0b42);
 #elif PACKETVER_MAIN_NUM >= 20161102 || PACKETVER_RE_NUM >= 20161026 || defined(PACKETVER_ZERO)
 DEFINE_PACKET_HEADER(ZC_ADD_EXCHANGE_ITEM, 0x0a96);
@@ -2677,7 +2670,7 @@ struct PACKET_ZC_CASH_ITEM_DELETE {
 #endif
 } __attribute__((packed));
 
-#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723
+#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723 || PACKETVER_ZERO_NUM >= 20221024
 struct PACKET_ZC_ITEM_PICKUP_PARTY {
 	int16 packetType;
 	uint32 AID;
@@ -2742,7 +2735,7 @@ struct PACKET_ZC_ACK_WEAPONREFINE {
 #endif
 } __attribute__((packed));
 
-#if PACKETVER_MAIN_NUM >= 20210303 || PACKETVER_RE_NUM >= 20211103
+#if PACKETVER_MAIN_NUM >= 20210303 || PACKETVER_RE_NUM >= 20211103 || PACKETVER_ZERO_NUM >= 20221024
 // PACKET_ZC_PROPERTY_HOMUN4
 struct PACKET_ZC_PROPERTY_HOMUN {
 	int16 packetType;
@@ -2927,7 +2920,7 @@ struct REPAIRITEM_INFO2 {
 	uint8 refine;  // unused?
 	struct EQUIPSLOTINFO slot;  // unused?
 } __attribute__((packed));
-#endif  // PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723
+#endif  // PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723 || PACKETVER_ZERO_NUM >= 20221024
 
 struct REPAIRITEM_INFO1 {
 	int16 index;
@@ -2996,7 +2989,7 @@ struct PACKET_ZC_ACK_SCHEDULER_CASHITEM {
 	struct PACKET_ZC_ACK_SCHEDULER_CASHITEM_sub items[];
 } __attribute__((packed));
 
-#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723
+#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723 || PACKETVER_ZERO_NUM >= 20221024
 struct PACKET_ZC_PC_PURCHASE_MYITEMLIST_sub {
 	uint32 price;
 	int16 index;
@@ -3021,7 +3014,7 @@ struct PACKET_ZC_PC_PURCHASE_MYITEMLIST {
 	struct PACKET_ZC_PC_PURCHASE_MYITEMLIST_sub items[];
 } __attribute__((packed));
 DEFINE_PACKET_HEADER(ZC_PC_PURCHASE_MYITEMLIST, 0x0b40);
-#else  // PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723
+#else  // PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723 || PACKETVER_ZERO_NUM >= 20221024
 struct PACKET_ZC_PC_PURCHASE_MYITEMLIST_sub {
 	uint32 price;
 	int16 index;
@@ -3047,9 +3040,9 @@ struct PACKET_ZC_PC_PURCHASE_MYITEMLIST {
 	struct PACKET_ZC_PC_PURCHASE_MYITEMLIST_sub items[];
 } __attribute__((packed));
 DEFINE_PACKET_HEADER(ZC_PC_PURCHASE_MYITEMLIST, 0x0136);
-#endif  // PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723
+#endif  // PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723 || PACKETVER_ZERO_NUM >= 20221024
 
-#if PACKETVER_MAIN_NUM >= 20210203 || PACKETVER_RE_NUM >= 20211103
+#if PACKETVER_MAIN_NUM >= 20210203 || PACKETVER_RE_NUM >= 20211103 || PACKETVER_ZERO_NUM >= 20221024
 struct PACKET_ZC_PC_PURCHASE_ITEMLIST_sub {
 #if PACKETVER_MAIN_NUM >= 20181121 || PACKETVER_RE_NUM >= 20180704 || PACKETVER_ZERO_NUM >= 20181114
 	uint32 itemId;
@@ -3140,7 +3133,7 @@ struct PACKET_ZC_MYITEMLIST_BUYING_STORE {
 	struct PACKET_ZC_MYITEMLIST_BUYING_STORE_sub items[];
 } __attribute__((packed));
 
-#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723
+#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723 || PACKETVER_ZERO_NUM >= 20221024
 struct PACKET_ZC_PC_PURCHASE_ITEMLIST_FROMMC_sub {
 	uint32 price;
 	uint16 amount;
@@ -3182,7 +3175,7 @@ struct PACKET_ZC_PC_PURCHASE_ITEMLIST_FROMMC_sub {
 #endif
 	uint8 identified;
 	uint8 damaged;
-#if !(PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723)
+#if !(PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723 || PACKETVER_ZERO_NUM >= 20221024)
 	uint8 refine;
 #endif
 	struct EQUIPSLOTINFO slot;
@@ -3194,7 +3187,7 @@ struct PACKET_ZC_PC_PURCHASE_ITEMLIST_FROMMC_sub {
 	uint32 location;
 	uint16 viewSprite;
 #endif
-#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723
+#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723 || PACKETVER_ZERO_NUM >= 20221024
 	uint8 refine;
 	uint8 grade;
 #endif
@@ -3304,7 +3297,7 @@ struct PACKET_ZC_MAKINGARROW_LIST {
 } __attribute__((packed));
 DEFINE_PACKET_HEADER(ZC_MAKINGARROW_LIST, 0x01ad);
 
-#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723
+#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723 || PACKETVER_ZERO_NUM >= 20221024
 #define REPAIRITEM_INFO REPAIRITEM_INFO2
 struct PACKET_ZC_REPAIRITEMLIST {
 	int16 packetType;
@@ -3312,7 +3305,7 @@ struct PACKET_ZC_REPAIRITEMLIST {
 	struct REPAIRITEM_INFO items[];
 } __attribute__((packed));
 DEFINE_PACKET_HEADER(ZC_REPAIRITEMLIST, 0x0b65);
-#else  // PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723
+#else  // PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723 || PACKETVER_ZERO_NUM >= 20221024
 #define REPAIRITEM_INFO REPAIRITEM_INFO1
 struct PACKET_ZC_REPAIRITEMLIST {
 	int16 packetType;
@@ -3320,7 +3313,7 @@ struct PACKET_ZC_REPAIRITEMLIST {
 	struct REPAIRITEM_INFO items[];
 } __attribute__((packed));
 DEFINE_PACKET_HEADER(ZC_REPAIRITEMLIST, 0x01fc);
-#endif  // PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723
+#endif  // PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723 || PACKETVER_ZERO_NUM >= 20221024
 
 struct PACKET_ZC_NOTIFY_WEAPONITEMLIST_sub {
 	int16 index;
@@ -3428,7 +3421,7 @@ struct PACKET_CZ_SEARCH_STORE_INFO {
 */
 } __attribute__((packed));
 
-#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723
+#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723 || PACKETVER_ZERO_NUM >= 20221024
 struct PACKET_ZC_SEARCH_STORE_INFO_ACK_sub {
 	uint32 storeId;
 	uint32 AID;
@@ -3710,7 +3703,7 @@ struct PACKET_ZC_AUTOSPELLLIST {
 DEFINE_PACKET_HEADER(ZC_AUTOSPELLLIST, 0x01cd);
 #endif
 
-#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723
+#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723 || PACKETVER_ZERO_NUM >= 20221024
 struct PACKET_ZC_CHANGE_ITEM_OPTION {
 	int16 packetType;
 	int16 index;
@@ -3840,7 +3833,7 @@ struct PACKET_CZ_PARTY_CONFIG {
 } __attribute__((packed));
 DEFINE_PACKET_HEADER(CZ_PARTY_CONFIG, 0x02c8);
 
-#if PACKETVER_MAIN_NUM >= 20210203 || PACKETVER_RE_NUM >= 20211103
+#if PACKETVER_MAIN_NUM >= 20210203 || PACKETVER_RE_NUM >= 20211103 || PACKETVER_ZERO_NUM >= 20221024
 struct PACKET_ZC_NPC_BARTER_MARKET_ITEMINFO_sub {
 #if PACKETVER_MAIN_NUM >= 20181121 || PACKETVER_RE_NUM >= 20180704 || PACKETVER_ZERO_NUM >= 20181114
 	uint32 nameid;
@@ -4523,7 +4516,7 @@ struct PACKET_CZ_NPC_EXPANDED_BARTER_MARKET_CLOSE {
 DEFINE_PACKET_HEADER(CZ_NPC_EXPANDED_BARTER_MARKET_CLOSE, 0x0b58);
 #endif
 
-#if PACKETVER_MAIN_NUM >= 20210203 || PACKETVER_RE_NUM >= 20211103
+#if PACKETVER_MAIN_NUM >= 20210203 || PACKETVER_RE_NUM >= 20211103 || PACKETVER_ZERO_NUM >= 20221024
 struct PACKET_ZC_NPC_EXPANDED_BARTER_MARKET_ITEMINFO_sub2 {
 #if PACKETVER_MAIN_NUM >= 20181121 || PACKETVER_RE_NUM >= 20180704 || PACKETVER_ZERO_NUM >= 20181114
 	uint32 nameid;
@@ -5264,13 +5257,13 @@ struct PACKET_CZ_REQ_TAKEOFF_EQUIP_ALL {
 DEFINE_PACKET_HEADER(CZ_REQ_TAKEOFF_EQUIP_ALL, 0x0bad);
 #endif  // PACKETVER_MAIN_NUM >= 20210818 || PACKETVER_RE_NUM >= 20211103 || PACKETVER_ZERO_NUM >= 20210818
 
-#if PACKETVER_MAIN_NUM >= 20210818 || PACKETVER_RE_NUM >= 20211103
+#if PACKETVER_MAIN_NUM >= 20210818 || PACKETVER_RE_NUM >= 20211103 || PACKETVER_ZERO_NUM >= 20221024
 struct PACKET_ZC_ACK_TAKEOFF_EQUIP_ALL {
 	int16 PacketType;
 	uint8 result;
 } __attribute__((packed));
 DEFINE_PACKET_HEADER(ZC_ACK_TAKEOFF_EQUIP_ALL, 0x0bae);
-#endif  // PACKETVER_MAIN_NUM >= 20210818 || PACKETVER_RE_NUM >= 20211103
+#endif  // PACKETVER_MAIN_NUM >= 20210818 || PACKETVER_RE_NUM >= 20211103 || PACKETVER_ZERO_NUM >= 20221024
 
 #if PACKETVER_ZERO_NUM >= 20210504
 struct PACKET_ZC_BATTLEFIELD_NOTIFY_HP {
@@ -5340,13 +5333,13 @@ struct PACKET_CZ_CHOOSE_MENU_ZERO {
 DEFINE_PACKET_HEADER(CZ_CHOOSE_MENU_ZERO, 0x0ba8);
 #endif  // PACKETVER_MAIN_NUM >= 20210317 || PACKETVER_RE_NUM >= 20211103 || PACKETVER_ZERO_NUM >= 20210317
 
-#if PACKETVER_MAIN_NUM >= 20210203 || PACKETVER_RE_NUM >= 20211103
+#if PACKETVER_MAIN_NUM >= 20210203 || PACKETVER_RE_NUM >= 20211103 || PACKETVER_ZERO_NUM >= 20221024
 struct PACKET_ZC_DIALOG_TEXT_ALIGN {
 	int16 PacketType;
 	uint8 align;
 } __attribute__((packed));
 DEFINE_PACKET_HEADER(ZC_DIALOG_TEXT_ALIGN, 0x0ba1);
-#endif  // PACKETVER_MAIN_NUM >= 20210203 || PACKETVER_RE_NUM >= 20211103
+#endif  // PACKETVER_MAIN_NUM >= 20210203 || PACKETVER_RE_NUM >= 20211103 || PACKETVER_ZERO_NUM >= 20221024
 
 #if PACKETVER_MAIN_NUM >= 20191016 || PACKETVER_RE_NUM >= 20191016 || PACKETVER_ZERO_NUM >= 20191008
 struct PACKET_CZ_GRADE_ENCHANT_SELECT_EQUIPMENT {
@@ -5356,7 +5349,7 @@ struct PACKET_CZ_GRADE_ENCHANT_SELECT_EQUIPMENT {
 DEFINE_PACKET_HEADER(CZ_GRADE_ENCHANT_SELECT_EQUIPMENT, 0x0b59);
 #endif
 
-#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723
+#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723 || PACKETVER_ZERO_NUM >= 20221024
 struct GRADE_ENCHANT_BLESSING {
 	int32 id;
 	int32 amount;
@@ -5404,7 +5397,7 @@ struct PACKET_CZ_GRADE_ENCHANT_CLOSE_UI {
 DEFINE_PACKET_HEADER(CZ_GRADE_ENCHANT_CLOSE_UI, 0x0b5c);
 #endif
 
-#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723
+#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723 || PACKETVER_ZERO_NUM >= 20221024
 struct PACKET_ZC_GRADE_ENCHANT_ACK {
 	int16 PacketType;
 	int16 index;
@@ -5414,7 +5407,7 @@ struct PACKET_ZC_GRADE_ENCHANT_ACK {
 DEFINE_PACKET_HEADER(ZC_GRADE_ENCHANT_ACK, 0x0b5d);
 #endif
 
-#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723
+#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200723 || PACKETVER_ZERO_NUM >= 20221024
 struct PACKET_ZC_GRADE_ENCHANT_BROADCAST_RESULT {
 	int16 packetType;
 	char name[NAME_LENGTH];
@@ -5462,7 +5455,7 @@ struct PACKET_ZC_WHISPER {
 DEFINE_PACKET_HEADER(ZC_WHISPER, 0x0097)
 #endif  // PACKETVER_MAIN_NUM >= 20131204 || PACKETVER_RE_NUM >= 20131120 || defined(PACKETVER_ZERO)
 
-#if PACKETVER_MAIN_NUM >= 20220216
+#if PACKETVER_MAIN_NUM >= 20220216 || PACKETVER_ZERO_NUM >= 20221024
 struct PACKET_ZC_UPDATE_GDID {
 	int16 PacketType;
 	uint32 guildId;
@@ -5474,7 +5467,7 @@ struct PACKET_ZC_UPDATE_GDID {
 	uint32 masterGID;
 } __attribute__((packed));
 DEFINE_PACKET_HEADER(ZC_UPDATE_GDID, 0x02f7)
-#else  // PACKETVER_MAIN_NUM >= 20220216
+#else  // PACKETVER_MAIN_NUM >= 20220216 || PACKETVER_ZERO_NUM >= 20221024
 struct PACKET_ZC_UPDATE_GDID {
 	int16 PacketType;
 	uint32 guildId;
@@ -5485,9 +5478,9 @@ struct PACKET_ZC_UPDATE_GDID {
 	char guildName[NAME_LENGTH];
 } __attribute__((packed));
 DEFINE_PACKET_HEADER(ZC_UPDATE_GDID, 0x016c)
-#endif  // PACKETVER_MAIN_NUM >= 20220216
+#endif  // PACKETVER_MAIN_NUM >= 20220216 || PACKETVER_ZERO_NUM >= 20221024
 
-#if PACKETVER_MAIN_NUM >= 20220216
+#if PACKETVER_MAIN_NUM >= 20220216 || PACKETVER_ZERO_NUM >= 20221024
 struct PACKET_CZ_APPROXIMATE_ACTOR {
 	int16 PacketType;
 	uint32 masterGID;
@@ -5495,7 +5488,7 @@ struct PACKET_CZ_APPROXIMATE_ACTOR {
 	uint8 unused2;
 } __attribute__((packed));
 DEFINE_PACKET_HEADER(CZ_APPROXIMATE_ACTOR, 0x0bb0)
-#endif  // PACKETVER_MAIN_NUM >= 20220216
+#endif  // PACKETVER_MAIN_NUM >= 20220216 || PACKETVER_ZERO_NUM >= 20221024
 
 struct PACKET_CZ_CONTACTNPC {
 	int16 PacketType;
@@ -5708,6 +5701,269 @@ struct PACKET_ZC_DISAPPEAR_BUYING_STORE_ENTRY {
 DEFINE_PACKET_HEADER(ZC_DISAPPEAR_BUYING_STORE_ENTRY, 0x0816);
 #endif
 
+#if PACKETVER_MAIN_NUM >= 20201118 || PACKETVER_RE_NUM >= 20211103 || PACKETVER_ZERO_NUM >= 20221024
+struct PACKET_ZC_OPEN_REFORM_UI {
+	int16 PacketType;
+	int32 ITID;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_OPEN_REFORM_UI, 0x0b8f);
+#endif  // PACKETVER_MAIN_NUM >= 20201118 || PACKETVER_RE_NUM >= 20211103 || PACKETVER_ZERO_NUM >= 20221024
+
+#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20211103 || PACKETVER_ZERO_NUM >= 20221024
+struct PACKET_CZ_CLOSE_REFORM_UI {
+	int16 PacketType;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(CZ_CLOSE_REFORM_UI, 0x0b90);
+#endif  // PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20211103 || PACKETVER_ZERO_NUM >= 20221024
+
+#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20211103 || PACKETVER_ZERO_NUM >= 20221024
+struct PACKET_CZ_ITEM_REFORM {
+	int16 PacketType;
+	int32 ITID;
+	int16 index;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(CZ_ITEM_REFORM, 0x0b91);
+#endif  // PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20211103 || PACKETVER_ZERO_NUM >= 20221024
+
+#if PACKETVER_MAIN_NUM >= 20201118 || PACKETVER_RE_NUM >= 20211103 || PACKETVER_ZERO_NUM >= 20221024
+struct PACKET_ZC_ITEM_REFORM_ACK {
+	int16 PacketType;
+	int16 index;
+	int8 result;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_ITEM_REFORM_ACK, 0x0b92);
+#endif  // PACKETVER_MAIN_NUM >= 20201118 || PACKETVER_RE_NUM >= 20211103 || PACKETVER_ZERO_NUM >= 20221024
+
+#if PACKETVER_MAIN_NUM >= 20220216 || PACKETVER_ZERO_NUM >= 20220316
+struct PACKET_CZ_USE_PACKAGEITEM {
+	int16 PacketType;
+	uint16 index;
+	uint32 AID;
+	uint32 itemID;
+	uint32 BoxIndex;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(CZ_USE_PACKAGEITEM, 0x0baf)
+#endif  // PACKETVER_MAIN_NUM >= 20220216 || PACKETVER_ZERO_NUM >= 20220316
+
+#if PACKETVER_MAIN_NUM >= 20201118 || PACKETVER_RE_NUM >= 20211103 || PACKETVER_ZERO_NUM >= 20221024
+struct PACKET_CZ_REQUEST_RANDOM_ENCHANT {
+	int16 PacketType;
+	int64 enchant_group;
+	int16 index;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(CZ_REQUEST_RANDOM_ENCHANT, 0x0b9b);
+#endif // PACKETVER_MAIN_NUM >= 20201118 || PACKETVER_RE_NUM >= 20211103 || PACKETVER_ZERO_NUM >= 20221024
+
+#if PACKETVER_MAIN_NUM >= 20201118 || PACKETVER_RE_NUM >= 20211103 || PACKETVER_ZERO_NUM >= 20221024
+struct PACKET_CZ_REQUEST_PERFECT_ENCHANT {
+	int16 PacketType;
+	int64 enchant_group;
+	int16 index;
+	uint32 ITID;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(CZ_REQUEST_PERFECT_ENCHANT, 0x0b9c);
+#endif // PACKETVER_MAIN_NUM >= 20201118 || PACKETVER_RE_NUM >= 20211103 || PACKETVER_ZERO_NUM >= 20221024
+
+#if PACKETVER_MAIN_NUM >= 20201118 || PACKETVER_RE_NUM >= 20211103 || PACKETVER_ZERO_NUM >= 20221024
+struct PACKET_CZ_REQUEST_UPGRADE_ENCHANT {
+	int16 PacketType;
+	int64 enchant_group;
+	int16 index;
+	int16 slot;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(CZ_REQUEST_UPGRADE_ENCHANT, 0x0b9d);
+#endif // PACKETVER_MAIN_NUM >= 20201118 || PACKETVER_RE_NUM >= 20211103 || PACKETVER_ZERO_NUM >= 20221024
+
+#if PACKETVER_MAIN_NUM >= 20201118 || PACKETVER_RE_NUM >= 20211103 || PACKETVER_ZERO_NUM >= 20221024
+struct PACKET_CZ_REQUEST_RESET_ENCHANT {
+	int16 PacketType;
+	int64 enchant_group;
+	int16 index;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(CZ_REQUEST_RESET_ENCHANT, 0x0b9e);
+#endif // PACKETVER_MAIN_NUM >= 20201118 || PACKETVER_RE_NUM >= 20211103 || PACKETVER_ZERO_NUM >= 20221024
+
+#if PACKETVER_MAIN_NUM >= 20210203 || PACKETVER_RE_NUM >= 20211103 || PACKETVER_ZERO_NUM >= 20221024
+struct PACKET_ZC_RESPONSE_ENCHANT {
+	int16 PacketType;
+	int32 msgId;
+	uint32 ITID;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_RESPONSE_ENCHANT, 0x0b9f);
+#endif // PACKETVER_MAIN_NUM >= 20201118 || PACKETVER_RE_NUM >= 20211103 || PACKETVER_ZERO_NUM >= 20221024
+
+#if PACKETVER_MAIN_NUM >= 20201118 || PACKETVER_RE_NUM >= 20211103 || PACKETVER_ZERO_NUM >= 20221024
+struct PACKET_CZ_CLOSE_UI_ENCHANT {
+	int16 PacketType;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(CZ_CLOSE_UI_ENCHANT, 0x0ba0);
+#endif // PACKETVER_MAIN_NUM >= 20201118 || PACKETVER_RE_NUM >= 20211103 || PACKETVER_ZERO_NUM >= 20221024
+
+#if PACKETVER_MAIN_NUM >= 20221005
+struct PACKET_ZC_SPECIALPOPUP {
+	int16 PacketType;
+	int32 ppId;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_SPECIALPOPUP, 0x0bbe);
+#endif  // PACKETVER_MAIN_NUM >= 20221005
+
+#if PACKETVER >= 20140611
+struct PACKET_ZC_GOLDPCCAFE_POINT {
+	// Note: 2014-04-30 has 1 byte less, but those packets are only functional after 2014-06-11Ragexe
+	uint16 PacketType;
+	int8 isActive; //< 1 = yes, 0 = no
+	int8 mode;
+	int32 point;
+	int32 playedTime;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_GOLDPCCAFE_POINT , 0x0a15);
+#endif // PACKETVER >= 20140611
+
+#if PACKETVER >= 20140430
+struct PACKET_CZ_DYNAMICNPC_CREATE_REQUEST {
+	uint16 PacketType;
+	char name[NAME_LENGTH];
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(CZ_DYNAMICNPC_CREATE_REQUEST, 0x0a16);
+#endif // PACKETVER >= 20140430
+
+#if PACKETVER_MAIN_NUM >= 20140430 || PACKETVER_RE_NUM >= 20140430 || defined(PACKETVER_ZERO)
+struct PACKET_ZC_DYNAMICNPC_CREATE_RESULT {
+	uint16 PacketType;
+	uint32 result; // enum dynamicnpc_create_result
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_DYNAMICNPC_CREATE_RESULT , 0x0a17);
+#endif // PACKETVER_MAIN_NUM >= 20140430 || PACKETVER_RE_NUM >= 20140430 || defined(PACKETVER_ZERO)
+
+struct PACKET_CZ_REQ_GUILD_EMBLEM_IMG1 {
+	int16 packetType;
+	int32 guild_id;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(CZ_REQ_GUILD_EMBLEM_IMG1, 0x0151);
+
+#if PACKETVER >= 20190724
+struct PACKET_CZ_REQ_GUILD_EMBLEM_IMG3 {
+	int16 packetType;
+	int32 guild_id;
+	int32 emblem_id;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(CZ_REQ_GUILD_EMBLEM_IMG3, 0x0b46);
+#endif  // PACKETVER >= 20190724
+
+#if PACKETVER_MAIN_NUM >= 20190619 || PACKETVER_RE_NUM >= 20190605 || PACKETVER_ZERO_NUM >= 20190626
+struct PACKET_CZ_REQ_GUILD_EMBLEM_IMG2 {
+	int16 packetType;
+	int32 guild_id;
+	int32 emblem_id;
+	int32 unused;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(CZ_REQ_GUILD_EMBLEM_IMG2, 0x0b1e);
+#elif PACKETVER_MAIN_NUM >= 20190227 || PACKETVER_RE_NUM >= 20190227 || PACKETVER_ZERO_NUM >= 20190313
+struct PACKET_CZ_REQ_GUILD_EMBLEM_IMG2 {
+	int16 packetType;
+	int32 guild_id;
+	int32 emblem_id;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(CZ_REQ_GUILD_EMBLEM_IMG2, 0x0b1e);
+#endif  // PACKETVER_MAIN_NUM >= 20190619 || PACKETVER_RE_NUM >= 20190605 || PACKETVER_ZERO_NUM >= 20190626
+
+#if PACKETVER_MAIN_NUM >= 20190807 || PACKETVER_RE_NUM >= 20190731 || PACKETVER_ZERO_NUM >= 20190814
+struct PACKET_ZC_CHANGE_GUILD {
+	int16 packetType;
+	int32 guild_id;
+	uint32 emblem_id;
+	uint32 AID;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_CHANGE_GUILD, 0x0b47);
+// 20190619 main exists in first versions, then removed
+// 20190605 re first versions with other packet size
+#elif PACKETVER_MAIN_NUM >= 20190703 || PACKETVER_RE_NUM >= 20190605 || PACKETVER_ZERO_NUM >= 20190709
+struct PACKET_ZC_CHANGE_GUILD {
+	int16 packetType;
+	int32 guild_id;
+	uint32 emblem_id;
+	uint32 AID;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_CHANGE_GUILD, 0x0b1f);
+#else  // PACKETVER_MAIN_NUM >= 20190807 || PACKETVER_RE_NUM >= 20190731 || PACKETVER_ZERO_NUM >= 20190814
+struct PACKET_ZC_CHANGE_GUILD {
+	int16 packetType;
+	uint32 AID;
+	int32 guild_id;
+	uint16 emblem_id;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_CHANGE_GUILD, 0x01b4);
+#endif  // PACKETVER_MAIN_NUM >= 20190807 || PACKETVER_RE_NUM >= 20190731 || PACKETVER_ZERO_NUM >= 20190814
+
+#if PACKETVER_MAIN_NUM >= 20190821 || PACKETVER_RE_NUM >= 20190807 || PACKETVER_ZERO_NUM >= 20190710
+enum ZC_GUILD_EMBLEM_TYPE {
+	ZC_GUILD_EMBLEM_TYPE_CLEAR = 0,
+	ZC_GUILD_EMBLEM_TYPE_ADD = 1,
+	ZC_GUILD_EMBLEM_TYPE_COMPLETE = 2,
+};
+
+struct PACKET_ZC_GUILD_EMBLEM_IMG {
+	int16 packetType;
+	int16 packetLength;
+	uint16 result;
+	int32 guild_id;
+	uint32 emblem_id;
+	char emblem_data[];
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_GUILD_EMBLEM_IMG, 0x0b36);
+#else  // PACKETVER_MAIN_NUM >= 20190821 || PACKETVER_RE_NUM >= 20190807 || PACKETVER_ZERO_NUM >= 20190710
+struct PACKET_ZC_GUILD_EMBLEM_IMG {
+	int16 packetType;
+	int16 packetLength;
+	int32 guild_id;
+	uint32 emblem_id;
+	char emblem_data[];
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_GUILD_EMBLEM_IMG, 0x0152);
+#endif  // PACKETVER_MAIN_NUM >= 20190821 || PACKETVER_RE_NUM >= 20190807 || PACKETVER_ZERO_NUM >= 20190710
+
+#if PACKETVER_MAIN_NUM >= 20171213 || PACKETVER_RE_NUM >= 20171213 || PACKETVER_ZERO_NUM >= 20171214
+struct PACKET_CZ_ADVENTURER_AGENCY_JOIN_REQ {
+	int16 packetType;
+	int GID;
+	int AID;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(CZ_ADVENTURER_AGENCY_JOIN_REQ, 0x0ae6);
+#endif  // PACKETVER_MAIN_NUM >= 20171213 || PACKETVER_RE_NUM >= 20171213 || PACKETVER_ZERO_NUM >= 20171214
+
+#if PACKETVER_MAIN_NUM >= 20191218 || PACKETVER_RE_NUM >= 20191211 || PACKETVER_ZERO_NUM >= 20191224
+struct PACKET_ZC_ADVENTURER_AGENCY_JOIN_RESULT {
+	int16 packetType;
+	char player_name[NAME_LENGTH];
+	char party_name[NAME_LENGTH];
+	int AID;
+	int result;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_ADVENTURER_AGENCY_JOIN_RESULT, 0x0afa);
+#endif  // PACKETVER_MAIN_NUM >= 20191218 || PACKETVER_RE_NUM >= 20191211 || PACKETVER_ZERO_NUM >= 20191224
+
+#if PACKETVER_MAIN_NUM >= 20191218 || PACKETVER_RE_NUM >= 20191211 || PACKETVER_ZERO_NUM >= 20191224
+struct PACKET_ZC_ADVENTURER_AGENCY_JOIN_REQ {
+	int16 packetType;
+	int GRID;
+	int AID;
+	char groupName[NAME_LENGTH];
+	int16 level;
+	int16 job;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_ADVENTURER_AGENCY_JOIN_REQ, 0x0ae7);
+#endif  // PACKETVER_MAIN_NUM >= 20191218 || PACKETVER_RE_NUM >= 20191211 || PACKETVER_ZERO_NUM >= 20191224
+
+#if PACKETVER_MAIN_NUM >= 20191218 || PACKETVER_RE_NUM >= 20191211 || PACKETVER_ZERO_NUM >= 20191224
+struct PACKET_CZ_ADVENTURER_AGENCY_JOIN_RESULT {
+	int16 packetType;
+	int GRID;
+	int AID;
+	int8 result;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(CZ_ADVENTURER_AGENCY_JOIN_RESULT, 0x0af8);
+#endif  // PACKETVER_MAIN_NUM >= 20191218 || PACKETVER_RE_NUM >= 20191211 || PACKETVER_ZERO_NUM >= 20191224
+
 #if !defined(sun) && (!defined(__NETBSD__) || __NetBSD_Version__ >= 600000000) // NetBSD 5 and Solaris don't like pragma pack but accept the packed attribute
 #pragma pack(pop)
 #endif // not NetBSD < 6 / Solaris

+ 5 - 7
src/map/path.cpp

@@ -145,8 +145,8 @@ bool path_search_long(struct shootpath_data *spd,int16 m,int16 x0,int16 y0,int16
 
 	dx = (x1 - x0);
 	if (dx < 0) {
-		SWAP(x0, x1);
-		SWAP(y0, y1);
+		std::swap(x0, x1);
+		std::swap(y0, y1);
 		dx = -dx;
 	}
 	dy = (y1 - y0);
@@ -198,13 +198,11 @@ bool path_search_long(struct shootpath_data *spd,int16 m,int16 x0,int16 y0,int16
 /// Pushes path_node to the binary node_heap.
 /// Ensures there is enough space in array to store new element.
 
-#define swap_ptrcast_pathnode(a, b) swap_ptrcast(struct path_node *, a, b)
-
 static void heap_push_node(struct node_heap *heap, struct path_node *node)
 {
 #ifndef __clang_analyzer__ // TODO: Figure out why clang's static analyzer doesn't like this
 	BHEAP_ENSURE2(*heap, 1, 256, struct path_node **);
-	BHEAP_PUSH2(*heap, node, NODE_MINTOPCMP, swap_ptrcast_pathnode);
+	BHEAP_PUSH2(*heap, node, NODE_MINTOPCMP);
 #endif // __clang_analyzer__
 }
 
@@ -217,7 +215,7 @@ static int heap_update_node(struct node_heap *heap, struct path_node *node)
 		ShowError("heap_update_node: node not found\n");
 		return 1;
 	}
-	BHEAP_UPDATE(*heap, i, NODE_MINTOPCMP, swap_ptrcast_pathnode);
+	BHEAP_UPDATE(*heap, i, NODE_MINTOPCMP);
 	return 0;
 }
 
@@ -372,7 +370,7 @@ bool path_search(struct walkpath_data *wpd, int16 m, int16 x0, int16 y0, int16 x
 			}
 
 			current = BHEAP_PEEK(g_open_set); // Look for the lowest f_cost node in the 'open' set
-			BHEAP_POP2(g_open_set, NODE_MINTOPCMP, swap_ptrcast_pathnode); // Remove it from 'open' set
+			BHEAP_POP2(g_open_set, NODE_MINTOPCMP); // Remove it from 'open' set
 
 			x      = current->x;
 			y      = current->y;

+ 24 - 18
src/map/pc.cpp

@@ -4288,6 +4288,7 @@ void pc_bonus(map_session_data *sd,int type,int val)
 		case SP_LONG_SP_GAIN_VALUE:
 			if(!sd->state.lr_flag)
 				sd->bonus.long_sp_gain_value += val;
+			break;
 		case SP_LONG_HP_GAIN_VALUE:
 			if(!sd->state.lr_flag)
 				sd->bonus.long_hp_gain_value += val;
@@ -8642,7 +8643,7 @@ int pc_need_status_point(map_session_data* sd, int type, int val)
 	high = low + val;
 
 	if ( val < 0 )
-		SWAP(low, high);
+		std::swap(low, high);
 
 	for ( ; low < high; low++ )
 		sp += PC_STATUS_POINT_COST(low);
@@ -8800,7 +8801,7 @@ int pc_need_trait_point(map_session_data* sd, int type, int val)
 	int high = low + val, sp = 0;
 
 	if (val < 0)
-		SWAP(low, high);
+		std::swap(low, high);
 
 	for (; low < high; low++)
 		sp += 1;
@@ -14104,19 +14105,11 @@ const std::string PlayerStatPointDatabase::getDefaultLocation() {
 }
 
 uint64 PlayerStatPointDatabase::parseBodyNode(const ryml::NodeRef& node) {
-	if (!this->nodesExist(node, { "Level", "Points" })) {
-		return 0;
-	}
 
 	uint16 level;
 
 	if (!this->asUInt16(node, "Level", level))
-		return 0;
-
-	uint32 point;
-
-	if (!this->asUInt32(node, "Points", point))
-		return 0;
+	    return 0;
 
 	if (level == 0) {
 		this->invalidWarning(node["Level"], "The minimum level is 1.\n");
@@ -14132,19 +14125,32 @@ uint64 PlayerStatPointDatabase::parseBodyNode(const ryml::NodeRef& node) {
 	bool exists = entry != nullptr;
 
 	if( !exists ){
-		entry = std::make_shared<s_statpoint_entry>();
-		entry->level = level;
-		entry->statpoints = point;
+	    if( !this->nodesExist( node, { "Points" } ) ){
+			return 0;
+	    }
+
+	    entry = std::make_shared<s_statpoint_entry>();
+	    entry->level = level;
 	}
 
-	if( this->nodeExists( node, "TraitPoints" ) ){
-		uint32 traitpoints;
+	if( this->nodeExists( node, "Points" ) ){
+	    uint32 points;
 
-		if( !this->asUInt32( node, "TraitPoints", traitpoints ) ){
+		if( !this->asUInt32( node, "Points", points ) ){
 			return 0;
 		}
 
-		entry->traitpoints = traitpoints;
+	    entry->statpoints = points;
+	}
+
+	if( this->nodeExists( node, "TraitPoints" ) ){
+	    uint32 traitpoints;
+
+	    if( !this->asUInt32( node, "TraitPoints", traitpoints ) ){
+	        return 0;
+	    }
+
+	    entry->traitpoints = traitpoints;
 	}else{
 		if( !exists ){
 			entry->traitpoints = 0;

+ 97 - 41
src/map/script.cpp

@@ -2472,8 +2472,7 @@ void script_warning(const char* src, const char* file, int start_line, const cha
 /*==========================================
  * Analysis of the script
  *------------------------------------------*/
-struct script_code* parse_script(const char *src,const char *file,int line,int options)
-{
+struct script_code* parse_script_( const char *src, const char *file, int line, int options, const char* src_file, int src_line, const char* src_func ){
 	const char *p,*tmpp;
 	int i;
 	struct script_code* code = NULL;
@@ -2653,7 +2652,7 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o
 	}
 #endif
 
-	CREATE(code,struct script_code,1);
+	CREATE2( code, struct script_code, 1, src_file, src_line, src_func );
 	code->script_buf  = script_buf;
 	code->script_size = script_size;
 	code->local.vars = NULL;
@@ -5566,33 +5565,51 @@ BUILDIN_FUNC(return)
 	return SCRIPT_CMD_SUCCESS;
 }
 
-/// Returns a random number from 0 to <range>-1.
-/// Or returns a random number from <min> to <max>.
-/// If <min> is greater than <max>, their numbers are switched.
-/// rand(<range>) -> <int>
-/// rand(<min>,<max>) -> <int>
+/// Returns a random number.
+/// rand(<range>) -> <int64> in the mathematical range [0, <range - 1>]
+/// rand(<min>,<max>) -> <int64> in the mathematical range [<min>, <max>]
 BUILDIN_FUNC(rand)
 {
-	int range;
-	int min;
+	int64 minimum;
+	int64 maximum;
 
-	if( script_hasdata(st,3) )
-	{// min,max
-		int max = script_getnum(st,3);
-		min = script_getnum(st,2);
-		if( max < min )
-			SWAP(min, max);
-		range = max;
+	// min,max
+	if( script_hasdata( st, 3 ) ){
+		minimum = script_getnum64( st, 2 );
+		maximum = script_getnum64( st, 3 );
+
+		if( minimum > maximum ){
+			ShowWarning( "buildin_rand: minimum (%" PRId64 ") is bigger than maximum (%" PRId64 ").\n", minimum, maximum );
+			// rnd_value already fixes this by swapping minimum and maximum automatically
+		}
+	// range
+	}else{
+		minimum = 0;
+		maximum = script_getnum64( st, 2 );
+
+		if( maximum < 0 ){
+			ShowError( "buildin_rand: range (%" PRId64 ") is negative.\n", maximum );
+			st->state = END;
+			return SCRIPT_CMD_FAILURE;
+		}
+
+		// The range version is exclusive maximum
+		maximum -= 1;
+
+		if( maximum < 1 ){
+			ShowError( "buildin_rand: range (%" PRId64 ") is too small. No randomness possible.\n", maximum );
+			st->state = END;
+			return SCRIPT_CMD_FAILURE;
+		}
 	}
-	else
-	{// range
-		min = 0;
-		range = script_getnum( st, 2 ) - 1;
+
+	if( minimum == maximum ){
+		ShowError( "buildin_rand: minimum (%" PRId64 ") and maximum (%" PRId64 ") are equal. No randomness possible.\n", minimum, maximum );
+		st->state = END;
+		return SCRIPT_CMD_FAILURE;
 	}
-	if( range <= 1 )
-		script_pushint(st, min);
-	else
-		script_pushint( st, rnd_value( min, range ) );
+
+	script_pushint64( st, rnd_value( minimum, maximum ) );
 
 	return SCRIPT_CMD_SUCCESS;
 }
@@ -5690,8 +5707,8 @@ BUILDIN_FUNC(areawarp)
 			y3 = 0;
 		} else if( x3 && y3 ) {
 			// normalize x3/y3 coordinates
-			if( x3 < x2 ) SWAP(x3,x2);
-			if( y3 < y2 ) SWAP(y3,y2);
+			if( x3 < x2 ) std::swap(x3,x2);
+			if( y3 < y2 ) std::swap(y3,y2);
 		}
 	}
 
@@ -5865,13 +5882,13 @@ BUILDIN_FUNC(warpparty)
 		case WARPPARTY_LEADER:
 			if (p->party.member[i].leader)
 				continue;
-			// Fall through
+			[[fallthrough]];
 		case WARPPARTY_RANDOMALL:
 			if (pl_sd == sd) {
 				ret = pc_setpos(pl_sd, mapindex, x, y, CLR_TELEPORT);
 				break;
 			}
-			// Fall through
+			[[fallthrough]];
 		case WARPPARTY_RANDOMALLAREA:
 			if(!mapdata->getMapFlag(MF_NORETURN) && !mapdata->getMapFlag(MF_NOWARP) && pc_job_can_entermap((enum e_job)pl_sd->status.class_, m, pc_get_group_level(pl_sd))){
 				if (rx || ry) {
@@ -15713,6 +15730,7 @@ BUILDIN_FUNC(recovery)
 				map_idx = sd->bl.m;
 			if(map_idx < 1)
 				return SCRIPT_CMD_FAILURE; //No sd and no map given - return
+			[[fallthrough]];
 		case 4:
 		{
 			struct s_mapiterator *iter;
@@ -17940,15 +17958,25 @@ BUILDIN_FUNC(npcshopitem)
 	nd->u.shop.count = 0;
 	for (n = 0, i = 3; n < amount; n++, i+=offs) {
 		t_itemid nameid = script_getnum( st, i );
+		std::shared_ptr<item_data> id = item_db.find(nameid);
 
-		if( !item_db.exists( nameid ) ){
+		if( !id ){
 			ShowError( "builtin_npcshopitem: Item ID %u does not exist.\n", nameid );
 			script_pushint( st, 0 );
 			return SCRIPT_CMD_FAILURE;
 		}
+		int32 price = script_getnum(st, i + 1);
+		if (price < 0) {
+			if (nd->subtype == NPCTYPE_CASHSHOP || nd->subtype == NPCTYPE_POINTSHOP || nd->subtype == NPCTYPE_ITEMSHOP) {
+				ShowError("builtin_npcshopitem: Invalid price in shop '%s'.\n", nd->exname);
+				script_pushint(st, 0);
+				return SCRIPT_CMD_FAILURE;
+			}
+			price = id->value_buy;
+		}
 
 		nd->u.shop.shop_item[n].nameid = nameid;
-		nd->u.shop.shop_item[n].value = script_getnum(st,i+1);
+		nd->u.shop.shop_item[n].value = price;
 #if PACKETVER >= 20131223
 		if (nd->subtype == NPCTYPE_MARKETSHOP) {
 			nd->u.shop.shop_item[n].qty = script_getnum(st,i+2);
@@ -17985,8 +18013,9 @@ BUILDIN_FUNC(npcshopadditem)
 		for (int n = 0, i = 3; n < amount; n++, i += offs) {
 			t_itemid nameid = script_getnum(st,i);
 			uint16 j;
+			std::shared_ptr<item_data> id = item_db.find(nameid);
 
-			if( !item_db.exists( nameid ) ){
+			if( !id ){
 				ShowError( "builtin_npcshopadditem: Item ID %u does not exist.\n", nameid );
 				script_pushint( st, 0 );
 				return SCRIPT_CMD_FAILURE;
@@ -18001,8 +18030,12 @@ BUILDIN_FUNC(npcshopadditem)
 				nd->u.shop.count++;
 			}
 
-			int32 stock = script_getnum( st, i + 2 );
+			int32 price = script_getnum(st, i + 1);
+			if (price < 0) {
+				price = id->value_buy;
+			}
 
+			int32 stock = script_getnum(st, i + 2);
 			if( stock < -1 ){
 				ShowError( "builtin_npcshopadditem: Invalid stock amount in marketshop '%s'.\n", nd->exname );
 				script_pushint( st, 0 );
@@ -18010,7 +18043,7 @@ BUILDIN_FUNC(npcshopadditem)
 			}
 
 			nd->u.shop.shop_item[j].nameid = nameid;
-			nd->u.shop.shop_item[j].value = script_getnum(st,i+1);
+			nd->u.shop.shop_item[j].value = price;
 			nd->u.shop.shop_item[j].qty = stock;
 
 			npc_market_tosql(nd->exname, &nd->u.shop.shop_item[j]);
@@ -18025,15 +18058,24 @@ BUILDIN_FUNC(npcshopadditem)
 	for (int n = nd->u.shop.count, i = 3, j = 0; j < amount; n++, i+=offs, j++)
 	{
 		t_itemid nameid = script_getnum( st, i );
+		std::shared_ptr<item_data> id = item_db.find(nameid);
 
-		if( !item_db.exists( nameid ) ){
+		if( !id ){
 			ShowError( "builtin_npcshopadditem: Item ID %u does not exist.\n", nameid );
 			script_pushint( st, 0 );
 			return SCRIPT_CMD_FAILURE;
 		}
-
+		int32 price = script_getnum(st, i + 1);
+		if (price < 0) {
+			if (nd->subtype == NPCTYPE_CASHSHOP || nd->subtype == NPCTYPE_POINTSHOP || nd->subtype == NPCTYPE_ITEMSHOP) {
+				ShowError("builtin_npcshopadditem: Invalid price in shop '%s'.\n", nd->exname);
+				script_pushint(st, 0);
+				return SCRIPT_CMD_FAILURE;
+			}
+			price = id->value_buy;
+		}
 		nd->u.shop.shop_item[n].nameid = nameid;
-		nd->u.shop.shop_item[n].value = script_getnum(st,i+1);
+		nd->u.shop.shop_item[n].value = price;
 		nd->u.shop.count++;
 	}
 
@@ -20326,8 +20368,8 @@ BUILDIN_FUNC(setcell)
 
 	int x,y;
 
-	if( x1 > x2 ) SWAP(x1,x2);
-	if( y1 > y2 ) SWAP(y1,y2);
+	if( x1 > x2 ) std::swap(x1,x2);
+	if( y1 > y2 ) std::swap(y1,y2);
 
 	for( y = y1; y <= y2; ++y )
 		for( x = x1; x <= x2; ++x )
@@ -23802,9 +23844,23 @@ BUILDIN_FUNC(npcshopupdate) {
 
 	for (i = 0; i < nd->u.shop.count; i++) {
 		if (nd->u.shop.shop_item[i].nameid == nameid) {
-
-			if (price != 0)
+			if (price != 0) {
+				if (price < 0) {
+					if (nd->subtype == NPCTYPE_CASHSHOP || nd->subtype == NPCTYPE_POINTSHOP || nd->subtype == NPCTYPE_ITEMSHOP) {
+						ShowError("builtin_npcshopupdate: Invalid price in shop '%s'.\n", nd->exname);
+						script_pushint(st, 0);
+						return SCRIPT_CMD_FAILURE;
+					}
+					std::shared_ptr<item_data> id = item_db.find(nameid);
+					if (!id) {
+						ShowError("buildin_npcshopupdate: Item ID %u does not exist.\n", nameid);
+						script_pushint(st, 0);
+						return SCRIPT_CMD_FAILURE;
+					}
+					price = id->value_buy;
+				}
 				nd->u.shop.shop_item[i].value = price;
+			}
 #if PACKETVER >= 20131223
 			if (nd->subtype == NPCTYPE_MARKETSHOP) {
 				nd->u.shop.shop_item[i].qty = stock;

+ 3 - 1
src/map/script.hpp

@@ -10,6 +10,7 @@
 #include <common/database.hpp>
 #include <common/cbasetypes.hpp>
 #include <common/db.hpp>
+#include <common/malloc.hpp>
 #include <common/mmo.hpp>
 #include <common/timer.hpp>
 
@@ -2205,7 +2206,8 @@ void script_error(const char* src, const char* file, int start_line, const char*
 void script_warning(const char* src, const char* file, int start_line, const char* error_msg, const char* error_pos);
 
 bool is_number(const char *p);
-struct script_code* parse_script(const char* src,const char* file,int line,int options);
+struct script_code* parse_script_( const char *src, const char *file, int line, int options, const char* src_file, int src_line, const char* src_func );
+#define parse_script( src, file, line, options ) parse_script_( ( src ), ( file ), ( line ), ( options ), ALC_MARK )
 void run_script(struct script_code *rootscript,int pos,int rid,int oid);
 
 bool set_reg_num(struct script_state* st, map_session_data* sd, int64 num, const char* name, const int64 value, struct reg_db *ref);

+ 17 - 2
src/map/script_constants.hpp

@@ -1894,6 +1894,12 @@
 	export_constant(SC_RUSH_QUAKE1);
 	export_constant(SC_RUSH_QUAKE2);
 	export_constant(SC_G_LIFEPOTION);
+	export_constant(SC_HNNOWEAPON);
+	export_constant(SC_SHIELDCHAINRUSH);
+	export_constant(SC_MISTYFROST);
+	export_constant(SC_GROUNDGRAVITY);
+	export_constant(SC_BREAKINGLIMIT);
+	export_constant(SC_RULEBREAK);
 
 #ifdef RENEWAL
 	export_constant(SC_EXTREMITYFIST2);
@@ -10065,12 +10071,21 @@
 	export_constant(UNT_LIGHTNING_LAND);
 	export_constant(UNT_VENOM_SWAMP);
 	export_constant(UNT_CONFLAGRATION);
-
 	export_constant(UNT_DEEPBLINDTRAP);
 	export_constant(UNT_SOLIDTRAP);
 	export_constant(UNT_SWIFTTRAP);
 	export_constant(UNT_FLAMETRAP);
-
+	export_constant(UNT_TWINKLING_GALAXY);
+	export_constant(UNT_STAR_CANNON);
+	export_constant(UNT_GRENADES_DROPPING);
+	export_constant(UNT_FUUMASHOUAKU);
+	export_constant(UNT_MISSION_BOMBARD);
+	export_constant(UNT_TOTEM_OF_TUTELARY);
+	export_constant(UNT_HYUN_ROKS_BREEZE);
+	export_constant(UNT_SHINKIROU);
+	export_constant(UNT_JACK_FROST_NOVA);
+	export_constant(UNT_GROUND_GRAVITATION);
+	export_constant(UNT_KUNAIWAIKYOKU);
 	export_constant(UNT_GD_LEADERSHIP);
 	export_constant(UNT_GD_GLORYWOUNDS);
 	export_constant(UNT_GD_SOULCOLD);

+ 1 - 1
src/map/searchstore.cpp

@@ -187,7 +187,7 @@ void searchstore_query(map_session_data* sd, unsigned char type, unsigned int mi
 	}
 
 	if( max_price < min_price )
-		SWAP(min_price, max_price);
+		std::swap(min_price, max_price);
 
 	sd->searchstore.uses--;
 	sd->searchstore.type = type;

+ 208 - 67
src/map/skill.cpp

@@ -1424,6 +1424,7 @@ int skill_additional_effect( struct block_list* src, struct block_list *bl, uint
 	case AS_VENOMKNIFE:
 		if (sd) //Poison chance must be that of Envenom. [Skotlex]
 			skill_lv = pc_checkskill(sd, TF_POISON);
+		[[fallthrough]];
 	case TF_POISON:
 	case AS_SPLASHER:
 		if(!sc_start2(src,bl,SC_POISON,(4*skill_lv+10),skill_lv,src->id,skill_get_time2(skill_id,skill_lv))
@@ -1433,6 +1434,7 @@ int skill_additional_effect( struct block_list* src, struct block_list *bl, uint
 		break;
 
 	case AS_SONICBLOW:
+	case HN_MEGA_SONIC_BLOW:
 		sc_start(src,bl,SC_STUN,(2*skill_lv+10),skill_lv,skill_get_time2(skill_id,skill_lv));
 		break;
 
@@ -1479,6 +1481,7 @@ int skill_additional_effect( struct block_list* src, struct block_list *bl, uint
 		break;
 
 	case WZ_METEOR:
+	case HN_METEOR_STORM_BUSTER:
 		sc_start(src,bl,SC_STUN,3*skill_lv,skill_lv,skill_get_time2(skill_id,skill_lv));
 		break;
 
@@ -1568,7 +1571,7 @@ int skill_additional_effect( struct block_list* src, struct block_list *bl, uint
 #ifndef RENEWAL
 	case PA_PRESSURE:
 		status_percent_damage(src, bl, 0, 15+5*skill_lv, false);
-		//Fall through
+		[[fallthrough]];
 	case HW_GRAVITATION:
 		//Pressure and Gravitation can trigger physical autospells
 		attack_type |= BF_NORMAL;
@@ -1695,6 +1698,7 @@ int skill_additional_effect( struct block_list* src, struct block_list *bl, uint
 
 	case LK_SPIRALPIERCE:
 	case ML_SPIRALPIERCE:
+	case HN_SPIRAL_PIERCE_MAX:
 		if( dstsd || ( dstmd && !status_bl_has_mode(bl,MD_STATUSIMMUNE) ) ) //Does not work on status immune
 			sc_start(src,bl,SC_STOP,100,0,skill_get_time2(skill_id,skill_lv));
 		break;
@@ -1728,6 +1732,7 @@ int skill_additional_effect( struct block_list* src, struct block_list *bl, uint
 		break;
 
 	case HW_NAPALMVULCAN:
+	case HN_NAPALM_VULCAN_STRIKE:
 		sc_start(src,bl,SC_CURSE,5*skill_lv,skill_lv,skill_get_time2(skill_id,skill_lv));
 		break;
 
@@ -2179,10 +2184,9 @@ int skill_additional_effect( struct block_list* src, struct block_list *bl, uint
 		break;
 	case TR_ROSEBLOSSOM:// Rose blossom seed can only bloom if the target is hit.
 		sc_start4(src, bl, SC_ROSEBLOSSOM, 100, skill_lv, TR_ROSEBLOSSOM_ATK, src->id, 0, skill_get_time(skill_id, skill_lv));
+		[[fallthrough]];
 	case WM_METALICSOUND:
 	case WM_REVERBERATION:
-	case TR_RHYTHMSHOOTING:
-	case TR_METALIC_FURY:
 		status_change_end(bl, SC_SOUNDBLEND);
 		break;
 	case EM_DIAMOND_STORM:
@@ -2203,6 +2207,11 @@ int skill_additional_effect( struct block_list* src, struct block_list *bl, uint
 	case MT_RUSH_QUAKE:
 		sc_start( src, bl, SC_RUSH_QUAKE1, 100, skill_lv, skill_get_time( skill_id, skill_lv ) );
 		break;
+	case HN_SHIELD_CHAIN_RUSH:
+	case HN_JACK_FROST_NOVA:
+	case HN_GROUND_GRAVITATION:
+		sc_start(src, bl, skill_get_sc(skill_id), 100, 0, skill_get_time2(skill_id, skill_lv));
+		break;
 	} //end switch skill_id
 
 	if (md && battle_config.summons_trigger_autospells && md->master_id && md->special_state.ai && md->special_state.ai != AI_ABR && md->special_state.ai != AI_BIONIC)
@@ -3305,11 +3314,13 @@ void skill_combo(struct block_list* src,struct block_list *dsrc, struct block_li
 				duration = 1;
 				target_id = 0; // Will target current auto-target instead
 			}
+			[[fallthrough]]; // so we can possibly cast TigerFist or straight to ExtremityFist
 		case CH_TIGERFIST:
 			if (!duration && pc_checkskill(sd, CH_CHAINCRUSH) > 0 && sd->spiritball > 1) {
 				duration = 1;
 				target_id = 0; // Will target current auto-target instead
 			}
+			[[fallthrough]]; // so we can possibly cast ChainCrush or straight to ExtremityFist
 		case CH_CHAINCRUSH:
 			if (!duration && pc_checkskill(sd, MO_EXTREMITYFIST) > 0 && sd->spiritball > 0 && sd->sc.getSCE(SC_EXPLOSIONSPIRITS)) {
 				duration = 1;
@@ -3814,7 +3825,7 @@ int64 skill_attack (int attack_type, struct block_list* src, struct block_list *
 			if(src->type == BL_PC)
 				dmg.blewcount = 10;
 			dmg.amotion = 0; //Disable delay or attack will do no damage since source is dead by the time it takes effect. [Skotlex]
-			// fall through
+			[[fallthrough]];
 		case KN_AUTOCOUNTER:
 		case NPC_CRITICALSLASH:
 		case TF_DOUBLE:
@@ -3896,7 +3907,7 @@ int64 skill_attack (int attack_type, struct block_list* src, struct block_list *
 			dmg.dmotion = clif_skill_damage(src, bl, tick, dmg.amotion, dmg.dmotion, damage, dmg.div_, skill_id, (flag&SD_LEVEL) ? -1 : skill_lv, DMG_SPLASH);
 			if( dsrc != src ) // avoid damage display redundancy
 				break;
-			//Fall through
+			[[fallthrough]];
 		case HT_LANDMINE:
 			dmg.dmotion = clif_skill_damage(dsrc,bl,tick, dmg.amotion, dmg.dmotion, damage, dmg.div_, skill_id, -1, dmg_type);
 			break;
@@ -3917,7 +3928,7 @@ int64 skill_attack (int attack_type, struct block_list* src, struct block_list *
 				type = DMG_SPLASH;
 			if (!(flag&SD_ANIMATION))
 				clif_skill_nodamage(dsrc, bl, skill_id, skill_lv, 1);
-			// Fall through
+			[[fallthrough]];
 		case WM_REVERBERATION:
 			dmg.dmotion = clif_skill_damage(dsrc, bl, tick, dmg.amotion, dmg.dmotion, damage, dmg.div_, skill_id, -2, dmg_type);
 			break;
@@ -3948,6 +3959,7 @@ int64 skill_attack (int attack_type, struct block_list* src, struct block_list *
 		case AB_DUPLELIGHT_MELEE:
 		case AB_DUPLELIGHT_MAGIC:
 			dmg.amotion = 300;/* makes the damage value not overlap with previous damage (when displayed by the client) */
+			[[fallthrough]];
 		default:
 			if( flag&SD_ANIMATION && dmg.div_ < 2 ) //Disabling skill animation doesn't works on multi-hit.
 				dmg_type = DMG_SPLASH;
@@ -4143,10 +4155,6 @@ int64 skill_attack (int attack_type, struct block_list* src, struct block_list *
 				if (status_get_lv(src) > 29 && rnd() % 100 < 10 * status_get_lv(src) / 30)
 					skill_addtimerskill(src, tick + dmg.amotion + skill_get_delay(skill_id, skill_lv), bl->id, 0, 0, skill_id, skill_lv, attack_type, flag|2);
 				break;
-			case ABC_DEFT_STAB:
-				if (skill_area_temp[1] == bl->id && rnd()%100 < 4 * skill_lv)// Need official autocast chance. [Rytech]
-					skill_addtimerskill(src, tick + dmg.amotion, bl->id, 0, 0, skill_id, skill_lv, BF_WEAPON, 2);
-				break;
 		}
 	}
 
@@ -4217,7 +4225,7 @@ static int skill_check_unit_range_sub(struct block_list *bl, va_list ap)
 		case AL_PNEUMA: //Pneuma doesn't work even if just one cell overlaps with Land Protector
 			if(g_skill_id == SA_LANDPROTECTOR)
 				break;
-			//Fall through
+			[[fallthrough]];
 		case MH_STEINWAND:
 		case MG_SAFETYWALL:
 		case SC_MAELSTROM:
@@ -4604,7 +4612,8 @@ static TIMER_FUNC(skill_timerskill){
 						if (unit)
 							break;
 					}
-				}	// Fall through
+				}
+					[[fallthrough]];
 				case WZ_JUPITEL:
 					// Official behaviour is to hit as long as there is a line of sight, regardless of distance
 					if (skl->type > 0 && !status_isdead(target) && path_search_long(NULL,src->m,src->x,src->y,target->x,target->y,CELL_CHKWALL)) {
@@ -4753,6 +4762,7 @@ static TIMER_FUNC(skill_timerskill){
 						int dummy = 1, i = skill_get_unit_range(skl->skill_id,skl->skill_lv);
 						map_foreachinarea(skill_cell_overlap, src->m, skl->x-i, skl->y-i, skl->x+i, skl->y+i, BL_SKILL, skl->skill_id, &dummy, src);
 					}
+					[[fallthrough]];
 				case WL_EARTHSTRAIN:
 					skill_unitsetting(src,skl->skill_id,skl->skill_lv,skl->x,skl->y,(skl->type<<16)|skl->flag);
 					break;
@@ -4768,6 +4778,22 @@ static TIMER_FUNC(skill_timerskill){
 				case NC_MAGMA_ERUPTION:
 					skill_unitsetting(src,skl->skill_id,skl->skill_lv,skl->x,skl->y,0);
 					break;
+				case HN_METEOR_STORM_BUSTER: {
+						int16 area = 4;
+						int16 tmpx = rnd_value( skl->x - area, skl->x + area );
+						int16 tmpy = rnd_value( skl->y - area, skl->y + area );
+
+						if( map_getcell(src->m, tmpx, tmpy, CELL_CHKLANDPROTECTOR) ) {
+							return 0;
+						}
+
+						int splash = skill_get_splash(skl->skill_id, skl->skill_lv);
+
+						clif_skill_poseffect(src, skl->skill_id, skl->skill_lv, tmpx, tmpy, tick);
+						map_foreachinarea(skill_area_sub, src->m, tmpx - splash, tmpy - splash, tmpx + splash, tmpy + splash, BL_CHAR, src, skl->skill_id, skl->skill_lv, tick, skl->flag | BCT_ENEMY | SD_SPLASH | SKILL_ALTDMG_FLAG | 1, skill_castend_damage_id);
+						skill_unitsetting(src, skl->skill_id, skl->skill_lv, tmpx, tmpy, skill_get_unit_interval(skl->skill_id));
+					}
+					break;
 			}
 		}
 	} while (0);
@@ -5211,27 +5237,20 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
 	case MT_TRIPLE_LASER:
 		skill_attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag);
 		break;
-
-	case IG_SHIELD_SHOOTING:
-		clif_skill_nodamage(src, bl, skill_id, skill_lv, 1);
-		skill_attack(BF_WEAPON, src, src, bl, skill_id, skill_lv, tick, flag);
-		sc_start(src, src, SC_SHIELD_POWER, 100, skill_lv, skill_get_time(skill_id, skill_lv));
-		break;
 	case DK_DRAGONIC_AURA:
 	case DK_STORMSLASH:
-	case IG_GRAND_JUDGEMENT:
 	case CD_EFFLIGO:
 	case ABC_FRENZY_SHOT:
 	case WH_HAWKRUSH:
 	case WH_HAWKBOOMERANG:
 	case TR_ROSEBLOSSOM:
 	case TR_RHYTHMSHOOTING:
+	case HN_MEGA_SONIC_BLOW:
+	case HN_SPIRAL_PIERCE_MAX:
 		clif_skill_nodamage(src, bl, skill_id, skill_lv, 1);
 		skill_attack(BF_WEAPON, src, src, bl, skill_id, skill_lv, tick, flag);
 		if (skill_id == DK_DRAGONIC_AURA)
 			sc_start(src, src, SC_DRAGONIC_AURA, 100, skill_lv, skill_get_time(skill_id,skill_lv));
-		else if (skill_id == IG_GRAND_JUDGEMENT)
-			sc_start(src, src, SC_SPEAR_SCAR, 100, skill_lv, skill_get_time(skill_id, skill_lv));
 		break;
 
 	case SHC_ETERNAL_SLASH:
@@ -5244,8 +5263,8 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
 		break;
 
 	case SHC_SHADOW_STAB:
-		if (sc && (sc->getSCE(SC_CLOAKING) || sc->getSCE(SC_CLOAKINGEXCEED)))
-			flag |= 2;// Flag to deal 2 hits.
+		if (sc && sc->getSCE(SC_CLOAKINGEXCEED))
+			flag |= 2;// Flag to deal 3 hits.
 
 		status_change_end(src, SC_CLOAKING);
 		status_change_end(src, SC_CLOAKINGEXCEED);
@@ -5360,6 +5379,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
 #ifndef RENEWAL
 	case SN_SHARPSHOOTING:
 		flag |= 2; // Flag for specific mob damage formula
+		[[fallthrough]];
 #endif
 	case MA_SHARPSHOOTING:
 	case NJ_KAMAITACHI:
@@ -5515,6 +5535,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
 
 	case SU_PICKYPECK:
 		clif_skill_nodamage(src, bl, skill_id, skill_lv, 1);
+		[[fallthrough]];
 	case SU_BITE:
 		skill_attack(BF_WEAPON, src, src, bl, skill_id, skill_lv, tick, flag);
 		break;
@@ -5530,6 +5551,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
 	case MC_CARTREVOLUTION:
 	case NPC_SPLASHATTACK:
 		flag |= SD_PREAMBLE; // a fake packet will be sent for the first target to be hit
+		[[fallthrough]];
 	case AS_SPLASHER:
 	case HT_BLITZBEAT:
 	case AC_SHOWER:
@@ -5671,6 +5693,10 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
 	case BO_EXPLOSIVE_POWDER:
 	case BO_MAYHEMIC_THORNS:
 	case NPC_WIDECRITICALWOUND:
+	case IG_SHIELD_SHOOTING:
+	case TR_METALIC_FURY:
+	case IG_GRAND_JUDGEMENT:
+	case HN_JUPITEL_THUNDER_STORM:
 		if( flag&1 ) {//Recursive invocation
 			int sflag = skill_area_temp[0] & 0xFFF;
 			int heal = 0;
@@ -5741,6 +5767,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
 				case DK_DRAGONIC_BREATH:
 				case DK_HACKANDSLASHER:
 				case MT_SPARK_BLASTER:
+				case HN_JUPITEL_THUNDER_STORM:
 					clif_skill_nodamage(src,bl,skill_id,skill_lv,1);
 					break;
 #ifdef RENEWAL
@@ -5867,6 +5894,11 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
 					// TODO: does this buff start before or after dealing damage? [Muh]
 					sc_start( src, src, SC_RUSH_QUAKE2, 100, skill_lv, skill_get_time2( skill_id, skill_lv ) );
 					break;
+				case IG_SHIELD_SHOOTING:
+				case IG_GRAND_JUDGEMENT:
+					clif_skill_nodamage(src, bl, skill_id, skill_lv, 1);
+					sc_start(src, src, skill_get_sc(skill_id), 100, skill_lv, skill_get_time(skill_id, skill_lv));
+					break;
 			}
 
 			// if skill damage should be split among targets, count them
@@ -5886,24 +5918,6 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
 			}
 		}
 		break;
-	case TR_METALIC_FURY:
-	{
-		if (flag & 1) {
-			clif_skill_nodamage(src, bl, skill_id, skill_lv, 1);
-			skill_attack(skill_get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, flag);
-		} else {
-			int area = skill_get_splash(skill_id, skill_lv);
-			int count = map_forcountinarea(skill_check_bl_sc,bl->m,bl->x - area,bl->y - area,bl->x + area,bl->y + area,5,BL_MOB,SC_SOUNDBLEND);
-			if (count > 0){
-				map_foreachinarea(skill_area_sub, bl->m, bl->x - area, bl->y - area, bl->x + area, bl->y + area, BL_CHAR,
-					src, skill_id, skill_lv, tick, flag | BCT_ENEMY | SD_SPLASH | 1, skill_castend_damage_id);
-			} else{
-				clif_skill_nodamage(src, bl, skill_id, skill_lv, 1);
-				skill_attack(skill_get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, flag);
-			}
-		}
-	}
-		break;
 
 	//Place units around target
 	case NJ_BAKUENRYU:
@@ -6073,6 +6087,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
 
 	case AL_HOLYLIGHT:
 		status_change_end(bl, SC_P_ALTER);
+		[[fallthrough]];
 	case MG_SOULSTRIKE:
 	case NPC_DARKSTRIKE:
 	case MG_COLDBOLT:
@@ -6101,6 +6116,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
 	case AG_ASTRAL_STRIKE_ATK:
 	case AG_DESTRUCTIVE_HURRICANE_CLIMAX:
 	case CD_ARBITRIUM:
+	case HN_METEOR_STORM_BUSTER:
 		skill_attack(BF_MAGIC,src,src,bl,skill_id,skill_lv,tick,flag);
 		break;
 
@@ -6175,6 +6191,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
 
 	case SL_SMA:
 		status_change_end(src, SC_SMA);
+		[[fallthrough]];
 	case SL_STIN:
 	case SL_STUN:
 	case SP_SPA:
@@ -6190,6 +6207,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
 		clif_emotion(src,ET_ANGER);
 		if (rnd() % 2 == 0)
 			break; // 50% chance
+		[[fallthrough]];
 	case SN_FALCONASSAULT:
 #ifndef RENEWAL
 	case PA_PRESSURE:
@@ -6246,6 +6264,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
 	case NPC_SELFDESTRUCTION:
 		if( tsc && tsc->getSCE(SC_HIDING) )
 			break;
+		[[fallthrough]];
 	case HVAN_EXPLOSION:
 		if (src != bl)
 			skill_attack(BF_MISC,src,src,bl,skill_id,skill_lv,tick,flag);
@@ -6568,6 +6587,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
 			}
 			break;
 		}
+		[[fallthrough]];
 	case RA_WUGBITE:
 		if( path_search(NULL,src->m,src->x,src->y,bl->x,bl->y,1,CELL_CHKNOREACH) ) {
 			skill_attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag);
@@ -7021,6 +7041,44 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
 			sc_start(src, bl, SC_VENOMIMPRESS, 100, skill_lv, skill_get_time(skill_id,skill_lv));
 		break;
 
+	case HN_DOUBLEBOWLINGBASH:
+		if (flag & 1) {
+			skill_attack(skill_get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, skill_area_temp[0] & 0xFFF);
+		} else {
+			int splash = skill_get_splash(skill_id, skill_lv);
+			clif_skill_nodamage(src, bl, skill_id, skill_lv, 1);
+			skill_area_temp[0] = map_foreachinallrange(skill_area_sub, bl, splash, BL_CHAR, src, skill_id, skill_lv, tick, BCT_ENEMY, skill_area_sub_count);
+			map_foreachinrange(skill_area_sub, bl, splash, BL_CHAR, src, skill_id, skill_lv, tick, flag | BCT_ENEMY | SD_SPLASH | 1, skill_castend_damage_id);
+			sc_start(src, src, SC_HNNOWEAPON, 100, skill_lv, skill_get_time2(skill_id, skill_lv));
+		}
+		break;
+
+	case HN_SHIELD_CHAIN_RUSH:
+		if (flag & 1) {
+			skill_attack(skill_get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, flag);
+		} else {
+			clif_skill_nodamage(src, bl, skill_id, skill_lv, 1);
+			map_foreachinrange(skill_area_sub, bl, skill_get_splash(skill_id, skill_lv), BL_CHAR, src, skill_id, skill_lv, tick, flag | BCT_ENEMY | SD_SPLASH | 1, skill_castend_damage_id);
+			sc_start(src, src, SC_HNNOWEAPON, 100, skill_lv, skill_get_time2(skill_id, skill_lv));
+		}
+		break;
+
+	case HN_JACK_FROST_NOVA:
+	case HN_HELLS_DRIVE:
+	case HN_GROUND_GRAVITATION:
+		if (flag & 1)
+			skill_attack(skill_get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, flag);
+		break;
+
+	case HN_NAPALM_VULCAN_STRIKE:
+		if (flag & 1) {
+			skill_attack(skill_get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, flag);
+		} else {
+			clif_skill_nodamage(src, bl, skill_id, skill_lv, 1);
+			map_foreachinrange(skill_area_sub, bl, skill_get_splash(skill_id, skill_lv), BL_CHAR, src, skill_id, skill_lv, tick, flag | BCT_ENEMY | SD_SPLASH | 1, skill_castend_damage_id);
+		}
+		break;
+
 	default:
 		ShowWarning("skill_castend_damage_id: Unknown skill used:%d\n",skill_id);
 		clif_skill_damage(src, bl, tick, status_get_amotion(src), tstatus->dmotion,
@@ -7204,6 +7262,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
 				if (sd) clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0) ;
 				break ;
 			}
+			[[fallthrough]];
  		case AL_HEAL:
 		case ALL_RESURRECTION:
 		case PR_ASPERSIO:
@@ -7332,11 +7391,14 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
 #endif
 			status_set_hp(src, 1, 0);
 			break;
-		} else if (status_isdead(bl) && flag&1) { //Revive
-			skill_area_temp[0]++; //Count it in, then fall-through to the Resurrection code.
-			skill_lv = 3; //Resurrection level 3 is used
-		} else //Invalid target, skip resurrection.
+		} else if (!(status_isdead(bl) && flag&1)) { 
+			//Invalid target, skip resurrection.
 			break;
+		}
+		//Revive
+		skill_area_temp[0]++; //Count it in, then fall-through to the Resurrection code.
+		skill_lv = 3; //Resurrection level 3 is used
+		[[fallthrough]];
 
 	case ALL_RESURRECTION:
 		if(sd && (map_flag_gvg2(bl->m) || map_getmapflag(bl->m, MF_BATTLEGROUND)))
@@ -7506,7 +7568,8 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
 		break;
 	case SA_SUMMONMONSTER:
 		clif_skill_nodamage(src,bl,skill_id,skill_lv,1);
-		if (sd) mob_once_spawn(sd, src->m, src->x, src->y,"--ja--", -1, 1, "", SZ_SMALL, AI_NONE);
+		if (sd)
+			mob_once_spawn(sd, src->m, src->x, src->y,"--ja--", -1, 1, "", SZ_SMALL, AI_NONE);
 		break;
 	case SA_LEVELUP:
 		clif_skill_nodamage(src,bl,skill_id,skill_lv,1);
@@ -7519,6 +7582,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
 		break;
 	case SA_QUESTION:
 		clif_emotion(src,ET_QUESTION);
+		[[fallthrough]];
 	case SA_GRAVITY:
 		clif_skill_nodamage(src,bl,skill_id,skill_lv,1);
 		break;
@@ -7774,6 +7838,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
 				clif_skill_fail(sd, skill_id, USESKILL_FAIL, 0);
 			break;
 		}
+		[[fallthrough]];
 	case PR_SLOWPOISON:
 	case PR_LEXAETERNA:
 #ifndef RENEWAL
@@ -7903,6 +7968,8 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
 	case NPC_DAMAGE_HEAL:
 	case NPC_RELIEVE_ON:
 	case NPC_RELIEVE_OFF:
+	case HN_BREAKINGLIMIT:
+	case HN_RULEBREAK:
 		clif_skill_nodamage(src,bl,skill_id,skill_lv,
 			sc_start(src,bl,type,100,skill_lv,skill_get_time(skill_id,skill_lv)));
 		break;
@@ -7969,7 +8036,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
 				if (skill_id == AG_DESTRUCTIVE_HURRICANE)
 					splash_size = 9; // 19x19
 				else if(skill_id == AG_CRYSTAL_IMPACT)
-					splash_size = AREA_SIZE; // 29x29 - Entire screen.
+					splash_size = 7; // 15x15
 			}
 
 			skill_area_temp[1] = 0;
@@ -8627,6 +8694,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
 	case SR_WINDMILL:
 	case GN_CART_TORNADO:
 		clif_skill_nodamage(src,bl,skill_id,skill_lv,1);
+		[[fallthrough]];
 	case SR_EARTHSHAKER:
 	case NC_INFRAREDSCAN:
 	case NPC_VAMPIRE_GIFT:
@@ -9125,6 +9193,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
 		if( !mer )
 			break;
 		sd = mer->master;
+		[[fallthrough]];
 	case WZ_ESTIMATION:
 		if( sd == NULL )
 			break;
@@ -9716,6 +9785,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
 	case SA_ELEMENTWIND:
 		if (sd && (!dstmd || status_has_mode(tstatus,MD_STATUSIMMUNE))) // Only works on monsters (Except status immune monsters).
 			break;
+		[[fallthrough]];
 	case NPC_ATTRICHANGE:
 	case NPC_CHANGEWATER:
 	case NPC_CHANGEGROUND:
@@ -10068,7 +10138,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
 							// if it is already trapping something don't spring it,
 							// remove trap should be used instead
 							break;
-						// otherwise fallthrough to below
+						[[fallthrough]];
 					case UNT_BLASTMINE:
 					case UNT_SKIDTRAP:
 					case UNT_LANDMINE:
@@ -10348,6 +10418,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
 			status_change_end(bl, SC_SWOO);
 			break;
 		}
+		[[fallthrough]];
 	case SL_SKA: // [marquis007]
 	case SL_SKE:
 		if (sd && !battle_config.allow_es_magic_pc && bl->type != BL_MOB) {
@@ -10600,6 +10671,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
 			}
 			break;
 		}
+		[[fallthrough]];
 	case NPC_WIDEBLEEDING:
 	case NPC_WIDEBLEEDING2:
 	case NPC_WIDECONFUSE:
@@ -12149,6 +12221,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
 			clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
 			break;
 		}
+		[[fallthrough]];
 	case KO_IZAYOI:
 	case OB_ZANGETSU:
 	case KG_KYOMU:
@@ -12789,6 +12862,11 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
 		}
 		break;
 
+	case HN_HELLS_DRIVE:
+		clif_skill_nodamage(src, bl, skill_id, skill_lv, 1);
+		map_foreachinrange(skill_area_sub, bl, skill_get_splash(skill_id, skill_lv), BL_CHAR, src, skill_id, skill_lv, tick, flag | BCT_ENEMY | 1, skill_castend_damage_id);
+		break;
+
 	default: {
 		std::shared_ptr<s_skill_db> skill = skill_db.find(skill_id);
 		ShowWarning("skill_castend_nodamage_id: missing code case for skill %s(%d)\n", skill ? skill->name : "UNKNOWN", skill_id);
@@ -13526,6 +13604,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui
 		case SC_ESCAPE:
 		case SU_CN_METEOR:
 		case NPC_RAINOFMETEOR:
+		case HN_METEOR_STORM_BUSTER:
 			break; //Effect is displayed on respective switch case.
 		default:
 			if(skill_get_inf(skill_id)&INF_SELF_SKILL)
@@ -13605,6 +13684,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui
 			return 0; // Don't consume gems if cast on Land Protector
 		}
 	}
+	[[fallthrough]];
 	case MG_FIREWALL:
 	case MG_THUNDERSTORM:
 	case AL_PNEUMA:
@@ -13738,6 +13818,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui
 	case EM_CONFLAGRATION:
 	case EM_TERRA_DRIVE:
 		flag|=1;//Set flag to 1 to prevent deleting ammo (it will be deleted on group-delete).
+		[[fallthrough]];
 	case GS_GROUNDDRIFT: //Ammo should be deleted right away.
 	case GN_WALLOFTHORN:
 	case GN_DEMONIC_FIRE:
@@ -13813,7 +13894,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui
 			if (pc_checkskill(sd, SU_SPIRITOFLAND))
 				sc_start(src, src, SC_DORAM_SVSP, 100, 100, skill_get_time(SU_SPIRITOFLAND, 1));
 		}
-	// Fall through
+		[[fallthrough]];
 	case WZ_METEOR:
 	{
 		int area = skill_get_splash(skill_id, skill_lv);
@@ -14054,6 +14135,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui
 
 	case AC_SHOWER:
 		status_change_end(src, SC_CAMOUFLAGE);
+		[[fallthrough]];
 	case MA_SHOWER:
 	case NC_COLDSLOWER:
 	case RK_DRAGONBREATH:
@@ -14430,6 +14512,41 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui
 		}
 		break;
 
+	case HN_JACK_FROST_NOVA:
+	case HN_GROUND_GRAVITATION: {
+			if( map_getcell(src->m, x, y, CELL_CHKLANDPROTECTOR) ) {
+				clif_skill_fail(sd,skill_id,USESKILL_FAIL,0);
+				return 0;
+			}
+
+			int splash = skill_get_splash(skill_id, skill_lv);
+
+			map_foreachinarea(skill_area_sub, src->m, x - splash, y - splash, x + splash, y + splash, BL_CHAR, src, skill_id, skill_lv, tick, flag | BCT_ENEMY | SD_SPLASH | SKILL_ALTDMG_FLAG | 1, skill_castend_damage_id);
+			skill_unitsetting(src, skill_id, skill_lv, x, y, flag);
+
+			for (i = 1; i <= (skill_get_time(skill_id, skill_lv) / skill_get_unit_interval(skill_id)); i++) {
+				skill_addtimerskill(src, tick + (t_tick)i*skill_get_unit_interval(skill_id), 0, x, y, skill_id, skill_lv, 0, flag);
+			}
+		}
+		break;
+
+	case HN_METEOR_STORM_BUSTER: {
+			if( map_getcell(src->m, x, y, CELL_CHKLANDPROTECTOR) ) {
+				clif_skill_fail(sd,skill_id,USESKILL_FAIL,0);
+				return 0;
+			}
+
+			int splash = skill_get_splash(skill_id, skill_lv);
+
+			map_foreachinarea(skill_area_sub, src->m, x - splash, y - splash, x + splash, y + splash, BL_CHAR, src, skill_id, skill_lv, tick, flag | BCT_ENEMY | SD_SPLASH | SKILL_ALTDMG_FLAG | 1, skill_castend_damage_id);
+			skill_unitsetting(src, skill_id, skill_lv, x, y, skill_get_unit_interval(skill_id));
+
+			for (i = 1; i <= (skill_get_time(skill_id, skill_lv) / skill_get_time2(skill_id, skill_lv)); i++) {
+				skill_addtimerskill(src, tick + (t_tick)i*skill_get_time2(skill_id, skill_lv), 0, x, y, skill_id, skill_lv, 0, flag);
+			}
+		}
+		break;
+
 	default:
 		ShowWarning("skill_castend_pos2: Unknown skill used:%d\n",skill_id);
 		return 1;
@@ -14769,6 +14886,7 @@ std::shared_ptr<s_skill_unit_group> skill_unitsetting(struct block_list *src, ui
 	case SU_CN_METEOR:
 	case SU_CN_METEOR2:
 	case NPC_RAINOFMETEOR:
+	case HN_METEOR_STORM_BUSTER:
 		limit = flag;
 		flag = 0; // Flag should not influence anything else for these skills
 		break;
@@ -14788,6 +14906,7 @@ std::shared_ptr<s_skill_unit_group> skill_unitsetting(struct block_list *src, ui
 	case MA_SKIDTRAP:
 		//Save position of caster
 		val1 = ((src->x)<<16)|(src->y);
+		[[fallthrough]];
 	case HT_ANKLESNARE:
 	case HT_SHOCKWAVE:
 	case HT_SANDMAN:
@@ -14960,12 +15079,16 @@ std::shared_ptr<s_skill_unit_group> skill_unitsetting(struct block_list *src, ui
 			switch (val1) {
 				case ELE_FIRE:
 					subunt++;
+					[[fallthrough]];
 				case ELE_WATER:
 					subunt++;
+					[[fallthrough]];
 				case ELE_POISON:
 					subunt++;
+					[[fallthrough]];
 				case ELE_DARK:
 					subunt++;
+					[[fallthrough]];
 				case ELE_WIND:
 					break;
 				default:
@@ -15001,6 +15124,7 @@ std::shared_ptr<s_skill_unit_group> skill_unitsetting(struct block_list *src, ui
 	case WM_POEMOFNETHERWORLD:	// Can't be placed on top of Land Protector.
 		if( skill_id == WM_POEMOFNETHERWORLD && map_flag_gvg2(src->m) )
 			target = BCT_ALL;
+		[[fallthrough]];
 	case WM_SEVERE_RAINSTORM:
 	case SO_WATER_INSIGNIA:
 	case SO_FIRE_INSIGNIA:
@@ -15470,6 +15594,7 @@ static int skill_unit_onplace(struct skill_unit *unit, struct block_list *bl, t_
 		case UNT_HERMODE:
 			if (sg->src_id!=bl->id && battle_check_target(&unit->bl,bl,BCT_PARTY|BCT_GUILD) > 0)
 				status_change_clear_buffs(bl, SCCB_HERMODE); //Should dispell only allies.
+			[[fallthrough]];
 		case UNT_RICHMANKIM:
 		case UNT_ETERNALCHAOS:
 		case UNT_DRUMBATTLEFIELD:
@@ -15947,11 +16072,13 @@ int skill_unit_onplace_timer(struct skill_unit *unit, struct block_list *bl, t_t
 		case UNT_VERDURETRAP:
 			if( bl->type == BL_PC )// it won't work on players
 				break;
+			[[fallthrough]];
 		case UNT_FIRINGTRAP:
 		case UNT_ICEBOUNDTRAP:
 		case UNT_CLUSTERBOMB:
 			if( bl->id == ss->id )// it won't trigger on caster
 				break;
+			[[fallthrough]];
 		case UNT_BLASTMINE:
 		case UNT_SHOCKWAVE:
 		case UNT_SANDMAN:
@@ -16469,6 +16596,7 @@ int skill_unit_onout(struct skill_unit *src, struct block_list *bl, t_tick tick)
 					}
 				}
 			}
+			[[fallthrough]];
 		case UNT_WHISTLE:
 		case UNT_ASSASSINCROSS:
 		case UNT_POEMBRAGI:
@@ -16528,6 +16656,7 @@ int skill_unit_onleft(uint16 skill_id, struct block_list *bl, t_tick tick)
 				//your own. Let's pray that scenario is pretty unlikely and noone will complain too much about it.
 				status_change_end(bl, SC_DANCING);
 			}
+			[[fallthrough]];
 		case MH_STEINWAND:
 		case MG_SAFETYWALL:
 		case AL_PNEUMA:
@@ -17168,15 +17297,15 @@ bool skill_check_condition_castbegin(map_session_data* sd, uint16 skill_id, uint
 	// perform skill-group checks
 	if(skill_id != WM_GREAT_ECHO && inf2[INF2_ISCHORUS]) {
 		if (skill_check_pc_partner(sd, skill_id, &skill_lv, AREA_SIZE, 0) < 1) {
-		    clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
-		    return false;
+			clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
+			return false;
 		}
 	}
 	else if(inf2[INF2_ISENSEMBLE]) {
-	    if (skill_check_pc_partner(sd, skill_id, &skill_lv, 1, 0) < 1 && !(sc && sc->getSCE(SC_KVASIR_SONATA))) {
-		    clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
-		    return false;
-	    }
+		if (skill_check_pc_partner(sd, skill_id, &skill_lv, 1, 0) < 1 && !(sc && sc->getSCE(SC_KVASIR_SONATA))) {
+			clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
+			return false;
+		}
 	}
 	// perform skill-specific checks (and actions)
 	switch( skill_id ) {
@@ -17191,6 +17320,7 @@ bool skill_check_condition_castbegin(map_session_data* sd, uint16 skill_id, uint
 				clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
 				return false;
 			}
+			[[fallthrough]];
 		case SA_CASTCANCEL:
 			if(sd->ud.skilltimer == INVALID_TIMER) {
 				clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
@@ -17478,6 +17608,7 @@ bool skill_check_condition_castbegin(map_session_data* sd, uint16 skill_id, uint
 				clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
 				return false;
 			}
+			[[fallthrough]];
 		case GD_EMERGENCYCALL:
 		case GD_ITEMEMERGENCYCALL:
 			// other checks were already done in skill_isNotOk()
@@ -17501,6 +17632,7 @@ bool skill_check_condition_castbegin(map_session_data* sd, uint16 skill_id, uint
 				clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
 				return false;
 			}
+			[[fallthrough]];
 		case NJ_BUNSINJYUTSU:
 			if (!(sc && sc->getSCE(SC_NEN))) {
 				clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
@@ -18363,7 +18495,7 @@ void skill_consume_requirement(map_session_data *sd, uint16 skill_id, uint16 ski
 			case MO_KITRANSLATION:
 				//Spiritual Bestowment only uses spirit sphere when giving it to someone
 				require.spiritball = 0;
-				//Fall through
+				[[fallthrough]];
 			default:
 				if(sd->state.autocast)
 					require.sp = 0;
@@ -18602,7 +18734,7 @@ struct s_skill_condition skill_get_requirement(map_session_data* sd, uint16 skil
 		case NC_REPAIR: // NOTE: Repair_Kit must be last in the ItemCost list depending on the skill's max level
 			req.itemid[1] = skill->require.itemid[skill->max];
 			req.amount[1] = skill->require.amount[skill->max];
-			// Fall through
+			[[fallthrough]];
 
 		/* Normal skill requirements and gemstone checks */
 		default:
@@ -19697,7 +19829,7 @@ int skill_attack_area(struct block_list *bl, va_list ap)
 				return 0; //Does not hit current cell
 			if (map_getcell(bl->m, bl->x, bl->y, CELL_CHKLANDPROTECTOR)) // Attack should not happen if the target is on Land Protector
 				return 0;
-			//Fall through
+			[[fallthrough]];
 		case NPC_ACIDBREATH:
 		case NPC_DARKNESSBREATH:
 		case NPC_FIREBREATH:
@@ -19979,6 +20111,7 @@ static int skill_cell_overlap(struct block_list *bl, va_list ap)
 		case GN_CRAZYWEED_ATK:
 			if (skill_get_unit_flag(unit->group->skill_id, UF_CRAZYWEEDIMMUNE))
 				break;
+			[[fallthrough]];
 		case HW_GANBANTEIN:
 		case LG_EARTHDRIVE:
 			// Officially songs/dances are removed
@@ -20161,6 +20294,7 @@ static int skill_trap_splash(struct block_list *bl, va_list ap)
 				if (su && su->group->unit_id == UNT_USED_TRAPS)
 					break;
 			}
+			[[fallthrough]];
 		case UNT_CLUSTERBOMB:
 			if( ss != bl )
 				skill_attack(BF_MISC,ss,src,bl,sg->skill_id,sg->skill_lv,tick,sg->val1|SD_LEVEL);
@@ -20189,6 +20323,7 @@ static int skill_trap_splash(struct block_list *bl, va_list ap)
 						break;
 				}
 			}
+			[[fallthrough]];
 		default: {
 				int split_count = 0;
 
@@ -20948,7 +21083,7 @@ static int skill_unit_timer_sub(DBKey key, DBData *data, va_list ap)
 				unit->limit = DIFF_TICK(tick + group->interval,group->tick);
 				if( unit->val1 <= 0 )
 					skill_delunit(unit);
-			break;
+				break;
 			case UNT_BLASTMINE:
 #ifdef RENEWAL
 			case UNT_CLAYMORETRAP:
@@ -20962,7 +21097,7 @@ static int skill_unit_timer_sub(DBKey key, DBData *data, va_list ap)
 				//clif_changetraplook(bl, UNT_FIREPILLAR_ACTIVE);
 				group->limit=DIFF_TICK(tick+1500,group->tick);
 				unit->limit=DIFF_TICK(tick+1500,group->tick);
-			break;
+				break;
 
 			case UNT_ANKLESNARE:
 			case UNT_ELECTRICSHOCKER:
@@ -20970,6 +21105,7 @@ static int skill_unit_timer_sub(DBKey key, DBData *data, va_list ap)
 					skill_delunit(unit);
 					break;
 				}
+				[[fallthrough]];
 			case UNT_SKIDTRAP:
 			case UNT_LANDMINE:
 			case UNT_SHOCKWAVE:
@@ -20999,7 +21135,7 @@ static int skill_unit_timer_sub(DBKey key, DBData *data, va_list ap)
 				}
 				skill_delunit(unit);
 			}
-			break;
+				break;
 
 			case UNT_WARP_ACTIVE:
 				// warp portal opens (morph to a UNT_WARP_WAITING cell)
@@ -21010,7 +21146,7 @@ static int skill_unit_timer_sub(DBKey key, DBData *data, va_list ap)
 				unit->limit = skill_get_time(group->skill_id,group->skill_lv);
 				// apply effect to all units standing on it
 				map_foreachincell(skill_unit_effect,unit->bl.m,unit->bl.x,unit->bl.y,group->bl_flag,&unit->bl,gettick(),1);
-			break;
+				break;
 
 			case UNT_CALLFAMILY:
 			{
@@ -21029,7 +21165,7 @@ static int skill_unit_timer_sub(DBKey key, DBData *data, va_list ap)
 				}
 				skill_delunit(unit);
 			}
-			break;
+				break;
 
 			case UNT_REVERBERATION:
 			case UNT_NETHERWORLD:
@@ -21052,7 +21188,7 @@ static int skill_unit_timer_sub(DBKey key, DBData *data, va_list ap)
 					map_foreachinrange(skill_area_sub, &unit->bl, unit->range, BL_CHAR|BL_SKILL, src, group->skill_id, group->skill_lv, tick, BCT_ENEMY|SD_ANIMATION|5, skill_castend_damage_id);
 				skill_delunit(unit);
 			}
-			break;
+				break;
 
 			case UNT_BANDING:
 			{
@@ -21066,7 +21202,7 @@ static int skill_unit_timer_sub(DBKey key, DBData *data, va_list ap)
 				group->limit = DIFF_TICK(tick+group->interval,group->tick);
 				unit->limit = DIFF_TICK(tick+group->interval,group->tick);
 			}
-			break;
+				break;
 
 			case UNT_B_TRAP:
 				{
@@ -21084,7 +21220,8 @@ static int skill_unit_timer_sub(DBKey key, DBData *data, va_list ap)
 
 			default:
 				if (group->val2 == 1 && (group->skill_id == WZ_METEOR || group->skill_id == SU_CN_METEOR || group->skill_id == SU_CN_METEOR2 || 
-					group->skill_id == AG_VIOLENT_QUAKE_ATK || group->skill_id == AG_ALL_BLOOM_ATK || group->skill_id == AG_ALL_BLOOM_ATK2 || group->skill_id == NPC_RAINOFMETEOR)) {
+					group->skill_id == AG_VIOLENT_QUAKE_ATK || group->skill_id == AG_ALL_BLOOM_ATK || group->skill_id == AG_ALL_BLOOM_ATK2 || group->skill_id == NPC_RAINOFMETEOR ||
+					group->skill_id == HN_METEOR_STORM_BUSTER)) {
 					// Deal damage before expiration
 					break;
 				}
@@ -21140,7 +21277,8 @@ static int skill_unit_timer_sub(DBKey key, DBData *data, va_list ap)
 				break;
 			default:
 				if (group->skill_id == WZ_METEOR || group->skill_id == SU_CN_METEOR || group->skill_id == SU_CN_METEOR2 || 
-					group->skill_id == AG_VIOLENT_QUAKE_ATK || group->skill_id == AG_ALL_BLOOM_ATK || group->skill_id == AG_ALL_BLOOM_ATK2 || group->skill_id == NPC_RAINOFMETEOR) {
+					group->skill_id == AG_VIOLENT_QUAKE_ATK || group->skill_id == AG_ALL_BLOOM_ATK || group->skill_id == AG_ALL_BLOOM_ATK2 || group->skill_id == NPC_RAINOFMETEOR ||
+					group->skill_id == HN_METEOR_STORM_BUSTER) {
 					if (group->val2 == 0 && (DIFF_TICK(tick, group->tick) >= group->limit - group->interval || DIFF_TICK(tick, group->tick) >= unit->limit - group->interval)) {
 						// Unit will expire the next interval, start dropping Meteor
 						block_list *src = map_id2bl(group->src_id);
@@ -21182,6 +21320,7 @@ static int skill_unit_timer_sub(DBKey key, DBData *data, va_list ap)
 		}
 		else if (group->skill_id == WZ_METEOR || group->skill_id == SU_CN_METEOR || group->skill_id == SU_CN_METEOR2 || 
 			group->skill_id == AG_VIOLENT_QUAKE_ATK || group->skill_id == AG_ALL_BLOOM_ATK || group->skill_id == AG_ALL_BLOOM_ATK2 || group->skill_id == NPC_RAINOFMETEOR ||
+			group->skill_id == HN_METEOR_STORM_BUSTER ||
 			((group->skill_id == CR_GRANDCROSS || group->skill_id == NPC_GRANDDARKNESS) && unit->val1 <= 0)) {
 			skill_delunit(unit);
 			return 0;
@@ -22129,6 +22268,7 @@ bool skill_produce_mix(map_session_data *sd, uint16 skill_id, t_itemid nameid, i
 		switch (skill_id) {
 			case ASC_CDP: //25% Damage yourself, and display same effect as failed potion.
 				status_percent_damage(NULL, &sd->bl, -25, 0, true);
+				[[fallthrough]];
 			case AM_PHARMACY:
 			case AM_TWILIGHT1:
 			case AM_TWILIGHT2:
@@ -23333,6 +23473,7 @@ int skill_block_check(struct block_list *bl, sc_type type , uint16 skill_id) {
 		case SC_KAGEHUMI:
 			if (skill_get_inf2(skill_id, INF2_IGNOREKAGEHUMI))
 				return 1;
+			break;
 		case SC_BITE:
 			if (skill_get_inf2(skill_id, INF2_IGNOREWUGBITE))
 				return 1;

+ 3 - 0
src/map/skill.hpp

@@ -39,6 +39,9 @@ class status_change;
 /// Used with tracking the hitcount of Earthquake for skills that can avoid the first attack
 #define NPC_EARTHQUAKE_FLAG 0x800
 
+/// To control alternative skill scalings
+#define SKILL_ALTDMG_FLAG 0x10
+
 /// Constants to identify a skill's nk value (damage properties)
 /// The NK value applies only to non INF_GROUND_SKILL skills
 /// when determining skill castend function to invoke.

+ 139 - 60
src/map/status.cpp

@@ -2017,11 +2017,24 @@ bool status_check_skilluse(struct block_list *src, struct block_list *target, ui
 
 		if (sc->getSCE(SC_BLADESTOP)) {
 			switch (sc->getSCE(SC_BLADESTOP)->val1) {
-				case 5: if (skill_id == MO_EXTREMITYFIST) break;
-				case 4: if (skill_id == MO_CHAINCOMBO) break;
-				case 3: if (skill_id == MO_INVESTIGATE) break;
-				case 2: if (skill_id == MO_FINGEROFFENSIVE) break;
-				default: return false;
+				case 5:
+					if (skill_id == MO_EXTREMITYFIST)
+						break;
+					[[fallthrough]];
+				case 4:
+					if (skill_id == MO_CHAINCOMBO)
+						break;
+					[[fallthrough]];
+				case 3:
+					if (skill_id == MO_INVESTIGATE)
+						break;
+					[[fallthrough]];
+				case 2:
+					if (skill_id == MO_FINGEROFFENSIVE)
+						break;
+					[[fallthrough]];
+				default:
+					return false;
 			}
 		}
 
@@ -2157,6 +2170,7 @@ bool status_check_skilluse(struct block_list *src, struct block_list *target, ui
 				return false; // Can't use Potion Pitcher on Mercenaries
 			if (tsc && tsc->getSCE(SC_ELEMENTAL_VEIL) && !(src && status_get_class_(src) == CLASS_BOSS) && !status_has_mode(status, MD_DETECTOR))
 				return false;
+			[[fallthrough]];
 		default:
 			// Check for chase-walk/hiding/cloaking opponents.
 			if( tsc ) {
@@ -4365,6 +4379,10 @@ int status_calc_pc_sub(map_session_data* sd, uint8 opt)
 		base_status->patk += skill * 3;
 		base_status->smatk += skill * 3;
 	}
+	if ((skill = pc_checkskill(sd, HN_SELFSTUDY_TATICS)) > 0)
+		base_status->patk += skill;
+	if ((skill = pc_checkskill(sd, HN_SELFSTUDY_SOCERY)) > 0)
+		base_status->smatk += skill;
 
 	// 2-Handed Staff Mastery
 	if( sd->status.weapon == W_2HSTAFF && ( skill = pc_checkskill( sd, AG_TWOHANDSTAFF ) ) > 0 ){
@@ -4489,15 +4507,19 @@ int status_calc_pc_sub(map_session_data* sd, uint8 opt)
 		skill = skill * 4;
 
 		sd->right_weapon.addrace[RC_DRAGON]+=skill;
-		sd->left_weapon.addrace[RC_DRAGON]+=skill;
+		if( !battle_config.left_cardfix_to_right ){
+			sd->left_weapon.addrace[RC_DRAGON] += skill;
+		}
 		sd->indexed_bonus.magic_addrace[RC_DRAGON]+=dragon_matk;
 		sd->indexed_bonus.subrace[RC_DRAGON]+=skill;
 	}
 	if ((skill = pc_checkskill(sd, AB_EUCHARISTICA)) > 0) {
 		sd->right_weapon.addrace[RC_DEMON] += skill;
 		sd->right_weapon.addele[ELE_DARK] += skill;
-		sd->left_weapon.addrace[RC_DEMON] += skill;
-		sd->left_weapon.addele[ELE_DARK] += skill;
+		if( !battle_config.left_cardfix_to_right ){
+			sd->left_weapon.addrace[RC_DEMON] += skill;
+			sd->left_weapon.addele[ELE_DARK] += skill;
+		}
 		sd->indexed_bonus.magic_addrace[RC_DEMON] += skill;
 		sd->indexed_bonus.magic_addele[ELE_DARK] += skill;
 		sd->indexed_bonus.subrace[RC_DEMON] += skill;
@@ -4521,8 +4543,10 @@ int status_calc_pc_sub(map_session_data* sd, uint8 opt)
 
 		sd->right_weapon.addrace[RC_UNDEAD] += race_atk[skill - 1];
 		sd->right_weapon.addrace[RC_DEMON] += race_atk[skill - 1];
-		sd->left_weapon.addrace[RC_UNDEAD] += race_atk[skill - 1];
-		sd->left_weapon.addrace[RC_DEMON] += race_atk[skill - 1];
+		if( !battle_config.left_cardfix_to_right ){
+			sd->left_weapon.addrace[RC_UNDEAD] += race_atk[skill - 1];
+			sd->left_weapon.addrace[RC_DEMON] += race_atk[skill - 1];
+		}
 		sd->indexed_bonus.subrace[RC_UNDEAD] += race_def[skill - 1];
 		sd->indexed_bonus.subrace[RC_DEMON] += race_def[skill - 1];
 	}
@@ -4536,7 +4560,9 @@ int status_calc_pc_sub(map_session_data* sd, uint8 opt)
 
 		for( uint8 size = SZ_SMALL; size < SZ_MAX; size++ ){
 			sd->right_weapon.addsize[size] += attack_bonus[size][skill - 1];
-			sd->left_weapon.addsize[size] += attack_bonus[size][skill - 1];
+			if( !battle_config.left_cardfix_to_right ){
+				sd->left_weapon.addsize[size] += attack_bonus[size][skill - 1];
+			}
 		}
 	}
 	if ((skill = pc_checkskill(sd, CD_FIDUS_ANIMUS)) > 0) {
@@ -4566,7 +4592,9 @@ int status_calc_pc_sub(map_session_data* sd, uint8 opt)
 
 		for( uint8 size = SZ_SMALL; size < SZ_MAX; size++ ){
 			sd->right_weapon.addsize[size] += attack_bonus[size][skill - 1];
-			sd->left_weapon.addsize[size] += attack_bonus[size][skill - 1];
+			if( !battle_config.left_cardfix_to_right ){
+				sd->left_weapon.addsize[size] += attack_bonus[size][skill - 1];
+			}
 		}
 	}
 	if ((skill = pc_checkskill(sd, ABC_MAGIC_SWORD_M)) > 0 && (sd->status.weapon == W_DAGGER || sd->status.weapon == W_1HSWORD || sd->status.weapon == W_DOUBLE_DD || sd->status.weapon == W_DOUBLE_SS || sd->status.weapon == W_DOUBLE_DS || sd->status.weapon == W_DOUBLE_DA || sd->status.weapon == W_DOUBLE_SA)) {
@@ -4613,8 +4641,10 @@ int status_calc_pc_sub(map_session_data* sd, uint8 opt)
 			i = sc->getSCE(SC_BASILICA)->val1 * 5;
 			sd->right_weapon.addele[ELE_DARK] += i;
 			sd->right_weapon.addele[ELE_UNDEAD] += i;
-			sd->left_weapon.addele[ELE_DARK] += i;
-			sd->left_weapon.addele[ELE_UNDEAD] += i;
+			if( !battle_config.left_cardfix_to_right ){
+				sd->left_weapon.addele[ELE_DARK] += i;
+				sd->left_weapon.addele[ELE_UNDEAD] += i;
+			}
 			sd->indexed_bonus.magic_atk_ele[ELE_HOLY] += sc->getSCE(SC_BASILICA)->val1 * 3;
 		}
 		if (sc->getSCE(SC_FIREWEAPON))
@@ -4630,20 +4660,22 @@ int status_calc_pc_sub(map_session_data* sd, uint8 opt)
 			sd->indexed_bonus.subele[ELE_HOLY] += sc->getSCE(SC_PROVIDENCE)->val2;
 			sd->indexed_bonus.subrace[RC_DEMON] += sc->getSCE(SC_PROVIDENCE)->val2;
 		}
-        if (sc->getSCE(SC_GEFFEN_MAGIC1)) {
-            sd->right_weapon.addrace[RC_PLAYER_HUMAN] += sc->getSCE(SC_GEFFEN_MAGIC1)->val1;
-            sd->right_weapon.addrace[RC_DEMIHUMAN] += sc->getSCE(SC_GEFFEN_MAGIC1)->val1;
-            sd->left_weapon.addrace[RC_PLAYER_HUMAN] += sc->getSCE(SC_GEFFEN_MAGIC1)->val1;
-            sd->left_weapon.addrace[RC_DEMIHUMAN] += sc->getSCE(SC_GEFFEN_MAGIC1)->val1;
-        }
-        if (sc->getSCE(SC_GEFFEN_MAGIC2)) {
-            sd->indexed_bonus.magic_addrace[RC_PLAYER_HUMAN] += sc->getSCE(SC_GEFFEN_MAGIC2)->val1;
-            sd->indexed_bonus.magic_addrace[RC_DEMIHUMAN] += sc->getSCE(SC_GEFFEN_MAGIC2)->val1;
-        }
-        if(sc->getSCE(SC_GEFFEN_MAGIC3)) {
-            sd->indexed_bonus.subrace[RC_PLAYER_HUMAN] += sc->getSCE(SC_GEFFEN_MAGIC3)->val1;
-            sd->indexed_bonus.subrace[RC_DEMIHUMAN] += sc->getSCE(SC_GEFFEN_MAGIC3)->val1;
-        }
+		if (sc->getSCE(SC_GEFFEN_MAGIC1)) {
+			sd->right_weapon.addrace[RC_PLAYER_HUMAN] += sc->getSCE(SC_GEFFEN_MAGIC1)->val1;
+			sd->right_weapon.addrace[RC_DEMIHUMAN] += sc->getSCE(SC_GEFFEN_MAGIC1)->val1;
+			if( !battle_config.left_cardfix_to_right ){
+				sd->left_weapon.addrace[RC_PLAYER_HUMAN] += sc->getSCE( SC_GEFFEN_MAGIC1 )->val1;
+				sd->left_weapon.addrace[RC_DEMIHUMAN] += sc->getSCE( SC_GEFFEN_MAGIC1 )->val1;
+			}
+		}
+		if (sc->getSCE(SC_GEFFEN_MAGIC2)) {
+			sd->indexed_bonus.magic_addrace[RC_PLAYER_HUMAN] += sc->getSCE(SC_GEFFEN_MAGIC2)->val1;
+			sd->indexed_bonus.magic_addrace[RC_DEMIHUMAN] += sc->getSCE(SC_GEFFEN_MAGIC2)->val1;
+		}
+		if(sc->getSCE(SC_GEFFEN_MAGIC3)) {
+			sd->indexed_bonus.subrace[RC_PLAYER_HUMAN] += sc->getSCE(SC_GEFFEN_MAGIC3)->val1;
+			sd->indexed_bonus.subrace[RC_DEMIHUMAN] += sc->getSCE(SC_GEFFEN_MAGIC3)->val1;
+		}
 		if(sc->getSCE(SC_ARMOR_ELEMENT_WATER)) {	// This status change should grant card-type elemental resist.
 			sd->indexed_bonus.subele[ELE_WATER] += sc->getSCE(SC_ARMOR_ELEMENT_WATER)->val1;
 			sd->indexed_bonus.subele[ELE_EARTH] += sc->getSCE(SC_ARMOR_ELEMENT_WATER)->val2;
@@ -7984,6 +8016,10 @@ static unsigned short status_calc_speed(struct block_list *bl, status_change *sc
 				val = max(val, sc->getSCE(SC_SP_SHA)->val2);
 			if (sc->getSCE(SC_CREATINGSTAR))
 				val = max(val, 90);
+			if (sc->getSCE(SC_SHIELDCHAINRUSH))
+				val = max(val, 20);
+			if (sc->getSCE(SC_GROUNDGRAVITY))
+				val = max(val, 20);
 
 			if( sd && sd->bonus.speed_rate + sd->bonus.speed_add_rate > 0 ) // Permanent item-based speedup
 				val = max( val, sd->bonus.speed_rate + sd->bonus.speed_add_rate );
@@ -9384,6 +9420,7 @@ static int status_get_sc_interval(enum sc_type type)
 		case SC_DEATHHURT:
 		case SC_GRADUAL_GRAVITY:
 		case SC_KILLING_AURA:
+		case SC_BOSSMAPINFO:
 			return 1000;
 		case SC_BURNING:
 		case SC_PYREXIA:
@@ -10398,6 +10435,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 					case SC_BERSERK:
 					case SC_SATURDAYNIGHTFEVER:
 						sc->getSCE(rem_sc)->val2 = 0; // Mark to not lose hp
+						[[fallthrough]];
 					default:
 						status_change_end(bl, rem_sc);
 						break;
@@ -10502,6 +10540,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 				if (sc && sc->getSCE(type)->val2 & BREAK_NECK)
 					return 0; // BREAK_NECK cannot be stacked with new breaks until the status is over.
 				val2 |= sce->val2; // Stackable ailments
+				[[fallthrough]];
 			default:
 				if (scdb->flag[SCF_OVERLAPIGNORELEVEL])
 					break;
@@ -10868,7 +10907,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 					diff = status->hp - (status->max_hp / 4);
 				status_zap(bl, diff, 0);
 			}
-			// Fall through
+			[[fallthrough]];
 		case SC_STONE:
 		case SC_POISON:
 		case SC_BLEEDING:
@@ -10889,6 +10928,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 				break;
 			tick_time = status_get_sc_interval(type);
 			val4 = tick - tick_time; // Remaining time
+			break;
 		case SC_LEECHESEND:
 			if (val3 == 0)
 				break;
@@ -10960,16 +11000,21 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 			}
 			break;
 		case SC_BOSSMAPINFO:
-			if( sd != NULL ) {
-				struct mob_data *boss_md = map_getmob_boss(bl->m); // Search for Boss on this Map
+			if( sd == nullptr ){
+				return 0;
+			}else{
+				// Search for Boss on this Map
+				mob_data* boss_md = map_getmob_boss( bl->m );
 
-				if( boss_md == NULL ) { // No MVP on this map
-					clif_bossmapinfo(sd, NULL, BOSS_INFO_NOT);
+				// No MVP on this map
+				if( boss_md == nullptr ){
+					clif_bossmapinfo( *sd, nullptr, BOSS_INFO_NOT );
 					return 0;
 				}
+
 				val1 = boss_md->bl.id;
-				tick_time = 1000; // [GodLesZ] tick time
-				val4 = tick / tick_time;
+				tick_time = status_get_sc_interval( type );
+				val4 = tick - tick_time; // Remaining time
 			}
 			break;
 		case SC_HIDING:
@@ -11227,6 +11272,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 			switch (val1) {
 				case 3: // 33*3 + 1 -> 100%
 					val2++;
+					[[fallthrough]];
 				case 1:
 				case 2: // 33, 66%
 					val2 += 33*val1;
@@ -11454,6 +11500,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 			// Level 1 ~ 5 & 6 ~ 10 has different duration
 			// Level 6 ~ 10 use effect of level 1 ~ 5
 			val1 = 1 + ((val1-1)%5);
+			[[fallthrough]];
 		case SC_SLOWCAST:
 			val2 = 20*val1; // Magic reflection/cast rate
 			break;
@@ -11975,17 +12022,20 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 		case SC_WILD_STORM:
 		case SC_UPHEAVAL:
 			val2 += 10;
+			[[fallthrough]];
 		case SC_HEATER:
 		case SC_COOLER:
 		case SC_BLAST:
 		case SC_CURSED_SOIL:
 			val2 += 10;
+			[[fallthrough]];
 		case SC_PYROTECHNIC:
 		case SC_AQUAPLAY:
 		case SC_GUST:
 		case SC_PETROLOGY:
 			val2 += 5;
 			val3 += 9000;
+			[[fallthrough]];
 		case SC_CIRCLE_OF_FIRE:
 		case SC_FIRE_CLOAK:
 		case SC_WATER_DROP:
@@ -12729,6 +12779,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 					break;
 				tick_time = tick;
 				tick = tick_time + max(val4, 0);
+				[[fallthrough]];
 			case SC_MAGICMUSHROOM:
 			case SC_PYREXIA:
 			case SC_LEECHESEND:
@@ -12951,8 +13002,28 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 			}
 			break;
 		case SC_BOSSMAPINFO:
-			if (sd)
-				clif_bossmapinfo(sd, map_id2boss(sce->val1), BOSS_INFO_ALIVE_WITHMSG); // First Message
+			if( sd == nullptr ){
+				return 0;
+			}else{
+				mob_data* boss_md = map_id2boss( sce->val1 );
+
+				if( boss_md == nullptr ){
+					return 0;
+				}
+
+				// Not on same map anymore
+				if( sd->bl.m != boss_md->bl.m ){
+					return 0;
+				// Boss is alive
+				}else if( boss_md->bl.prev != nullptr ){
+					sce->val2 = 0;
+					clif_bossmapinfo( *sd, boss_md, BOSS_INFO_ALIVE_WITHMSG );
+				// Boss is dead
+				}else if( boss_md->spawn_timer != INVALID_TIMER ){
+					sce->val2 = 1;
+					clif_bossmapinfo( *sd, boss_md, BOSS_INFO_DEAD );
+				}
+			}
 			break;
 		case SC_FULL_THROTTLE:
 		case SC_MERC_HPUP:
@@ -13332,16 +13403,18 @@ int status_change_end(struct block_list* bl, enum sc_type type, int tid)
 					skill_castend_damage_id(src, bl, sce->val2, sce->val1, gettick(), SD_LEVEL );
 			}
 			break;
-		case SC_CLOSECONFINE2:{
-			struct block_list *src = sce->val2?map_id2bl(sce->val2):NULL;
-			status_change *sc2 = src?status_get_sc(src):NULL;
-			if (src && sc2 && sc2->getSCE(SC_CLOSECONFINE)) {
-				// If status was already ended, do nothing.
-				// Decrease count
-				if (--(sc2->getSCE(SC_CLOSECONFINE)->val1) <= 0) // No more holds, free him up.
-					status_change_end(src, SC_CLOSECONFINE);
+		case SC_CLOSECONFINE2:
+			{
+				struct block_list *src = sce->val2?map_id2bl(sce->val2):nullptr;
+				status_change *sc2 = src?status_get_sc(src):nullptr;
+				if (src && sc2 && sc2->getSCE(SC_CLOSECONFINE)) {
+					// If status was already ended, do nothing.
+					// Decrease count
+					if (--(sc2->getSCE(SC_CLOSECONFINE)->val1) <= 0) // No more holds, free him up.
+						status_change_end(src, SC_CLOSECONFINE);
+				}
 			}
-		}
+			[[fallthrough]];
 		case SC_CLOSECONFINE:
 			if (sce->val2 > 0) {
 				// Caster has been unlocked... nearby chars need to be unlocked.
@@ -14043,22 +14116,27 @@ TIMER_FUNC(status_change_timer){
 		break;
 
 	case SC_BOSSMAPINFO:
-		if( sd && --(sce->val4) >= 0 ) {
-			struct mob_data *boss_md = map_id2boss(sce->val1);
+		if( sd && sce->val4 >= 0 ){
+			mob_data* boss_md = map_id2boss( sce->val1 );
 
-			if (boss_md) {
-				if (sd->bl.m != boss_md->bl.m) // Not on same map anymore
-					return 0;
-				else if (boss_md->bl.prev != NULL) { // Boss is alive - Update X, Y on minimap
-					sce->val2 = 0;
-					clif_bossmapinfo(sd, boss_md, BOSS_INFO_ALIVE);
-				} else if (boss_md->spawn_timer != INVALID_TIMER && !sce->val2) { // Boss is dead
-					sce->val2 = 1;
-					clif_bossmapinfo(sd, boss_md, BOSS_INFO_DEAD);
-				}
+			if( boss_md == nullptr ){
+				sce->val4 = 0;
+				break;
+			}
+
+			// Not on same map anymore
+			if( sd->bl.m != boss_md->bl.m ){
+				sce->val4 = 0;
+				break;
+			// Boss is alive - Update X, Y on minimap
+			}else if( boss_md->bl.prev != nullptr ){
+				sce->val2 = 0;
+				clif_bossmapinfo( *sd, boss_md, BOSS_INFO_ALIVE );
+			// Boss is dead
+			}else if( boss_md->spawn_timer != INVALID_TIMER && sce->val2 == 0 ){
+				sce->val2 = 1;
+				clif_bossmapinfo( *sd, boss_md, BOSS_INFO_DEAD );
 			}
-			sc_timer_next(1000 + tick);
-			return 0;
 		}
 		break;
 
@@ -14102,6 +14180,7 @@ TIMER_FUNC(status_change_timer){
 					sp= 4*(sce->val1>>16);
 					// Upkeep is also every 10 secs.
 #ifndef RENEWAL
+				[[fallthrough]];
 				case DC_DONTFORGETME:
 #endif
 					s=10;

+ 9 - 0
src/map/status.hpp

@@ -1284,6 +1284,15 @@ enum sc_type : int16 {
 	SC_RUSH_QUAKE2,
 	
 	SC_G_LIFEPOTION,
+
+	// Hyper Novice
+	SC_HNNOWEAPON,
+	SC_SHIELDCHAINRUSH,
+	SC_MISTYFROST,
+	SC_GROUNDGRAVITY,
+	SC_BREAKINGLIMIT,
+	SC_RULEBREAK,
+
 #ifdef RENEWAL
 	SC_EXTREMITYFIST2, //! NOTE: This SC should be right before SC_MAX, so it doesn't disturb if RENEWAL is disabled
 #endif

+ 1 - 1
src/map/unit.cpp

@@ -3290,7 +3290,7 @@ int unit_remove_map_(struct block_list *bl, clr_type clrtype, const char* file,
 				map_delblock(bl);
 				break;
 			}
-			// Fall through
+			[[fallthrough]];
 		default:
 			clif_clearunit_area(bl, clrtype);
 			map_delblock(bl);

+ 12 - 12
src/web/web.cpp

@@ -44,26 +44,26 @@ struct Web_Config web_config {};
 struct Inter_Config inter_config {};
 std::shared_ptr<httplib::Server> http_server;
 
-int login_server_port = 3306;
 std::string login_server_ip = "127.0.0.1";
+uint16 login_server_port = 3306;
 std::string login_server_id = "ragnarok";
 std::string login_server_pw = "";
 std::string login_server_db = "ragnarok";
 
-int  char_server_port = 3306;
 std::string char_server_ip = "127.0.0.1";
+uint16  char_server_port = 3306;
 std::string char_server_id = "ragnarok";
 std::string char_server_pw = "";
 std::string char_server_db = "ragnarok";
 
-int map_server_port = 3306;
 std::string map_server_ip = "127.0.0.1";
+uint16 map_server_port = 3306;
 std::string map_server_id = "ragnarok";
 std::string map_server_pw = "";
 std::string map_server_db = "ragnarok";
 
-int web_server_port = 3306;
 std::string web_server_ip = "127.0.0.1";
+uint16 web_server_port = 3306;
 std::string web_server_id = "ragnarok";
 std::string web_server_pw = "";
 std::string web_server_db = "ragnarok";
@@ -188,7 +188,7 @@ int inter_config_read(const char* cfgName)
 		else if(!strcmpi(w1,"login_server_ip"))
 			login_server_ip = w2;
 		else if(!strcmpi(w1,"login_server_port"))
-			login_server_port = atoi(w2);
+			login_server_port = (uint16)strtoul( w2, nullptr, 10 );
 		else if(!strcmpi(w1,"login_server_id"))
 			login_server_id = w2;
 		else if(!strcmpi(w1,"login_server_pw"))
@@ -198,7 +198,7 @@ int inter_config_read(const char* cfgName)
 		else if(!strcmpi(w1,"char_server_ip"))
 			char_server_ip = w2;
 		else if(!strcmpi(w1,"char_server_port"))
-			char_server_port = atoi(w2);
+			char_server_port = (uint16)strtoul( w2, nullptr, 10 );
 		else if(!strcmpi(w1,"char_server_id"))
 			char_server_id = w2;
 		else if(!strcmpi(w1,"char_server_pw"))
@@ -208,7 +208,7 @@ int inter_config_read(const char* cfgName)
 		else if(!strcmpi(w1,"map_server_ip"))
 			map_server_ip = w2;
 		else if(!strcmpi(w1,"map_server_port"))
-			map_server_port = atoi(w2);
+			map_server_port = (uint16)strtoul( w2, nullptr, 10 );
 		else if(!strcmpi(w1,"map_server_id"))
 			map_server_id = w2;
 		else if(!strcmpi(w1,"map_server_pw"))
@@ -218,7 +218,7 @@ int inter_config_read(const char* cfgName)
 		else if(!strcmpi(w1,"web_server_ip"))
 			web_server_ip = w2;
 		else if(!strcmpi(w1,"web_server_port"))
-			web_server_port = atoi(w2);
+			web_server_port = (uint16)strtoul( w2, nullptr, 10 );
 		else if(!strcmpi(w1,"web_server_id"))
 			web_server_id = w2;
 		else if(!strcmpi(w1,"web_server_pw"))
@@ -276,7 +276,7 @@ int web_sql_init(void) {
 	ShowInfo("Connecting to the Login DB server.....\n");
 
 	if (SQL_ERROR == Sql_Connect(login_handle, login_server_id.c_str(), login_server_pw.c_str(), login_server_ip.c_str(), login_server_port, login_server_db.c_str())) {
-		ShowError("Couldn't connect with uname='%s',host='%s',port='%d',database='%s'\n",
+		ShowError("Couldn't connect with uname='%s',host='%s',port='%hu',database='%s'\n",
 			login_server_id.c_str(), login_server_ip.c_str(), login_server_port, login_server_db.c_str());
 		Sql_ShowDebug(login_handle);
 		Sql_Free(login_handle);
@@ -293,7 +293,7 @@ int web_sql_init(void) {
 	ShowInfo("Connecting to the Char DB server.....\n");
 
 	if (SQL_ERROR == Sql_Connect(char_handle, char_server_id.c_str(), char_server_pw.c_str(), char_server_ip.c_str(), char_server_port, char_server_db.c_str())) {
-		ShowError("Couldn't connect with uname='%s',host='%s',port='%d',database='%s'\n",
+		ShowError("Couldn't connect with uname='%s',host='%s',port='%hu',database='%s'\n",
 			char_server_id.c_str(), char_server_ip.c_str(), char_server_port, char_server_db.c_str());
 		Sql_ShowDebug(char_handle);
 		Sql_Free(char_handle);
@@ -310,7 +310,7 @@ int web_sql_init(void) {
 	ShowInfo("Connecting to the Map DB server.....\n");
 
 	if (SQL_ERROR == Sql_Connect(map_handle, map_server_id.c_str(), map_server_pw.c_str(), map_server_ip.c_str(), map_server_port, map_server_db.c_str())) {
-		ShowError("Couldn't connect with uname='%s',host='%s',port='%d',database='%s'\n",
+		ShowError("Couldn't connect with uname='%s',host='%s',port='%hu',database='%s'\n",
 			map_server_id.c_str(), map_server_ip.c_str(), map_server_port, map_server_db.c_str());
 		Sql_ShowDebug(map_handle);
 		Sql_Free(map_handle);
@@ -327,7 +327,7 @@ int web_sql_init(void) {
 	ShowInfo("Connecting to the Web DB server.....\n");
 
 	if (SQL_ERROR == Sql_Connect(web_handle, web_server_id.c_str(), web_server_pw.c_str(), web_server_ip.c_str(), web_server_port, web_server_db.c_str())) {
-		ShowError("Couldn't connect with uname='%s',host='%s',port='%d',database='%s'\n",
+		ShowError("Couldn't connect with uname='%s',host='%s',port='%hu',database='%s'\n",
 			web_server_id.c_str(), web_server_ip.c_str(), web_server_port, web_server_db.c_str());
 		Sql_ShowDebug(web_handle);
 		Sql_Free(web_handle);

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