Przeglądaj źródła

Initial release of item package selection (#7239)

Thanks to @aleos89 and @Atemo

Co-authored-by: Atemo <capucrath@gmail.com>
Co-authored-by: Aleos <aleos89@users.noreply.github.com>
Lemongrass3110 2 lat temu
rodzic
commit
38b8d5a994

+ 39 - 0
db/import-tmpl/item_packages.yml

@@ -0,0 +1,39 @@
+# This file is a part of rAthena.
+#   Copyright(C) 2022 rAthena Development Team
+#   https://rathena.org - https://github.com/rathena
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+###########################################################################
+# Item Package Database
+###########################################################################
+#
+# Item Package Settings
+#
+###########################################################################
+# - Item                       Item that triggers Item Package Selection.
+#   Groups:                    Groups that can be selected.
+#     - Group                  Group ID that can be selected (has to match the client's LUA file).
+#       Items:                 Items that will be given out.
+#         - Item               Item that will be given out.
+#           Amount             Amount of the item. (Default: 1)
+#                              To remove an item via import set amount to 0.
+#           RentalHours        Rental time in hours. (Default: 0)
+#           Refine             Refine level of the item. (Default: 0)
+#           RandomOptionGroup  Name of the random option group that will be applied. (Default: none)
+###########################################################################
+
+Header:
+  Type: ITEM_PACKAGE_DB
+  Version: 1

+ 45 - 0
db/item_packages.yml

@@ -0,0 +1,45 @@
+# This file is a part of rAthena.
+#   Copyright(C) 2022 rAthena Development Team
+#   https://rathena.org - https://github.com/rathena
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+###########################################################################
+# Item Package Database
+###########################################################################
+#
+# Item Package Settings
+#
+###########################################################################
+# - Item                       Item that triggers Item Package Selection.
+#   Groups:                    Groups that can be selected.
+#     - Group                  Group ID that can be selected (has to match the client's LUA file).
+#       Items:                 Items that will be given out.
+#         - Item               Item that will be given out.
+#           Amount             Amount of the item. (Default: 1)
+#                              To remove an item via import set amount to 0.
+#           RentalHours        Rental time in hours. (Default: 0)
+#           Refine             Refine level of the item. (Default: 0)
+#           RandomOptionGroup  Name of the random option group that will be applied. (Default: none)
+###########################################################################
+
+Header:
+  Type: ITEM_PACKAGE_DB
+  Version: 1
+
+Footer:
+  Imports:
+  - Path: db/re/item_packages.yml
+    Mode: Renewal
+  - Path: db/import/item_packages.yml

+ 467 - 0
db/re/item_db_usable.yml

@@ -51335,6 +51335,18 @@ Body:
     Weight: 10
     Script: |
       item_reform();
+  - Id: 101060
+    AegisName: Select_Example1
+    Name: TestA
+    Type: DelayConsume
+    Flags:
+      BuyingStore: true
+  - Id: 101062
+    AegisName: Select_Example2
+    Name: TestB
+    Type: DelayConsume
+    Flags:
+      BuyingStore: true
   - Id: 101075
     AegisName: SLD_Card_Recipe
     Name: Sealed Boss Card Thump Box
@@ -52089,6 +52101,45 @@ Body:
       Container: true
     Script: |
       getgroupitem(IG_Enchant_Stone_Box27);
+  - Id: 101423
+    AegisName: Boost_Armor_Box
+    Name: Boost Armor Box    # !todo check english name
+    Type: DelayConsume
+    EquipLevelMin: 100
+    Trade:
+      NoDrop: true
+      NoTrade: true
+      NoStorage: true
+      NoCart: true
+      NoGuildStorage: true
+      NoMail: true
+      NoAuction: true
+  - Id: 101453
+    AegisName: Special_Coin_Pack
+    Name: Special Coin Pack    # !todo check english name
+    Type: DelayConsume
+    EquipLevelMin: 200
+    Trade:
+      NoDrop: true
+      NoTrade: true
+      NoSell: true
+      NoStorage: true
+      NoCart: true
+      NoGuildStorage: true
+      NoMail: true
+      NoAuction: true
+  - Id: 101454
+    AegisName: Metal_W_Box
+    Name: Metal Weapon Box    # !todo check english name
+    Type: DelayConsume
+    Trade:
+      NoDrop: true
+      NoTrade: true
+      NoStorage: true
+      NoCart: true
+      NoGuildStorage: true
+      NoMail: true
+      NoAuction: true
   - Id: 101455
     AegisName: E_Auto_Up
     Name: Automatic (bound) upgrade package    # !todo check english name
@@ -52104,6 +52155,54 @@ Body:
       NoAuction: true
     Script: |
       laphine_upgrade();
+  - Id: 101456
+    AegisName: Memento_Box
+    Name: Souvenir Box    # !todo check english name
+    Type: DelayConsume
+    Trade:
+      NoDrop: true
+      NoTrade: true
+      NoStorage: true
+      NoCart: true
+      NoGuildStorage: true
+      NoMail: true
+      NoAuction: true
+  - Id: 101457
+    AegisName: P_Memento_Box
+    Name: Premium Souvenir Box    # !todo check english name
+    Type: DelayConsume
+    Trade:
+      NoDrop: true
+      NoTrade: true
+      NoStorage: true
+      NoCart: true
+      NoGuildStorage: true
+      NoMail: true
+      NoAuction: true
+  - Id: 101458
+    AegisName: Booster_Hat_Box
+    Name: Booster Costume Helmet Box    # !todo check english name
+    Type: DelayConsume
+    Trade:
+      NoDrop: true
+      NoTrade: true
+      NoStorage: true
+      NoCart: true
+      NoGuildStorage: true
+      NoMail: true
+      NoAuction: true
+  - Id: 101459
+    AegisName: Booster_Back_Box
+    Name: Booster Costume Backpack Box    # !todo check english name
+    Type: DelayConsume
+    Trade:
+      NoDrop: true
+      NoTrade: true
+      NoStorage: true
+      NoCart: true
+      NoGuildStorage: true
+      NoMail: true
+      NoAuction: true
   - Id: 101463
     AegisName: HD_Elunium_10Box_MSP
     Name: (Limited) HD Elunium 10 Box
@@ -52134,6 +52233,20 @@ Body:
     Script: |
       getitem 6240,10;
       getitembound 23919,11,Bound_Account;
+  - Id: 101470
+    AegisName: aegis_101470
+    Name: Stats Soul Potion Selection Box
+    Type: DelayConsume
+    Flags:
+      BuyingStore: true
+  - Id: 101471
+    AegisName: aegis_101471
+    Name: Alchemist Selection Box
+    Type: DelayConsume
+    Buy: 20
+    Weight: 10
+    Flags:
+      BuyingStore: true
   - Id: 101482
     AegisName: Freedom_Stick_Cube
     Name: Freedom Stick Remodeling Cube
@@ -52173,6 +52286,149 @@ Body:
     Script: |
       sc_start SC_FOOD_INT_CASH,1800000,15;
       sc_start SC_MATKPOTION,600000,rand(11,111);
+  - Id: 101542
+    AegisName: aegis_101542
+    Name: Full Penetration Shadow Selection Box
+    Type: DelayConsume
+    Weight: 10
+    Flags:
+      BuyingStore: true
+  - Id: 101543
+    AegisName: aegis_101543
+    Name: Full Penetration Shadow Earring Box
+    Type: Usable
+    Weight: 10
+    Flags:
+      Container: true
+    Script: |
+      getgroupitem(IG_S_FULLPENE_EARRING,true);
+  - Id: 101544
+    AegisName: aegis_101544
+    Name: Full Penetration Shadow Pendant Box
+    Type: Usable
+    Weight: 10
+    Flags:
+      Container: true
+    Script: |
+      getgroupitem(IG_S_FULLPENE_PENDANT,true);
+  - Id: 101545
+    AegisName: aegis_101545
+    Name: Full Penetration Shadow Armor Box
+    Type: Usable
+    Weight: 10
+    Flags:
+      Container: true
+    Script: |
+      getgroupitem(IG_S_FULLPENE_ARMOR,true);
+  - Id: 101546
+    AegisName: aegis_101546
+    Name: Full Penetration Shadow Shoes Box
+    Type: Usable
+    Weight: 10
+    Flags:
+      Container: true
+    Script: |
+      getgroupitem(IG_S_FULLPENE_SHOES,true);
+  - Id: 101547
+    AegisName: aegis_101547
+    Name: Full Tempest Shadow Selection Box
+    Type: DelayConsume
+    Weight: 10
+    Flags:
+      BuyingStore: true
+  - Id: 101548
+    AegisName: aegis_101548
+    Name: Full Tempest Shadow Earring Box
+    Type: Usable
+    Weight: 10
+    Flags:
+      Container: true
+    Script: |
+      getgroupitem(IG_S_FULLTEMP_EARRING,true);
+  - Id: 101549
+    AegisName: aegis_101549
+    Name: Full Tempest Shadow Pendant Box
+    Type: Usable
+    Weight: 10
+    Flags:
+      Container: true
+    Script: |
+      getgroupitem(IG_S_FULLTEMP_PENDANT,true);
+  - Id: 101550
+    AegisName: aegis_101550
+    Name: Full Tempest Shadow Armor Box
+    Type: Usable
+    Weight: 10
+    Flags:
+      Container: true
+    Script: |
+      getgroupitem(IG_S_FULLTEMP_ARMOR,true);
+  - Id: 101551
+    AegisName: aegis_101551
+    Name: Full Tempest Shadow Shoes Box
+    Type: Usable
+    Weight: 10
+    Flags:
+      Container: true
+    Script: |
+      getgroupitem(IG_S_FULLTEMP_SHOES,true);
+  - Id: 101552
+    AegisName: aegis_101552
+    Name: Durable Shadow Selection Box
+    Type: DelayConsume
+    Weight: 10
+    Flags:
+      BuyingStore: true
+  - Id: 101553
+    AegisName: aegis_101553
+    Name: Durable Shadow Weapon Box
+    Type: Usable
+    Weight: 10
+    Flags:
+      Container: true
+    Script: |
+      getgroupitem(IG_S_DURABLE_WEAPON,true);
+  - Id: 101554
+    AegisName: aegis_101554
+    Name: Durable Shadow Shield Box
+    Type: Usable
+    Weight: 10
+    Flags:
+      Container: true
+    Script: |
+      getgroupitem(IG_S_DURABLE_SHIELD,true);
+  - Id: 101555
+    AegisName: aegis_101555
+    Name: Clever Shadow Selection Box
+    Type: DelayConsume
+    Weight: 10
+    Flags:
+      BuyingStore: true
+  - Id: 101556
+    AegisName: aegis_101556
+    Name: Clever Shadow Weapon Box
+    Type: Usable
+    Weight: 10
+    Flags:
+      Container: true
+    Script: |
+      getgroupitem(IG_S_CLEVER_WEAPON,true);
+  - Id: 101557
+    AegisName: aegis_101557
+    Name: Clever Shadow Shield Box
+    Type: Usable
+    Weight: 10
+    Flags:
+      Container: true
+    Script: |
+      getgroupitem(IG_S_CLEVER_SHIELD,true);
+  - Id: 101563
+    AegisName: aegis_101563
+    Name: Helmet Selection Box for OS Weapons
+    Type: DelayConsume
+    Weight: 10
+    Flags:
+      BuyingStore: true
   - Id: 101564
     AegisName: AllMighty_Up
     Name: Almighty Shadow Spellbook
@@ -52182,6 +52438,13 @@ Body:
       BuyingStore: true
     Script: |
       laphine_upgrade();
+  - Id: 101565
+    AegisName: aegis_101565
+    Name: Shadow Spellbook Selection Box
+    Type: DelayConsume
+    Weight: 10
+    Flags:
+      BuyingStore: true
   - Id: 101639
     AegisName: D_Gw_Extractor
     Name: Dim Glacier Extractor    # !todo check english name
@@ -52197,6 +52460,99 @@ Body:
       NoAuction: true
     Script: |
       laphine_synthesis();
+  - Id: 101654
+    AegisName: aegis_101654
+    Name: Almighty Shadow Selection Box    # !todo check english name
+    Type: DelayConsume
+    Weight: 10
+    Flags:
+      BuyingStore: true
+  - Id: 101655
+    AegisName: aegis_101655
+    Name: Almighty Shadow Earring Box    # !todo check english name
+    Type: Usable
+    Weight: 10
+    Flags:
+      Container: true
+    Script: |
+      getgroupitem(IG_S_ALLMIGHTY_EARRING,true);
+  - Id: 101656
+    AegisName: aegis_101656
+    Name: Almighty Shadow Pendant Box    # !todo check english name
+    Type: Usable
+    Weight: 10
+    Flags:
+      Container: true
+    Script: |
+      getgroupitem(IG_S_ALLMIGHTY_PENDANT,true);
+  - Id: 101657
+    AegisName: aegis_101657
+    Name: True Gemstone Shadow Selection Box    # !todo check english name
+    Type: DelayConsume
+    Weight: 10
+    Flags:
+      BuyingStore: true
+  - Id: 101658
+    AegisName: aegis_101658
+    Name: True Gemstone Shadow Earring Box    # !todo check english name
+    Type: Usable
+    Weight: 10
+    Flags:
+      Container: true
+    Script: |
+      getgroupitem(IG_S_TRUEGEM_EARRING,true);
+  - Id: 101659
+    AegisName: aegis_101659
+    Name: True Gemstone Shadow Pendant Box    # !todo check english name
+    Type: Usable
+    Weight: 10
+    Flags:
+      Container: true
+    Script: |
+      getgroupitem(IG_S_TRUEGEM_PENDANT,true);
+  - Id: 101660
+    AegisName: aegis_101660
+    Name: True Gemstone Shadow Shoes Box    # !todo check english name
+    Type: Usable
+    Weight: 10
+    Flags:
+      Container: true
+    Script: |
+      getgroupitem(IG_S_TRUEGEM_SHOES,true);
+  - Id: 101661
+    AegisName: aegis_101661
+    Name: True Gemstone Shadow Armor Box    # !todo check english name
+    Type: Usable
+    Weight: 10
+    Flags:
+      Container: true
+    Script: |
+      getgroupitem(IG_S_TRUEGEM_ARMOR,true);
+  - Id: 101662
+    AegisName: aegis_101662
+    Name: Perfect Size Shadow Selection Box    # !todo check english name
+    Type: DelayConsume
+    Weight: 10
+    Flags:
+      BuyingStore: true
+  - Id: 101663
+    AegisName: aegis_101663
+    Name: Perfect Size Shadow Weapon Box    # !todo check english name
+    Type: Usable
+    Weight: 10
+    Flags:
+      Container: true
+    Script: |
+      getgroupitem(IG_S_PERFECTSIZE_WEAPON,true);
+  - Id: 101664
+    AegisName: aegis_101664
+    Name: Perfect Size Shadow Armor Box    # !todo check english name
+    Type: Usable
+    Weight: 10
+    Flags:
+      Container: true
+    Script: |
+      getgroupitem(IG_S_PERFECTSIZE_ARMOR,true);
   - Id: 101665
     AegisName: EXPShadow_Mix2
     Name: Experience Shadow Pickbox (Weapon)    # !todo check english name
@@ -52215,6 +52571,117 @@ Body:
       Container: true
     Script: |
       getgroupitem(IG_Enchant_Stone_Box28);
+  - Id: 101717
+    AegisName: aegis_101717
+    Name: Maximum Mammoth Shadow Earring Box    # !todo check english name
+    Type: Usable
+    Weight: 10
+    Flags:
+      Container: true
+    Script: |
+      getgroupitem(IG_S_M_MAMMOTH_EARRING,true);
+  - Id: 101718
+    AegisName: aegis_101718
+    Name: Maximum Mammoth Shadow Pendant Box    # !todo check english name
+    Type: Usable
+    Weight: 10
+    Flags:
+      Container: true
+    Script: |
+      getgroupitem(IG_S_M_MAMMOTH_PENDANT,true);
+  - Id: 101719
+    AegisName: aegis_101719
+    Name: Maximum Mammoth Shadow Armor Box    # !todo check english name
+    Type: Usable
+    Weight: 10
+    Flags:
+      Container: true
+    Script: |
+      getgroupitem(IG_S_M_MAMMOTH_ARMOR,true);
+  - Id: 101720
+    AegisName: aegis_101720
+    Name: Maximum Mammoth Shadow Shoes Box    # !todo check english name
+    Type: Usable
+    Weight: 10
+    Flags:
+      Container: true
+    Script: |
+      getgroupitem(IG_S_M_MAMMOTH_SHOES,true);
+  - Id: 101721
+    AegisName: aegis_101721
+    Name: Spell Caster Shadow Earring Box    # !todo check english name
+    Type: Usable
+    Weight: 10
+    Flags:
+      Container: true
+    Script: |
+      getgroupitem(IG_S_SPELLCASTER_EARRING,true);
+  - Id: 101722
+    AegisName: aegis_101722
+    Name: Spell Caster Shadow Pendant Box    # !todo check english name
+    Type: Usable
+    Weight: 10
+    Flags:
+      Container: true
+    Script: |
+      getgroupitem(IG_S_SPELLCASTER_PENDANT,true);
+  - Id: 101723
+    AegisName: aegis_101723
+    Name: Spell Caster Shadow Armor Box    # !todo check english name
+    Type: Usable
+    Weight: 10
+    Flags:
+      Container: true
+    Script: |
+      getgroupitem(IG_S_SPELLCASTER_ARMOR,true);
+  - Id: 101724
+    AegisName: aegis_101724
+    Name: Spell Caster Shadow Shoes Box    # !todo check english name
+    Type: Usable
+    Weight: 10
+    Flags:
+      Container: true
+    Script: |
+      getgroupitem(IG_S_SPELLCASTER_SHOES,true);
+  - Id: 101725
+    AegisName: aegis_101725
+    Name: Absorb Shadow Weapon Box    # !todo check english name
+    Type: Usable
+    Weight: 10
+    Flags:
+      Container: true
+    Script: |
+      getgroupitem(IG_S_ABSORB_WEAPON,true);
+  - Id: 101726
+    AegisName: aegis_101726
+    Name: Absorb Shadow Shield Box    # !todo check english name
+    Type: Usable
+    Weight: 10
+    Flags:
+      Container: true
+    Script: |
+      getgroupitem(IG_S_ABSORB_SHIELD,true);
+  - Id: 101727
+    AegisName: aegis_101727
+    Name: Maximum Mammoth Shadow Selection Box    # !todo check english name
+    Type: DelayConsume
+    Weight: 10
+    Flags:
+      BuyingStore: true
+  - Id: 101728
+    AegisName: aegis_101728
+    Name: Spell Caster Shadow Selection Box    # !todo check english name
+    Type: DelayConsume
+    Weight: 10
+    Flags:
+      BuyingStore: true
+  - Id: 101729
+    AegisName: aegis_101729
+    Name: Absorb Shadow Selection Box    # !todo check english name
+    Type: DelayConsume
+    Weight: 10
+    Flags:
+      BuyingStore: true
   - Id: 200055
     AegisName: C_Acid_B_50Box
     Name: Acid Bomb 50 Box

+ 210 - 0
db/re/item_group_db.yml

@@ -31265,3 +31265,213 @@ Body:
             Rate: 360
           - Item: Critical_Stone_Bottom
             Rate: 360
+  - Group: S_FULLPENE_EARRING
+    SubGroups:
+      - SubGroup: 0
+        List:
+          - Item: S_FullPene_Earring
+            RefineMinimum: 7
+            RefineMaximum: 10
+  - Group: S_FULLPENE_PENDANT
+    SubGroups:
+      - SubGroup: 0
+        List:
+          - Item: S_FullPene_Pendant
+            RefineMinimum: 7
+            RefineMaximum: 10
+  - Group: S_FULLPENE_ARMOR
+    SubGroups:
+      - SubGroup: 0
+        List:
+          - Item: S_FullPene_Armor
+            RefineMinimum: 7
+            RefineMaximum: 10
+  - Group: S_FULLPENE_SHOES
+    SubGroups:
+      - SubGroup: 0
+        List:
+          - Item: S_FullPene_Shoes
+            RefineMinimum: 7
+            RefineMaximum: 10
+  - Group: S_FULLTEMP_EARRING
+    SubGroups:
+      - SubGroup: 0
+        List:
+          - Item: S_FullTemp_Earring
+            RefineMinimum: 7
+            RefineMaximum: 10
+  - Group: S_FULLTEMP_PENDANT
+    SubGroups:
+      - SubGroup: 0
+        List:
+          - Item: S_FullTemp_Pendant
+            RefineMinimum: 7
+            RefineMaximum: 10
+  - Group: S_FULLTEMP_ARMOR
+    SubGroups:
+      - SubGroup: 0
+        List:
+          - Item: S_FullTemp_Armor
+            RefineMinimum: 7
+            RefineMaximum: 10
+  - Group: S_FULLTEMP_SHOES
+    SubGroups:
+      - SubGroup: 0
+        List:
+          - Item: S_FullTemp_Shoes
+            RefineMinimum: 7
+            RefineMaximum: 10
+  - Group: S_DURABLE_WEAPON
+    SubGroups:
+      - SubGroup: 0
+        List:
+          - Item: S_Durable_Weapon
+            RefineMinimum: 7
+            RefineMaximum: 10
+  - Group: S_DURABLE_SHIELD
+    SubGroups:
+      - SubGroup: 0
+        List:
+          - Item: S_Durable_Shield
+            RefineMinimum: 7
+            RefineMaximum: 10
+  - Group: S_CLEVER_WEAPON
+    SubGroups:
+      - SubGroup: 0
+        List:
+          - Item: S_Clever_Weapon
+            RefineMinimum: 7
+            RefineMaximum: 10
+  - Group: S_CLEVER_SHIELD
+    SubGroups:
+      - SubGroup: 0
+        List:
+          - Item: S_Clever_Shield
+            RefineMinimum: 7
+            RefineMaximum: 10
+  - Group: S_ALLMIGHTY_EARRING
+    SubGroups:
+      - SubGroup: 0
+        List:
+          - Item: S_AllMighty_Earring
+            RefineMinimum: 7
+            RefineMaximum: 10
+  - Group: S_ALLMIGHTY_PENDANT
+    SubGroups:
+      - SubGroup: 0
+        List:
+          - Item: S_AllMighty_Pendant
+            RefineMinimum: 7
+            RefineMaximum: 10
+  - Group: S_TRUEGEM_EARRING
+    SubGroups:
+      - SubGroup: 0
+        List:
+          - Item: S_TrueGem_Earring
+            RefineMinimum: 7
+            RefineMaximum: 10
+  - Group: S_TRUEGEM_PENDANT
+    SubGroups:
+      - SubGroup: 0
+        List:
+          - Item: S_TrueGem_Pendant
+            RefineMinimum: 7
+            RefineMaximum: 10
+  - Group: S_TRUEGEM_SHOES
+    SubGroups:
+      - SubGroup: 0
+        List:
+          - Item: S_TrueGem_Shoes
+            RefineMinimum: 7
+            RefineMaximum: 10
+  - Group: S_TRUEGEM_ARMOR
+    SubGroups:
+      - SubGroup: 0
+        List:
+          - Item: S_TrueGem_Armor
+            RefineMinimum: 7
+            RefineMaximum: 10
+  - Group: S_PERFECTSIZE_WEAPON
+    SubGroups:
+      - SubGroup: 0
+        List:
+          - Item: S_PerfectSize_Weapon
+            RefineMinimum: 7
+            RefineMaximum: 10
+  - Group: S_PERFECTSIZE_ARMOR
+    SubGroups:
+      - SubGroup: 0
+        List:
+          - Item: S_PerfectSize_Armor
+            RefineMinimum: 7
+            RefineMaximum: 10
+  - Group: S_M_MAMMOTH_EARRING
+    SubGroups:
+      - SubGroup: 0
+        List:
+          - Item: S_M_Mammoth_Earring
+            RefineMinimum: 7
+            RefineMaximum: 10
+  - Group: S_M_MAMMOTH_PENDANT
+    SubGroups:
+      - SubGroup: 0
+        List:
+          - Item: S_M_Mammoth_Pendant
+            RefineMinimum: 7
+            RefineMaximum: 10
+  - Group: S_M_MAMMOTH_ARMOR
+    SubGroups:
+      - SubGroup: 0
+        List:
+          - Item: S_M_Mammoth_Armor
+            RefineMinimum: 7
+            RefineMaximum: 10
+  - Group: S_M_MAMMOTH_SHOES
+    SubGroups:
+      - SubGroup: 0
+        List:
+          - Item: S_M_Mammoth_Shoes
+            RefineMinimum: 7
+            RefineMaximum: 10
+  - Group: S_SPELLCASTER_EARRING
+    SubGroups:
+      - SubGroup: 0
+        List:
+          - Item: S_SpellCaster_Earring
+            RefineMinimum: 7
+            RefineMaximum: 10
+  - Group: S_SPELLCASTER_PENDANT
+    SubGroups:
+      - SubGroup: 0
+        List:
+          - Item: S_SpellCaster_Pendant
+            RefineMinimum: 7
+            RefineMaximum: 10
+  - Group: S_SPELLCASTER_ARMOR
+    SubGroups:
+      - SubGroup: 0
+        List:
+          - Item: S_SpellCaster_Armor
+            RefineMinimum: 7
+            RefineMaximum: 10
+  - Group: S_SPELLCASTER_SHOES
+    SubGroups:
+      - SubGroup: 0
+        List:
+          - Item: S_SpellCaster_Shoes
+            RefineMinimum: 7
+            RefineMaximum: 10
+  - Group: S_ABSORB_WEAPON
+    SubGroups:
+      - SubGroup: 0
+        List:
+          - Item: S_Absorb_Weapon
+            RefineMinimum: 7
+            RefineMaximum: 10
+  - Group: S_ABSORB_SHIELD
+    SubGroups:
+      - SubGroup: 0
+        List:
+          - Item: S_Absorb_Shield
+            RefineMinimum: 7
+            RefineMaximum: 10

+ 531 - 0
db/re/item_packages.yml

@@ -0,0 +1,531 @@
+# This file is a part of rAthena.
+#   Copyright(C) 2022 rAthena Development Team
+#   https://rathena.org - https://github.com/rathena
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+###########################################################################
+# Item Package Database
+###########################################################################
+#
+# Item Package Settings
+#
+###########################################################################
+# - Item                       Item that triggers Item Package Selection.
+#   Groups:                    Groups that can be selected.
+#     - Group                  Group ID that can be selected (has to match the client's LUA file).
+#       Items:                 Items that will be given out.
+#         - Item               Item that will be given out.
+#           Amount             Amount of the item. (Default: 1)
+#                              To remove an item via import set amount to 0.
+#           RentalHours        Rental time in hours. (Default: 0)
+#           Refine             Refine level of the item. (Default: 0)
+#           RandomOptionGroup  Name of the random option group that will be applied. (Default: none)
+###########################################################################
+
+Header:
+  Type: ITEM_PACKAGE_DB
+  Version: 1
+
+Body:
+  - Item: Select_Example1
+    Groups:
+      - Group: 0
+        Items:
+          - Item: Cotton_Shirt
+            Refine: 7
+#            RandomOptionGroup: TODO <insert random option group name>
+          - Item: Shoes
+            Refine: 5
+#            RandomOptionGroup: TODO <insert random option group name>
+          - Item: Muffler
+            Refine: 3
+#            RandomOptionGroup: TODO <insert random option group name>
+          - Item: Event_Pierrot_Nose
+            RentalHours: 24
+#            RandomOptionGroup: TODO <insert random option group name>
+      - Group: 1
+        Items:
+          - Item: Red_Potion
+            Amount: 100
+          - Item: Orange_Potion
+            Amount: 50
+          - Item: White_Potion
+            Amount: 10
+      - Group: 2
+        Items:
+          - Item: Jellopy
+            Amount: 10
+          - Item: Hinalle
+          - Item: Yellow_Gemstone
+            Amount: 3
+          - Item: Azure_Jewel
+          - Item: Spore_Doll
+            Amount: 2
+  - Item: Select_Example2
+    Groups:
+      - Group: 0
+        Items:
+          - Item: Knife
+            Refine: 4
+#            RandomOptionGroup: TODO <insert random option group name>
+          - Item: Cotton_Shirt
+            Refine: 4
+#            RandomOptionGroup: TODO <insert random option group name>
+          - Item: Red_Potion
+            Amount: 100
+          - Item: Ring
+            RentalHours: 24
+#            RandomOptionGroup: TODO <insert random option group name>
+      - Group: 1
+        Items:
+          - Item: Tsurugi
+            Refine: 5
+#            RandomOptionGroup: TODO <insert random option group name>
+          - Item: Padded_Armor
+            Refine: 5
+#            RandomOptionGroup: TODO <insert random option group name>
+          - Item: Yellow_Potion
+            Amount: 50
+      - Group: 2
+        Items:
+          - Item: Sword
+            Refine: 20
+#            RandomOptionGroup: TODO <insert random option group name>
+          - Item: Guard
+            RentalHours: 168
+            Refine: 5
+#            RandomOptionGroup: TODO <insert random option group name>
+          - Item: White_Herb
+            Amount: 100
+      - Group: 3
+        Items:
+          - Item: Fabre_Card
+          - Item: Pupa_Card
+          - Item: Drops_Card
+          - Item: Poring__Card
+          - Item: Lunatic_Card
+          - Item: Pecopeco_Egg_Card
+          - Item: Picky_Card
+          - Item: Chonchon_Card
+          - Item: Wilow_Card
+          - Item: Picky__Card
+          - Item: Thief_Bug_Egg_Card
+          - Item: Andre_Egg_Card
+          - Item: Roda_Frog_Card
+          - Item: Condor_Card
+          - Item: Thief_Bug_Card
+          - Item: Savage_Babe_Card
+          - Item: Andre_Larva_Card
+          - Item: Hornet_Card
+          - Item: Farmiliar_Card
+          - Item: Rocker_Card
+      - Group: 4
+        Items:
+          - Item: Poring_Card
+      - Group: 5
+        Items:
+          - Item: LI_Nyangvine_Box3_26
+            Amount: 5
+      - Group: 6
+        Items:
+          - Item: C_Hair_Of_The_Strong
+#            RandomOptionGroup: TODO <insert random option group name>
+          - Item: C_Imp_Hat
+#            RandomOptionGroup: TODO <insert random option group name>
+      - Group: 7
+        Items:
+          - Item: C_Classical_Fhat
+      - Group: 8
+        Items:
+          - Item: Wing_Of_Fly
+            Amount: 3
+            RentalHours: 24
+          - Item: Wing_Of_Butterfly
+            Amount: 5
+            RentalHours: 168
+          - Item: Old_Blue_Box
+            RentalHours: 1
+      - Group: 9
+        Items:
+          - Item: Red_Potion
+            Amount: 10
+          - Item: Red_Potion
+            Amount: 5
+          - Item: Red_Potion
+          - Item: Red_Potion
+            Amount: 3
+            RentalHours: 1
+      - Group: 10
+        Items:
+          - Item: Guard_
+          - Item: Guard_
+          - Item: Guard_
+      - Group: 11
+        Items:
+          - Item: Orange_Potion
+            Amount: 800
+  - Item: Boost_Armor_Box
+    Groups:
+      - Group: 0
+        Items:
+          - Item: Attacker_Booster_Plate_
+          - Item: Attacker_Booster_Manteau_
+          - Item: Attacker_Booster_Greaves_
+          - Item: Attacker_Booster_Ring
+          - Item: Boost_Up_1
+            Amount: 3
+      - Group: 1
+        Items:
+          - Item: Ranger_Booster_Suits_
+          - Item: Ranger_Booster_Manteau_
+          - Item: Ranger_Booster_Boots_
+          - Item: Range_Booster_Brooch
+          - Item: Boost_Up_1
+            Amount: 3
+      - Group: 2
+        Items:
+          - Item: Elemental_Booster_Robe_
+          - Item: Elemental_Booster_Muffler_
+          - Item: Elemental_Booster_Shoes_
+          - Item: Elemental_Booster_Earring
+          - Item: Boost_Up_1
+            Amount: 3
+      - Group: 3
+        Items:
+          - Item: Defender_Booster_Robe_
+          - Item: Defender_Booster_Muffler_
+          - Item: Defender_Booster_Shoes_
+          - Item: Defender_Booster_Earring
+          - Item: Boost_Up_1
+            Amount: 3
+  - Item: Special_Coin_Pack
+    Groups:
+      - Group: 0
+        Items:
+          - Item: EP17_1_EVT39
+            Amount: 3
+          - Item: EP17_1_EVT02
+            Amount: 18
+      - Group: 1
+        Items:
+          - Item: BarMealTicket
+            Amount: 20
+      - Group: 2
+        Items:
+          - Item: Ep18_Amethyst_Fragment
+            Amount: 20
+      - Group: 3
+        Items:
+          - Item: Ep19_Snow_Flower
+            Amount: 20
+  - Item: Metal_W_Box
+    Groups:
+      - Group: 0
+        Items:
+          - Item: Metal_Two_Hand_Sword
+            Refine: 7
+      - Group: 1
+        Items:
+          - Item: Metal_Lance
+            Refine: 7
+      - Group: 2
+        Items:
+          - Item: Metal_Mace
+            Refine: 7
+      - Group: 3
+        Items:
+          - Item: Metal_Two_Handed_Axe
+            Refine: 7
+      - Group: 4
+        Items:
+          - Item: Metal_Dagger
+            Refine: 7
+      - Group: 5
+        Items:
+          - Item: Metal_Book
+            Refine: 7
+      - Group: 6
+        Items:
+          - Item: Metal_Staff
+            Refine: 7
+      - Group: 7
+        Items:
+          - Item: Metal_Katar
+            Refine: 7
+      - Group: 8
+        Items:
+          - Item: Metal_Bow
+            Refine: 7
+      - Group: 9
+        Items:
+          - Item: Metal_Revolver
+            Refine: 7
+      - Group: 10
+        Items:
+          - Item: Metal_Foxtail
+            Refine: 7
+  - Item: Memento_Box
+    Groups:
+      - Group: 0
+        Items:
+          - Item: Booster_Mask_A
+      - Group: 1
+        Items:
+          - Item: Booster_Mask_B
+      - Group: 2
+        Items:
+          - Item: Booster_Mask_C
+  - Item: P_Memento_Box
+    Groups:
+      - Group: 0
+        Items:
+          - Item: Booster_Scarf_A
+      - Group: 1
+        Items:
+          - Item: Booster_Scarf_B
+      - Group: 2
+        Items:
+          - Item: Booster_Scarf_C
+  - Item: Booster_Hat_Box
+    Groups:
+      - Group: 0
+        Items:
+          - Item: C_Pretty_Rabbit_Hood_E
+      - Group: 1
+        Items:
+          - Item: C_Black_Cat_Hood_kr
+      - Group: 2
+        Items:
+          - Item: C_Squirrel_Ear_Hat_Kr
+      - Group: 3
+        Items:
+          - Item: C_Black_Moon_Cat_kr
+  - Item: Booster_Back_Box
+    Groups:
+      - Group: 0
+        Items:
+          - Item: C_School_Bag_RD_E
+      - Group: 1
+        Items:
+          - Item: C_School_Bag_BL
+      - Group: 2
+        Items:
+          - Item: C_School_Bag_BU
+      - Group: 3
+        Items:
+          - Item: C_School_Bag_PU
+  - Item: aegis_101470
+    Groups:
+      - Group: 0
+        Items:
+          - Item: Minus_Str
+            Amount: 6
+      - Group: 1
+        Items:
+          - Item: Minus_Agi
+            Amount: 6
+      - Group: 2
+        Items:
+          - Item: Minus_Vit
+            Amount: 6
+      - Group: 3
+        Items:
+          - Item: Minus_Int
+            Amount: 6
+      - Group: 4
+        Items:
+          - Item: Minus_Dex
+            Amount: 6
+      - Group: 5
+        Items:
+          - Item: Minus_Luk
+            Amount: 6
+      - Group: 6
+        Items:
+          - Item: Minus_Str
+          - Item: Minus_Agi
+          - Item: Minus_Vit
+          - Item: Minus_Int
+          - Item: Minus_Dex
+          - Item: Minus_Luk
+  - Item: aegis_101471
+    Groups:
+      - Group: 0
+        Items:
+          - Item: Fire_Bottle
+            Amount: 50
+      - Group: 1
+        Items:
+          - Item: Acid_Bottle
+            Amount: 50
+      - Group: 2
+        Items:
+          - Item: MenEater_Plant_Bottle
+            Amount: 50
+      - Group: 3
+        Items:
+          - Item: Coating_Bottle
+            Amount: 50
+      - Group: 4
+        Items:
+          - Item: Mini_Bottle
+            Amount: 50
+  - Item: aegis_101542
+    Groups:
+      - Group: 0
+        Items:
+          - Item: aegis_101543
+      - Group: 1
+        Items:
+          - Item: aegis_101544
+      - Group: 2
+        Items:
+          - Item: aegis_101545
+      - Group: 3
+        Items:
+          - Item: aegis_101546
+  - Item: aegis_101547
+    Groups:
+      - Group: 0
+        Items:
+          - Item: aegis_101548
+      - Group: 1
+        Items:
+          - Item: aegis_101549
+      - Group: 2
+        Items:
+          - Item: aegis_101550
+      - Group: 3
+        Items:
+          - Item: aegis_101551
+  - Item: aegis_101552
+    Groups:
+      - Group: 0
+        Items:
+          - Item: aegis_101553
+      - Group: 1
+        Items:
+          - Item: aegis_101554
+  - Item: aegis_101555
+    Groups:
+      - Group: 0
+        Items:
+          - Item: aegis_101556
+      - Group: 1
+        Items:
+          - Item: aegis_101557
+  - Item: aegis_101563
+    Groups:
+      - Group: 0
+        Items:
+          - Item: Ignis_CapK
+      - Group: 1
+        Items:
+          - Item: Phantom_Cap
+      - Group: 2
+        Items:
+          - Item: Stripe_Hat
+      - Group: 3
+        Items:
+          - Item: Clock_Casket_RD
+      - Group: 4
+        Items:
+          - Item: Large_Sorcerer_Crown
+      - Group: 5
+        Items:
+          - Item: Scorpio_Diadem_K
+      - Group: 6
+        Items:
+          - Item: Sagittarius_DiademK
+  - Item: aegis_101565
+    Groups:
+      - Group: 0
+        Items:
+          - Item: Class_Sha_R_M_Melee
+      - Group: 1
+        Items:
+          - Item: Class_Sha_R_M_Magic
+      - Group: 2
+        Items:
+          - Item: Skill_Sha_R_M_Melee
+      - Group: 3
+        Items:
+          - Item: Skill_Sha_R_M_Magic
+  - Item: aegis_101654
+    Groups:
+      - Group: 0
+        Items:
+          - Item: aegis_101655
+      - Group: 1
+        Items:
+          - Item: aegis_101656
+  - Item: aegis_101657
+    Groups:
+      - Group: 0
+        Items:
+          - Item: aegis_101658
+      - Group: 1
+        Items:
+          - Item: aegis_101659
+      - Group: 2
+        Items:
+          - Item: aegis_101660
+      - Group: 3
+        Items:
+          - Item: aegis_101661
+  - Item: aegis_101662
+    Groups:
+      - Group: 0
+        Items:
+          - Item: aegis_101663
+      - Group: 1
+        Items:
+          - Item: aegis_101664
+  - Item: aegis_101727
+    Groups:
+      - Group: 0
+        Items:
+          - Item: aegis_101717
+      - Group: 1
+        Items:
+          - Item: aegis_101718
+      - Group: 2
+        Items:
+          - Item: aegis_101719
+      - Group: 3
+        Items:
+          - Item: aegis_101720
+  - Item: aegis_101728
+    Groups:
+      - Group: 0
+        Items:
+          - Item: aegis_101721
+      - Group: 1
+        Items:
+          - Item: aegis_101722
+      - Group: 2
+        Items:
+          - Item: aegis_101723
+      - Group: 3
+        Items:
+          - Item: aegis_101724
+  - Item: aegis_101729
+    Groups:
+      - Group: 0
+        Items:
+          - Item: aegis_101725
+      - Group: 1
+        Items:
+          - Item: aegis_101726

+ 1 - 1
sql-files/logs.sql

@@ -177,7 +177,7 @@ CREATE TABLE IF NOT EXISTS `picklog` (
   `id` int(11) NOT NULL auto_increment,
   `time` datetime NOT NULL,
   `char_id` int(11) NOT NULL default '0',
-  `type` enum('M','P','L','T','V','S','N','C','A','R','G','E','B','O','I','X','D','U','$','F','Y','Z','Q','H','J','W','0','1','2') NOT NULL default 'P',
+  `type` enum('M','P','L','T','V','S','N','C','A','R','G','E','B','O','I','X','D','U','$','F','Y','Z','Q','H','J','W','0','1','2','3') NOT NULL default 'P',
   `nameid` int(10) unsigned NOT NULL default '0',
   `amount` int(11) NOT NULL default '1',
   `refine` tinyint(3) unsigned NOT NULL default '0',

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

@@ -0,0 +1,3 @@
+ALTER TABLE `picklog`
+	MODIFY `type` enum('M','P','L','T','V','S','N','C','A','R','G','E','B','O','I','X','D','U','$','F','Y','Z','Q','H','J','W','0','1','2','3') NOT NULL default 'P'
+;

+ 1 - 1
src/char/packets.hpp

@@ -34,7 +34,7 @@ struct CHARACTER_INFO{
 	int32 virtue;
 	int32 honor;
 	int16 jobpoint;
-#if PACKETVER_RE_NUM >= 20211103
+#if PACKETVER_RE_NUM >= 20211103 || PACKETVER_MAIN_NUM >= 20220330
 	int64 hp;
 	int64 maxhp;
 	int64 sp;

+ 1 - 1
src/config/packets.hpp

@@ -19,7 +19,7 @@
 #ifndef PACKETVER_RE
 	/// From November 2015 only RagexeRE are supported.
 	/// After July 2018 only Ragexe are supported.
-	#if ( PACKETVER > 20151104 && PACKETVER < 20180704 ) || PACKETVER >= 20200902
+	#if ( PACKETVER > 20151104 && PACKETVER < 20180704 ) || ( PACKETVER >= 20200902 && PACKETVER <= 20211118 )
 		#define PACKETVER_RE
 	#endif
 #endif

+ 93 - 13
src/map/clif.cpp

@@ -23856,7 +23856,7 @@ void clif_parse_enchantgrade_close( int fd, struct map_session_data* sd ){
 }
 
 void clif_reputation_type( struct map_session_data& sd, int64 type, int64 points ){
-#if PACKETVER_RE_NUM >= 20211103
+#if PACKETVER_RE_NUM >= 20211103 || PACKETVER_MAIN_NUM >= 20220330
 	struct PACKET_ZC_REPUTE_INFO* p = (struct PACKET_ZC_REPUTE_INFO*)packet_buffer;
 
 	p->packetType = HEADER_ZC_REPUTE_INFO;
@@ -23873,7 +23873,7 @@ void clif_reputation_type( struct map_session_data& sd, int64 type, int64 points
 }
 
 void clif_reputation_list( struct map_session_data& sd ){
-#if PACKETVER_RE_NUM >= 20211103
+#if PACKETVER_RE_NUM >= 20211103 || PACKETVER_MAIN_NUM >= 20220330
 	struct PACKET_ZC_REPUTE_INFO* p = (struct PACKET_ZC_REPUTE_INFO*)packet_buffer;
 
 	p->packetType = HEADER_ZC_REPUTE_INFO;
@@ -23898,7 +23898,7 @@ void clif_reputation_list( struct map_session_data& sd ){
 }
 
 void clif_item_reform_open( struct map_session_data& sd, t_itemid item ){
-#if PACKETVER_RE_NUM >= 20211103
+#if PACKETVER_RE_NUM >= 20211103 || PACKETVER_MAIN_NUM >= 20220330
 	struct PACKET_ZC_OPEN_REFORM_UI p = {};
 
 	p.packetType = HEADER_ZC_OPEN_REFORM_UI;
@@ -23911,13 +23911,13 @@ void clif_item_reform_open( struct map_session_data& sd, t_itemid item ){
 }
 
 void clif_parse_item_reform_close( int fd, struct map_session_data* sd ){
-#if PACKETVER_RE_NUM >= 20211103
+#if PACKETVER_RE_NUM >= 20211103 || PACKETVER_MAIN_NUM >= 20220330
 	sd->state.item_reform = 0;
 #endif
 }
 
 void clif_item_reform_result( struct map_session_data& sd, uint16 index, uint8 result ){
-#if PACKETVER_RE_NUM >= 20211103
+#if PACKETVER_RE_NUM >= 20211103 || PACKETVER_MAIN_NUM >= 20220330
 	struct PACKET_ZC_ITEM_REFORM_ACK p = {};
 
 	p.packetType = HEADER_ZC_ITEM_REFORM_ACK;
@@ -23934,7 +23934,7 @@ void clif_item_reform_result( struct map_session_data& sd, uint16 index, uint8 r
 }
 
 void clif_parse_item_reform_start( int fd, struct map_session_data* sd ){
-#if PACKETVER_RE_NUM >= 20211103
+#if PACKETVER_RE_NUM >= 20211103 || PACKETVER_MAIN_NUM >= 20220330
 	// Not opened
 	if( sd->state.item_reform == 0 ){
 		return;
@@ -24088,7 +24088,7 @@ void clif_parse_item_reform_start( int fd, struct map_session_data* sd ){
 }
 
 void clif_enchantwindow_open( struct map_session_data& sd, uint64 clientLuaIndex ){
-#if PACKETVER_RE_NUM >= 20211103
+#if PACKETVER_RE_NUM >= 20211103 || PACKETVER_MAIN_NUM >= 20220330
 	// Hardcoded clientside check
 	if( sd.weight > ( ( sd.max_weight * 70 ) / 100 ) ){
 		clif_msg_color( &sd, C_ENCHANT_OVERWEIGHT, color_table[COLOR_RED] );
@@ -24110,7 +24110,7 @@ void clif_enchantwindow_open( struct map_session_data& sd, uint64 clientLuaIndex
 }
 
 void clif_enchantwindow_result( struct map_session_data& sd, bool success, t_itemid enchant = 0 ){
-#if PACKETVER_RE_NUM >= 20211103
+#if PACKETVER_RE_NUM >= 20211103 || PACKETVER_MAIN_NUM >= 20220330
 	struct PACKET_ZC_RESPONSE_ENCHANT p = {};
 
 	p.packetType = HEADER_ZC_RESPONSE_ENCHANT;
@@ -24164,7 +24164,7 @@ bool clif_parse_enchant_basecheck( struct item& selected_item, std::shared_ptr<s
 }
 
 void clif_parse_enchantwindow_general( int fd, struct map_session_data* sd ){
-#if PACKETVER_RE_NUM >= 20211103
+#if PACKETVER_RE_NUM >= 20211103 || PACKETVER_MAIN_NUM >= 20220330
 	struct PACKET_CZ_REQUEST_RANDOM_ENCHANT *p = (struct PACKET_CZ_REQUEST_RANDOM_ENCHANT*)RFIFOP( fd, 0 );
 
 	if( sd->state.item_enchant_index != p->clientLuaIndex ){
@@ -24293,7 +24293,7 @@ void clif_parse_enchantwindow_general( int fd, struct map_session_data* sd ){
 }
 
 void clif_parse_enchantwindow_perfect( int fd, struct map_session_data* sd ){
-#if PACKETVER_RE_NUM >= 20211103
+#if PACKETVER_RE_NUM >= 20211103 || PACKETVER_MAIN_NUM >= 20220330
 	struct PACKET_CZ_REQUEST_PERFECT_ENCHANT *p = (struct PACKET_CZ_REQUEST_PERFECT_ENCHANT*)RFIFOP( fd, 0 );
 
 	if( sd->state.item_enchant_index != p->clientLuaIndex ){
@@ -24393,7 +24393,7 @@ void clif_parse_enchantwindow_perfect( int fd, struct map_session_data* sd ){
 }
 
 void clif_parse_enchantwindow_upgrade( int fd, struct map_session_data* sd ){
-#if PACKETVER_RE_NUM >= 20211103
+#if PACKETVER_RE_NUM >= 20211103 || PACKETVER_MAIN_NUM >= 20220330
 	struct PACKET_CZ_REQUEST_UPGRADE_ENCHANT *p = (struct PACKET_CZ_REQUEST_UPGRADE_ENCHANT*)RFIFOP( fd, 0 );
 
 	if( sd->state.item_enchant_index != p->clientLuaIndex ){
@@ -24490,7 +24490,7 @@ void clif_parse_enchantwindow_upgrade( int fd, struct map_session_data* sd ){
 }
 
 void clif_parse_enchantwindow_reset( int fd, struct map_session_data* sd ){
-#if PACKETVER_RE_NUM >= 20211103
+#if PACKETVER_RE_NUM >= 20211103 || PACKETVER_MAIN_NUM >= 20220330
 	struct PACKET_CZ_REQUEST_RESET_ENCHANT *p = (struct PACKET_CZ_REQUEST_RESET_ENCHANT*)RFIFOP( fd, 0 );
 
 	if( sd->state.item_enchant_index != p->clientLuaIndex ){
@@ -24608,11 +24608,91 @@ void clif_parse_enchantwindow_reset( int fd, struct map_session_data* sd ){
 }
 
 void clif_parse_enchantwindow_close( int fd, struct map_session_data* sd ){
-#if PACKETVER_RE_NUM >= 20211103
+#if PACKETVER_RE_NUM >= 20211103 || PACKETVER_MAIN_NUM >= 20220330
 	sd->state.item_enchant_index = 0;
 #endif
 }
 
+void clif_parse_itempackage_select( int fd, struct map_session_data* sd ){
+#if PACKETVER_MAIN_NUM >= 20220216 || PACKETVER_ZERO_NUM >= 20220316
+	struct PACKET_CZ_USE_PACKAGEITEM* p = (struct PACKET_CZ_USE_PACKAGEITEM*)RFIFOP( fd, 0 );
+
+	if( p->AID != sd->status.account_id ){
+		return;
+	}
+
+	uint16 index = server_index( p->index );
+
+	if( index >= MAX_INVENTORY ){
+		return;
+	}
+
+	if( sd->inventory_data[index] == nullptr ){
+		return;
+	}
+
+	if( sd->inventory_data[index]->nameid != p->itemID ){
+		return;
+	}
+
+	if( sd->inventory_data[index]->elv > sd->status.base_level ){
+		return;
+	}
+
+	std::shared_ptr<s_item_package> package = item_package_db.find( p->itemID );
+
+	if( package == nullptr ){
+		return;
+	}
+
+	std::shared_ptr<s_item_package_group> group = util::umap_find( package->groups, p->BoxIndex );
+
+	if( group == nullptr ){
+		return;
+	}
+
+	if( pc_delitem( sd, index, 1, 0, 0, LOG_TYPE_PACKAGE ) != 0 ){
+		return;
+	}
+
+	for( const auto& entry : group->items ){
+		struct item item = {};
+
+		item.nameid = entry.second->item_id;
+		item.identify = 1;
+		item.refine = (char)entry.second->refine;
+
+		if( entry.second->rentalhours ){
+			item.expire_time = (uint32)( time( nullptr ) + entry.second->rentalhours * 3600 );
+		}
+
+		// Check if it is a pet egg
+		std::shared_ptr<s_pet_db> pet = pet_db_search( item.nameid, PET_EGG );
+
+		if( pet != nullptr ){
+			for( int i = 0; i < entry.second->amount; i++ ){
+				pet_create_egg( sd, item.nameid );
+			}
+		}else if( entry.second->amount > 1 && ( !itemdb_isstackable( item.nameid ) || item.expire_time > 0 ) ){
+			for( int i = 0; i < entry.second->amount; i++ ){
+				// New random options on each iteration
+				if( entry.second->randomOptionGroup != nullptr ){
+					entry.second->randomOptionGroup->apply( item );
+				}
+
+				pc_additem( sd, &item, 1, LOG_TYPE_PACKAGE );
+			}
+		}else{
+			if( entry.second->randomOptionGroup != nullptr ){
+				entry.second->randomOptionGroup->apply( item );
+			}
+
+			pc_additem( sd, &item, entry.second->amount, LOG_TYPE_PACKAGE );
+		}
+	}
+#endif
+}
+
 /*==========================================
  * Main client packet processing function
  *------------------------------------------*/

+ 5 - 1
src/map/clif_packetdb.hpp

@@ -2451,7 +2451,7 @@
 	parseable_packet( HEADER_CZ_GRADE_ENCHANT_CLOSE_UI, sizeof( struct PACKET_CZ_GRADE_ENCHANT_CLOSE_UI ), clif_parse_enchantgrade_close, 0 );
 #endif
 
-#if PACKETVER_RE_NUM >= 20211103 || PACKETVER_ZERO_NUM >= 20210818
+#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 );
@@ -2465,4 +2465,8 @@
 	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 || PACKETVER_ZERO_NUM >= 20220316
+	parseable_packet( HEADER_CZ_USE_PACKAGEITEM, sizeof( struct PACKET_CZ_USE_PACKAGEITEM ), clif_parse_itempackage_select, 0 );
+#endif
+
 #endif /* CLIF_PACKETDB_HPP */

+ 1 - 1
src/map/clif_shuffle.hpp

@@ -4741,7 +4741,7 @@
 #endif
 	parseable_packet(0x0368,6,clif_parse_GetCharNameRequest,2);
 	parseable_packet(0x0369,6,clif_parse_SolveCharName,2);
-#if PACKETVER_RE_NUM >= 20211103
+#if PACKETVER_RE_NUM >= 20211103 || PACKETVER_MAIN_NUM >= 20220330
 	parseable_packet( 0x0436, 23, clif_parse_WantToConnection, 2, 6, 10, 14, 22 );
 #else
 	parseable_packet( 0x0436, 19, clif_parse_WantToConnection, 2, 6, 10, 14, 18 );

+ 180 - 0
src/map/itemdb.cpp

@@ -2478,6 +2478,184 @@ uint64 ItemEnchantDatabase::parseBodyNode( const ryml::NodeRef& node ){
 
 ItemEnchantDatabase item_enchant_db;
 
+const std::string ItemPackageDatabase::getDefaultLocation(){
+	return std::string( db_path ) + "/item_packages.yml";
+}
+
+uint64 ItemPackageDatabase::parseBodyNode( const ryml::NodeRef& node ){
+	t_itemid item_id;
+
+	{
+		std::string name;
+
+		if( !this->asString( node, "Item", name ) ){
+			return 0;
+		}
+
+		std::shared_ptr<item_data> id = item_db.search_aegisname( name.c_str() );
+
+		if( id == nullptr ){
+			this->invalidWarning( node["Item"], "Unknown item \"%s\".\n", name.c_str() );
+			return 0;
+		}
+
+		item_id = id->nameid;
+	}
+
+	std::shared_ptr<s_item_package> entry = this->find( item_id );
+	bool exists = entry != nullptr;
+
+	if( !exists ){
+		if( !this->nodesExist( node, { "Groups" } ) ){
+			return 0;
+		}
+
+		entry = std::make_shared<s_item_package>();
+		entry->item_id = item_id;
+	}
+
+	if( this->nodeExists( node, "Groups" ) ){
+		for( const ryml::NodeRef& groupNode : node["Groups"] ){
+			uint32 groupIndex;
+
+			if( !this->asUInt32( groupNode, "Group", groupIndex) ){
+				return 0;
+			}
+
+			std::shared_ptr<s_item_package_group> group = util::umap_find( entry->groups, groupIndex );
+			bool group_exists = group != nullptr;
+
+			if( !group_exists ){
+				if( !this->nodesExist( groupNode, { "Items" } ) ){
+					return 0;
+				}
+
+				group = std::make_shared<s_item_package_group>();
+				group->groupIndex = groupIndex;
+			}
+
+			for( const ryml::NodeRef& itemNode : groupNode["Items"] ){
+				std::string name;
+
+				if( !this->asString( itemNode, "Item", name ) ){
+					return 0;
+				}
+
+				std::shared_ptr<item_data> id = item_db.search_aegisname( name.c_str() );
+
+				if( id == nullptr ){
+					this->invalidWarning( itemNode["Item"], "Unknown item \"%s\".\n", name.c_str() );
+					return 0;
+				}
+
+				std::shared_ptr<s_item_package_item> package_item = util::umap_find( group->items, id->nameid );
+				bool package_item_exists = package_item != nullptr;
+
+				if( !package_item_exists ){
+					package_item = std::make_shared<s_item_package_item>();
+					package_item->item_id = id->nameid;
+				}
+
+				if( this->nodeExists( itemNode, "Amount" ) ){
+					uint16 amount;
+
+					if( !this->asUInt16( itemNode, "Amount", amount ) ){
+						return 0;
+					}
+
+					if( amount > MAX_AMOUNT ){
+						this->invalidWarning( itemNode["Amount"], "Amount %hu is too high, capping to MAX_AMOUNT...\n", amount );
+						amount = MAX_AMOUNT;
+					}else if( amount == 0 ){
+						if( !package_item_exists ){
+							this->invalidWarning( itemNode["Amount"], "Trying to remove non existant item \"%s\".\n", name.c_str() );
+							return 0;
+						}else{
+							group->items.erase( id->nameid );
+						}
+					}
+
+					package_item->amount = amount;
+				}else{
+					if( !package_item_exists ){
+						package_item->amount = 1;
+					}
+				}
+
+				if( this->nodeExists( itemNode, "RentalHours" ) ){
+					uint16 rentalhours;
+
+					if( !this->asUInt16( itemNode, "RentalHours", rentalhours ) ){
+						return 0;
+					}
+
+					package_item->rentalhours = rentalhours;
+				}else{
+					if( !package_item_exists ){
+						package_item->rentalhours = 0;
+					}
+				}
+
+				if( this->nodeExists( itemNode, "Refine" ) ){
+					uint16 refine;
+
+					if( !this->asUInt16( itemNode, "Refine", refine ) ){
+						return 0;
+					}
+
+					if( refine > MAX_REFINE ){
+						this->invalidWarning( itemNode["Refine"], "Refine %hu is too high, capping to MAX_REFINE...\n", refine );
+						refine = MAX_REFINE;
+					}
+
+					package_item->refine = refine;
+				}else{
+					if( !package_item_exists ){
+						package_item->refine = 0;
+					}
+				}
+
+				if( this->nodeExists( itemNode, "RandomOptionGroup" ) ){
+					std::string name;
+
+					if( !this->asString( itemNode, "RandomOptionGroup", name ) ){
+						return 0;
+					}
+
+					uint16 option_group_id;
+
+					if( !random_option_group.option_get_id( name, option_group_id ) ){
+						this->invalidWarning( itemNode["RandomOptionGroup"], "Unknown random option group \"%s\".\n", name.c_str() );
+						return 0;
+					}
+
+					package_item->randomOptionGroup = random_option_group.find( option_group_id );
+				}else{
+					if( !package_item_exists ){
+						package_item->randomOptionGroup = nullptr;
+					}
+				}
+
+				if( !package_item_exists ){
+					group->items[package_item->item_id] = package_item;
+				}
+			}
+
+			if( !group_exists ){
+				entry->groups[group->groupIndex] = group;
+			}
+		}
+	}
+
+	if( !exists ){
+		this->put( entry->item_id, entry );
+	}
+
+	return 1;
+}
+
+ItemPackageDatabase item_package_db;
+
 /*==========================================
  * Finds up to N matches. Returns number of matches [Skotlex]
  * @param *data
@@ -4295,6 +4473,7 @@ static void itemdb_read(void) {
 	laphine_upgrade_db.load();
 	item_reform_db.load();
 	item_enchant_db.load();
+	item_package_db.load();
 
 	if (battle_config.feature_roulette)
 		itemdb_parse_roulette_db();
@@ -4363,6 +4542,7 @@ void do_final_itemdb(void) {
 	laphine_upgrade_db.clear();
 	item_reform_db.clear();
 	item_enchant_db.clear();
+	item_package_db.clear();
 	if (battle_config.feature_roulette)
 		itemdb_roulette_free();
 }

+ 60 - 0
src/map/itemdb.hpp

@@ -995,6 +995,36 @@ enum e_random_item_group {
 	IG_BS_ITEM_M_S_55,
 	IG_BS_ITEM_M_S_56,
 	IG_ENCHANT_STONE_BOX28,
+	IG_S_FULLPENE_EARRING,
+	IG_S_FULLPENE_PENDANT,
+	IG_S_FULLPENE_ARMOR,
+	IG_S_FULLPENE_SHOES,
+	IG_S_FULLTEMP_EARRING,
+	IG_S_FULLTEMP_PENDANT,
+	IG_S_FULLTEMP_ARMOR,
+	IG_S_FULLTEMP_SHOES,
+	IG_S_DURABLE_WEAPON,
+	IG_S_DURABLE_SHIELD,
+	IG_S_CLEVER_WEAPON,
+	IG_S_CLEVER_SHIELD,
+	IG_S_ALLMIGHTY_EARRING,
+	IG_S_ALLMIGHTY_PENDANT,
+	IG_S_TRUEGEM_EARRING,
+	IG_S_TRUEGEM_PENDANT,
+	IG_S_TRUEGEM_SHOES,
+	IG_S_TRUEGEM_ARMOR,
+	IG_S_PERFECTSIZE_WEAPON,
+	IG_S_PERFECTSIZE_ARMOR,
+	IG_S_M_MAMMOTH_EARRING,
+	IG_S_M_MAMMOTH_PENDANT,
+	IG_S_M_MAMMOTH_ARMOR,
+	IG_S_M_MAMMOTH_SHOES,
+	IG_S_SPELLCASTER_EARRING,
+	IG_S_SPELLCASTER_PENDANT,
+	IG_S_SPELLCASTER_ARMOR,
+	IG_S_SPELLCASTER_SHOES,
+	IG_S_ABSORB_WEAPON,
+	IG_S_ABSORB_SHIELD,
 
 	IG_MAX,
 };
@@ -1488,6 +1518,36 @@ public:
 
 extern ItemEnchantDatabase item_enchant_db;
 
+struct s_item_package_item{
+	t_itemid item_id;
+	uint16 amount;
+	uint16 rentalhours;
+	uint16 refine;
+	std::shared_ptr<s_random_opt_group> randomOptionGroup;
+};
+
+struct s_item_package_group{
+	uint32 groupIndex;
+	std::unordered_map<t_itemid, std::shared_ptr<s_item_package_item>> items;
+};
+
+struct s_item_package{
+	t_itemid item_id;
+	std::unordered_map<uint32, std::shared_ptr<s_item_package_group>> groups;
+};
+
+class ItemPackageDatabase : public TypesafeYamlDatabase<t_itemid, s_item_package>{
+public:
+	ItemPackageDatabase() : TypesafeYamlDatabase( "ITEM_PACKAGE_DB", 1 ){
+
+	}
+
+	const std::string getDefaultLocation();
+	uint64 parseBodyNode( const ryml::NodeRef& node );
+};
+
+extern ItemPackageDatabase item_package_db;
+
 uint16 itemdb_searchname_array(std::map<t_itemid, std::shared_ptr<item_data>> &data, uint16 size, const char *str);
 struct item_data* itemdb_search(t_itemid nameid);
 std::shared_ptr<item_data> itemdb_exists(t_itemid nameid);

+ 1 - 0
src/map/log.cpp

@@ -90,6 +90,7 @@ static char log_picktype2char(e_log_pick_type type)
 		case LOG_TYPE_ENCHANTGRADE:		return '0';  // Enchantgrade UI
 		case LOG_TYPE_REFORM:			return '1';  // Reform UI
 		case LOG_TYPE_ENCHANT:			return '2';  // Echant UI
+		case LOG_TYPE_PACKAGE:			return '3';  // Item Package Selection
 	}
 
 	// should not get here, fallback

+ 1 - 0
src/map/log.hpp

@@ -56,6 +56,7 @@ enum e_log_pick_type : uint32
 	LOG_TYPE_ENCHANTGRADE     = 0x04000000,
 	LOG_TYPE_REFORM           = 0x08000000,
 	LOG_TYPE_ENCHANT          = 0x10000000,
+	LOG_TYPE_PACKAGE          = 0x20000000,
 	// combinations
 	LOG_TYPE_LOOT             = LOG_TYPE_PICKDROP_MONSTER|LOG_TYPE_CONSUME,
 	// all

+ 1 - 0
src/map/map-server.vcxproj

@@ -337,6 +337,7 @@
     <Copy SourceFiles="$(SolutionDir)db\import-tmpl\item_enchant.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\item_enchant.yml')" />
     <Copy SourceFiles="$(SolutionDir)db\import-tmpl\item_group_db.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\item_group_db.yml')" />
     <Copy SourceFiles="$(SolutionDir)db\import-tmpl\item_noequip.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\item_noequip.txt')" />
+    <Copy SourceFiles="$(SolutionDir)db\import-tmpl\item_packages.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\item_packages.yml')" />
     <Copy SourceFiles="$(SolutionDir)db\import-tmpl\item_randomopt_db.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\item_randomopt_db.yml')" />
     <Copy SourceFiles="$(SolutionDir)db\import-tmpl\item_randomopt_group.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\item_randomopt_group.yml')" />
     <Copy SourceFiles="$(SolutionDir)db\import-tmpl\item_reform.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\item_reform.yml')" />

+ 9 - 0
src/map/packets.hpp

@@ -328,6 +328,14 @@ 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));
+
 // 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 )
@@ -395,6 +403,7 @@ 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)
 
 const int16 MAX_INVENTORY_ITEM_PACKET_NORMAL = ( ( INT16_MAX - ( sizeof( struct packet_itemlist_normal ) - ( sizeof( struct NORMALITEM_INFO ) * MAX_ITEMLIST) ) ) / sizeof( struct NORMALITEM_INFO ) );
 const int16 MAX_INVENTORY_ITEM_PACKET_EQUIP = ( ( INT16_MAX - ( sizeof( struct packet_itemlist_equip ) - ( sizeof( struct EQUIPITEM_INFO ) * MAX_ITEMLIST ) ) ) / sizeof( struct EQUIPITEM_INFO ) );

+ 1 - 1
src/map/script.cpp

@@ -26394,7 +26394,7 @@ BUILDIN_FUNC(item_reform){
 }
 
 BUILDIN_FUNC(item_enchant){
-#if PACKETVER_RE_NUM < 20211103
+#if !( PACKETVER_RE_NUM >= 20211103 || PACKETVER_MAIN_NUM >= 20220330 )
 	ShowError( "buildin_item_enchant: This command requires packet version 2021-11-03 or newer.\n" );
 	return SCRIPT_CMD_FAILURE;
 #else

+ 30 - 0
src/map/script_constants.hpp

@@ -5782,6 +5782,36 @@
 	export_constant(IG_BS_ITEM_M_S_55);
 	export_constant(IG_BS_ITEM_M_S_56);
 	export_constant(IG_ENCHANT_STONE_BOX28);
+	export_constant(IG_S_FULLPENE_EARRING);
+	export_constant(IG_S_FULLPENE_PENDANT);
+	export_constant(IG_S_FULLPENE_ARMOR);
+	export_constant(IG_S_FULLPENE_SHOES);
+	export_constant(IG_S_FULLTEMP_EARRING);
+	export_constant(IG_S_FULLTEMP_PENDANT);
+	export_constant(IG_S_FULLTEMP_ARMOR);
+	export_constant(IG_S_FULLTEMP_SHOES);
+	export_constant(IG_S_DURABLE_WEAPON);
+	export_constant(IG_S_DURABLE_SHIELD);
+	export_constant(IG_S_CLEVER_WEAPON);
+	export_constant(IG_S_CLEVER_SHIELD);
+	export_constant(IG_S_ALLMIGHTY_EARRING);
+	export_constant(IG_S_ALLMIGHTY_PENDANT);
+	export_constant(IG_S_TRUEGEM_EARRING);
+	export_constant(IG_S_TRUEGEM_PENDANT);
+	export_constant(IG_S_TRUEGEM_SHOES);
+	export_constant(IG_S_TRUEGEM_ARMOR);
+	export_constant(IG_S_PERFECTSIZE_WEAPON);
+	export_constant(IG_S_PERFECTSIZE_ARMOR);
+	export_constant(IG_S_M_MAMMOTH_EARRING);
+	export_constant(IG_S_M_MAMMOTH_PENDANT);
+	export_constant(IG_S_M_MAMMOTH_ARMOR);
+	export_constant(IG_S_M_MAMMOTH_SHOES);
+	export_constant(IG_S_SPELLCASTER_EARRING);
+	export_constant(IG_S_SPELLCASTER_PENDANT);
+	export_constant(IG_S_SPELLCASTER_ARMOR);
+	export_constant(IG_S_SPELLCASTER_SHOES);
+	export_constant(IG_S_ABSORB_WEAPON);
+	export_constant(IG_S_ABSORB_SHIELD);
 
 	/* unit stop walking */
 	export_constant(USW_NONE);