Initial implementation of enchantgrade UI (#6913)

Includes walkscript conversion of kRO scripts

Thanks to @Asheraf, @Balferian, @JohnnyPlayy, @aleos89, @Atemo, @eppc0330 and @Pokye.

Co-authored-by: JohnnyPlayy <lenon32@gmail.com>
Co-authored-by: Asheraf <Asheraf@users.noreply.github.com>
Co-authored-by: Balferian <balfear@yandex.ru>
Co-authored-by: Aleos <aleos89@users.noreply.github.com>
Co-authored-by: Atemo <Atemo@users.noreply.github.com>
This commit is contained in:
Lemongrass3110 2022-06-07 16:45:35 +02:00 committed by GitHub
parent 24cfdc68de
commit 001981cf66
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 1565 additions and 88 deletions

View File

@ -1010,6 +1010,9 @@ Body:
Aliases: Aliases:
- famepoint - famepoint
- famepoints - famepoints
- Command: enchantgradeui
Help: |
Opens the enchantgrade UI.
Footer: Footer:
Imports: Imports:

View File

@ -8,37 +8,40 @@
//-------------------------------------------------------------- //--------------------------------------------------------------
// Enable Logs? (Note 3) // Enable Logs? (Note 3)
// 0x0000000 - Don't log at all // 0x00000000 - Don't log at all
// 0x0000001 - (T) Log trades // 0x00000001 - (T) Log trades
// 0x0000002 - (V) Log vending transactions // 0x00000002 - (V) Log vending transactions
// 0x0000004 - (P) Log items drop/picked by players // 0x00000004 - (P) Log items drop/picked by players
// 0x0000008 - (L) Log items drop/looted by monsters // 0x00000008 - (L) Log items drop/looted by monsters
// 0x0000010 - (S) Log NPC transactions (buy/sell) // 0x00000010 - (S) Log NPC transactions (buy/sell)
// 0x0000020 - (N) Log Script transactions (items deleted/acquired through quests) // 0x00000020 - (N) Log Script transactions (items deleted/acquired through quests)
// 0x0000040 - (D) Log items stolen from mobs (Steal/Gank) // 0x00000040 - (D) Log items stolen from mobs (Steal/Gank)
// 0x0000080 - (C) Log player-used items (consumables/pet&hom&merc food/items used for skills&attacks) // 0x00000080 - (C) Log player-used items (consumables/pet&hom&merc food/items used for skills&attacks)
// 0x0000100 - (O) Log produced/ingredient items // 0x00000100 - (O) Log produced/ingredient items
// 0x0000200 - (U) Log MVP prize items // 0x00000200 - (U) Log MVP prize items
// 0x0000400 - (A) Log player created/deleted items (through @/# commands) // 0x00000400 - (A) Log player created/deleted items (through @/# commands)
// 0x0000800 - (R) Log items placed/retrieved from storage. // 0x00000800 - (R) Log items placed/retrieved from storage.
// 0x0001000 - (G) Log items placed/retrieved from guild storage. // 0x00001000 - (G) Log items placed/retrieved from guild storage.
// 0x0002000 - (E) Log mail system transactions. // 0x00002000 - (E) Log mail system transactions.
// 0x0004000 - (I) Log auction system transactions. // 0x00004000 - (I) Log auction system transactions.
// 0x0008000 - (B) Log buying store transactions // 0x00008000 - (B) Log buying store transactions
// 0x0010000 - (X) Log all other transactions (rentals expiring/inserting cards/items removed by item_check/ // 0x00010000 - (X) Log all other transactions (rentals expiring/inserting cards/items removed by item_check/
// rings deleted by divorce/pet egg (un)hatching/pet armor (un)equipping/Weapon Refine skill/Remove Trap skill/Stylist) // rings deleted by divorce/pet egg (un)hatching/pet armor (un)equipping/Weapon Refine skill/Remove Trap skill/Stylist)
// 0x0020000 - ($) Log cash transactions // 0x00020000 - ($) Log cash transactions
// 0x0040000 - (K) Log account bank transactions // 0x00040000 - (K) Log account bank transactions
// 0x0080000 - (F) Removed bound items when guild/party is broken // 0x00080000 - (F) Removed bound items when guild/party is broken
// 0x0100000 - (Y) Log Roulette Lottery // 0x00100000 - (Y) Log Roulette Lottery
// 0x0200000 - (Z) Merged items from item mergers process. // 0x00200000 - (Z) Merged items from item mergers process.
// 0x0400000 - (Q) Log items given from quest-granted drops. // 0x00400000 - (Q) Log items given from quest-granted drops.
// 0x0800000 - (H) Log items consumed by Private Airship system // 0x00800000 - (H) Log items consumed by Private Airship system
// 0x1000000 - (J) Log Barter Shop transactions // 0x01000000 - (J) Log Barter Shop transactions
// 0x2000000 - (W) Log Laphine system transactions // 0x02000000 - (W) Log Laphine system transactions
// 0x04000000 - (0) Enchantgrade UI
// 0x08000000 - (1) Reform UI
// 0x10000000 - (2) Enchant UI
// Example: Log trades+vending+script items+created items: 1+2+32+1024 = 1059 // Example: Log trades+vending+script items+created items: 1+2+32+1024 = 1059
// Please note that moving items from inventory to cart and back is not logged by design. // Please note that moving items from inventory to cart and back is not logged by design.
enable_logs: 0xFFFFFFF enable_logs: 0xFFFFFFFF
// Use MySQL Logs? (Note 1) // Use MySQL Logs? (Note 1)
sql_logs: yes sql_logs: yes

View File

@ -921,7 +921,10 @@
// @mobinfo RES/MRES // @mobinfo RES/MRES
827: RES:%d MRES:%d 827: RES:%d MRES:%d
//828-899 free // General packet version check messages
828: This command requires packet version %s or newer.
//829-899 free
//------------------------------------ //------------------------------------
// More atcommands message // More atcommands message

58
db/enchantgrade.yml Normal file
View File

@ -0,0 +1,58 @@
# 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/>.
#
###########################################################################
# Enchantgrade Database
###########################################################################
#
# Enchantgrade Settings
#
###########################################################################
# - Type Item type.
# Levels: Enchantgrade settings per item level.
# - Level Item level.
# Grades: Enchantgrade settings per grade level.
# - Grade Enchantgrade level.
# Refine Required refine level.
# Chance Base chance of success out of 0~10000.
# Bonus Enchantgrade bonus. (Default: 0)
# Announce Announce if someone tries to increase the enchantgrade. (Default: true)
# Catalyst: Catalyst item to increase chance of success.
# Item The item that can be used.
# AmountPerStep Amount of Item needed.
# Set to 0 to disable the catalyst.
# MaximumSteps Maximum amount of times Item can be used.
# ChanceIncrease Amount at which the chance increases for each Item used.
# Options: Success chance based on cost type.
# - Option Index of the client option.
# Item Required item.
# Amount Amount of required item. (Default: 1)
# Set to 0 to remove an option.
# Price Amount of zeny required. (Default: 0)
# BreakingRate Chance of item breaking out of 0~10000. (Default: 0)
# DowngradeAmount Number of refine levels reduced on failure. (Default: 0)
###########################################################################
Header:
Type: ENCHANTGRADE_DB
Version: 1
Footer:
Imports:
- Path: db/re/enchantgrade.yml
Mode: Renewal
- Path: db/import/enchantgrade.yml

View File

@ -0,0 +1,52 @@
# 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/>.
#
###########################################################################
# Enchantgrade Database
###########################################################################
#
# Enchantgrade Settings
#
###########################################################################
# - Type Item type.
# Levels: Enchantgrade settings per item level.
# - Level Item level.
# Grades: Enchantgrade settings per grade level.
# - Grade Enchantgrade level.
# Refine Required refine level.
# Chance Base chance of success out of 0~10000.
# Bonus Enchantgrade bonus. (Default: 0)
# Announce Announce if someone tries to increase the enchantgrade. (Default: true)
# Catalyst: Catalyst item to increase chance of success.
# Item The item that can be used.
# AmountPerStep Amount of Item needed.
# Set to 0 to disable the catalyst.
# MaximumSteps Maximum amount of times Item can be used.
# ChanceIncrease Amount at which the chance increases for each Item used.
# Options: Success chance based on cost type.
# - Option Index of the client option.
# Item Required item.
# Amount Amount of required item. (Default: 1)
# Set to 0 to remove an option.
# Price Amount of zeny required. (Default: 0)
# BreakingRate Chance of item breaking out of 0~10000. (Default: 0)
# DowngradeAmount Number of refine levels reduced on failure. (Default: 0)
###########################################################################
Header:
Type: ENCHANTGRADE_DB
Version: 1

214
db/re/enchantgrade.yml Normal file
View File

@ -0,0 +1,214 @@
# 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/>.
#
###########################################################################
# Enchantgrade Database
###########################################################################
#
# Enchantgrade Settings
#
###########################################################################
# - Type Item type.
# Levels: Enchantgrade settings per item level.
# - Level Item level.
# Grades: Enchantgrade settings per grade level.
# - Grade Enchantgrade level.
# Refine Required refine level.
# Chance Base chance of success out of 0~10000.
# Bonus Enchantgrade bonus. (Default: 0)
# Announce Announce if someone tries to increase the enchantgrade. (Default: true)
# Catalyst: Catalyst item to increase chance of success.
# Item The item that can be used.
# AmountPerStep Amount of Item needed.
# Set to 0 to disable the catalyst.
# MaximumSteps Maximum amount of times Item can be used.
# ChanceIncrease Amount at which the chance increases for each Item used.
# Options: Success chance based on cost type.
# - Option Index of the client option.
# Item Required item.
# Amount Amount of required item. (Default: 1)
# Set to 0 to remove an option.
# Price Amount of zeny required. (Default: 0)
# BreakingRate Chance of item breaking out of 0~10000. (Default: 0)
# DowngradeAmount Number of refine levels reduced on failure. (Default: 0)
###########################################################################
Header:
Type: ENCHANTGRADE_DB
Version: 1
Body:
- Type: Armor
Levels:
- Level: 2
Grades:
- Grade: None
Refine: 11
Chance: 7000
Bonus: 10
Catalyst:
Item: Blessed_Etel_Dust
AmountPerStep: 1
MaximumSteps: 10
ChanceIncrease: 100
Options:
- Option: 0
Item: Etel_Skyblue_Jewel
Amount: 1
Zeny: 175000
BreakingRate: 10000
- Option: 1
Item: Etel_Skyblue_Jewel
Amount: 5
Zeny: 875000
- Grade: D
Refine: 11
Chance: 6000
Bonus: 30
Catalyst:
Item: Blessed_Etel_Dust
AmountPerStep: 3
MaximumSteps: 10
ChanceIncrease: 100
Options:
- Option: 0
Item: Etel_Topaz
Amount: 1
Zeny: 175000
BreakingRate: 10000
- Option: 1
Item: Etel_Topaz
Amount: 5
Zeny: 875000
- Grade: C
Refine: 11
Chance: 5000
Bonus: 50
Catalyst:
Item: Blessed_Etel_Dust
AmountPerStep: 5
MaximumSteps: 10
ChanceIncrease: 100
Options:
- Option: 0
Item: Etel_Violet_Jewel
Amount: 1
Zeny: 175000
BreakingRate: 10000
- Option: 1
Item: Etel_Violet_Jewel
Amount: 5
Zeny: 875000
- Grade: B
Refine: 11
Chance: 4000
Bonus: 100
Catalyst:
Item: Blessed_Etel_Dust
AmountPerStep: 7
MaximumSteps: 10
ChanceIncrease: 100
Options:
- Option: 0
Item: Etel_Amber
Amount: 2
Zeny: 175000
BreakingRate: 10000
- Option: 1
Item: Etel_Amber
Amount: 10
Zeny: 875000
- Type: Weapon
Levels:
- Level: 5
Grades:
- Grade: None
Refine: 11
Chance: 7000
Bonus: 10
Catalyst:
Item: Blessed_Etel_Dust
AmountPerStep: 1
MaximumSteps: 10
ChanceIncrease: 100
Options:
- Option: 0
Item: Etel_Skyblue_Jewel
Amount: 1
Zeny: 175000
BreakingRate: 10000
- Option: 1
Item: Etel_Skyblue_Jewel
Amount: 5
Zeny: 875000
- Grade: D
Refine: 11
Chance: 6000
Bonus: 30
Catalyst:
Item: Blessed_Etel_Dust
AmountPerStep: 3
MaximumSteps: 10
ChanceIncrease: 100
Options:
- Option: 0
Item: Etel_Topaz
Amount: 1
Zeny: 175000
BreakingRate: 10000
- Option: 1
Item: Etel_Topaz
Amount: 5
Zeny: 875000
- Grade: C
Refine: 11
Chance: 5000
Bonus: 50
Catalyst:
Item: Blessed_Etel_Dust
AmountPerStep: 5
MaximumSteps: 10
ChanceIncrease: 100
Options:
- Option: 0
Item: Etel_Violet_Jewel
Amount: 1
Zeny: 175000
BreakingRate: 10000
- Option: 1
Item: Etel_Violet_Jewel
Amount: 5
Zeny: 875000
- Grade: B
Refine: 11
Chance: 4000
Bonus: 100
Catalyst:
Item: Blessed_Etel_Dust
AmountPerStep: 7
MaximumSteps: 10
ChanceIncrease: 100
Options:
- Option: 0
Item: Etel_Amber
Amount: 2
Zeny: 175000
BreakingRate: 10000
- Option: 1
Item: Etel_Amber
Amount: 10
Zeny: 875000

View File

@ -61756,6 +61756,7 @@ Body:
AegisName: Amber AegisName: Amber
Name: Amber Name: Amber
Type: Etc Type: Etc
Buy: 45000
Weight: 100 Weight: 100
- Id: 1000322 - Id: 1000322
AegisName: Etel_Dust AegisName: Etel_Dust

View File

@ -1178,6 +1178,12 @@ If args are given, sets camera position.
--------------------------------------- ---------------------------------------
@enchantgradeui
Opens the enchantgrade UI.
---------------------------------------
============================== ==============================
| 5. Administrative Commands | | 5. Administrative Commands |
============================== ==============================

View File

@ -8164,7 +8164,15 @@ This function is intended for use in item scripts.
Opens the Bank UI for the attached player or the given character ID. Opens the Bank UI for the attached player or the given character ID.
This command requires packet version 2015-01-28 or newer. This command requires packet version 2015-12-02 or newer.
---------------------------------------
*enchantgradeui {<char id>};
Opens the enchantgrade UI for the attached character or the player given by the char ID parameter.
This command requires packet version 2020-07-24 or newer.
--------------------------------------- ---------------------------------------
\\ \\
@ -9784,6 +9792,8 @@ QMARK_PURPLE - Purple Marker
Opens the quest UI for the attached player or the given character ID. Opens the quest UI for the attached player or the given character ID.
Use 0 as the quest ID to open the main quest UI. If the quest ID is not 0 then the quest UI is opened to the given quest. If the quest data is not populated in the client LUB then a message will be displayed saying the quest doesn't exist. Use 0 as the quest ID to open the main quest UI. If the quest ID is not 0 then the quest UI is opened to the given quest. If the quest data is not populated in the client LUB then a message will be displayed saying the quest doesn't exist.
This command requires packet version 2015-12-02 or newer.
--------------------------------------- ---------------------------------------
============================ ============================

View File

@ -52,3 +52,4 @@ Footer:
- Path: npc/re/merchants/barters/quests_16_2.yml - Path: npc/re/merchants/barters/quests_16_2.yml
- Path: npc/re/merchants/barters/quests_17_1.yml - Path: npc/re/merchants/barters/quests_17_1.yml
- Path: npc/re/merchants/barters/refine.yml - Path: npc/re/merchants/barters/refine.yml
- Path: npc/re/merchants/barters/enchantgrade.yml

View File

@ -0,0 +1,110 @@
# 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/>.
#
###########################################################################
# Barter Database
###########################################################################
#
# Barter Settings
#
###########################################################################
# - Name NPC name.
# Map Map name. (Default: not on a map)
# X Map x coordinate. (Default: 0)
# Y Map y coordinate. (Default: 0)
# Direction Direction the NPC is looking. (Default: North)
# Sprite Sprite name of the NPC. (Default: FakeNpc)
# Items: List of sold items.
# - Index Index of the item inside the shop. (0-...)
# Maximum index depends on client.
# Item Aegis name of the item.
# Stock Amount of item in stock. 0 means unlimited. (Default: 0)
# Zeny Cost of them item in Zeny. (Default: 0)
# RequiredItems: List of required items (Optional)
# - Index Index of the required item. (0-4)
# Item Aegis name of required item.
# Amount Amount of required item. (Default: 1)
# Refine Refine level of required item. (Default: 0)
###########################################################################
Header:
Type: BARTER_DB
Version: 1
Body:
###########################################################################
##= Enchant Grade Exchange
###########################################################################
- Name: EnchantGradeExchange
Items:
- Index: 0
Item: Etel_Stone
Zeny: 100000
RequiredItems:
- Index: 0
Item: Etel_Dust
Amount: 5
- Index: 1
Item: Blessed_Etel_Dust
Zeny: 100000
RequiredItems:
- Index: 0
Item: Etel_Dust
Amount: 5
- Index: 1
Item: Blacksmith_Blessing
Amount: 1
- Index: 2
Item: Etel_Skyblue_Jewel
Zeny: 100000
RequiredItems:
- Index: 0
Item: Etel_Stone
Amount: 3
- Index: 1
Item: Skyblue_Jewel
Amount: 1
- Index: 3
Item: Etel_Topaz
Zeny: 200000
RequiredItems:
- Index: 0
Item: Etel_Stone
Amount: 6
- Index: 1
Item: Golden_Jewel
Amount: 1
- Index: 4
Item: Etel_Violet_Jewel
Zeny: 300000
RequiredItems:
- Index: 0
Item: Etel_Stone
Amount: 10
- Index: 1
Item: Violet_Jewel
Amount: 1
- Index: 5
Item: Etel_Amber
Zeny: 300000
RequiredItems:
- Index: 0
Item: Etel_Stone
Amount: 15
- Index: 1
Item: Amber
Amount: 1

View File

@ -0,0 +1,131 @@
//===== rAthena Script =======================================
//= Enchant Grade
//===== Changelogs: ==========================================
//= 1.0 First Version. [JohnnyPlayy]
//= 1.1 Fixed small issues. [Lemongrass]
//= 1.2 Added translation. [Asheraf]
//= 1.3 Added paramarket NPC and warps. [Balfear]
//= 1.4 Translated paramarket NPC. [Lemongrass]
//============================================================
grademk,34,184,4 script Sratos#sratos 4_JP_GARM_H,{
mes "[Sratos]";
mes "Hello, dear customer who walked in, let's hope for a miracle today.";
mes "How can I help you?";
next;
switch( select( "Enhance the equipment's grade.", "Exchange Etel items", "What is Grade Enhancement?" ) ){
case 1:
mes "[Sratos]";
mes "Our customer. You want to enhance the grade of equipment.";
mes "It is not easy to move the magical power of jewels.";
next;
mes "[Sratos]";
mes "Magical power can explode on the spot.";
mes "Then the weapon that will inherit the magical power also explodes!";
next;
switch( select( "I'll still do it!", "I'll think about it." ) ){
case 1:
mes "[Sratos]";
mes "I wish good luck to our courageous customers!";
close2;
enchantgradeui();
end;
case 2:
mes "[Sratos]";
mes "Whenever you have the courage to challenge, please come back.";
close;
}
case 2:
mes "[Sratos]";
mes "These are jewels used to enhance grades.";
mes "Etel Dust, the jewels that will be the base, and if you give me a small fee I'll exchange it for Etel jewels.";
close2;
callshop "EnchantGradeExchange";
end;
case 3:
mes "[Sratos]";
mes "Occasionally, unstable jewels with a lot of pure magical power are found.";
mes "We call these etheric gems, right?";
next;
mes "[Sratos]";
mes "You can transfer the magical power of the etheric gem to other weapons, but of course there is some risk.";
mes "It's delicate, so if you aren't careful, pop! It will explode.";
next;
mes "[Sratos]";
mes "Anyway, if you use this etheric gem, you can enhance the weapon you are using.";
mes "Performance gets better. We call this grade enhancement.";
next;
mes "[Sratos]";
mes "You too, wouldn't you be happy if the weapons you love grow one step further?";
mes "We are the people who assist it. It's a bit risky, though. ahahaha.";
close;
}
OnInit:
setunittitle(getnpcid(0), "<Grade Enhancer>");
end;
}
paramk,34,184,4 script Suribell#suribell 4_F_FRUIT,{
mes "[Suribell]";
mes "May good luck always be with you!";
mes "Welcome to Paramarket's Grade Enhancement Center~";
next;
switch( select( "Enhance the equipment's grade.", "Exchange Etel items", "What is Grade Enhancement?" )) {
case 1:
mes "[Suribell]";
mes "Do you want to unlock the potential of your favorite equipment?";
mes "Explosions may also occur in the process of dealing with magical powers.";
next;
mes "[Suribell]";
mes "Still, if you're trying to enhance your grade... !";
mes "I, Suribell, will do my best!";
next;
switch( select( "I'll still do it!", "I'll think about it." ) ){
case 1:
mes "[Suribell]";
mes "Let's hold hands and have faith! Try clenching your teeth!";
close2;
enchantgradeui();
end;
case 2:
mes "[Suribell]";
mes "Okay! Let's drink a glass of cold water!";
close;
}
case 2:
mes "[Suribell]";
mes "You need etheric gems to enhance grades!";
mes "If you combine Etel Dust and jewels to make it, it is fine! An Etel jewel for adventurers is complete!";
mes "Would you like to combine jewels and Etel Dust?";
close2;
callshop "EnchantGradeExchange";
end;
case 3:
mes "[Suribell]";
mes "Occasionally, unstable jewels with a lot of pure magical power are found.";
mes "I decided to call such gems etheric gems.";
mes "Who? I am Suribell!";
next;
mes "[Suribell]";
mes "The magical power of etheric gems sometimes awakens the hidden potential of equipment.";
mes "We call it grade enhancement because it goes up one tier!";
next;
mes "[Suribell]";
mes "The adventurer may have a potential that is unknown to him.";
mes "There is a risk that it can be destroyed if done wrong, but try it with faith!";
close;
}
OnInit:
setunittitle(getnpcid(0), "<Grade Enhancer>");
end;
}
// = Portals
//============================================================
prontera,50,293,0 warp Grademk_Int 1,1,grademk,13,172
grademk,9,172,0 warp Grademk_Out 1,1,prontera,50,290
paramk,8,171,0 warp grade_in 1,1,paramk,141,64
paramk,145,64,0 warp grade_out 1,1,paramk,11,171

