Converted produce_db and skill_changematerial_db into YAML

This commit is contained in:
Atemo 2023-05-17 21:16:46 +02:00
parent ccd7e5c14a
commit 480cf26283
16 changed files with 7403 additions and 330 deletions

View File

@ -0,0 +1,49 @@
# This file is a part of rAthena.
# Copyright(C) 2022 rAthena Development Team
# https://rathena.org - https://github.com/rathena
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
###########################################################################
# Item Produce Database
###########################################################################
#
# Item Produce Settings
#
###########################################################################
# - ItemLevel Number which determines what kind of a crafting window will pop-up.
# Recipe:
# - Product AegisName of the produced item.
# SkillName Skill name required. (Default: null)
# SkillLevel Skill level required. (Default: 1)
# Consumed: List of items consumed to produce the Product.
# - Item AegisName of the consumed item.
# Amount Amount required.
# Clear Remove the item with the given AegisName from Consumed. (Optional)
# NotConsumed: List of items not consumed to produce the Product. (Default: null)
# - Item AegisName of the unconsumed item.
# Clear Remove the item with the given AegisName from NotConsumed. (Optional)
#
###########################################################################
# Additional fields for Change Material (ItemLevel: 26):
#
# BaseRate Base rate (in n/10%). (Default: 1000)
# Make: List of item amounts with their individual rate produced by Change Material. (Default: null)
# - Amount Amount of item created (unique to the list).
# Rate Rate to create the Amount (in n/10%). Default: 1000. 0 to remove on import.
###########################################################################
Header:
Type: PRODUCE_DB
Version: 1

View File

@ -1,11 +0,0 @@
// Change Material Database
//
// Structure of Database:
// ID,ProductID,BaseRate,MakeAmount1,MakeAmountRate1...,MakeAmount5,MakeAmountRate5
//
// NOTE:
// - ID is used to identify item order that will be used for overwriting on db/import.
// Value is started from 0 until 74 (MAX_SKILL_CHANGEMATERIAL_DB-1). Use same ID on import file to overwrite original result & requirements
// - Up to 5 ID/Amount pairs can be specified.
// - Rate = n/10%

54
db/pre-re/produce_db.yml Normal file
View File

@ -0,0 +1,54 @@
# This file is a part of rAthena.
# Copyright(C) 2022 rAthena Development Team
# https://rathena.org - https://github.com/rathena
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
###########################################################################
# Item Produce Database
###########################################################################
#
# Item Produce Settings
#
###########################################################################
# - ItemLevel Number which determines what kind of a crafting window will pop-up.
# Recipe:
# - Product AegisName of the produced item.
# SkillName Skill name required. (Default: null)
# SkillLevel Skill level required. (Default: 1)
# Consumed: List of items consumed to produce the Product.
# - Item AegisName of the consumed item.
# Amount Amount required.
# Clear Remove the item with the given AegisName from Consumed. (Optional)
# NotConsumed: List of items not consumed to produce the Product. (Default: null)
# - Item AegisName of the unconsumed item.
# Clear Remove the item with the given AegisName from NotConsumed. (Optional)
#
###########################################################################
# Additional fields for Change Material (ItemLevel: 26):
#
# BaseRate Base rate (in n/10%). (Default: 1000)
# Make: List of item amounts with their individual rate produced by Change Material. (Default: null)
# - Amount Amount of item created (unique to the list).
# Rate Rate to create the Amount (in n/10%). Default: 1000. 0 to remove on import.
###########################################################################
Header:
Type: PRODUCE_DB
Version: 1
Footer:
Imports:
- Path: db/pre-re/skill_produce_db.yml
- Path: db/pre-re/skill_changematerial_db.yml

View File

@ -0,0 +1,45 @@
# This file is a part of rAthena.
# Copyright(C) 2022 rAthena Development Team
# https://rathena.org - https://github.com/rathena
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
###########################################################################
# Item Produce Database
###########################################################################
#
# Item Produce Settings
#
###########################################################################
# - ItemLevel Number which determines what kind of a crafting window will pop-up.
# Recipe:
# - Product AegisName of the produced item.
# SkillName Skill name required. (Default: null)
# SkillLevel Skill level required. (Default: 1)
# Consumed: List of items consumed to produce the Product.
# - Item AegisName of the consumed item.
# Amount Amount required.
# Clear Remove the item with the given AegisName from Consumed. (Optional)
# NotConsumed: List of items not consumed to produce the Product. (Default: null)
# - Item AegisName of the unconsumed item.
# Clear Remove the item with the given AegisName from NotConsumed. (Optional)
# BaseRate Base rate (in n/10%). (Default: 1000)
# Make: List of item amounts with their individual rate produced by Change Material. (Default: null)
# - Amount Amount of item created (unique to the list).
# Rate Rate to create the Amount (in n/10%). Default: 1000. 0 to remove on import.
###########################################################################
Header:
Type: PRODUCE_DB
Version: 1

File diff suppressed because it is too large Load Diff

57
db/produce_db.yml Normal file
View File

@ -0,0 +1,57 @@
# This file is a part of rAthena.
# Copyright(C) 2022 rAthena Development Team
# https://rathena.org - https://github.com/rathena
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
###########################################################################
# Item Produce Database
###########################################################################
#
# Item Produce Settings
#
###########################################################################
# - ItemLevel Number which determines what kind of a crafting window will pop-up.
# Recipe:
# - Product AegisName of the produced item.
# SkillName Skill name required. (Default: null)
# SkillLevel Skill level required. (Default: 1)
# Consumed: List of items consumed to produce the Product.
# - Item AegisName of the consumed item.
# Amount Amount required.
# Clear Remove the item with the given AegisName from Consumed. (Optional)
# NotConsumed: List of items not consumed to produce the Product. (Default: null)
# - Item AegisName of the unconsumed item.
# Clear Remove the item with the given AegisName from NotConsumed. (Optional)
#
###########################################################################
# Additional fields for Change Material (ItemLevel: 26):
#
# BaseRate Base rate (in n/10%). (Default: 1000)
# Make: List of item amounts with their individual rate produced by Change Material. (Default: null)
# - Amount Amount of item created (unique to the list).
# Rate Rate to create the Amount (in n/10%). Default: 1000. 0 to remove on import.
###########################################################################
Header:
Type: PRODUCE_DB
Version: 1
Footer:
Imports:
- Path: db/pre-re/produce_db.yml
Mode: Prerenewal
- Path: db/re/produce_db.yml
Mode: Renewal
- Path: db/import/produce_db.yml

54
db/re/produce_db.yml Normal file
View File

@ -0,0 +1,54 @@
# This file is a part of rAthena.
# Copyright(C) 2022 rAthena Development Team
# https://rathena.org - https://github.com/rathena
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
###########################################################################
# Item Produce Database
###########################################################################
#
# Item Produce Settings
#
###########################################################################
# - ItemLevel Number which determines what kind of a crafting window will pop-up.
# Recipe:
# - Product AegisName of the produced item.
# SkillName Skill name required. (Default: null)
# SkillLevel Skill level required. (Default: 1)
# Consumed: List of items consumed to produce the Product.
# - Item AegisName of the consumed item.
# Amount Amount required.
# Clear Remove the item with the given AegisName from Consumed. (Optional)
# NotConsumed: List of items not consumed to produce the Product. (Default: null)
# - Item AegisName of the unconsumed item.
# Clear Remove the item with the given AegisName from NotConsumed. (Optional)
#
###########################################################################
# Additional fields for Change Material (ItemLevel: 26):
#
# BaseRate Base rate (in n/10%). (Default: 1000)
# Make: List of item amounts with their individual rate produced by Change Material. (Default: null)
# - Amount Amount of item created (unique to the list).
# Rate Rate to create the Amount (in n/10%). Default: 1000. 0 to remove on import.
###########################################################################
Header:
Type: PRODUCE_DB
Version: 1
Footer:
Imports:
- Path: db/re/skill_produce_db.yml
- Path: db/re/skill_changematerial_db.yml

View File

