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:
- famepoint
- famepoints
- Command: enchantgradeui
Help: |
Opens the enchantgrade UI.
Footer:
Imports:

View File

@ -8,37 +8,40 @@
//--------------------------------------------------------------
// Enable Logs? (Note 3)
// 0x0000000 - Don't log at all
// 0x0000001 - (T) Log trades
// 0x0000002 - (V) Log vending transactions
// 0x0000004 - (P) Log items drop/picked by players
// 0x0000008 - (L) Log items drop/looted by monsters
// 0x0000010 - (S) Log NPC transactions (buy/sell)
// 0x0000020 - (N) Log Script transactions (items deleted/acquired through quests)
// 0x0000040 - (D) Log items stolen from mobs (Steal/Gank)
// 0x0000080 - (C) Log player-used items (consumables/pet&hom&merc food/items used for skills&attacks)
// 0x0000100 - (O) Log produced/ingredient items
// 0x0000200 - (U) Log MVP prize items
// 0x0000400 - (A) Log player created/deleted items (through @/# commands)
// 0x0000800 - (R) Log items placed/retrieved from storage.
// 0x0001000 - (G) Log items placed/retrieved from guild storage.
// 0x0002000 - (E) Log mail system transactions.
// 0x0004000 - (I) Log auction system transactions.
// 0x0008000 - (B) Log buying store transactions
// 0x0010000 - (X) Log all other transactions (rentals expiring/inserting cards/items removed by item_check/
// 0x00000000 - Don't log at all
// 0x00000001 - (T) Log trades
// 0x00000002 - (V) Log vending transactions
// 0x00000004 - (P) Log items drop/picked by players
// 0x00000008 - (L) Log items drop/looted by monsters
// 0x00000010 - (S) Log NPC transactions (buy/sell)
// 0x00000020 - (N) Log Script transactions (items deleted/acquired through quests)
// 0x00000040 - (D) Log items stolen from mobs (Steal/Gank)
// 0x00000080 - (C) Log player-used items (consumables/pet&hom&merc food/items used for skills&attacks)
// 0x00000100 - (O) Log produced/ingredient items
// 0x00000200 - (U) Log MVP prize items
// 0x00000400 - (A) Log player created/deleted items (through @/# commands)
// 0x00000800 - (R) Log items placed/retrieved from storage.
// 0x00001000 - (G) Log items placed/retrieved from guild storage.
// 0x00002000 - (E) Log mail system transactions.
// 0x00004000 - (I) Log auction system transactions.
// 0x00008000 - (B) Log buying store transactions
// 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)
// 0x0020000 - ($) Log cash transactions
// 0x0040000 - (K) Log account bank transactions
// 0x0080000 - (F) Removed bound items when guild/party is broken
// 0x0100000 - (Y) Log Roulette Lottery
// 0x0200000 - (Z) Merged items from item mergers process.
// 0x0400000 - (Q) Log items given from quest-granted drops.
// 0x0800000 - (H) Log items consumed by Private Airship system
// 0x1000000 - (J) Log Barter Shop transactions
// 0x2000000 - (W) Log Laphine system transactions
// 0x00020000 - ($) Log cash transactions
// 0x00040000 - (K) Log account bank transactions
// 0x00080000 - (F) Removed bound items when guild/party is broken
// 0x00100000 - (Y) Log Roulette Lottery
// 0x00200000 - (Z) Merged items from item mergers process.
// 0x00400000 - (Q) Log items given from quest-granted drops.
// 0x00800000 - (H) Log items consumed by Private Airship system
// 0x01000000 - (J) Log Barter Shop 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
// 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)
sql_logs: yes

View File

@ -921,7 +921,10 @@
// @mobinfo RES/MRES
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

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
Name: Amber
Type: Etc
Buy: 45000
Weight: 100
- Id: 1000322
AegisName: Etel_Dust

View File

@ -1178,6 +1178,12 @@ If args are given, sets camera position.
---------------------------------------
@enchantgradeui
Opens the enchantgrade UI.
---------------------------------------
==============================
| 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.
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.
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_17_1.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,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,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,269,193,4 shop Trader#moc8 89,2609:-1,1516:-1,1522:-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_rockridge.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_Stylist.txt
npc: npc/re/merchants/flute.txt