View File

@ -125,7 +125,7 @@ morocc,154,55,6 shop Jeweler#moc3 99,730:-1,2613:-1
morocc,171,103,4 shop Item Collector#moc3 85,911:-1,528:-1,919:-1,925:-1 morocc,171,103,4 shop Item Collector#moc3 85,911:-1,528:-1,919:-1,925:-1
morocc,205,247,2 shop Item Collector#moc4 85,911:-1,528:-1,919:-1,925:-1 morocc,205,247,2 shop Item Collector#moc4 85,911:-1,528:-1,919:-1,925:-1
morocc,140,90,6 shop Trader#moc6 99,513:-1,513:-1,513:-1,513:-1,513:-1,513:-1 morocc,140,90,6 shop Trader#moc6 99,513:-1,513:-1,513:-1,513:-1,513:-1,513:-1
morocc,166,54,2 shop Jeweler#moc4 102,721:-1,723:-1,726:-1,728:-1,729:-1 morocc,166,54,2 shop Jeweler#moc4 102,721:-1,723:-1,726:-1,728:-1,729:-1,1000321:-1
morocc,34,68,0 shop Trader#moc7 93,748:-1 morocc,34,68,0 shop Trader#moc7 93,748:-1
morocc,269,193,4 shop Trader#moc8 89,2609:-1,1516:-1,1522:-1 morocc,269,193,4 shop Trader#moc8 89,2609:-1,1516:-1,1522:-1
morocc,256,191,5 shop Trader#moc9 93,2612:-1 morocc,256,191,5 shop Trader#moc9 93,2612:-1