@ -0,0 +1,911 @@
# This file is a part of rAthena.
# Copyright(C) 2022 rAthena Development Team
# https://rathena.org - https://github.com/rathena
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
###########################################################################
# Item Produce Database
###########################################################################
#
# Item Produce Settings
#
###########################################################################
# - ItemLevel Number which determines what kind of a crafting window will pop-up.
# Recipe:
# - Product AegisName of the produced item.
# Skill: Skill requirement. (Default: null)
# Name Skill name required.
# Level Skill level required.
# Consumed: List of items consumed to produce the Product.
# - Item AegisName of the consumed item.
# Amount Amount required.
# Clear Remove the item with the given AegisName from Consumed. (Optional)
# NotConsumed: List of items not consumed to produce the Product. (Default: null)
# - Item AegisName of the unconsumed item.
# Clear Remove the item with the given AegisName from NotConsumed. (Optional)
# BaseRate Base rate (in n/10%). (Default: 1000)
# Make: List of item amounts with their individual rate produced by Change Material. (Default: null)
# - Amount Amount of item created (unique to the list).
# Rate Rate to create the Amount (in n/10%). Default: 1000. 0 to remove on import.
###########################################################################
Header:
Type: PRODUCE_DB
Version: 1
Body:
- ItemLevel: 26
Recipe:
- Product: Sacred_Masque
BaseRate: 800
Make:
- Amount: 8
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Grasshopper's_Leg
Amount: 45
- Item: Yoyo_Tail
Amount: 35
- Product: Long_Hair
Make:
- Amount: 4
Rate: 800
- Amount: 6
Rate: 200
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Pencil_Case
Amount: 40
- Item: Tiger's_Skin
Amount: 5
- Product: Phracon
BaseRate: 800
Make:
- Amount: 8
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Glass_Bead
Amount: 40
- Item: Spawn
Amount: 45
- Product: Lantern
BaseRate: 800
Make:
- Amount: 3
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Blossom_Of_Maneater
Amount: 20
- Item: Solid_Shell
Amount: 10
- Product: Acorn
BaseRate: 800
Make:
- Amount: 4
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Cactus_Needle
Amount: 30
- Item: Snail's_Shell
Amount: 10
- Product: Frozen_Heart
BaseRate: 800
Make:
- Amount: 6
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Moth_Dust
Amount: 35
- Item: Raccoondog_Doll
Amount: 25
- Product: Horrendous_Mouth
BaseRate: 800
Make:
- Amount: 9
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Dragon_Scale
Amount: 45
- Item: Stem
Amount: 45
- Product: Detrimindexta
BaseRate: 800
Make:
- Amount: 5
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Chrysalis
Amount: 40
- Item: Flesh_Of_Clam
Amount: 10
- Product: Detonator
BaseRate: 800
Make:
- Amount: 7
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Feather_Of_Birds
Amount: 25
- Item: Nose_Ring
Amount: 45
- Product: Tweezer
BaseRate: 800
Make:
- Amount: 4
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Monkey_Doll
Amount: 5
- Item: Worm_Peelings
Amount: 40
- Product: Petite_DiablOfs_Horn
Make:
- Amount: 1
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Resin
Amount: 10
- Item: Stone_Heart
Amount: 5
- Product: Root_Of_Maneater
Make:
- Amount: 4
Rate: 800
- Amount: 6
Rate: 200
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Talon
Amount: 25
- Item: Tooth_Of_
Amount: 20
- Product: Conch
BaseRate: 800
Make:
- Amount: 3
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Gill
Amount: 5
- Item: Immortal_Heart
Amount: 25
- Product: Rotten_Scale
BaseRate: 800
Make:
- Amount: 7
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Shell
Amount: 20
- Item: Thin_N'_Long_Tongue
Amount: 50
- Product: Elder_Pixie's_Beard
Make:
- Amount: 8
Rate: 800
- Amount: 12
Rate: 200
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Bee_Sting
Amount: 35
- Item: Petite_DiablOfs_Wing
Amount: 45
- Product: Lizard_Scruff
BaseRate: 800
Make:
- Amount: 3
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Karvodailnirol
Amount: 15
- Item: Scale_Of_Snakes
Amount: 20
- Product: Emveretarcon
BaseRate: 800
Make:
- Amount: 4
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Grasshopper_Doll
Amount: 40
- Item: Heart_Of_Mermaid
Amount: 5
- Product: Chinese_Ink
BaseRate: 800
Make:
- Amount: 4
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Bear's_Foot
Amount: 20
- Item: Black_Ladle
Amount: 25
- Product: Spiderweb
BaseRate: 800
Make:
- Amount: 8
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Fin
Amount: 50
- Item: Slender_Snake
Amount: 35
- Product: Reins
BaseRate: 800
Make:
- Amount: 8
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Chonchon_Doll
Amount: 30
- Item: Stuffed_Doll
Amount: 50
- Product: Wooden_Block
BaseRate: 800
Make:
- Amount: 2
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Rotten_Bandage
Amount: 10
- Item: Single_Cell
Amount: 10
- Product: Tentacle
Make:
- Amount: 4
Rate: 800
- Amount: 6
Rate: 200
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Decayed_Nail
Amount: 40
- Item: Wild_Boar's_Mane
Amount: 5
- Product: Mixture
Make:
- Amount: 4
Rate: 800
- Amount: 6
Rate: 200
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Posionous_Canine
Amount: 15
- Item: Powder_Of_Butterfly
Amount: 30
- Product: Colorful_Shell
Make:
- Amount: 9
Rate: 800
- Amount: 13
Rate: 200
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Horn
Amount: 50
- Item: Zargon
Amount: 45
- Product: Wing_Of_Moth
BaseRate: 800
Make:
- Amount: 5
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Frozen_Rose
Amount: 20
- Item: Reptile_Tongue
Amount: 30
- Product: Nipper
Make:
- Amount: 6
Rate: 800
- Amount: 9
Rate: 200
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Earthworm_Peeling
Amount: 40
- Item: Sticky_Mucus
Amount: 25
- Product: Turtle_Shell
BaseRate: 800
Make:
- Amount: 4
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Fluff
Amount: 5
- Item: Poring_Doll
Amount: 40
- Product: Nail_Of_Orc
BaseRate: 800
Make:
- Amount: 6
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Garlet
Amount: 10
- Item: Raccoon_Leaf
Amount: 50
- Product: Dragon_Canine
Make:
- Amount: 8
Rate: 800
- Amount: 12
Rate: 200
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Osiris_Doll
Amount: 50
- Item: Sticky_Webfoot
Amount: 35
- Product: Skirt_Of_Virgin
BaseRate: 800
Make:
- Amount: 6
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Head_Of_Medusa
Amount: 35
- Item: Scales_Shell
Amount: 30
- Product: Dragon_Train
BaseRate: 800
Make:
- Amount: 6
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Sharpened_Cuspid
Amount: 35
- Item: Tooth_Of_Bat
Amount: 25
- Product: Dokkaebi_Horn
BaseRate: 800
Make:
- Amount: 4
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Lip_Of_Ancient_Fish
Amount: 25
- Item: Shining_Scales
Amount: 15
- Product: Grit
BaseRate: 800
Make:
- Amount: 8
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Crystal_Mirror
Amount: 35
- Item: Limb_Of_Mantis
Amount: 50
- Product: Sharp_Scale
BaseRate: 800
Make:
- Amount: 3
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Clam_Shell
Amount: 20
- Item: Horseshoe
Amount: 10
- Product: Short_Leg
BaseRate: 800
Make:
- Amount: 6
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Claw_Of_Wolves
Amount: 20
- Item: Scell
Amount: 45
- Product: Starsand_Of_Witch
BaseRate: 800
Make:
- Amount: 2
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Blue_Porcelain
Amount: 15
- Item: Insect_Feeler
Amount: 10
- Product: Fox_Tail
Make:
- Amount: 2
Rate: 800
- Amount: 3
Rate: 200
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Animal's_Skin
Amount: 10
- Item: Rouge
Amount: 15
- Product: Cobold_Hair
Make:
- Amount: 6
Rate: 800
- Amount: 9
Rate: 200
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Jellopy
Amount: 45
- Item: Wedding_Bouquet
Amount: 20
- Product: Jaws_Of_Ant
Make:
- Amount: 4
Rate: 800
- Amount: 6
Rate: 200
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Spore_Doll
Amount: 20
- Item: Witherless_Rose
Amount: 20
- Product: Voucher_Of_Orcish_Hero
BaseRate: 800
Make:
- Amount: 5
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Nail_Of_Mole
Amount: 45
- Item: Tree_Root
Amount: 5
- Product: Sacred_Marks
BaseRate: 800
Make:
- Amount: 4
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Pumpkin_Head
Amount: 30
- Item: Scorpion's_Tail
Amount: 10
- Product: Alchol
BaseRate: 800
Make:
- Amount: 9
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Orcish_Voucher
Amount: 50
- Item: Skel_Bone
Amount: 40
- Product: Crap_Shell
BaseRate: 800
Make:
- Amount: 8
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Baphomet_Doll
Amount: 50
- Item: Fish_Tail
Amount: 30
- Product: Tendon
BaseRate: 800
Make:
- Amount: 3
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Feather
Amount: 5
- Item: Orcish_Cuspid
Amount: 25
- Product: Tiger_Footskin
BaseRate: 800
Make:
- Amount: 2
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Pointed_Scale
Amount: 5
- Item: White_Platter
Amount: 20
- Product: Hinalle
Make:
- Amount: 2
Rate: 200
- Amount: 4
Rate: 800
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Bunch_Of_Flowers
Amount: 45
- Item: Moustache_Of_Mole
Amount: 40
- Product: Counteragent
BaseRate: 800
Make:
- Amount: 4
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Evil_Horn
Amount: 15
- Item: Mementos
Amount: 30
- Product: Tooth_Of_Ancient_Fish
Make:
- Amount: 6
Rate: 800
- Amount: 9
Rate: 200
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Bill_Of_Birds
Amount: 35
- Item: Transparent_Cloth
Amount: 30
- Product: Rat_Tail
Make:
- Amount: 7
Rate: 800
- Amount: 10
Rate: 200
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Golden_Hair
Amount: 40
- Item: Mushroom_Spore
Amount: 35
- Product: Coal
BaseRate: 500
Make:
- Amount: 1
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Guard
Amount: 1
- Product: Steel
Make:
- Amount: 10
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Tsurugi
Amount: 1
- Product: Cigar
Make:
- Amount: 1
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Orcish_Axe
Amount: 1
- Product: Bone_Wand
BaseRate: 200
Make:
- Amount: 1
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Broken_Farming_Utensil
Amount: 100
- Item: Clattering_Skull
Amount: 100
- Product: Cigar
Make:
- Amount: 1
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Orcish_Axe
Amount: 1
- Item: Orcish_Voucher
Amount: 100
- Product: Starsand_Of_Witch
BaseRate: 800
Make:
- Amount: 2
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Moth_Dust
Amount: 100
- Item: Scell
Amount: 100
- Product: Soft_Feather
Make:
- Amount: 1
Rate: 200
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Feather
Amount: 30
- Item: Feather_Of_Birds
Amount: 30
- Product: Wind_Of_Verdure
Make:
- Amount: 1
Rate: 500
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Ice_Piece
Amount: 100
- Product: Crystal_Blue
Make:
- Amount: 1
Rate: 500
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Claw_Of_Wolves
Amount: 100
- Product: Soft_Silk_Cloth
Make:
- Amount: 2
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Transparent_Cloth
Amount: 10
- Product: Transparent_Cloth
Make:
- Amount: 5
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Soft_Silk_Cloth
Amount: 2
- Product: Boost500_To_Throw
Make:
- Amount: 1
Rate: 100
- Amount: 2
Rate: 250
- Amount: 5
Rate: 500
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Boost500
Amount: 10
- Item: Empty_Potion
Amount: 10
- Item: Flexible_String
Amount: 10
- Product: Full_SwingK_To_Throw
Make:
- Amount: 1
Rate: 100
- Amount: 2
Rate: 250
- Amount: 5
Rate: 500
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Empty_Potion
Amount: 10
- Item: Flexible_String
Amount: 10
- Item: Full_SwingK
Amount: 10
- Product: Mana_Plus_To_Throw
Make:
- Amount: 1
Rate: 100
- Amount: 2
Rate: 250
- Amount: 5
Rate: 500
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Empty_Potion
Amount: 10
- Item: Flexible_String
Amount: 10
- Item: Mana_Plus
Amount: 10
- Product: Cure_Free_To_Throw
Make:
- Amount: 1
Rate: 100
- Amount: 2
Rate: 250
- Amount: 5
Rate: 500
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Cure_Free
Amount: 10
- Item: Empty_Potion
Amount: 10
- Item: Flexible_String
Amount: 10
- Product: Stamina_Up_M_To_Throw
Make:
- Amount: 1
Rate: 100
- Amount: 2
Rate: 250
- Amount: 5
Rate: 500
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Empty_Potion
Amount: 10
- Item: Flexible_String
Amount: 10
- Item: Stamina_Up_M
Amount: 10
- Product: Digestive_F_To_Throw
Make:
- Amount: 1
Rate: 100
- Amount: 2
Rate: 250
- Amount: 5
Rate: 500
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Digestive_F
Amount: 10
- Item: Empty_Potion
Amount: 10
- Item: Flexible_String
Amount: 10
- Product: HP_Inc_PotS_To_Throw
Make:
- Amount: 10
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Bottle_To_Throw
Amount: 10
- Item: HP_Increase_PotionS
Amount: 10
- Product: HP_Inc_PotM_To_Throw
Make:
- Amount: 10
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Bottle_To_Throw
Amount: 10
- Item: HP_Increase_PotionM
Amount: 10
- Product: HP_Inc_PotL_To_Throw
Make:
- Amount: 10
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Bottle_To_Throw
Amount: 10
- Item: HP_Increase_PotionL
Amount: 10
- Product: SP_Inc_PotS_To_Throw
Make:
- Amount: 10
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Bottle_To_Throw
Amount: 10
- Item: SP_Increase_PotionS
Amount: 10
- Product: SP_Inc_PotM_To_Throw
Make:
- Amount: 10
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Bottle_To_Throw
Amount: 10
- Item: SP_Increase_PotionM
Amount: 10
- Product: SP_Inc_PotL_To_Throw
Make:
- Amount: 10
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Bottle_To_Throw
Amount: 10
- Item: SP_Increase_PotionL
Amount: 10
- Product: En_White_PotZ_To_Throw
Make:
- Amount: 10
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Bottle_To_Throw
Amount: 10
- Item: Enrich_White_PotionZ
Amount: 10
- Product: Vitata500_To_Throw
Make:
- Amount: 10
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Bottle_To_Throw
Amount: 10
- Item: Vitata500
Amount: 10
- Product: En_Cel_Juice_To_Throw
Make:
- Amount: 10
SkillName: GN_CHANGEMATERIAL
SkillLevel: 1
Consumed:
- Item: Bottle_To_Throw
Amount: 10
- Item: Enrich_Celermine_Juice
Amount: 10