View File

@ -169,12 +169,15 @@ CREATE TABLE IF NOT EXISTS `npclog` (
# Private Airs(H)ip
# Barter Shop (J)
# Laphine systems (W)
# Enchantgrade UI (0)
# Reform UI (1)
# Enchant UI (2)
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') 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',
`amount` int(11) NOT NULL default '1',
`refine` tinyint(3) unsigned NOT NULL default '0',
@ -224,13 +227,15 @@ CREATE TABLE IF NOT EXISTS `picklog` (
# Ban(K) Transactions
# Barter Shop (J)
# (X) Other
# Enchantgrade UI (0)
# Enchant UI (2)
CREATE TABLE IF NOT EXISTS `zenylog` (
`id` int(11) NOT NULL auto_increment,
`time` datetime NOT NULL,
`char_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',
`map` varchar(11) NOT NULL default '',
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
#endif
enum e_enchantgrade : uint16{
ENCHANTGRADE_NONE = 0,
ENCHANTGRADE_D,
ENCHANTGRADE_C,
ENCHANTGRADE_B,
ENCHANTGRADE_A
};
#ifdef RENEWAL
#define MAX_WEAPON_LEVEL 5
#define MAX_ARMOR_LEVEL 2
#define MAX_ENCHANTGRADE ENCHANTGRADE_A
#else
#define MAX_WEAPON_LEVEL 4
#define MAX_ARMOR_LEVEL 1
#define MAX_ENCHANTGRADE ENCHANTGRADE_NONE
#endif
// for produce

View File

@ -10662,7 +10662,7 @@ ACMD_FUNC( stylist ){
return -1;
}
clif_ui_open( sd, OUT_UI_STYLIST, 0 );
clif_ui_open( *sd, OUT_UI_STYLIST, 0 );
return 0;
#endif
}
@ -10697,6 +10697,23 @@ ACMD_FUNC(addfame)
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"
/**
@ -11019,6 +11036,7 @@ void atcommand_basecommands(void) {
ACMD_DEF(refineui),
ACMD_DEFR(stylist, ATCMD_NOCONSOLE|ATCMD_NOAUTOTRADE),
ACMD_DEF(addfame),
ACMD_DEFR(enchantgradeui, ATCMD_NOCONSOLE|ATCMD_NOAUTOTRADE),
};
AtCommandInfo* atcommand;
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
/// 0AE2 <type>.B <data>.L
void clif_ui_open( struct map_session_data *sd, enum out_ui_type ui_type, int32 data ){
nullpo_retv(sd);
void clif_ui_open( struct map_session_data& sd, enum out_ui_type ui_type, int32 data ){
#if PACKETVER >= 20151202
// If the UI requires state tracking
switch( ui_type ){
case OUT_UI_STYLIST:
sd->state.stylist_open = true;
sd.state.stylist_open = true;
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));
WFIFOW(fd,0) = 0xae2;
WFIFOB(fd,2) = ui_type;
WFIFOL(fd,3) = data;
WFIFOSET(fd,packet_len(0xae2));
p.PacketType = HEADER_ZC_UI_OPEN;
p.UIType = ui_type;
#if PACKETVER >= 20171122
p.data = data;
#endif
clif_send( &p, sizeof( p ), &sd.bl, SELF );
#endif
}
/// 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 ) ){
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() ){
clif_ui_open( sd, OUT_UI_ATTENDANCE, pc_attendance_counter( sd ) );
clif_ui_open( *sd, OUT_UI_ATTENDANCE, pc_attendance_counter( sd ) );
}else{
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
}
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
*------------------------------------------*/

View File

@ -1162,10 +1162,11 @@ enum out_ui_type : int8 {
OUT_UI_BANK = 0,
OUT_UI_STYLIST,
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_weight_limit( struct map_session_data* sd );

View File

@ -2375,7 +2375,6 @@
// 2018-03-07bRagexeRE
#if PACKETVER >= 20180307
parseable_packet(0x0A68,3,clif_parse_open_ui,2);
packet(0x0AE2,7);
parseable_packet(0x0AEF,2,clif_parse_attendance_request,0);
packet(0x0AF0,10);
#endif
@ -2447,6 +2446,9 @@
#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_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
#if PACKETVER_RE_NUM >= 20211103 || PACKETVER_ZERO_NUM >= 20210818

View File

@ -86,7 +86,10 @@ static char log_picktype2char(e_log_pick_type type)
case LOG_TYPE_QUEST: return 'Q'; // (Q)uest Item
case LOG_TYPE_PRIVATE_AIRSHIP: return 'H'; // Private Airs(H)ip
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

View File

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

View File

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

View File

@ -387,6 +387,7 @@ struct map_session_data {
bool stylist_open;
bool barter_open;
bool barter_extended_open;
bool enchantgrade_open; // Whether the enchantgrade window is open or not
unsigned int block_action : 10;
bool refineui_open;
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.barter_open || sd->state.barter_extended_open
|| 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
static bool pc_cant_act( struct map_session_data* sd ){

View File

@ -25739,7 +25739,7 @@ BUILDIN_FUNC( openstylist ){
return SCRIPT_CMD_FAILURE;
}
clif_ui_open( sd, OUT_UI_STYLIST, 0 );
clif_ui_open( *sd, OUT_UI_STYLIST, 0 );
return SCRIPT_CMD_SUCCESS;
#else
@ -25860,6 +25860,10 @@ BUILDIN_FUNC(randomoptgroup)
}
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;
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);
}
clif_ui_open( sd, OUT_UI_QUEST, quest_id );
clif_ui_open( *sd, OUT_UI_QUEST, quest_id );
return SCRIPT_CMD_SUCCESS;
#endif
}
BUILDIN_FUNC(openbank){
#if PACKETVER < 20150128
ShowError( "buildin_openbank: This command requires PACKETVER 20150128 or newer.\n" );
#if PACKETVER < 20151202
ShowError( "buildin_openbank: This command requires PACKETVER 20151202 or newer.\n" );
return SCRIPT_CMD_FAILURE;
#else
struct map_session_data* sd = nullptr;
@ -25895,7 +25900,7 @@ BUILDIN_FUNC(openbank){
return SCRIPT_CMD_FAILURE;
}
clif_ui_open( sd, OUT_UI_BANK, 0 );
clif_ui_open( *sd, OUT_UI_BANK, 0 );
return SCRIPT_CMD_SUCCESS;
#endif
}
@ -25994,6 +25999,23 @@ BUILDIN_FUNC(getjobexp_ratio){
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"
// 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(getbaseexp_ratio, "i??"),
BUILDIN_DEF(getjobexp_ratio, "i??"),
BUILDIN_DEF(enchantgradeui, "?" ),
#include "../custom/script_def.inc"
{NULL,NULL,NULL},

View File

@ -8996,6 +8996,14 @@
export_constant(SCF_REMOVEONUNEQUIPWEAPON);
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_constant2
#undef export_parameter

View File

@ -544,6 +544,399 @@ uint64 SizeFixDatabase::parseBodyNode(const ryml::NodeRef& node) {
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
* @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;
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) {
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;
#ifdef RENEWAL
// TODO: additional grade bonus
if( enchantgrade_info != nullptr ){
wa->atk2 += ( ( ( info->bonus / 100 ) * enchantgrade_info->bonus ) / 100 );
}
if( wlv == 5 ){
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 ){
wa->matk += info->bonus / 100;
// TODO: additional grade bonus
if( enchantgrade_info != nullptr ){
wa->matk += ( ( ( info->bonus / 100 ) * enchantgrade_info->bonus ) / 100 );
}
}
#endif
// Overrefine bonus.
@ -15184,10 +15588,12 @@ void status_readdb( bool reload ){
size_fix_db.reload();
refine_db.reload();
status_db.reload();
enchantgrade_db.reload();
}else{
size_fix_db.load();
refine_db.load();
status_db.load();
enchantgrade_db.load();
}
elemental_attribute_db.load();
}
@ -15211,6 +15617,7 @@ void do_init_status(void) {
/** Destroy status data */
void do_final_status(void) {
ers_destroy(sc_data_ers);
enchantgrade_db.clear();
size_fix_db.clear();
refine_db.clear();
status_db.clear();

View File

@ -144,6 +144,59 @@ public:
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.
enum sc_type : int16 {
SC_NONE = -1,