View File

@ -126,6 +126,7 @@ npc: npc/re/merchants/enchan_mal.txt
npc: npc/re/merchants/enchan_mora.txt npc: npc/re/merchants/enchan_mora.txt
npc: npc/re/merchants/enchan_rockridge.txt npc: npc/re/merchants/enchan_rockridge.txt
npc: npc/re/merchants/enchan_verus.txt npc: npc/re/merchants/enchan_verus.txt
npc: npc/re/merchants/enchantgrade.txt
npc: npc/re/merchants/Extended_Ammunition.txt npc: npc/re/merchants/Extended_Ammunition.txt
npc: npc/re/merchants/Extended_Stylist.txt npc: npc/re/merchants/Extended_Stylist.txt
npc: npc/re/merchants/flute.txt npc: npc/re/merchants/flute.txt

View File

@ -169,12 +169,15 @@ CREATE TABLE IF NOT EXISTS `npclog` (
# Private Airs(H)ip # Private Airs(H)ip
# Barter Shop (J) # Barter Shop (J)
# Laphine systems (W) # Laphine systems (W)
# Enchantgrade UI (0)
# Reform UI (1)
# Enchant UI (2)
CREATE TABLE IF NOT EXISTS `picklog` ( CREATE TABLE IF NOT EXISTS `picklog` (
`id` int(11) NOT NULL auto_increment, `id` int(11) NOT NULL auto_increment,
`time` datetime NOT NULL, `time` datetime NOT NULL,
`char_id` int(11) NOT NULL default '0', `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') 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') NOT NULL default 'P',
`nameid` int(10) unsigned NOT NULL default '0', `nameid` int(10) unsigned NOT NULL default '0',
`amount` int(11) NOT NULL default '1', `amount` int(11) NOT NULL default '1',
`refine` tinyint(3) unsigned NOT NULL default '0', `refine` tinyint(3) unsigned NOT NULL default '0',
@ -224,13 +227,15 @@ CREATE TABLE IF NOT EXISTS `picklog` (
# Ban(K) Transactions # Ban(K) Transactions
# Barter Shop (J) # Barter Shop (J)
# (X) Other # (X) Other
# Enchantgrade UI (0)
# Enchant UI (2)
CREATE TABLE IF NOT EXISTS `zenylog` ( CREATE TABLE IF NOT EXISTS `zenylog` (
`id` int(11) NOT NULL auto_increment, `id` int(11) NOT NULL auto_increment,
`time` datetime NOT NULL, `time` datetime NOT NULL,
`char_id` int(11) NOT NULL default '0', `char_id` int(11) NOT NULL default '0',
`src_id` int(11) NOT NULL default '0', `src_id` int(11) NOT NULL default '0',
`type` enum('T','V','P','M','S','N','D','C','A','E','I','B','K','J','X') NOT NULL default 'S', `type` enum('T','V','P','M','S','N','D','C','A','E','I','B','K','J','X','0','2') NOT NULL default 'S',
`amount` int(11) NOT NULL default '0', `amount` int(11) NOT NULL default '0',
`map` varchar(11) NOT NULL default '', `map` varchar(11) NOT NULL default '',
PRIMARY KEY (`id`), PRIMARY KEY (`id`),

View File

@ -0,0 +1,7 @@
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') NOT NULL default 'P'
;
ALTER TABLE `zenylog`
MODIFY `type` enum('T','V','P','M','S','N','D','C','A','E','I','B','K','J','X','0','2') NOT NULL default 'S'
;

View File

@ -111,12 +111,22 @@ typedef uint32 t_itemid;
#define MAX_BARTER_REQUIREMENTS 5 #define MAX_BARTER_REQUIREMENTS 5
#endif #endif
enum e_enchantgrade : uint16{
ENCHANTGRADE_NONE = 0,
ENCHANTGRADE_D,
ENCHANTGRADE_C,
ENCHANTGRADE_B,
ENCHANTGRADE_A
};
#ifdef RENEWAL #ifdef RENEWAL
#define MAX_WEAPON_LEVEL 5 #define MAX_WEAPON_LEVEL 5
#define MAX_ARMOR_LEVEL 2 #define MAX_ARMOR_LEVEL 2
#define MAX_ENCHANTGRADE ENCHANTGRADE_A
#else #else
#define MAX_WEAPON_LEVEL 4 #define MAX_WEAPON_LEVEL 4
#define MAX_ARMOR_LEVEL 1 #define MAX_ARMOR_LEVEL 1
#define MAX_ENCHANTGRADE ENCHANTGRADE_NONE
#endif #endif
// for produce // for produce

View File

@ -10662,7 +10662,7 @@ ACMD_FUNC( stylist ){
return -1; return -1;
} }
clif_ui_open( sd, OUT_UI_STYLIST, 0 ); clif_ui_open( *sd, OUT_UI_STYLIST, 0 );
return 0; return 0;
#endif #endif
} }
@ -10697,6 +10697,23 @@ ACMD_FUNC(addfame)
return 0; return 0;
} }
/**
* Opens the enchantgrade UI
* Usage: @enchantgradeui
*/
ACMD_FUNC( enchantgradeui ){
nullpo_retr( -1, sd );
#if !( PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200724 )
sprintf( atcmd_output, msg_txt( sd, 798 ), "2020-07-24" ); // This command requires packet version %s or newer.
clif_displaymessage( fd, atcmd_output );
return -1;
#else
clif_ui_open( *sd, OUT_UI_ENCHANTGRADE, 0 );
return 0;
#endif
}
#include "../custom/atcommand.inc" #include "../custom/atcommand.inc"
/** /**
@ -11019,6 +11036,7 @@ void atcommand_basecommands(void) {
ACMD_DEF(refineui), ACMD_DEF(refineui),
ACMD_DEFR(stylist, ATCMD_NOCONSOLE|ATCMD_NOAUTOTRADE), ACMD_DEFR(stylist, ATCMD_NOCONSOLE|ATCMD_NOAUTOTRADE),
ACMD_DEF(addfame), ACMD_DEF(addfame),
ACMD_DEFR(enchantgradeui, ATCMD_NOCONSOLE|ATCMD_NOAUTOTRADE),
}; };
AtCommandInfo* atcommand; AtCommandInfo* atcommand;
int i; int i;

View File

@ -21551,23 +21551,32 @@ void clif_parse_changedress( int fd, struct map_session_data* sd ){
/// Opens an UI window of the given type and initializes it with the given data /// Opens an UI window of the given type and initializes it with the given data
/// 0AE2 <type>.B <data>.L /// 0AE2 <type>.B <data>.L
void clif_ui_open( struct map_session_data *sd, enum out_ui_type ui_type, int32 data ){ void clif_ui_open( struct map_session_data& sd, enum out_ui_type ui_type, int32 data ){
nullpo_retv(sd); #if PACKETVER >= 20151202
// If the UI requires state tracking // If the UI requires state tracking
switch( ui_type ){ switch( ui_type ){
case OUT_UI_STYLIST: case OUT_UI_STYLIST:
sd->state.stylist_open = true; sd.state.stylist_open = true;
break; break;
case OUT_UI_ENCHANTGRADE:
#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200724
sd.state.enchantgrade_open = true;
break;
#else
return;
#endif
} }
int fd = sd->fd; struct PACKET_ZC_UI_OPEN p = {};
WFIFOHEAD(fd,packet_len(0xae2)); p.PacketType = HEADER_ZC_UI_OPEN;
WFIFOW(fd,0) = 0xae2; p.UIType = ui_type;
WFIFOB(fd,2) = ui_type; #if PACKETVER >= 20171122
WFIFOL(fd,3) = data; p.data = data;
WFIFOSET(fd,packet_len(0xae2)); #endif
clif_send( &p, sizeof( p ), &sd.bl, SELF );
#endif
} }
/// Request to open an UI window of the given type /// Request to open an UI window of the given type
@ -21578,7 +21587,7 @@ void clif_parse_open_ui( int fd, struct map_session_data* sd ){
if( !pc_has_permission( sd, PC_PERM_ATTENDANCE ) ){ if( !pc_has_permission( sd, PC_PERM_ATTENDANCE ) ){
clif_messagecolor( &sd->bl, color_table[COLOR_RED], msg_txt( sd, 791 ), false, SELF ); // You are not allowed to use the attendance system. clif_messagecolor( &sd->bl, color_table[COLOR_RED], msg_txt( sd, 791 ), false, SELF ); // You are not allowed to use the attendance system.
}else if( pc_attendance_enabled() ){ }else if( pc_attendance_enabled() ){
clif_ui_open( sd, OUT_UI_ATTENDANCE, pc_attendance_counter( sd ) ); clif_ui_open( *sd, OUT_UI_ATTENDANCE, pc_attendance_counter( sd ) );
}else{ }else{
clif_msg_color( sd, MSG_ATTENDANCE_DISABLED, color_table[COLOR_RED] ); clif_msg_color( sd, MSG_ATTENDANCE_DISABLED, color_table[COLOR_RED] );
} }
@ -23454,6 +23463,338 @@ void clif_parse_laphine_upgrade( int fd, struct map_session_data* sd ){
#endif #endif
} }
void clif_enchantgrade_add( struct map_session_data& sd, uint16 index = UINT16_MAX, std::shared_ptr<s_enchantgradelevel> gradeLevel = nullptr ){
#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200724
struct PACKET_ZC_GRADE_ENCHANT_MATERIAL_LIST* p = (struct PACKET_ZC_GRADE_ENCHANT_MATERIAL_LIST*)packet_buffer;
p->PacketType = HEADER_ZC_GRADE_ENCHANT_MATERIAL_LIST;
p->PacketLength = sizeof( struct PACKET_ZC_GRADE_ENCHANT_MATERIAL_LIST );
if( index < UINT16_MAX ){
p->index = client_index( index );
if( sd.inventory.u.items_inventory[index].refine >= gradeLevel->refine ){
p->success_chance = gradeLevel->chance / 100;
}else{
p->success_chance = 0;
}
p->blessing_info.id = client_nameid( gradeLevel->catalyst.item );
p->blessing_info.amount = gradeLevel->catalyst.amountPerStep;
p->blessing_info.max_blessing = gradeLevel->catalyst.maximumSteps;
p->blessing_info.bonus = gradeLevel->catalyst.chanceIncrease / 100;
// Not displayed by client
p->protect_itemid = 0;
p->protect_amount = 0;
int i = 0;
for( const auto& pair : gradeLevel->options ){
std::shared_ptr<s_enchantgradeoption> option = pair.second;
p->material_info[i].nameid = client_nameid( option->item );
p->material_info[i].amount = option->amount;
p->material_info[i].price = option->zeny;
p->material_info[i].downgrade = option->downgrade_amount > 0;
p->material_info[i].breakable = option->breaking_rate > 0;
p->PacketLength += sizeof( struct GRADE_ENCHANT_MATERIAL );
i++;
}
}else{
p->index = -1;
p->success_chance = 0;
p->blessing_info.id = 0;
p->blessing_info.amount = 0;
p->blessing_info.max_blessing = 0;
p->blessing_info.bonus = 0;
p->protect_itemid = 0;
p->protect_amount = 0;
}
clif_send( p, p->PacketLength, &sd.bl, SELF );
#endif
}
void clif_parse_enchantgrade_add( int fd, struct map_session_data* sd ){
#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200724
nullpo_retv( sd );
if( !sd->state.enchantgrade_open ){
return;
}
struct PACKET_CZ_GRADE_ENCHANT_SELECT_EQUIPMENT* p = (struct PACKET_CZ_GRADE_ENCHANT_SELECT_EQUIPMENT*)RFIFOP( fd, 0 );
uint16 index = server_index( p->index );
if( index >= MAX_INVENTORY || sd->inventory_data[index] == nullptr ){
return;
}
std::shared_ptr<s_enchantgrade> enchantgrade = enchantgrade_db.find( sd->inventory_data[index]->type );
// Unsupported item type - no answer, because client should have actually prevented this request
if( enchantgrade == nullptr ){
return;
}
uint16 level = 0;
if( sd->inventory_data[index]->type == IT_WEAPON ){
level = sd->inventory_data[index]->weapon_level;
}else if( sd->inventory_data[index]->type == IT_ARMOR ){
level = sd->inventory_data[index]->armor_level;
}
const auto& enchantgradelevels = enchantgrade->levels.find( level );
// Cannot upgrade this weapon or armor level
if( enchantgradelevels == enchantgrade->levels.end() ){
clif_enchantgrade_add( *sd );
return;
}
std::shared_ptr<s_enchantgradelevel> enchantgradelevel = util::map_find( enchantgradelevels->second, (e_enchantgrade)sd->inventory.u.items_inventory[index].enchantgrade );
// Cannot increase enchantgrade any further - no answer, because client should have actually prevented this request
if( enchantgradelevel == nullptr ){
return;
}
clif_enchantgrade_add( *sd, index, enchantgradelevel );
#endif
}
/// <summary>
/// Sends the result for trying to enchant an item
/// </summary>
/// <param name="sd">The player session</param>
/// <param name="index">The target item</param>
/// <param name="result">
/// 0= The grade has been successfully upgraded.
/// 1= Refinement failed.
/// 2= The refine level has decreased.
/// 3= Equipment destroyed.
/// 4= The equipment is protected.
/// </param>
void clif_enchantgrade_result( struct map_session_data& sd, uint16 index, e_enchantgrade_result result ){
#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200724
struct PACKET_ZC_GRADE_ENCHANT_ACK p = {};
p.PacketType = HEADER_ZC_GRADE_ENCHANT_ACK;
p.index = client_index( index );
p.enchantgrade = sd.inventory.u.items_inventory[index].enchantgrade;
p.result = result;
clif_send( &p, sizeof( p ), &sd.bl, SELF );
#endif
}
void clif_enchantgrade_announce( struct map_session_data& sd, struct item& item, bool success ){
#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200724
struct PACKET_ZC_GRADE_ENCHANT_BROADCAST_RESULT p = {};
p.packetType = HEADER_ZC_GRADE_ENCHANT_BROADCAST_RESULT;
safestrncpy( p.name, sd.status.name, sizeof( p.name ) );
p.itemId = client_nameid( item.nameid );
p.enchantgrade = item.enchantgrade;
p.status = success;
clif_send( &p, sizeof( p ), nullptr, ALL_CLIENT );
#endif
}
void clif_parse_enchantgrade_start( int fd, struct map_session_data* sd ){
#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200724
nullpo_retv( sd );
if( !sd->state.enchantgrade_open ){
return;
}
struct PACKET_CZ_GRADE_ENCHANT_REQUEST* p = (struct PACKET_CZ_GRADE_ENCHANT_REQUEST*)RFIFOP( fd, 0 );
uint16 index = server_index( p->index );
if( index >= MAX_INVENTORY || sd->inventory_data[index] == nullptr ){
return;
}
std::shared_ptr<s_enchantgrade> enchantgrade = enchantgrade_db.find( sd->inventory_data[index]->type );
// Unsupported item type - no answer
if( enchantgrade == nullptr ){
return;
}
uint16 level = 0;
if( sd->inventory_data[index]->type == IT_WEAPON ){
level = sd->inventory_data[index]->weapon_level;
}else if( sd->inventory_data[index]->type == IT_ARMOR ){
level = sd->inventory_data[index]->armor_level;
}
const auto& enchantgradelevels = enchantgrade->levels.find( level );
// Cannot upgrade this weapon or armor level - no answer
if( enchantgradelevels == enchantgrade->levels.end() ){
return;
}
std::shared_ptr<s_enchantgradelevel> enchantgradelevel = util::map_find( enchantgradelevels->second, (e_enchantgrade)sd->inventory.u.items_inventory[index].enchantgrade );
// Cannot increase enchantgrade any further - no answer
if( enchantgradelevel == nullptr ){
return;
}
// Not refined enough
if( sd->inventory.u.items_inventory[index].refine < enchantgradelevel->refine ){
return;
}
std::shared_ptr<s_enchantgradeoption> option = util::map_find( enchantgradelevel->options, (uint16)p->material_index );
// Unknown option id - no answer
if( option == nullptr ){
return;
}
// Not enough zeny
if( sd->status.zeny < option->zeny ){
return;
}
uint16 totalChance = enchantgradelevel->chance;
uint16 steps = min( p->blessing_amount, enchantgradelevel->catalyst.maximumSteps );
std::unordered_map<uint16, uint16> requiredItems;
if( p->blessing_flag ){
// If the catalysator item is the same as the option item build the sum of amounts
if( enchantgradelevel->catalyst.item == option->item ){
uint16 amount = enchantgradelevel->catalyst.amountPerStep * steps + option->amount;
int16 index = pc_search_inventory( sd, enchantgradelevel->catalyst.item );
if( index < 0 ){
return;
}
if( sd->inventory.u.items_inventory[index].amount < amount ){
return;
}
requiredItems[index] = amount;
}else{
uint16 amount = enchantgradelevel->catalyst.amountPerStep * steps;
// Check catalysator item
int16 index = pc_search_inventory( sd, enchantgradelevel->catalyst.item );
if( index < 0 ){
return;
}
if( sd->inventory.u.items_inventory[index].amount < amount ){
return;
}
requiredItems[index] = amount;
// Check option item
index = pc_search_inventory( sd, option->item );
if( index < 0 ){
return;
}
if( sd->inventory.u.items_inventory[index].amount < option->amount ){
return;
}
requiredItems[index] = option->amount;
}
totalChance += steps * enchantgradelevel->catalyst.chanceIncrease;
}else{
// Check option item
int16 index = pc_search_inventory( sd, option->item );
if( index < 0 ){
return;
}
if( sd->inventory.u.items_inventory[index].amount < option->amount ){
return;
}
requiredItems[index] = option->amount;
}
// All items should be there, start deleting
for( const auto& pair : requiredItems ){
if( pc_delitem( sd, pair.first, pair.second, 0, 0, LOG_TYPE_ENCHANTGRADE ) != 0 ){
return;
}
}
if( pc_payzeny( sd, option->zeny, LOG_TYPE_ENCHANTGRADE, nullptr ) > 0 ){
return;
}
if( rnd()%10000 < totalChance ){
// Log removal of item
log_pick_pc( sd, LOG_TYPE_ENCHANTGRADE, -1, &sd->inventory.u.items_inventory[index] );
// Increase enchantgrade
sd->inventory.u.items_inventory[index].enchantgrade = min( sd->inventory.u.items_inventory[index].enchantgrade + 1, MAX_ENCHANTGRADE );
// On successful enchantgrade increase the refine is reset
sd->inventory.u.items_inventory[index].refine = 0;
// Log retrieving the item again -> with the new refine and enchantgrade
log_pick_pc( sd, LOG_TYPE_ENCHANTGRADE, 1, &sd->inventory.u.items_inventory[index] );
// Show success
clif_enchantgrade_result( *sd, index, ENCHANTGRADE_UPGRADE_SUCCESS );
// Check if it has to be announced
if( enchantgradelevel->announce ){
clif_enchantgrade_announce( *sd, sd->inventory.u.items_inventory[index], true );
}
}else{
// Check if it has to be announced (has to be done before deleting the item from inventory)
if( enchantgradelevel->announce ){
clif_enchantgrade_announce( *sd, sd->inventory.u.items_inventory[index], false );
}
// Delete the item if it is breakable
if( option->breaking_rate > 0 && ( rnd() % 10000 ) < option->breaking_rate ){
// Delete the item
pc_delitem( sd, index, 1, 0, 0, LOG_TYPE_ENCHANTGRADE );
// Show failure
clif_enchantgrade_result( *sd, index, ENCHANTGRADE_UPGRADE_BREAK );
// Downgrade the item if necessary
}else if( option->downgrade_amount > 0 ){
// Log removal of item
log_pick_pc( sd, LOG_TYPE_ENCHANTGRADE, -1, &sd->inventory.u.items_inventory[index] );
// Decrease refine level
sd->inventory.u.items_inventory[index].refine = cap_value( sd->inventory.u.items_inventory[index].refine - option->downgrade_amount, 0, MAX_REFINE );
// Log retrieving the item again -> with the new refine
log_pick_pc( sd, LOG_TYPE_ENCHANTGRADE, 1, &sd->inventory.u.items_inventory[index] );
// Show downgrade
clif_enchantgrade_result( *sd, index, ENCHANTGRADE_UPGRADE_DOWNGRADE );
// Only show failure, but dont do anything
}else{
clif_enchantgrade_result( *sd, index, ENCHANTGRADE_UPGRADE_FAILED );
}
}
#endif
}
void clif_parse_enchantgrade_close( int fd, struct map_session_data* sd ){
#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200724
nullpo_retv( sd );
sd->state.enchantgrade_open = false;
#endif
}
/*========================================== /*==========================================
* Main client packet processing function * Main client packet processing function
*------------------------------------------*/ *------------------------------------------*/

View File

@ -1162,10 +1162,11 @@ enum out_ui_type : int8 {
OUT_UI_BANK = 0, OUT_UI_BANK = 0,
OUT_UI_STYLIST, OUT_UI_STYLIST,
OUT_UI_QUEST = 6, OUT_UI_QUEST = 6,
OUT_UI_ATTENDANCE = 7 OUT_UI_ATTENDANCE,
OUT_UI_ENCHANTGRADE,
}; };
void clif_ui_open( struct map_session_data *sd, enum out_ui_type ui_type, int32 data ); void clif_ui_open( struct map_session_data& sd, enum out_ui_type ui_type, int32 data );
void clif_attendence_response( struct map_session_data *sd, int32 data ); void clif_attendence_response( struct map_session_data *sd, int32 data );
void clif_weight_limit( struct map_session_data* sd ); void clif_weight_limit( struct map_session_data* sd );

View File

@ -2375,7 +2375,6 @@
// 2018-03-07bRagexeRE // 2018-03-07bRagexeRE
#if PACKETVER >= 20180307 #if PACKETVER >= 20180307
parseable_packet(0x0A68,3,clif_parse_open_ui,2); parseable_packet(0x0A68,3,clif_parse_open_ui,2);
packet(0x0AE2,7);
parseable_packet(0x0AEF,2,clif_parse_attendance_request,0); parseable_packet(0x0AEF,2,clif_parse_attendance_request,0);
packet(0x0AF0,10); packet(0x0AF0,10);
#endif #endif
@ -2447,6 +2446,9 @@
#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200724 #if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200724
parseable_packet( HEADER_CZ_UNCONFIRMED_TSTATUS_UP, sizeof( PACKET_CZ_UNCONFIRMED_TSTATUS_UP ), clif_parse_traitstatus_up, 0 ); parseable_packet( HEADER_CZ_UNCONFIRMED_TSTATUS_UP, sizeof( PACKET_CZ_UNCONFIRMED_TSTATUS_UP ), clif_parse_traitstatus_up, 0 );
parseable_packet( HEADER_CZ_GRADE_ENCHANT_SELECT_EQUIPMENT, sizeof( struct PACKET_CZ_GRADE_ENCHANT_SELECT_EQUIPMENT ), clif_parse_enchantgrade_add, 0 );
parseable_packet( HEADER_CZ_GRADE_ENCHANT_REQUEST, sizeof( struct PACKET_CZ_GRADE_ENCHANT_REQUEST ), clif_parse_enchantgrade_start, 0 );
parseable_packet( HEADER_CZ_GRADE_ENCHANT_CLOSE_UI, sizeof( struct PACKET_CZ_GRADE_ENCHANT_CLOSE_UI ), clif_parse_enchantgrade_close, 0 );
#endif #endif
#if PACKETVER_RE_NUM >= 20211103 || PACKETVER_ZERO_NUM >= 20210818 #if PACKETVER_RE_NUM >= 20211103 || PACKETVER_ZERO_NUM >= 20210818

View File

@ -87,6 +87,9 @@ static char log_picktype2char(e_log_pick_type type)
case LOG_TYPE_PRIVATE_AIRSHIP: return 'H'; // Private Airs(H)ip case LOG_TYPE_PRIVATE_AIRSHIP: return 'H'; // Private Airs(H)ip
case LOG_TYPE_BARTER: return 'J'; // Barter Shop case LOG_TYPE_BARTER: return 'J'; // Barter Shop
case LOG_TYPE_LAPHINE: return 'W'; // Laphine UI case LOG_TYPE_LAPHINE: return 'W'; // Laphine UI
case LOG_TYPE_ENCHANTGRADE: return '0'; // Enchantgrade UI
case LOG_TYPE_REFORM: return '1'; // Reform UI
case LOG_TYPE_ENCHANT: return '2'; // Echant UI
} }
// should not get here, fallback // should not get here, fallback

View File

@ -26,37 +26,40 @@ enum e_log_chat_type : uint8
enum e_log_pick_type : uint32 enum e_log_pick_type : uint32
{ {
LOG_TYPE_NONE = 0x0000000, LOG_TYPE_NONE = 0x00000000,
LOG_TYPE_TRADE = 0x0000001, LOG_TYPE_TRADE = 0x00000001,
LOG_TYPE_VENDING = 0x0000002, LOG_TYPE_VENDING = 0x00000002,
LOG_TYPE_PICKDROP_PLAYER = 0x0000004, LOG_TYPE_PICKDROP_PLAYER = 0x00000004,
LOG_TYPE_PICKDROP_MONSTER = 0x0000008, LOG_TYPE_PICKDROP_MONSTER = 0x00000008,
LOG_TYPE_NPC = 0x0000010, LOG_TYPE_NPC = 0x00000010,
LOG_TYPE_SCRIPT = 0x0000020, LOG_TYPE_SCRIPT = 0x00000020,
LOG_TYPE_STEAL = 0x0000040, LOG_TYPE_STEAL = 0x00000040,
LOG_TYPE_CONSUME = 0x0000080, LOG_TYPE_CONSUME = 0x00000080,
LOG_TYPE_PRODUCE = 0x0000100, LOG_TYPE_PRODUCE = 0x00000100,
LOG_TYPE_MVP = 0x0000200, LOG_TYPE_MVP = 0x00000200,
LOG_TYPE_COMMAND = 0x0000400, LOG_TYPE_COMMAND = 0x00000400,
LOG_TYPE_STORAGE = 0x0000800, LOG_TYPE_STORAGE = 0x00000800,
LOG_TYPE_GSTORAGE = 0x0001000, LOG_TYPE_GSTORAGE = 0x00001000,
LOG_TYPE_MAIL = 0x0002000, LOG_TYPE_MAIL = 0x00002000,
LOG_TYPE_AUCTION = 0x0004000, LOG_TYPE_AUCTION = 0x00004000,
LOG_TYPE_BUYING_STORE = 0x0008000, LOG_TYPE_BUYING_STORE = 0x00008000,
LOG_TYPE_OTHER = 0x0010000, LOG_TYPE_OTHER = 0x00010000,
LOG_TYPE_CASH = 0x0020000, LOG_TYPE_CASH = 0x00020000,
LOG_TYPE_BANK = 0x0040000, LOG_TYPE_BANK = 0x00040000,
LOG_TYPE_BOUND_REMOVAL = 0x0080000, LOG_TYPE_BOUND_REMOVAL = 0x00080000,
LOG_TYPE_ROULETTE = 0x0100000, LOG_TYPE_ROULETTE = 0x00100000,
LOG_TYPE_MERGE_ITEM = 0x0200000, LOG_TYPE_MERGE_ITEM = 0x00200000,
LOG_TYPE_QUEST = 0x0400000, LOG_TYPE_QUEST = 0x00400000,
LOG_TYPE_PRIVATE_AIRSHIP = 0x0800000, LOG_TYPE_PRIVATE_AIRSHIP = 0x00800000,
LOG_TYPE_BARTER = 0x1000000, LOG_TYPE_BARTER = 0x01000000,
LOG_TYPE_LAPHINE = 0x2000000, LOG_TYPE_LAPHINE = 0x02000000,
LOG_TYPE_ENCHANTGRADE = 0x04000000,
LOG_TYPE_REFORM = 0x08000000,
LOG_TYPE_ENCHANT = 0x10000000,
// combinations // combinations
LOG_TYPE_LOOT = LOG_TYPE_PICKDROP_MONSTER|LOG_TYPE_CONSUME, LOG_TYPE_LOOT = LOG_TYPE_PICKDROP_MONSTER|LOG_TYPE_CONSUME,
// all // all
LOG_TYPE_ALL = 0xFFFFFFF, LOG_TYPE_ALL = 0xFFFFFFFF,
}; };
enum e_log_cash_type : uint8 enum e_log_cash_type : uint8

View File

@ -322,6 +322,7 @@
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\const.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\const.yml')" /> <Copy SourceFiles="$(SolutionDir)db\import-tmpl\const.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\const.yml')" />
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\create_arrow_db.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\create_arrow_db.yml')" /> <Copy SourceFiles="$(SolutionDir)db\import-tmpl\create_arrow_db.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\create_arrow_db.yml')" />
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\elemental_db.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\elemental_db.yml')" /> <Copy SourceFiles="$(SolutionDir)db\import-tmpl\elemental_db.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\elemental_db.yml')" />
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\enchantgrade.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\enchantgrade.yml')" />
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\exp_homun.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\exp_homun.yml')" /> <Copy SourceFiles="$(SolutionDir)db\import-tmpl\exp_homun.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\exp_homun.yml')" />
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\exp_guild.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\exp_guild.yml')" /> <Copy SourceFiles="$(SolutionDir)db\import-tmpl\exp_guild.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\exp_guild.yml')" />
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\guild_skill_tree.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\guild_skill_tree.yml')" /> <Copy SourceFiles="$(SolutionDir)db\import-tmpl\guild_skill_tree.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\guild_skill_tree.yml')" />

View File

@ -5340,7 +5340,7 @@ DEFINE_PACKET_HEADER(CZ_GRADE_ENCHANT_CLOSE_UI, 0x0b5c);
struct PACKET_ZC_GRADE_ENCHANT_ACK { struct PACKET_ZC_GRADE_ENCHANT_ACK {
int16 PacketType; int16 PacketType;
int16 index; int16 index;
int16 grade; int16 enchantgrade;
int result; int result;
} __attribute__((packed)); } __attribute__((packed));
DEFINE_PACKET_HEADER(ZC_GRADE_ENCHANT_ACK, 0x0b5d); DEFINE_PACKET_HEADER(ZC_GRADE_ENCHANT_ACK, 0x0b5d);
@ -5351,7 +5351,7 @@ struct PACKET_ZC_GRADE_ENCHANT_BROADCAST_RESULT {
int16 packetType; int16 packetType;
char name[NAME_LENGTH]; char name[NAME_LENGTH];
uint32 itemId; uint32 itemId;
int16 grade; int16 enchantgrade;
int8 status; int8 status;
} __attribute__((packed)); } __attribute__((packed));
DEFINE_PACKET_HEADER(ZC_GRADE_ENCHANT_BROADCAST_RESULT, 0x0b5e); DEFINE_PACKET_HEADER(ZC_GRADE_ENCHANT_BROADCAST_RESULT, 0x0b5e);

View File

@ -13995,7 +13995,7 @@ void pc_scdata_received(struct map_session_data *sd) {
clif_weight_limit( sd ); clif_weight_limit( sd );
if( pc_has_permission( sd, PC_PERM_ATTENDANCE ) && pc_attendance_enabled() && !pc_attendance_rewarded_today( sd ) ){ if( pc_has_permission( sd, PC_PERM_ATTENDANCE ) && pc_attendance_enabled() && !pc_attendance_rewarded_today( sd ) ){
clif_ui_open( sd, OUT_UI_ATTENDANCE, pc_attendance_counter( sd ) ); clif_ui_open( *sd, OUT_UI_ATTENDANCE, pc_attendance_counter( sd ) );
} }
sd->state.pc_loaded = true; sd->state.pc_loaded = true;

View File

@ -387,6 +387,7 @@ struct map_session_data {
bool stylist_open; bool stylist_open;
bool barter_open; bool barter_open;
bool barter_extended_open; bool barter_extended_open;
bool enchantgrade_open; // Whether the enchantgrade window is open or not
unsigned int block_action : 10; unsigned int block_action : 10;
bool refineui_open; bool refineui_open;
t_itemid inventory_expansion_confirmation; t_itemid inventory_expansion_confirmation;
@ -1067,7 +1068,7 @@ static bool pc_cant_act2( struct map_session_data* sd ){
|| sd->state.stylist_open || sd->state.inventory_expansion_confirmation || sd->npc_shopid || sd->state.stylist_open || sd->state.inventory_expansion_confirmation || sd->npc_shopid
|| sd->state.barter_open || sd->state.barter_extended_open || sd->state.barter_open || sd->state.barter_extended_open
|| sd->state.laphine_synthesis || sd->state.laphine_upgrade || sd->state.laphine_synthesis || sd->state.laphine_upgrade
|| sd->state.roulette_open; || sd->state.roulette_open || sd->state.enchantgrade_open;
} }
// equals pc_cant_act2 and additionally checks for chat rooms and npcs // equals pc_cant_act2 and additionally checks for chat rooms and npcs
static bool pc_cant_act( struct map_session_data* sd ){ static bool pc_cant_act( struct map_session_data* sd ){

View File

@ -25739,7 +25739,7 @@ BUILDIN_FUNC( openstylist ){
return SCRIPT_CMD_FAILURE; return SCRIPT_CMD_FAILURE;
} }
clif_ui_open( sd, OUT_UI_STYLIST, 0 ); clif_ui_open( *sd, OUT_UI_STYLIST, 0 );
return SCRIPT_CMD_SUCCESS; return SCRIPT_CMD_SUCCESS;
#else #else
@ -25860,6 +25860,10 @@ BUILDIN_FUNC(randomoptgroup)
} }
BUILDIN_FUNC( open_quest_ui ){ BUILDIN_FUNC( open_quest_ui ){
#if PACKETVER < 20151202
ShowError( "buildin_open_quest_ui: This command requires PACKETVER 20151202 or newer.\n" );
return SCRIPT_CMD_FAILURE;
#else
struct map_session_data* sd; struct map_session_data* sd;
if (!script_charid2sd(3, sd)) if (!script_charid2sd(3, sd))
@ -25874,14 +25878,15 @@ BUILDIN_FUNC( open_quest_ui ){
ShowWarning("buildin_open_quest_ui: Character %d doesn't have quest %d.\n", sd->status.char_id, quest_id); ShowWarning("buildin_open_quest_ui: Character %d doesn't have quest %d.\n", sd->status.char_id, quest_id);
} }
clif_ui_open( sd, OUT_UI_QUEST, quest_id ); clif_ui_open( *sd, OUT_UI_QUEST, quest_id );
return SCRIPT_CMD_SUCCESS; return SCRIPT_CMD_SUCCESS;
#endif
} }
BUILDIN_FUNC(openbank){ BUILDIN_FUNC(openbank){
#if PACKETVER < 20150128 #if PACKETVER < 20151202
ShowError( "buildin_openbank: This command requires PACKETVER 20150128 or newer.\n" ); ShowError( "buildin_openbank: This command requires PACKETVER 20151202 or newer.\n" );
return SCRIPT_CMD_FAILURE; return SCRIPT_CMD_FAILURE;
#else #else
struct map_session_data* sd = nullptr; struct map_session_data* sd = nullptr;
@ -25895,7 +25900,7 @@ BUILDIN_FUNC(openbank){
return SCRIPT_CMD_FAILURE; return SCRIPT_CMD_FAILURE;
} }
clif_ui_open( sd, OUT_UI_BANK, 0 ); clif_ui_open( *sd, OUT_UI_BANK, 0 );
return SCRIPT_CMD_SUCCESS; return SCRIPT_CMD_SUCCESS;
#endif #endif
} }
@ -25994,6 +25999,23 @@ BUILDIN_FUNC(getjobexp_ratio){
return SCRIPT_CMD_SUCCESS; return SCRIPT_CMD_SUCCESS;
} }
BUILDIN_FUNC( enchantgradeui ){
#if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200724
struct map_session_data* sd;
if( !script_charid2sd( 2, sd ) ){
return SCRIPT_CMD_FAILURE;
}
clif_ui_open( *sd, OUT_UI_ENCHANTGRADE, 0 );
return SCRIPT_CMD_SUCCESS;
#else
ShowError( "buildin_enchantgradeui: This command requires PACKETVER 2020-07-24 or newer.\n" );
return SCRIPT_CMD_FAILURE;
#endif
}
#include "../custom/script.inc" #include "../custom/script.inc"
// declarations that were supposed to be exported from npc_chat.cpp // declarations that were supposed to be exported from npc_chat.cpp
@ -26713,6 +26735,8 @@ struct script_function buildin_func[] = {
BUILDIN_DEF(openbank,"?"), BUILDIN_DEF(openbank,"?"),
BUILDIN_DEF(getbaseexp_ratio, "i??"), BUILDIN_DEF(getbaseexp_ratio, "i??"),
BUILDIN_DEF(getjobexp_ratio, "i??"), BUILDIN_DEF(getjobexp_ratio, "i??"),
BUILDIN_DEF(enchantgradeui, "?" ),
#include "../custom/script_def.inc" #include "../custom/script_def.inc"
{NULL,NULL,NULL}, {NULL,NULL,NULL},

View File

@ -8996,6 +8996,14 @@
export_constant(SCF_REMOVEONUNEQUIPWEAPON); export_constant(SCF_REMOVEONUNEQUIPWEAPON);
export_constant(SCF_REMOVEONUNEQUIPARMOR); export_constant(SCF_REMOVEONUNEQUIPARMOR);
/* enchantgrades */
export_constant(ENCHANTGRADE_NONE);
export_constant(ENCHANTGRADE_D);
export_constant(ENCHANTGRADE_C);
export_constant(ENCHANTGRADE_B);
export_constant(ENCHANTGRADE_A);
export_constant(MAX_ENCHANTGRADE);
#undef export_constant #undef export_constant
#undef export_constant2 #undef export_constant2
#undef export_parameter #undef export_parameter

View File

@ -544,6 +544,399 @@ uint64 SizeFixDatabase::parseBodyNode(const ryml::NodeRef& node) {
SizeFixDatabase size_fix_db; SizeFixDatabase size_fix_db;
const std::string EnchantgradeDatabase::getDefaultLocation(){
return std::string(db_path) + "/enchantgrade.yml";
}
uint64 EnchantgradeDatabase::parseBodyNode( const ryml::NodeRef& node ){
if( !this->nodesExist( node, { "Type", "Levels" } ) ){
return 0;
}
std::string itemtype_constant;
if( !this->asString( node, "Type", itemtype_constant ) ){
return 0;
}
int64 constant_value;
if( !script_get_constant( ( "IT_" + itemtype_constant ).c_str(), &constant_value ) ){
this->invalidWarning( node["Type"], "Unknown item type \"%s\".\n", itemtype_constant.c_str() );
return 0;
}
uint16 itemtype = static_cast<uint16>( constant_value );
uint16 itemtype_maxlevel;
if( itemtype == IT_WEAPON ){
itemtype_maxlevel = MAX_WEAPON_LEVEL;
}else if( itemtype == IT_ARMOR ){
itemtype_maxlevel = MAX_ARMOR_LEVEL;
}else{
this->invalidWarning( node["Type"], "Item type \"%s\" is not supported.\n", itemtype_constant.c_str() );
return 0;
}
std::shared_ptr<s_enchantgrade> enchantgrade = this->find( itemtype );
bool exists = enchantgrade != nullptr;
if( !exists ){
enchantgrade = std::make_shared<s_enchantgrade>();
enchantgrade->itemtype = itemtype;
}
for( const ryml::NodeRef& levelNode : node["Levels"] ){
if( !this->nodesExist( levelNode, { "Level", "Grades" } ) ){
return 0;
}
uint16 level;
if( !this->asUInt16( levelNode, "Level", level ) ){
return 0;
}
if( level == 0 || level > itemtype_maxlevel ){
this->invalidWarning( levelNode["Level"], "Level %hu is invalid for item type %s[1~%hu].\n", level, itemtype_constant.c_str(), itemtype_maxlevel );
return 0;
}
std::map<e_enchantgrade, std::shared_ptr<s_enchantgradelevel>>& grades = enchantgrade->levels[level];
for( const ryml::NodeRef& gradeNode : levelNode["Grades"] ){
std::string gradeConstant;
if( !this->asString( gradeNode, "Grade", gradeConstant ) ){
return 0;
}
if( !script_get_constant( ( "ENCHANTGRADE_" + gradeConstant ).c_str(), &constant_value ) ){
this->invalidWarning( node["Grade"], "Unknown grade \"%s\".\n", gradeConstant.c_str() );
return 0;
}
if( constant_value >= MAX_ENCHANTGRADE ){
this->invalidWarning( gradeNode["Grade"], "Grade %" PRId64 " is too high. Maximum: %hu.\n", constant_value, MAX_ENCHANTGRADE - 1 );
return 0;
}
e_enchantgrade gradeLevel = (e_enchantgrade)constant_value;
std::shared_ptr<s_enchantgradelevel> grade = util::map_find( grades, gradeLevel );
bool gradeExists = grade != nullptr;
if( !gradeExists ){
grade = std::make_shared<s_enchantgradelevel>();
grade->grade = gradeLevel;
if( !this->nodesExist( gradeNode, { "Refine", "Chance", "Options" } ) ){
return 0;
}
}
if( this->nodeExists( gradeNode, "Refine" ) ){
uint16 refine;
if( !this->asUInt16( gradeNode, "Refine", refine ) ){
return 0;
}
if( refine > MAX_REFINE ){
this->invalidWarning( gradeNode["Refine"], "Refine %hu is too high, capping to %hu...\n", refine, MAX_REFINE );
refine = MAX_REFINE;
}
grade->refine = refine;
}
if( this->nodeExists( gradeNode, "Chance" ) ){
uint16 chance;
if( !this->asUInt16Rate( gradeNode, "Chance", chance ) ){
return 0;
}
grade->chance = chance;
}
if( this->nodeExists( gradeNode, "Bonus" ) ){
uint16 bonus;
if( !this->asUInt16( gradeNode, "Bonus", bonus ) ){
return 0;
}
grade->bonus = bonus;
}else{
if( !gradeExists ){
grade->bonus = 0;
}
}
if( this->nodeExists( gradeNode, "Announce" ) ){
bool announce;
if( !this->asBool( gradeNode, "Announce", announce ) ){
return 0;
}
grade->announce = announce;
}else{
if( !gradeExists ){
grade->announce = true;
}
}
if( this->nodeExists( gradeNode, "Catalyst") ){
const ryml::NodeRef& catalystNode = gradeNode["Catalyst"];
if( this->nodeExists( catalystNode, "Item" ) ){
std::string itemName;
if( !this->asString( catalystNode, "Item", itemName ) ){
return 0;
}
std::shared_ptr<item_data> id = item_db.search_aegisname( itemName.c_str() );
if( id == nullptr ){
this->invalidWarning( catalystNode["Item"], "Unknown item \"%s\".\n", itemName.c_str() );
return 0;
}
grade->catalyst.item = id->nameid;
}else{
if( !gradeExists ){
grade->catalyst.item = 0;
}
}
if( this->nodeExists( catalystNode, "AmountPerStep" ) ){
uint16 amountPerStep;
if( !this->asUInt16( catalystNode, "AmountPerStep", amountPerStep ) ){
return 0;
}
grade->catalyst.amountPerStep = amountPerStep;
}else{
if( !gradeExists ){
grade->catalyst.amountPerStep = 0;
}
}
if( this->nodeExists( catalystNode, "MaximumSteps" ) ){
uint16 maximumSteps;
if( !this->asUInt16( catalystNode, "MaximumSteps", maximumSteps ) ){
return 0;
}
grade->catalyst.maximumSteps = maximumSteps;
}else{
if( !gradeExists ){
grade->catalyst.maximumSteps = 0;
}
}
if( this->nodeExists( catalystNode, "ChanceIncrease" ) ){
uint16 chanceIncrease;
if( !this->asUInt16Rate( catalystNode, "ChanceIncrease", chanceIncrease ) ){
return 0;
}
grade->catalyst.chanceIncrease = chanceIncrease;
}else{
if( !gradeExists ){
grade->catalyst.chanceIncrease = 0;
}
}
}else{
if( !gradeExists ){
grade->catalyst.item = 0;
grade->catalyst.amountPerStep = 0;
grade->catalyst.maximumSteps = 0;
grade->catalyst.chanceIncrease = 0;
}
}
if( this->nodeExists( gradeNode, "Options" ) ){
for( const ryml::NodeRef& optionNode : gradeNode["Options"] ){
uint16 optionIndex;
if( !this->asUInt16( optionNode, "Option", optionIndex ) ){
return 0;
}
std::shared_ptr<s_enchantgradeoption> option = util::map_find( grade->options, optionIndex );
bool optionExists = option != nullptr;
if( !optionExists ){
option = std::make_shared<s_enchantgradeoption>();
option->id = optionIndex;
}
if( this->nodeExists( optionNode, "Amount" ) ){
uint16 amount;
if( !this->asUInt16( optionNode, "Amount", amount ) ){
return 0;
}
if( amount > MAX_AMOUNT ){
this->invalidWarning( optionNode["Amount"], "Amount %hu is too high, capping to %hu...\n", amount, MAX_AMOUNT );
amount = MAX_AMOUNT;
}
if( amount == 0 ){
if( grade->options.erase( optionIndex ) > 0 ){
continue;
}else{
this->invalidWarning( optionNode["Amount"], "Trying to remove invalid option %hu...\n", optionIndex );
return 0;
}
}
option->amount = amount;
}else{
if( !optionExists ){
option->amount = 1;
}
}
if( this->nodeExists( optionNode, "Item" ) ){
std::string itemName;
if( !this->asString( optionNode, "Item", itemName ) ){
return 0;
}
std::shared_ptr<item_data> id = item_db.search_aegisname( itemName.c_str() );
if( id == nullptr ){
this->invalidWarning( optionNode["Item"], "Unknown item \"%s\".\n", itemName.c_str() );
return 0;
}
option->item = id->nameid;
}else{
if( !optionExists ){
option->item = 0;
}
}
if( this->nodeExists( optionNode, "Zeny" ) ){
uint32 zeny;
if( !this->asUInt32( optionNode, "Zeny", zeny ) ){
return 0;
}
option->zeny = zeny;
}else{
if( !optionExists ){
option->zeny = 0;
}
}
if( this->nodeExists( optionNode, "BreakingRate" ) ){
uint16 breaking_rate;
if( !this->asUInt16Rate( optionNode, "BreakingRate", breaking_rate ) ){
return 0;
}
option->breaking_rate = breaking_rate;
}else{
if( !optionExists ){
option->breaking_rate = 0;
}
}
if( this->nodeExists( optionNode, "DowngradeAmount" ) ){
uint16 downgrade_amount;
if( !this->asUInt16( optionNode, "DowngradeAmount", downgrade_amount ) ){
return 0;
}
if( downgrade_amount > MAX_REFINE ){
this->invalidWarning( optionNode["DowngradeAmount"], "Downgrade amount %hu is invalid, skipping.\n", downgrade_amount );
return 0;
}
option->downgrade_amount = downgrade_amount;
}else{
if( !optionExists ){
option->downgrade_amount = 0;
}
}
if( !optionExists ){
grade->options[optionIndex] = option;
}
}
}
if( !gradeExists ){
grades[gradeLevel] = grade;
}
}
}
if( !exists ){
this->put( itemtype, enchantgrade );
}
return 1;
}
std::shared_ptr<s_enchantgradelevel> EnchantgradeDatabase::findCurrentLevelInfo( const struct item_data& data, struct item& item ){
std::shared_ptr<s_enchantgrade> enchantgrade = enchantgrade_db.find( data.type );
// Unsupported item type - no answer
if( enchantgrade == nullptr ){
return nullptr;
}
uint16 level = 0;
if( data.type == IT_WEAPON ){
level = data.weapon_level;
}else if( data.type == IT_ARMOR ){
level = data.armor_level;
}
const auto& enchantgradelevels = enchantgrade->levels.find( level );
// Cannot upgrade this weapon or armor level - no answer
if( enchantgradelevels == enchantgrade->levels.end() ){
return nullptr;
}
return util::map_find( enchantgradelevels->second, (e_enchantgrade)( item.enchantgrade - 1 ) );
}
void EnchantgradeDatabase::loadingFinished(){
for( const auto& it_itemTypes : *this ){
for( const auto& it_itemLevels : it_itemTypes.second->levels ){
for( const auto& it_enchantgrades : it_itemLevels.second ){
std::shared_ptr<s_enchantgradelevel> enchantgradelevel = it_enchantgrades.second;
if( enchantgradelevel->catalyst.amountPerStep == 0 ){
enchantgradelevel->catalyst.item = 0;
enchantgradelevel->catalyst.chanceIncrease = 0;
enchantgradelevel->catalyst.maximumSteps = 0;
}
}
}
}
}
EnchantgradeDatabase enchantgrade_db;
/** /**
* Get icon ID of SC * Get icon ID of SC
* @param type: SC type * @param type: SC type
@ -3256,6 +3649,13 @@ int status_calc_pc_sub(struct map_session_data* sd, uint8 opt)
sd->inventory.u.items_inventory[index].refine = MAX_REFINE; sd->inventory.u.items_inventory[index].refine = MAX_REFINE;
std::shared_ptr<s_refine_level_info> info = refine_db.findCurrentLevelInfo( *sd->inventory_data[index], sd->inventory.u.items_inventory[index] ); std::shared_ptr<s_refine_level_info> info = refine_db.findCurrentLevelInfo( *sd->inventory_data[index], sd->inventory.u.items_inventory[index] );
#ifdef RENEWAL
std::shared_ptr<s_enchantgradelevel> enchantgrade_info = nullptr;
if( sd->inventory.u.items_inventory[index].enchantgrade > 0 ){
enchantgrade_info = enchantgrade_db.findCurrentLevelInfo( *sd->inventory_data[index], sd->inventory.u.items_inventory[index] );
}
#endif
if (sd->inventory_data[index]->type == IT_WEAPON) { if (sd->inventory_data[index]->type == IT_WEAPON) {
int wlv = sd->inventory_data[index]->weapon_level; int wlv = sd->inventory_data[index]->weapon_level;
@ -3277,7 +3677,9 @@ int status_calc_pc_sub(struct map_session_data* sd, uint8 opt)
wa->atk2 += info->bonus / 100; wa->atk2 += info->bonus / 100;
#ifdef RENEWAL #ifdef RENEWAL
// TODO: additional grade bonus if( enchantgrade_info != nullptr ){
wa->atk2 += ( ( ( info->bonus / 100 ) * enchantgrade_info->bonus ) / 100 );
}
if( wlv == 5 ){ if( wlv == 5 ){
base_status->patk += sd->inventory.u.items_inventory[index].refine * 2; base_status->patk += sd->inventory.u.items_inventory[index].refine * 2;
@ -3294,7 +3696,9 @@ int status_calc_pc_sub(struct map_session_data* sd, uint8 opt)
if( info != nullptr && sd->weapontype1 != W_BOW ){ if( info != nullptr && sd->weapontype1 != W_BOW ){
wa->matk += info->bonus / 100; wa->matk += info->bonus / 100;
// TODO: additional grade bonus if( enchantgrade_info != nullptr ){
wa->matk += ( ( ( info->bonus / 100 ) * enchantgrade_info->bonus ) / 100 );
}
} }
#endif #endif
// Overrefine bonus. // Overrefine bonus.
@ -15184,10 +15588,12 @@ void status_readdb( bool reload ){
size_fix_db.reload(); size_fix_db.reload();
refine_db.reload(); refine_db.reload();
status_db.reload(); status_db.reload();
enchantgrade_db.reload();
}else{ }else{
size_fix_db.load(); size_fix_db.load();
refine_db.load(); refine_db.load();
status_db.load(); status_db.load();
enchantgrade_db.load();
} }
elemental_attribute_db.load(); elemental_attribute_db.load();
} }
@ -15211,6 +15617,7 @@ void do_init_status(void) {
/** Destroy status data */ /** Destroy status data */
void do_final_status(void) { void do_final_status(void) {
ers_destroy(sc_data_ers); ers_destroy(sc_data_ers);
enchantgrade_db.clear();
size_fix_db.clear(); size_fix_db.clear();
refine_db.clear(); refine_db.clear();
status_db.clear(); status_db.clear();

View File

@ -144,6 +144,59 @@ public:
extern AttributeDatabase elemental_attribute_db; extern AttributeDatabase elemental_attribute_db;
enum e_enchantgrade_result{
ENCHANTGRADE_UPGRADE_SUCCESS,
ENCHANTGRADE_UPGRADE_FAILED,
ENCHANTGRADE_UPGRADE_DOWNGRADE,
ENCHANTGRADE_UPGRADE_BREAK,
ENCHANTGRADE_UPGRADE_PROTECTED,
};
struct s_enchantgradeoption{
uint16 id;
t_itemid item;
uint16 amount;
uint32 zeny;
uint16 breaking_rate;
uint16 downgrade_amount;
};
struct s_enchantgradelevel{
e_enchantgrade grade;
uint16 refine;
uint16 chance;
uint16 bonus;
bool announce;
struct{
t_itemid item;
uint16 amountPerStep;
uint16 maximumSteps;
uint16 chanceIncrease;
}catalyst;
std::map<uint16,std::shared_ptr<s_enchantgradeoption>> options;
};
struct s_enchantgrade{
uint16 itemtype;
std::map<uint16,std::map<e_enchantgrade,std::shared_ptr<s_enchantgradelevel>>> levels;
};
class EnchantgradeDatabase : public TypesafeYamlDatabase<uint16, s_enchantgrade>{
public:
EnchantgradeDatabase() : TypesafeYamlDatabase( "ENCHANTGRADE_DB", 1 ){
}
const std::string getDefaultLocation() override;
uint64 parseBodyNode( const ryml::NodeRef& node ) override;
void loadingFinished() override;
// Additional
std::shared_ptr<s_enchantgradelevel> findCurrentLevelInfo( const struct item_data& data, struct item& item );
};
extern EnchantgradeDatabase enchantgrade_db;
/// Status changes listing. These code are for use by the server. /// Status changes listing. These code are for use by the server.
enum sc_type : int16 { enum sc_type : int16 {
SC_NONE = -1, SC_NONE = -1,