2535
db/re/skill_produce_db.yml Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,28 @@
###########################################################################
# Item Produce Database
###########################################################################
#
# Item Produce Settings
#
###########################################################################
# - ItemLevel Number which determines what kind of a crafting window will pop-up.
# Recipe:
# - Product AegisName of the produced item.
# SkillName Skill name required. (Default: null)
# SkillLevel Skill level required. (Default: 1)
# Consumed: List of items consumed to produce the Product.
# - Item AegisName of the consumed item.
# Amount Amount required.
# Clear Remove the item with the given AegisName from Consumed. (Optional)
# NotConsumed: List of items not consumed to produce the Product. (Default: null)
# - Item AegisName of the unconsumed item.
# Clear Remove the item with the given AegisName from NotConsumed. (Optional)
#
###########################################################################
# Additional fields for Change Material (ItemLevel: 26):
#
# BaseRate Base rate (in n/10%). (Default: 1000)
# Make: List of item amounts with their individual rate produced by Change Material. (Default: null)
# - Amount Amount of item created (unique to the list).
# Rate Rate to create the Amount (in n/10%). Default: 1000. 0 to remove on import.
###########################################################################

View File

@ -6383,37 +6383,34 @@ void clif_skill_estimation(map_session_data *sd,struct block_list *dst)
void clif_skill_produce_mix_list( map_session_data *sd, int skill_id, int trigger ){
nullpo_retv(sd);
int fd = sd->fd;
if( !session_isActive( fd ) ){
return;
}
if (sd->menuskill_id == skill_id)
return; //Avoid resending the menu twice or more times...
if (skill_id == GC_CREATENEWPOISON)
skill_id = GC_RESEARCHNEWPOISON;
WFIFOHEAD( fd, sizeof( struct PACKET_ZC_MAKABLEITEMLIST ) + MAX_SKILL_PRODUCE_DB * sizeof( struct PACKET_ZC_MAKABLEITEMLIST_sub ) );
struct PACKET_ZC_MAKABLEITEMLIST *p = (struct PACKET_ZC_MAKABLEITEMLIST *)WFIFOP( fd, 0 );
struct PACKET_ZC_MAKABLEITEMLIST *p = (struct PACKET_ZC_MAKABLEITEMLIST *)packet_buffer;
p->packetType = 0x18d;
int count = 0;
for( int i = 0; i < MAX_SKILL_PRODUCE_DB; i++ ){
if (skill_can_produce_mix(sd,skill_produce_db[i].nameid, trigger, 1) &&
(skill_id <= 0 || skill_produce_db[i].req_skill == skill_id)
)
{
p->items[count].itemId = client_nameid( skill_produce_db[i].nameid );
p->items[count].material[0] = 0;
p->items[count].material[1] = 0;
p->items[count].material[2] = 0;
count++;
for (const auto &itemlvit : skill_produce_db) {
if (itemlvit.second->data.empty())
continue;
for (const auto &datait : itemlvit.second->data) {
if (skill_can_produce_mix(sd, datait.second->nameid, trigger, 1) != nullptr &&
(skill_id <= 0 || (skill_id > 0 && datait.second->req_skill == skill_id))
)
{
p->items[count].itemId = client_nameid( datait.second->nameid );
p->items[count].material[0] = 0;
p->items[count].material[1] = 0;
p->items[count].material[2] = 0;
count++;
}
}
}
p->packetLength = sizeof( struct PACKET_ZC_MAKABLEITEMLIST ) + count * sizeof( struct PACKET_ZC_MAKABLEITEMLIST_sub );
WFIFOSET( fd, p->packetLength );
clif_send( p, p->packetLength, &sd->bl, SELF );
if( count > 0 ){
sd->menuskill_id = skill_id;
@ -6442,31 +6439,28 @@ void clif_cooking_list( map_session_data *sd, int trigger, uint16 skill_id, int
return;
}
int fd = sd->fd;
if( !session_isActive( fd ) ){
return;
}
WFIFOHEAD( fd, sizeof( struct PACKET_ZC_MAKINGITEM_LIST ) + MAX_SKILL_PRODUCE_DB * sizeof( struct PACKET_ZC_MAKINGITEM_LIST_sub ) );
struct PACKET_ZC_MAKINGITEM_LIST *p = (struct PACKET_ZC_MAKINGITEM_LIST *)WFIFOP( fd, 0 );
struct PACKET_ZC_MAKINGITEM_LIST *p = (struct PACKET_ZC_MAKINGITEM_LIST *)packet_buffer;
p->packetType = 0x25a;
p->makeItem = list_type; // list type
int count = 0;
for( int i = 0; i < MAX_SKILL_PRODUCE_DB; i++ ){
if( !skill_can_produce_mix( sd, skill_produce_db[i].nameid, trigger, qty ) ){
for (const auto &itemlvit : skill_produce_db) {
if (itemlvit.second->data.empty())
continue;
}
for (const auto &datait : itemlvit.second->data) {
if( skill_can_produce_mix( sd, datait.second->nameid, trigger, qty ) == nullptr ){
continue;
}
p->items[count].itemId = client_nameid( skill_produce_db[i].nameid );
count++;
p->items[count].itemId = client_nameid( datait.second->nameid );
count++;
}
}
if( count > 0 || skill_id == AM_PHARMACY ){
p->packetLength = sizeof( struct PACKET_ZC_MAKINGITEM_LIST ) + count * sizeof( struct PACKET_ZC_MAKINGITEM_LIST_sub );
WFIFOSET( fd, p->packetLength );
clif_send( p, p->packetLength, &sd->bl, SELF );
sd->menuskill_id = skill_id;
sd->menuskill_val = trigger;
@ -6477,7 +6471,7 @@ void clif_cooking_list( map_session_data *sd, int trigger, uint16 skill_id, int
clif_msg_skill( sd, skill_id, INVENTORY_SPACE_FULL );
#else
p->packetLength = sizeof( struct PACKET_ZC_MAKINGITEM_LIST ) + count * sizeof( struct PACKET_ZC_MAKINGITEM_LIST_sub );
WFIFOSET( fd, p->packetLength );
clif_send( p, p->packetLength, &sd->bl, SELF );
#endif
}
}
@ -13230,10 +13224,10 @@ void clif_parse_ProduceMix(int fd,map_session_data *sd){
return;
}
int produce_idx;
std::shared_ptr<s_skill_produce_db_entry> produce = skill_can_produce_mix(sd,p->itemId,sd->menuskill_val, 1);
if( (produce_idx = skill_can_produce_mix(sd,p->itemId,sd->menuskill_val, 1)) )
skill_produce_mix(sd,0,p->itemId,p->material[0],p->material[1],p->material[2],1,produce_idx-1);
if( produce != nullptr )
skill_produce_mix(sd,0,p->itemId,p->material[0],p->material[1],p->material[2],1,produce);
clif_menuskill_clear(sd);
}
@ -13253,7 +13247,6 @@ void clif_parse_Cooking(int fd,map_session_data *sd) {
const struct PACKET_CZ_REQ_MAKINGITEM *p = (struct PACKET_CZ_REQ_MAKINGITEM *)RFIFOP( fd, 0 );
int amount = sd->menuskill_val2 ? sd->menuskill_val2 : 1;
short food_idx = -1;
if( p->type == 6 && sd->menuskill_id != GN_MIX_COOKING && sd->menuskill_id != GN_S_PHARMACY )
return;
@ -13264,8 +13257,11 @@ void clif_parse_Cooking(int fd,map_session_data *sd) {
clif_menuskill_clear(sd);
return;
}
if( (food_idx = skill_can_produce_mix(sd,p->itemId,sd->menuskill_val, amount)) )
skill_produce_mix(sd,(p->type>1?sd->menuskill_id:0),p->itemId,0,0,0,amount,food_idx-1);
std::shared_ptr<s_skill_produce_db_entry> produce = skill_can_produce_mix(sd,p->itemId,sd->menuskill_val, amount);
if( produce != nullptr )
skill_produce_mix(sd,(p->type>1?sd->menuskill_id:0),p->itemId,0,0,0,amount,produce);
clif_menuskill_clear(sd);
}
@ -13457,7 +13453,7 @@ void clif_parse_SelectArrow(int fd,map_session_data *sd) {
skill_arrow_create(sd,p->itemId);
break;
case SA_CREATECON:
skill_produce_mix(sd,SA_CREATECON,p->itemId,0,0,0,1,-1);
skill_produce_mix(sd,SA_CREATECON,p->itemId,0,0,0,1, nullptr);
break;
case GC_POISONINGWEAPON:
skill_poisoningweapon(sd,p->itemId);
@ -19521,10 +19517,14 @@ void clif_elementalconverter_list( map_session_data *sd ){
p->packetType = HEADER_ZC_MAKINGARROW_LIST;
int count = 0;
for( int i = 0; i < MAX_SKILL_PRODUCE_DB; i++ ){
if( skill_can_produce_mix( sd, skill_produce_db[i].nameid, 23, 1 ) ){
p->items[count].itemId = client_nameid( skill_produce_db[i].nameid );
count++;
for (const auto &itemlvit : skill_produce_db) {
if (itemlvit.second->data.empty())
continue;
for (const auto &datait : itemlvit.second->data) {
if( skill_can_produce_mix( sd, datait.second->nameid, 23, 1 ) ){
p->items[count].itemId = client_nameid( datait.second->nameid );
count++;
}
}
}

View File

@ -363,12 +363,11 @@
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\mob_item_ratio.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\mob_item_ratio.yml')" />
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\mob_skill_db.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\mob_skill_db.txt')" />
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\pet_db.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\pet_db.yml')" />
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\produce_db.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\produce_db.txt')" />
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\produce_db.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\produce_db.yml')" />
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\quest_db.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\quest_db.yml')" />
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\refine.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\refine.yml')" />
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\reputation.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\reputation.yml')" />
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\size_fix.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\size_fix.yml')" />
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\skill_changematerial_db.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\skill_changematerial_db.txt')" />
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\skill_damage_db.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\skill_damage_db.txt')" />
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\skill_db.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\skill_db.yml')" />
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\skill_nocast_db.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\skill_nocast_db.txt')" />

View File

@ -64,26 +64,11 @@ struct skill_usave {
uint16 skill_id, skill_lv;
};
struct s_skill_produce_db skill_produce_db[MAX_SKILL_PRODUCE_DB];
static unsigned short skill_produce_count;
AbraDatabase abra_db;
MagicMushroomDatabase magic_mushroom_db;
ReadingSpellbookDatabase reading_spellbook_db;
SkillArrowDatabase skill_arrow_db;
#define MAX_SKILL_CHANGEMATERIAL_DB 75
#define MAX_SKILL_CHANGEMATERIAL_SET 3
struct s_skill_changematerial_db {
t_itemid nameid;
unsigned short rate;
unsigned short qty[MAX_SKILL_CHANGEMATERIAL_SET];
unsigned short qty_rate[MAX_SKILL_CHANGEMATERIAL_SET];
};
struct s_skill_changematerial_db skill_changematerial_db[MAX_SKILL_CHANGEMATERIAL_DB];
static unsigned short skill_changematerial_count;
MagicMushroomDatabase magic_mushroom_db;
SkillProduceDatabase skill_produce_db;
struct s_skill_unit_layout skill_unit_layout[MAX_SKILL_UNIT_LAYOUT];
int firewall_unit_pos;
@ -9204,7 +9189,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
case AL_HOLYWATER:
if(sd) {
if (skill_produce_mix(sd, skill_id, ITEMID_HOLY_WATER, 0, 0, 0, 1, -1)) {
if (skill_produce_mix(sd, skill_id, ITEMID_HOLY_WATER, 0, 0, 0, 1, nullptr)) {
struct skill_unit* su;
if ((su = map_find_skill_unit_oncell(bl, bl->x, bl->y, NJ_SUITON, NULL, 0)) != NULL)
skill_delunit(su);
@ -9239,7 +9224,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
break;
case ASC_CDP:
if(sd) {
if(skill_produce_mix(sd, skill_id, ITEMID_POISON_BOTTLE, 0, 0, 0, 1, -1)) //Produce a Poison Bottle.
if(skill_produce_mix(sd, skill_id, ITEMID_POISON_BOTTLE, 0, 0, 0, 1, nullptr)) //Produce a Poison Bottle.
clif_skill_nodamage(src,bl,skill_id,skill_lv,1);
else
clif_skill_fail(sd,skill_id,USESKILL_FAIL_STUFF_INSUFFICIENT,0);
@ -9429,7 +9414,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
if (sd) {
clif_skill_nodamage(src,bl,skill_id,skill_lv,1);
//Prepare 200 White Potions.
if (!skill_produce_mix(sd, skill_id, ITEMID_WHITE_POTION, 0, 0, 0, 200, -1))
if (!skill_produce_mix(sd, skill_id, ITEMID_WHITE_POTION, 0, 0, 0, 200, nullptr))
clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
}
break;
@ -9437,29 +9422,33 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
if (sd) {
clif_skill_nodamage(src,bl,skill_id,skill_lv,1);
//Prepare 200 Slim White Potions.
if (!skill_produce_mix(sd, skill_id, ITEMID_WHITE_SLIM_POTION, 0, 0, 0, 200, -1))
if (!skill_produce_mix(sd, skill_id, ITEMID_WHITE_SLIM_POTION, 0, 0, 0, 200, nullptr))
clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
}
break;
case AM_TWILIGHT3:
if (sd) {
int ebottle = pc_search_inventory(sd,ITEMID_EMPTY_BOTTLE);
short alcohol_idx = -1, acid_idx = -1, fire_idx = -1;
std::shared_ptr<s_skill_produce_db_entry> produce_alcohol = skill_can_produce_mix(sd,ITEMID_ALCOHOL,-1, 100);
std::shared_ptr<s_skill_produce_db_entry> produce_acid = skill_can_produce_mix(sd,ITEMID_ACID_BOTTLE,-1, 50);
std::shared_ptr<s_skill_produce_db_entry> produce_fire = skill_can_produce_mix(sd,ITEMID_FIRE_BOTTLE,-1, 50);
if( ebottle >= 0 )
ebottle = sd->inventory.u.items_inventory[ebottle].amount;
//check if you can produce all three, if not, then fail:
if (!(alcohol_idx = skill_can_produce_mix(sd,ITEMID_ALCOHOL,-1, 100)) //100 Alcohol
|| !(acid_idx = skill_can_produce_mix(sd,ITEMID_ACID_BOTTLE,-1, 50)) //50 Acid Bottle
|| !(fire_idx = skill_can_produce_mix(sd,ITEMID_FIRE_BOTTLE,-1, 50)) //50 Flame Bottle
if (produce_alcohol == nullptr //100 Alcohol
|| produce_acid == nullptr //50 Acid Bottle
|| produce_fire == nullptr //50 Flame Bottle
|| ebottle < 200 //200 empty bottle are required at total.
) {
clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
break;
}
clif_skill_nodamage(src,bl,skill_id,skill_lv,1);
skill_produce_mix(sd, skill_id, ITEMID_ALCOHOL, 0, 0, 0, 100, alcohol_idx-1);
skill_produce_mix(sd, skill_id, ITEMID_ACID_BOTTLE, 0, 0, 0, 50, acid_idx-1);
skill_produce_mix(sd, skill_id, ITEMID_FIRE_BOTTLE, 0, 0, 0, 50, fire_idx-1);
skill_produce_mix(sd, skill_id, ITEMID_ALCOHOL, 0, 0, 0, 100, produce_alcohol);
skill_produce_mix(sd, skill_id, ITEMID_ACID_BOTTLE, 0, 0, 0, 50, produce_acid);
skill_produce_mix(sd, skill_id, ITEMID_FIRE_BOTTLE, 0, 0, 0, 50, produce_fire);
}
break;
case SA_DISPELL:
@ -10818,7 +10807,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
case AB_ANCILLA:
if( sd ) {
clif_skill_nodamage(src,bl,skill_id,skill_lv,1);
skill_produce_mix(sd, skill_id, ITEMID_ANCILLA, 0, 0, 0, 1, -1);
skill_produce_mix(sd, skill_id, ITEMID_ANCILLA, 0, 0, 0, 1, nullptr);
}
break;
@ -21406,74 +21395,83 @@ void skill_unit_move_unit_group(std::shared_ptr<s_skill_unit_group> group, int16
* @param nameid Product requested
* @param trigger Trigger criteria to match will 'ItemLv'
* @param qty Amount of item will be created
* @return 0 If failed or Index+1 of item found on skill_produce_db[]
* @return nullptr If failed or s_skill_produce_db_entry on success
*/
short skill_can_produce_mix(map_session_data *sd, t_itemid nameid, int trigger, int qty)
std::shared_ptr<s_skill_produce_db_entry> skill_can_produce_mix(map_session_data *sd, t_itemid nameid, int trigger, int qty)
{
nullpo_ret(sd);
if (sd == nullptr)
return nullptr;
if (!item_db.exists(nameid))
return 0;
if (!nameid || !item_db.exists(nameid))
return nullptr;
short i, j;
std::shared_ptr<s_skill_produce_db_entry> produce = nullptr;
for (i = 0; i < MAX_SKILL_PRODUCE_DB; i++) {
if (skill_produce_db[i].nameid == nameid) {
if ((j = skill_produce_db[i].req_skill) > 0 &&
pc_checkskill(sd,j) < skill_produce_db[i].req_skill_lv)
continue; // must iterate again to check other skills that produce it. [malufett]
if (j > 0 && sd->menuskill_id > 0 && sd->menuskill_id != j)
continue; // special case
break;
for (const auto &itemlvit : skill_produce_db) {
if (itemlvit.second->data.empty())
continue;
for (const auto &datait : itemlvit.second->data) {
if (datait.second->nameid == nameid) {
if (datait.second->req_skill > 0 && pc_checkskill(sd, datait.second->req_skill) < datait.second->req_skill_lv)
continue; // must iterate again to check other skills that produce it. [malufett]
if (datait.second->req_skill > 0 && sd->menuskill_id > 0 && sd->menuskill_id != datait.second->req_skill)
continue; // special case
produce = datait.second;
break;
}
}
if (produce != nullptr)
break;
}
if (nameid == ITEMID_HOMUNCULUS_SUPPLEMENT) { // Temporary check since the produce_db specifically wants the Pharmacy skill to use
if (pc_checkskill(sd, AM_BIOETHICS) == 0)
return 0;
return nullptr;
}
if (i >= MAX_SKILL_PRODUCE_DB)
return 0;
if (produce == nullptr)
return nullptr;
// Cannot carry the produced stuff
if (pc_checkadditem(sd, nameid, qty) == CHKADDITEM_OVERAMOUNT)
return 0;
return nullptr;
// Matching the requested produce list
if (trigger >= 0) {
if (trigger > 20) { // Non-weapon, non-food item (itemlv must match)
if (skill_produce_db[i].itemlv != trigger)
return 0;
if (produce->itemlv != trigger)
return nullptr;
} else if (trigger > 10) { // Food (any item level between 10 and 20 will do)
if (skill_produce_db[i].itemlv <= 10 || skill_produce_db[i].itemlv > 20)
return 0;
if (produce->itemlv <= 10 || produce->itemlv > 20)
return nullptr;
} else { // Weapon (itemlv must be higher or equal)
if (skill_produce_db[i].itemlv > trigger)
return 0;
if (produce->itemlv > trigger)
return nullptr;
}
}
// Check on player's inventory
for (j = 0; j < MAX_PRODUCE_RESOURCE; j++) {
t_itemid nameid_produce;
if (produce->materials.empty())
return produce;
if (!(nameid_produce = skill_produce_db[i].mat_id[j]))
continue;
if (skill_produce_db[i].mat_amount[j] == 0) {
if (pc_search_inventory(sd,nameid_produce) < 0)
return 0;
// Check on player's inventory
for (const auto &it : produce->materials) {
if (!item_db.exists(it.first))
return nullptr;
if (it.second == 0) {
if (pc_search_inventory(sd, it.first) < 0)
return nullptr;
} else {
unsigned short idx, amt;
for (idx = 0, amt = 0; idx < MAX_INVENTORY; idx++)
if (sd->inventory.u.items_inventory[idx].nameid == nameid_produce)
if (sd->inventory.u.items_inventory[idx].nameid == it.first)
amt += sd->inventory.u.items_inventory[idx].amount;
if (amt < qty * skill_produce_db[i].mat_amount[j])
return 0;
if (amt < qty * it.second)
return nullptr;
}
}
return i + 1;
return produce;
}
/**
@ -21485,41 +21483,40 @@ short skill_can_produce_mix(map_session_data *sd, t_itemid nameid, int trigger,
* @param slot2
* @param slot3
* @param qty Amount of requested item
* @param produce_idx Index of produce entry in skill_produce_db[]. (Optional. Assumed the requirements are complete, checked somewhere)
* @param s_skill_produce_db_entry. (Optional. Assumed the requirements are complete, checked somewhere)
* @return True is success, False if failed
*/
bool skill_produce_mix(map_session_data *sd, uint16 skill_id, t_itemid nameid, int slot1, int slot2, int slot3, int qty, short produce_idx)
bool skill_produce_mix(map_session_data *sd, uint16 skill_id, t_itemid nameid, int slot1, int slot2, int slot3, int qty, std::shared_ptr<s_skill_produce_db_entry> produce)
{
int slot[3];
int i, sc, ele, idx, equip, wlv, make_per = 0, flag = 0, skill_lv = 0;
int num = -1; // exclude the recipe
struct status_data *status;
nullpo_ret(sd);
status = status_get_status_data(&sd->bl);
if (!item_db.exists(nameid))
return false;
int i, sc, ele, equip, wlv, make_per = 0, flag = 0, skill_lv = 0;
int num = -1; // exclude the recipe
struct status_data *status = status_get_status_data(&sd->bl);
if( sd->skill_id_old == skill_id )
skill_lv = sd->skill_lv_old;
if (produce_idx == -1) {
if( !(idx = skill_can_produce_mix(sd,nameid,-1, qty)) )
if (produce == nullptr) {
produce = skill_can_produce_mix(sd,nameid,-1, qty);
if( produce == nullptr )
return false;
idx--;
}
else
idx = produce_idx;
if (qty < 1)
qty = 1;
if (!skill_id) //A skill can be specified for some override cases.
skill_id = skill_produce_db[idx].req_skill;
skill_id = produce->req_skill;
if( skill_id == GC_RESEARCHNEWPOISON )
skill_id = GC_CREATENEWPOISON;
int slot[3];
slot[0] = slot1;
slot[1] = slot2;
slot[2] = slot3;
@ -21542,30 +21539,32 @@ bool skill_produce_mix(map_session_data *sd, uint16 skill_id, t_itemid nameid, i
}
}
for (i = 0; i < MAX_PRODUCE_RESOURCE; i++) {
short x, j;
t_itemid id = skill_produce_db[idx].mat_id[i];
if (!produce->materials.empty()) {
for (const auto &mat : produce->materials) {
short x, j;
t_itemid id = mat.first;
if (!item_db.exists(id))
continue;
num++;
x = (skill_id == RK_RUNEMASTERY ? 1 : qty) * skill_produce_db[idx].mat_amount[i];
do {
int y = 0;
if (!item_db.exists(id))
continue;
num++;
x = (skill_id == RK_RUNEMASTERY ? 1 : qty) * mat.second;
do {
int y = 0;
j = pc_search_inventory(sd,id);
j = pc_search_inventory(sd,id);
if (j >= 0) {
y = sd->inventory.u.items_inventory[j].amount;
if (y > x)
y = x;
pc_delitem(sd,j,y,0,0,LOG_TYPE_PRODUCE);
} else {
ShowError("skill_produce_mix: material item error\n");
return false;
}
x -= y;
} while( j >= 0 && x > 0 );
if (j >= 0) {
y = sd->inventory.u.items_inventory[j].amount;
if (y > x)
y = x;
pc_delitem(sd,j,y,0,0,LOG_TYPE_PRODUCE);
} else {
ShowError("skill_produce_mix: material item error\n");
return false;
}
x -= y;
} while( j >= 0 && x > 0 );
}
}
if ((equip = (itemdb_isequip(nameid) && skill_id != GN_CHANGEMATERIAL && skill_id != GN_MAKEBOMB)) && itemdb_type(nameid) == IT_WEAPON )
@ -21698,12 +21697,7 @@ bool skill_produce_mix(map_session_data *sd, uint16 skill_id, t_itemid nameid, i
qty = 1+rnd()%pc_checkskill(sd,GC_RESEARCHNEWPOISON);
break;
case GN_CHANGEMATERIAL:
for (i = 0; i < MAX_SKILL_CHANGEMATERIAL_DB; i++) {
if (skill_changematerial_db[i].nameid == nameid) {
make_per = skill_changematerial_db[i].rate * 10;
break;
}
}
make_per = produce->baserate * 10;
break;
case GN_S_PHARMACY:
{
@ -21828,7 +21822,7 @@ bool skill_produce_mix(map_session_data *sd, uint16 skill_id, t_itemid nameid, i
+ 20 * (sd->status.base_level + 1)
+ 20 * (status->dex + 1)
+ 100 * (rnd()%(30+5*(sd->cook_mastery/400) - (6+sd->cook_mastery/80)) + (6+sd->cook_mastery/80))
- 400 * (skill_produce_db[idx].itemlv - 11 + 1)
- 400 * (produce->itemlv - 11 + 1)
- 10 * (100 - status->luk + 1)
- 500 * (num - 1)
- 100 * (rnd()%4 + 1);
@ -21984,36 +21978,33 @@ bool skill_produce_mix(map_session_data *sd, uint16 skill_id, t_itemid nameid, i
clif_misceffect(&sd->bl,3);
break;
default: //Those that don't require a skill?
if (skill_produce_db[idx].itemlv > 10 && skill_produce_db[idx].itemlv <= 20) { //Cooking items.
if (produce->itemlv > 10 && produce->itemlv <= 20) { //Cooking items.
clif_specialeffect(&sd->bl, EF_COOKING_OK, AREA);
pc_setparam(sd, SP_COOKMASTERY, sd->cook_mastery + ( 1 << ( (skill_produce_db[idx].itemlv - 11) / 2 ) ) * 5);
pc_setparam(sd, SP_COOKMASTERY, sd->cook_mastery + ( 1 << ( (produce->itemlv - 11) / 2 ) ) * 5);
}
break;
}
}
if (skill_id == GN_CHANGEMATERIAL && tmp_item.amount) { //Success
int j, k = 0, l;
int k = 0, l;
bool isStackable = itemdb_isstackable(tmp_item.nameid);
for (i = 0; i < MAX_SKILL_CHANGEMATERIAL_DB; i++) {
if (skill_changematerial_db[i].nameid == nameid){
for (j = 0; j < MAX_SKILL_CHANGEMATERIAL_SET; j++){
if (rnd()%1000 < skill_changematerial_db[i].qty_rate[j]){
uint16 total_qty = qty * skill_changematerial_db[i].qty[j];
tmp_item.amount = (isStackable ? total_qty : 1);
for (l = 0; l < total_qty; l += tmp_item.amount) {
if ((flag = pc_additem(sd,&tmp_item,tmp_item.amount,LOG_TYPE_PRODUCE))) {
clif_additem(sd,0,0,flag);
if( battle_config.skill_drop_items_full ){
map_addflooritem(&tmp_item,tmp_item.amount,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0,0);
}
if (!produce->qty.empty()) {
for (const auto &qtyit : produce->qty) {
if (rnd()%1000 < qtyit.second){
uint16 total_qty = qty * qtyit.first;
tmp_item.amount = (isStackable ? total_qty : 1);
for (l = 0; l < total_qty; l += tmp_item.amount) {
if ((flag = pc_additem(sd,&tmp_item,tmp_item.amount,LOG_TYPE_PRODUCE))) {
clif_additem(sd,0,0,flag);
if( battle_config.skill_drop_items_full ){
map_addflooritem(&tmp_item,tmp_item.amount,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0,0);
}
}
k++;
}
k++;
}
break;
}
}
if (k) {
@ -22138,10 +22129,10 @@ bool skill_produce_mix(map_session_data *sd, uint16 skill_id, t_itemid nameid, i
clif_msg_skill(sd, skill_id, ITEM_PRODUCE_FAIL);
break;
default:
if (skill_produce_db[idx].itemlv > 10 && skill_produce_db[idx].itemlv <= 20 ) { //Cooking items.
if (produce->itemlv > 10 && produce->itemlv <= 20 ) { //Cooking items.
clif_specialeffect(&sd->bl, EF_COOKING_FAIL, AREA);
// todo: What in the world is this calculation
pc_setparam(sd, SP_COOKMASTERY, sd->cook_mastery - ( 1 << ((skill_produce_db[idx].itemlv - 11) / 2) ) - ( ( ( 1 << ((skill_produce_db[idx].itemlv - 11) / 2) ) >> 1 ) * 3 ));
pc_setparam(sd, SP_COOKMASTERY, sd->cook_mastery - ( 1 << ((produce->itemlv - 11) / 2) ) - ( ( ( 1 << ((produce->itemlv - 11) / 2) ) >> 1 ) * 3 ));
}
break;
}
@ -22483,49 +22474,54 @@ int skill_elementalanalysis(map_session_data* sd, int n, uint16 skill_lv, unsign
}
int skill_changematerial(map_session_data *sd, int n, unsigned short *item_list) {
int i, j, k, c, p = 0, amount;
int k, c, p = 0, amount;
t_itemid nameid;
nullpo_ret(sd);
nullpo_ret(item_list);
uint16 item_lv = 26;
std::shared_ptr<s_skill_produce_db> produce = skill_produce_db.find(item_lv);
if (produce == nullptr || produce->data.empty())
return 0;
// Search for objects that can be created.
for( i = 0; i < MAX_SKILL_PRODUCE_DB; i++ ) {
if( skill_produce_db[i].itemlv == 26 && skill_produce_db[i].nameid > 0 ) {
p = 0;
do {
c = 0;
// Verification of overlap between the objects required and the list submitted.
for( j = 0; j < MAX_PRODUCE_RESOURCE; j++ ) {
if( skill_produce_db[i].mat_id[j] > 0 ) {
for( k = 0; k < n; k++ ) {
int idx = item_list[k*2+0]-2;
for (const auto &datait : produce->data) {
std::shared_ptr<s_skill_produce_db_entry> data = datait.second;
if( idx < 0 || idx >= MAX_INVENTORY ){
return 0;
}
if (!item_db.exists(data->nameid))
return 0;
if (data->materials.empty())
return 0;
nameid = sd->inventory.u.items_inventory[idx].nameid;
amount = item_list[k*2+1];
if( nameid > 0 && sd->inventory.u.items_inventory[idx].identify == 0 ){
clif_msg_skill(sd,GN_CHANGEMATERIAL,ITEM_UNIDENTIFIED);
return 0;
}
if( nameid == skill_produce_db[i].mat_id[j] && (amount-p*skill_produce_db[i].mat_amount[j]) >= skill_produce_db[i].mat_amount[j]
&& (amount-p*skill_produce_db[i].mat_amount[j])%skill_produce_db[i].mat_amount[j] == 0 ) // must be in exact amount
c++; // match
}
p = 0;
do {
c = 0;
// Verification of overlap between the objects required and the list submitted.
for (const auto &mat : data->materials) {
for( k = 0; k < n; k++ ) {
int idx = item_list[k*2]-2;
if( idx < 0 || idx >= MAX_INVENTORY ){
return 0;
}
else
break; // No more items required
nameid = sd->inventory.u.items_inventory[idx].nameid;
amount = item_list[k*2+1];
if( nameid > 0 && sd->inventory.u.items_inventory[idx].identify == 0 ){
clif_msg_skill(sd,GN_CHANGEMATERIAL,ITEM_UNIDENTIFIED);
return 0;
}
if (nameid == mat.first && (amount - p * mat.second) >= mat.second && (amount - p * mat.second) % mat.second == 0) // must be in exact amount
c++; // match
}
p++;
} while(n == j && c == n);
p--;
if ( p > 0 ) {
skill_produce_mix(sd,GN_CHANGEMATERIAL,skill_produce_db[i].nameid,0,0,0,p,i);
return 1;
}
p++;
} while(n == data->materials.size() && c == n);
p--;
if ( p > 0 ) {
skill_produce_mix(sd,GN_CHANGEMATERIAL,datait.second->nameid,0,0,0,p, datait.second);
return 1;
}
}
@ -24574,48 +24570,222 @@ static bool skill_parse_row_nocastdb(char* split[], int columns, int current)
return true;
}
/** Reads Produce db
* Structure: ProduceItemID,ItemLV,RequireSkill,Requireskill_lv,MaterialID1,MaterialAmount1,...
bool SkillProduceDatabase::add_itemconsumed(const ryml::NodeRef& node, std::shared_ptr<s_skill_produce_db_entry> &entry, bool isConsumed) {
for (const auto &it : node) {
if (this->nodeExists(it, "Clear")) {
std::string item_name;
if (!this->asString(it, "Clear", item_name))
return 0;
std::shared_ptr<item_data> item = item_db.search_aegisname(item_name.c_str());
if (item == nullptr) {
this->invalidWarning(it["Clear"], "Item %s does not exist.\n", item_name.c_str());
return 0;
}
if (entry->materials.erase(item->nameid) == 0)
this->invalidWarning(it["Clear"], "Item %s was not defined.\n", item_name.c_str());
continue;
}
std::string item_name;
if (!this->asString(it, "Item", item_name))
return 0;
std::shared_ptr<item_data> item = item_db.search_aegisname(item_name.c_str());
if (item == nullptr) {
this->invalidWarning(it["Item"], "Item %s does not exist.\n", item_name.c_str());
return 0;
}
uint16 amount;
if (!isConsumed)
amount = 0;
else {
if (!this->asUInt16Rate(it, "Amount", amount, MAX_AMOUNT))
return 0;
}
entry->materials[item->nameid] = amount;
}
return 1;
}
const std::string SkillProduceDatabase::getDefaultLocation() {
return std::string(db_path) + "/produce_db.yml";
}
/**
* Reads and parses an entry from the produce_db.
* @param node: YAML node containing the entry.
* @return count of successfully parsed rows
*/
static bool skill_parse_row_producedb(char* split[], int columns, int current)
{
unsigned short x, y;
unsigned short id = atoi(split[0]);
t_itemid nameid = 0;
bool found = false;
uint64 SkillProduceDatabase::parseBodyNode(const ryml::NodeRef &node) {
uint16 itemlv;
if (id >= ARRAYLENGTH(skill_produce_db)) {
ShowError("skill_parse_row_producedb: Maximum db entries reached.\n");
return false;
if (!this->asUInt16(node, "ItemLevel", itemlv))
return 0;
std::shared_ptr<s_skill_produce_db> produce = this->find(itemlv);
bool exists = produce != nullptr;
if (!exists) {
if (!this->nodesExist(node, { "Recipe" }))
return 0;
produce = std::make_shared<s_skill_produce_db>();
produce->itemlv = itemlv;
}
// Clear previous data, for importing support
memset(&skill_produce_db[id], 0, sizeof(skill_produce_db[id]));
// Import just for clearing/disabling from original data
if (!(nameid = strtoul(split[1], nullptr, 10))) {
//ShowInfo("skill_parse_row_producedb: Product list with ID %d removed from list.\n", id);
return true;
t_itemid nameid;
const ryml::NodeRef &subNode = node["Recipe"];
for (const auto &subit : subNode) {
std::string produced_name;
if (this->nodeExists(subit, "Clear")) {
if (!this->asString(subit, "Clear", produced_name))
return 0;
std::shared_ptr<item_data> item = item_db.search_aegisname(produced_name.c_str());
if (item == nullptr) {
this->invalidWarning(subit["Clear"], "Item %s does not exist.\n", produced_name.c_str());
return 0;
}
nameid = item->nameid;
if (produce->data.erase(nameid) == 0)
this->invalidWarning(subit["Clear"], "Item %s was not defined.\n", produced_name.c_str());
continue;
}
if (!this->asString(subit, "Product", produced_name))
return 0;
std::shared_ptr<item_data> item = item_db.search_aegisname(produced_name.c_str());
if (item == nullptr) {
this->invalidWarning(subit["Product"], "Item %s does not exist.\n", produced_name.c_str());
return 0;
}
nameid = item->nameid;
bool id_exists = produce->data.count(nameid) != 0;
std::shared_ptr<s_skill_produce_db_entry> entry;
if (id_exists)
entry = produce->data[nameid];
else {
entry = std::make_shared<s_skill_produce_db_entry>();
entry->nameid = nameid;
}
entry->itemlv = itemlv;
if (this->nodeExists(subit, "BaseRate")) { // note: BaseRate is only used for skill changematerial (itemlv 26)
uint16 baserate;
if (!this->asUInt16Rate(subit, "BaseRate", baserate, 1000))
return 0;
entry->baserate = baserate;
} else {
if (!id_exists) {
entry->baserate = 1000;
}
}
if (this->nodeExists(subit, "Make")) { // note: Quantity is only used for skill changematerial (itemlv 26)
const ryml::NodeRef &QuantityNode = subit["Make"];
for (const auto &Quantityit : QuantityNode) {
uint16 amount;
if (!this->asUInt16Rate(Quantityit, "Amount", amount, MAX_AMOUNT))
return 0;
uint16 rate;
if (this->nodeExists(Quantityit, "Rate")) {
if (!this->asUInt16(Quantityit, "Rate", rate))
return 0;
if (rate == 0) {
if (entry->qty.erase(amount) == 0)
this->invalidWarning(Quantityit["Rate"], "Amount %hu was not defined.\n", amount);
continue;
}
if (rate > 1000) {
this->invalidWarning(Quantityit["Rate"], "Rate %hu can't be higher than 1000, capping.\n", rate);
rate = 1000;
}
} else {
rate = 1000;
}
entry->qty[amount] = rate;
}
}
if (this->nodeExists(subit, "SkillName")) {
std::string skill_name;
if (!this->asString(subit, "SkillName", skill_name))
return 0;
uint16 skill_id = skill_name2id(skill_name.c_str());
if (!skill_id) {
this->invalidWarning(subit["SkillName"], "Invalid skill name \"%s\", skipping.\n", skill_name.c_str());
return 0;
}
entry->req_skill = skill_id;
}
if (this->nodeExists(subit, "SkillLevel")) {
uint16 skill_lv;
if (!this->asUInt16(subit, "SkillLevel", skill_lv))
return 0;
entry->req_skill_lv = static_cast<uint8>(skill_lv);
} else {
if (!id_exists) {
entry->req_skill_lv = 1;
}
}
if (this->nodeExists(subit, "Consumed")) {
if (!this->add_itemconsumed(subit["Consumed"], entry, true))
return 0;
}
if (this->nodeExists(subit, "NotConsumed")) {
if (!this->add_itemconsumed(subit["NotConsumed"], entry, false))
return 0;
}
if (!id_exists) {
produce->data.insert({ nameid, entry });
this->total_id++;
}
}
if (!item_db.exists(nameid)) {
ShowError("skill_parse_row_producedb: Invalid item %u.\n", nameid);
return false;
}
if (!exists)
this->put(itemlv, produce);
skill_produce_db[id].nameid = nameid;
skill_produce_db[id].itemlv = atoi(split[2]);
skill_produce_db[id].req_skill = atoi(split[3]);
skill_produce_db[id].req_skill_lv = atoi(split[4]);
for (x = 5, y = 0; x+1 < columns && split[x] && split[x+1] && y < MAX_PRODUCE_RESOURCE; x += 2, y++) {
skill_produce_db[id].mat_id[y] = strtoul(split[x], nullptr, 10);
skill_produce_db[id].mat_amount[y] = atoi(split[x+1]);
}
if (!found)
skill_produce_count++;
return true;
return 1;
}
const std::string SkillArrowDatabase::getDefaultLocation() {
@ -24764,62 +24934,6 @@ uint64 AbraDatabase::parseBodyNode(const ryml::NodeRef& node) {
return 1;
}
/** Reads change material db
* Structure: ProductID,BaseRate,MakeAmount1,MakeAmountRate1...,MakeAmount5,MakeAmountRate5
*/
static bool skill_parse_row_changematerialdb(char* split[], int columns, int current)
{
uint16 id = atoi(split[0]);
t_itemid nameid = strtoul(split[1], nullptr, 10);
short rate = atoi(split[2]);
bool found = false;
int x, y;
if (id >= MAX_SKILL_CHANGEMATERIAL_DB) {
ShowError("skill_parse_row_changematerialdb: Maximum amount of entries reached (%d), increase MAX_SKILL_CHANGEMATERIAL_DB\n",MAX_SKILL_CHANGEMATERIAL_DB);
return false;
}
// Clear previous data, for importing support
if (skill_changematerial_db[id].nameid > 0) {
found = true;
memset(&skill_changematerial_db[id], 0, sizeof(skill_changematerial_db[id]));
}
// Import just for clearing/disabling from original data
// NOTE: If import for disabling, better disable list from produce_db instead of here, or creation just failed with deleting requirements.
if (nameid == 0) {
memset(&skill_changematerial_db[id], 0, sizeof(skill_changematerial_db[id]));
//ShowInfo("skill_parse_row_changematerialdb: Change Material list with ID %d removed from list.\n", id);
return true;
}
// Entry must be exists in skill_produce_db and with required skill GN_CHANGEMATERIAL
for (x = 0; x < MAX_SKILL_PRODUCE_DB; x++) {
if (skill_produce_db[x].nameid == nameid)
if( skill_produce_db[x].req_skill == GN_CHANGEMATERIAL )
break;
}
if (x >= MAX_SKILL_PRODUCE_DB) {
ShowError("skill_parse_row_changematerialdb: Not supported item ID (%u) for Change Material. \n", nameid);
return false;
}
skill_changematerial_db[id].nameid = nameid;
skill_changematerial_db[id].rate = rate;
for (x = 3, y = 0; x+1 < columns && split[x] && split[x+1] && y < MAX_SKILL_CHANGEMATERIAL_SET; x += 2, y++) {
skill_changematerial_db[id].qty[y] = atoi(split[x]);
skill_changematerial_db[id].qty_rate[y] = atoi(split[x+1]);
}
if (!found)
skill_changematerial_count++;
return true;
}
/**
* Reads skill damage adjustment
* @author [Lilith]
@ -24900,10 +25014,6 @@ static void skill_readdb(void) {
//add other path here
};
memset(skill_produce_db,0,sizeof(skill_produce_db));
memset(skill_changematerial_db,0,sizeof(skill_changematerial_db));
skill_produce_count = skill_changematerial_count = 0;
skill_db.load();
for(i=0; i<ARRAYLENGTH(dbsubpath); i++){
@ -24921,9 +25031,6 @@ static void skill_readdb(void) {
}
sv_readdb(dbsubpath2, "skill_nocast_db.txt" , ',', 2, 2, -1, skill_parse_row_nocastdb, i > 0);
sv_readdb(dbsubpath2, "produce_db.txt" , ',', 5, 5+2*MAX_PRODUCE_RESOURCE, MAX_SKILL_PRODUCE_DB, skill_parse_row_producedb, i > 0);
sv_readdb(dbsubpath1, "skill_changematerial_db.txt" , ',', 5, 5+2*MAX_SKILL_CHANGEMATERIAL_SET, MAX_SKILL_CHANGEMATERIAL_DB, skill_parse_row_changematerialdb, i > 0);
sv_readdb(dbsubpath1, "skill_damage_db.txt" , ',', 4, 3+SKILLDMG_MAX, -1, skill_parse_row_skilldamage, i > 0);
aFree(dbsubpath1);
@ -24934,6 +25041,7 @@ static void skill_readdb(void) {
magic_mushroom_db.load();
reading_spellbook_db.load();
skill_arrow_db.load();
skill_produce_db.load();
skill_init_unit_layout();
skill_init_nounit_layout();
@ -24945,6 +25053,7 @@ void skill_reload (void) {
magic_mushroom_db.clear();
reading_spellbook_db.clear();
skill_arrow_db.clear();
skill_produce_db.clear();
skill_readdb();
@ -24989,6 +25098,7 @@ void do_final_skill(void)
magic_mushroom_db.clear();
reading_spellbook_db.clear();
skill_arrow_db.clear();
skill_produce_db.clear();
db_destroy(skillunit_db);
db_destroy(skillusave_db);

View File

@ -28,8 +28,6 @@ struct s_skill_unit_group;
struct status_change_entry;
class status_change;
#define MAX_SKILL_PRODUCE_DB 300 /// Max Produce DB
#define MAX_PRODUCE_RESOURCE 12 /// Max Produce requirements
#define MAX_SKILL_LEVEL 13 /// Max Skill Level (for skill_db storage)
#define MAX_MOBSKILL_LEVEL 100 /// Max monster skill level (on skill usage)
#define MAX_SKILL_CRIMSON_MARKER 3 /// Max Crimson Marker targets (RL_C_MARKER)
@ -439,15 +437,38 @@ enum e_skill_blown {
};
/// Create Database item
struct s_skill_produce_db {
struct s_skill_produce_db_entry {
t_itemid nameid; /// Product ID
unsigned short req_skill; /// Required Skill
unsigned char req_skill_lv, /// Required Skill Level
uint16 req_skill; /// Required Skill
uint16 req_skill_lv, /// Required Skill Level
itemlv; /// Item Level
t_itemid mat_id[MAX_PRODUCE_RESOURCE]; /// Materials needed
unsigned short mat_amount[MAX_PRODUCE_RESOURCE]; /// Amount of each materials
std::unordered_map<t_itemid, uint16> materials;
// additional rates/quantity data for skill_changematerial
uint16 baserate;
std::unordered_map<uint16, uint16> qty;
};
extern struct s_skill_produce_db skill_produce_db[MAX_SKILL_PRODUCE_DB];
struct s_skill_produce_db {
uint16 itemlv; /// Item Level
std::unordered_map<t_itemid, std::shared_ptr<s_skill_produce_db_entry>> data; /// item, entry
};
class SkillProduceDatabase : public TypesafeYamlDatabase<uint16, s_skill_produce_db> {
private:
uint16 total_id = 0;
public:
SkillProduceDatabase() : TypesafeYamlDatabase("PRODUCE_DB", 1) {
}
const std::string getDefaultLocation() override;
uint64 parseBodyNode(const ryml::NodeRef& node) override;
bool add_itemconsumed(const ryml::NodeRef& node, std::shared_ptr<s_skill_produce_db_entry> &entry, bool isConsumed);
};
extern SkillProduceDatabase skill_produce_db;
/// Creating database arrow
struct s_skill_arrow_db {
@ -621,8 +642,8 @@ bool skill_isNotOk_mercenary(uint16 skill_id, s_mercenary_data *md);
bool skill_isNotOk_npcRange(struct block_list *src, uint16 skill_id, uint16 skill_lv, int pos_x, int pos_y);
// Item creation
short skill_can_produce_mix( map_session_data *sd, t_itemid nameid, int trigger, int qty);
bool skill_produce_mix( map_session_data *sd, uint16 skill_id, t_itemid nameid, int slot1, int slot2, int slot3, int qty, short produce_idx );
std::shared_ptr<s_skill_produce_db_entry> skill_can_produce_mix(map_session_data *sd, t_itemid nameid, int trigger, int qty);
bool skill_produce_mix( map_session_data *sd, uint16 skill_id, t_itemid nameid, int slot1, int slot2, int slot3, int qty, std::shared_ptr<s_skill_produce_db_entry> produce );
bool skill_arrow_create( map_session_data *sd, t_itemid nameid);

View File

@ -156,6 +156,16 @@ static void skilltree_txt_data(const std::string &modePath, const std::string &f
sv_readdb(modePath.c_str(), "skill_tree.txt", ',', 3 + MAX_PC_SKILL_REQUIRE * 2, 5 + MAX_PC_SKILL_REQUIRE * 2, -1, pc_readdb_skilltree, false);
}
// Produce database data to memory
static void produce_txt_data(const std::string &modePath, const std::string &fixedPath) {
skill_produce.clear();
if (fileExists(modePath + "/produce_db.txt"))
sv_readdb(modePath.c_str(), "produce_db.txt", ',', 5, 5+2*MAX_PRODUCE_RESOURCE, MAX_SKILL_PRODUCE_DB, skill_parse_row_producedb, false);
if (fileExists(fixedPath + "/skill_changematerial_db.txt"))
sv_readdb(fixedPath.c_str(), "skill_changematerial_db.txt", ',', 5, 5+2*MAX_SKILL_CHANGEMATERIAL_SET, MAX_SKILL_CHANGEMATERIAL_DB, skill_parse_row_changematerialdb, false);
}
template<typename Func>
bool process( const std::string& type, uint32 version, const std::vector<std::string>& paths, const std::string& name, Func lambda, const std::string& rename = "" ){
for( const std::string& path : paths ){
@ -560,13 +570,28 @@ bool Csv2YamlTool::initialize( int argc, char* argv[] ){
})) {
return 0;
}
produce_txt_data(path_db_mode, path_db);
if (!process("PRODUCE_DB", 1, { path_db_mode }, "produce_db", [](const std::string &path, const std::string &name_ext) -> bool {
return skill_producedb_yaml();
})) {
return 0;
}
produce_txt_data(path_db_import, path_db_import);
if (!process("PRODUCE_DB", 1, { path_db_import }, "produce_db", [](const std::string &path, const std::string &name_ext) -> bool {
return skill_producedb_yaml();
})) {
return 0;
}
// TODO: add implementations ;-)
homunculus_txt_data(path_db_import, path_db_import);
if (!process("HOMUNCULUS_DB", 1, { path_db_import }, "homunculus_db", [](const std::string& path, const std::string& name_ext) -> bool {
return sv_readdb(path.c_str(), name_ext.c_str(), ',', 50, 50, MAX_HOMUNCULUS_CLASS, read_homunculusdb, false);
})) {
return 0;
}
return 0;
}
// TODO: add implementations ;-)
@ -2975,7 +3000,7 @@ static bool itemdb_read_db(const char* file) {
body << YAML::Key << "NoUse";
body << YAML::BeginMap;
if (it_nouse->second.override != 100)
body << YAML::Key << "Override" << YAML::Value << it_nouse->second.override;
body << YAML::Key << "Override" << YAML::Value << it_nouse->second.override;
body << YAML::Key << "Sitting" << YAML::Value << "true";
body << YAML::EndMap;
}
@ -2986,7 +3011,7 @@ static bool itemdb_read_db(const char* file) {
body << YAML::Key << "Trade";
body << YAML::BeginMap;
if (it_trade->second.override != 100)
body << YAML::Key << "Override" << YAML::Value << it_trade->second.override;
body << YAML::Key << "Override" << YAML::Value << it_trade->second.override;
if (it_trade->second.drop)
body << YAML::Key << "NoDrop" << YAML::Value << it_trade->second.drop;
if (it_trade->second.trade)
@ -5281,3 +5306,166 @@ static bool read_homunculusdb(char* str[], int columns, int current) {
int main( int argc, char *argv[] ){
return main_core<Csv2YamlTool>( argc, argv );
}
// Copied and adjusted from skill.cpp
static bool skill_parse_row_producedb(char* split[], int columns, int current) {
t_itemid nameid = static_cast<t_itemid>(strtoul(split[1], nullptr, 10));
if (nameid == 0) {
ShowError("skill_parse_row_producedb: Removing an item for this DB must be done manually. Skipping.\n");
return false;
}
std::string *item_name = util::umap_find(aegis_itemnames, nameid);
if (!item_name) {
ShowError("skill_parse_row_producedb: Invalid item %u.\n", nameid);
return false;
}
uint16 skill_id = static_cast<uint16>(strtoul(split[3], nullptr, 10));
std::string* skill_name = util::umap_find( aegis_skillnames, skill_id );
if (skill_id != 0 && skill_name == nullptr) {
ShowError( "Skill name for skill id %hu is not known.\n", skill_id );
return false;
}
s_skill_produce_db_csv entry = {};
uint32 skill_lv = strtoul(split[4], nullptr, 10);
uint32 itemlv = strtoul(split[2], nullptr, 10);
entry.produced_name = *item_name;
if (skill_name != nullptr) {
entry.req_skill_name = *skill_name;
entry.req_skill_lv = skill_lv;
}
for (uint8 x = 5; x+1 < columns && split[x] && split[x+1]; x += 2) {
nameid = static_cast<t_itemid>(strtoul(split[x], nullptr, 10));
item_name = util::umap_find(aegis_itemnames, nameid);
if (!item_name) {
ShowError("skill_parse_row_producedb: Invalid item %u.\n", nameid);
return false;
}
uint32 amount = strtoul(split[x+1], nullptr, 10);
if (amount == 0)
entry.item_notconsumed.push_back(*item_name);
else
entry.item_consumed[ *item_name ] = amount;
}
const auto &exists = skill_produce.find(itemlv);
if (exists != skill_produce.end())
exists->second.push_back(entry);
else {
std::vector<s_skill_produce_db_csv> produce;
produce.push_back(entry);
skill_produce.insert({ itemlv, produce });
}
return true;
}
// Copied and adjusted from skill.cpp
static bool skill_parse_row_changematerialdb(char* split[], int columns, int current)
{
t_itemid nameid = static_cast<t_itemid>(strtoul(split[1], nullptr, 10));
// Import just for clearing/disabling from original data
// NOTE: If import for disabling, better disable list from produce_db instead of here, or creation just failed with deleting requirements.
if (nameid == 0) {
ShowError("skill_parse_row_changematerialdb: Removing an item for this DB must be done manually. Skipping.\n");
return false;
}
std::string *produced_name = util::umap_find(aegis_itemnames, nameid);
if (!produced_name) {
ShowError("skill_parse_row_changematerialdb: Invalid item %u.\n", nameid);
return false;
}
s_skill_changematerial_db_csv item = {};
item.baserate = static_cast<uint16>(strtoul(split[2], nullptr, 10));
for (uint16 x = 3; x+1 < columns && split[x] && split[x+1]; x += 2) {
item.qty.insert({ static_cast<uint16>(strtoul(split[x], nullptr, 10)), static_cast<uint16>(strtoul(split[x+1], nullptr, 10)) });
}
skill_changematerial_db.insert({ *produced_name, item });
return true;
}
static bool skill_producedb_yaml(void) {
for (const auto &produceit : skill_produce) {
body << YAML::BeginMap;
body << YAML::Key << "ItemLevel" << YAML::Value << produceit.first;
body << YAML::Key << "Recipe";
body << YAML::BeginSeq;
for (const auto &it : produceit.second) {
body << YAML::BeginMap;
body << YAML::Key << "Product" << YAML::Value << it.produced_name;
// additional lines from skill_changematerial_db (which uses ItemLV 26)
if (produceit.first == 26) {
s_skill_changematerial_db_csv* changematerial = util::umap_find( skill_changematerial_db, it.produced_name );
if (changematerial != nullptr) {
if (changematerial->baserate != 1000)
body << YAML::Key << "BaseRate" << YAML::Value << changematerial->baserate;
if (!changematerial->qty.empty()) {
body << YAML::Key << "Make";
body << YAML::BeginSeq;
for (const auto &qit : changematerial->qty) {
body << YAML::BeginMap;
body << YAML::Key << "Amount" << YAML::Value << qit.first;
if (qit.second != 1000)
body << YAML::Key << "Rate" << YAML::Value << qit.second;
body << YAML::EndMap;
}
body << YAML::EndSeq;
}
}
}
if (it.req_skill_lv > 0) {
body << YAML::Key << "SkillName" << YAML::Value << it.req_skill_name;
body << YAML::Key << "SkillLevel" << YAML::Value << it.req_skill_lv;
}
if (!it.item_consumed.empty()) {
body << YAML::Key << "Consumed";
body << YAML::BeginSeq;
for (const auto &itemit : it.item_consumed) {
body << YAML::BeginMap;
body << YAML::Key << "Item" << YAML::Value << itemit.first;
body << YAML::Key << "Amount" << YAML::Value << itemit.second;
body << YAML::EndMap;
}
body << YAML::EndSeq;
}
if (!it.item_notconsumed.empty()) {
body << YAML::Key << "NotConsumed";
body << YAML::BeginSeq;
for (const auto &itemit : it.item_notconsumed) {
body << YAML::BeginMap;
body << YAML::Key << "Item" << YAML::Value << itemit;
body << YAML::EndMap;
}
body << YAML::EndSeq;
}
body << YAML::EndMap;
}
body << YAML::EndSeq;
body << YAML::EndMap;
}
return true;
}

View File

@ -42,6 +42,10 @@ namespace rathena{
///Maximum amount of items a combo may require
#define MAX_ITEMS_PER_COMBO 6
#define MAX_HOM_SKILL_REQUIRE 5
#define MAX_SKILL_CHANGEMATERIAL_DB 75
#define MAX_SKILL_CHANGEMATERIAL_SET 3
#define MAX_SKILL_PRODUCE_DB 300 /// Max Produce DB
#define MAX_PRODUCE_RESOURCE 12 /// Max Produce requirements
struct s_skill_tree_entry_csv {
std::string skill_name;
@ -65,6 +69,23 @@ std::unordered_map<uint16, s_skill_db> skill_nearnpc;
std::unordered_map<int32, std::vector<s_homun_skill_tree_entry>> hom_skill_tree;
struct s_skill_produce_db_csv {
std::string produced_name,
req_skill_name;
uint32 req_skill_lv,
itemlv;
std::map<std::string, uint32> item_consumed;
std::vector<std::string> item_notconsumed;
};
std::map<uint32, std::vector<s_skill_produce_db_csv>> skill_produce;
struct s_skill_changematerial_db_csv {
uint16 baserate;
std::map<uint16, uint16> qty;
};
std::unordered_map<std::string, s_skill_changematerial_db_csv> skill_changematerial_db;
static unsigned int level_penalty[3][CLASS_MAX][MAX_LEVEL * 2 + 1];
struct s_item_flag_csv2yaml {
@ -508,6 +529,9 @@ static bool mob_parse_row_chatdb(char* fields[], int columns, int current);
static bool read_homunculus_expdb(const char* file);
static bool mob_readdb_group(char* str[], int columns, int current);
static bool mob_readdb_group_yaml(void);
static bool skill_parse_row_producedb(char* fields[], int columns, int current);
static bool skill_producedb_yaml();
static bool skill_parse_row_changematerialdb(char* fields[], int columns, int current);
static bool skill_parse_row_createarrowdb(char* fields[], int columns, int current);
static bool pc_read_statsdb(const char* file);
static bool guild_read_castledb(char* str[], int columns, int current);