From 38b8d5a9947bb4d2c379a9d4007cd8c7bc05463b Mon Sep 17 00:00:00 2001 From: Lemongrass3110 Date: Mon, 12 Sep 2022 22:06:04 +0200 Subject: [PATCH] Initial release of item package selection (#7239) Thanks to @aleos89 and @Atemo Co-authored-by: Atemo Co-authored-by: Aleos --- db/import-tmpl/item_packages.yml | 39 ++ db/item_packages.yml | 45 ++ db/re/item_db_usable.yml | 467 ++++++++++++++++ db/re/item_group_db.yml | 210 ++++++++ db/re/item_packages.yml | 531 +++++++++++++++++++ sql-files/logs.sql | 2 +- sql-files/upgrades/upgrade_20220912_logs.sql | 3 + src/char/packets.hpp | 2 +- src/config/packets.hpp | 2 +- src/map/clif.cpp | 106 +++- src/map/clif_packetdb.hpp | 6 +- src/map/clif_shuffle.hpp | 2 +- src/map/itemdb.cpp | 180 +++++++ src/map/itemdb.hpp | 60 +++ src/map/log.cpp | 1 + src/map/log.hpp | 1 + src/map/map-server.vcxproj | 1 + src/map/packets.hpp | 9 + src/map/script.cpp | 2 +- src/map/script_constants.hpp | 30 ++ 20 files changed, 1680 insertions(+), 19 deletions(-) create mode 100644 db/import-tmpl/item_packages.yml create mode 100644 db/item_packages.yml create mode 100644 db/re/item_packages.yml create mode 100644 sql-files/upgrades/upgrade_20220912_logs.sql diff --git a/db/import-tmpl/item_packages.yml b/db/import-tmpl/item_packages.yml new file mode 100644 index 0000000000..2ed2b8e32c --- /dev/null +++ b/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 . +# +########################################################################### +# 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 diff --git a/db/item_packages.yml b/db/item_packages.yml new file mode 100644 index 0000000000..7c81c5d701 --- /dev/null +++ b/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 . +# +########################################################################### +# 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 diff --git a/db/re/item_db_usable.yml b/db/re/item_db_usable.yml index 5b4be37b83..9c81f4d8d4 100644 --- a/db/re/item_db_usable.yml +++ b/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 diff --git a/db/re/item_group_db.yml b/db/re/item_group_db.yml index 21bf6c4b4e..f13af44a01 100644 --- a/db/re/item_group_db.yml +++ b/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 diff --git a/db/re/item_packages.yml b/db/re/item_packages.yml new file mode 100644 index 0000000000..a0c095497d --- /dev/null +++ b/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 . +# +########################################################################### +# 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 + - Item: Shoes + Refine: 5 +# RandomOptionGroup: TODO + - Item: Muffler + Refine: 3 +# RandomOptionGroup: TODO + - Item: Event_Pierrot_Nose + RentalHours: 24 +# RandomOptionGroup: TODO + - 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 + - Item: Cotton_Shirt + Refine: 4 +# RandomOptionGroup: TODO + - Item: Red_Potion + Amount: 100 + - Item: Ring + RentalHours: 24 +# RandomOptionGroup: TODO + - Group: 1 + Items: + - Item: Tsurugi + Refine: 5 +# RandomOptionGroup: TODO + - Item: Padded_Armor + Refine: 5 +# RandomOptionGroup: TODO + - Item: Yellow_Potion + Amount: 50 + - Group: 2 + Items: + - Item: Sword + Refine: 20 +# RandomOptionGroup: TODO + - Item: Guard + RentalHours: 168 + Refine: 5 +# RandomOptionGroup: TODO + - 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 + - Item: C_Imp_Hat +# RandomOptionGroup: TODO + - 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 diff --git a/sql-files/logs.sql b/sql-files/logs.sql index d024a98120..a23f4c7423 100644 --- a/sql-files/logs.sql +++ b/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', diff --git a/sql-files/upgrades/upgrade_20220912_logs.sql b/sql-files/upgrades/upgrade_20220912_logs.sql new file mode 100644 index 0000000000..16b965b9f3 --- /dev/null +++ b/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' +; diff --git a/src/char/packets.hpp b/src/char/packets.hpp index 509e0e853a..4820c5fc95 100644 --- a/src/char/packets.hpp +++ b/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; diff --git a/src/config/packets.hpp b/src/config/packets.hpp index c861b1bdd3..b216feb6e9 100644 --- a/src/config/packets.hpp +++ b/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 diff --git a/src/map/clif.cpp b/src/map/clif.cpp index 36ebf0ca85..8e8e382a05 100644 --- a/src/map/clif.cpp +++ b/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= 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 package = item_package_db.find( p->itemID ); + + if( package == nullptr ){ + return; + } + + std::shared_ptr 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 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 *------------------------------------------*/ diff --git a/src/map/clif_packetdb.hpp b/src/map/clif_packetdb.hpp index 968dcb527f..554ab64adf 100644 --- a/src/map/clif_packetdb.hpp +++ b/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 */ diff --git a/src/map/clif_shuffle.hpp b/src/map/clif_shuffle.hpp index 25919c4e67..3f2d151075 100644 --- a/src/map/clif_shuffle.hpp +++ b/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 ); diff --git a/src/map/itemdb.cpp b/src/map/itemdb.cpp index 5f26c1663c..8773b3f9a3 100644 --- a/src/map/itemdb.cpp +++ b/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 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 entry = this->find( item_id ); + bool exists = entry != nullptr; + + if( !exists ){ + if( !this->nodesExist( node, { "Groups" } ) ){ + return 0; + } + + entry = std::make_shared(); + 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 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(); + group->groupIndex = groupIndex; + } + + for( const ryml::NodeRef& itemNode : groupNode["Items"] ){ + std::string name; + + if( !this->asString( itemNode, "Item", name ) ){ + return 0; + } + + std::shared_ptr 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 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(); + 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(); } diff --git a/src/map/itemdb.hpp b/src/map/itemdb.hpp index 3745ff65db..b8d5831b30 100644 --- a/src/map/itemdb.hpp +++ b/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 randomOptionGroup; +}; + +struct s_item_package_group{ + uint32 groupIndex; + std::unordered_map> items; +}; + +struct s_item_package{ + t_itemid item_id; + std::unordered_map> groups; +}; + +class ItemPackageDatabase : public TypesafeYamlDatabase{ +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> &data, uint16 size, const char *str); struct item_data* itemdb_search(t_itemid nameid); std::shared_ptr itemdb_exists(t_itemid nameid); diff --git a/src/map/log.cpp b/src/map/log.cpp index 73385890ec..eb06d7d78b 100644 --- a/src/map/log.cpp +++ b/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 diff --git a/src/map/log.hpp b/src/map/log.hpp index 9cb636a3b6..02b091af3a 100644 --- a/src/map/log.hpp +++ b/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 diff --git a/src/map/map-server.vcxproj b/src/map/map-server.vcxproj index e5fd9ba87d..3fbfc1d389 100644 --- a/src/map/map-server.vcxproj +++ b/src/map/map-server.vcxproj @@ -337,6 +337,7 @@ + diff --git a/src/map/packets.hpp b/src/map/packets.hpp index 111f55b341..40eecf64a7 100644 --- a/src/map/packets.hpp +++ b/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 ) ); diff --git a/src/map/script.cpp b/src/map/script.cpp index 9d23dcf96c..c8d4f0493b 100644 --- a/src/map/script.cpp +++ b/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 diff --git a/src/map/script_constants.hpp b/src/map/script_constants.hpp index 8e7a902207..a99fa0d88f 100644 --- a/src/map/script_constants.hpp +++ b/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);