Sfoglia il codice sorgente

Refine overhaul (#2295)

* Converted refine_db.txt to refine_db.yml
* Refine success rates can now be set in refine_db.yml. rAthena's default NPCs will respect this database by default.
* Added shadow equipment refiner
Thanks to @Akkarinage @aleos89 @Atemo and @Mikegyver for their inputs.
Jittapan Pluemsumran 7 anni fa
parent
commit
e24d30a711

+ 5 - 0
conf/battle/items.conf

@@ -110,3 +110,8 @@ default_bind_on_equip: 4
 // no = Bound items are unable to be sold at Itemshops
 // yes = Bound items are able to be sold at Itemshops
 allow_bound_sell: no
+
+// Turn on event refine chance (see db/{pre-}re/refine_db.yml)
+// no = normal refine chances in effect (official/default value)
+// yes = event refine chances in effect
+event_refine_chance: no

+ 0 - 32
db/import-tmpl/refine_db.txt

@@ -1,32 +0,0 @@
-// Refine Database [Renewal]
-//
-// Structure of Database:
-// Type,Stats per level,Random bonus start level,Random bonus value,Chance+1:Bonus+1,Chance+2:Bonus+2,Chance+3:Bonus+3,...
-//
-// For armors, values of 100 add 1 armor defense.
-// For weapons, values of 100 add 1 ATK&MATK.
-//
-// Type:
-//	0 - Armors
-//	1 - Level 1 weapons
-//	2 - Level 2 weapons
-//	3 - Level 3 weapons
-//	4 - Level 4 weapons
-//
-// Stats per level:
-// This value is applied for every upgrade level.
-//
-// Random bonus start level:
-// This value specifies the start point for those levels that give a random bonus value (usually the first unsafe upgrade).
-//
-// Random bonus value:
-// A random number between 0 and (Random bonus start level - Upgrade level + 1) * this value is applied for all upgrades past
-// Random bonus start level. This is only applied for weapons, and not displayed client-side.
-//
-// Chance:
-// 100 = 100%
-//
-// Notes:
-// Changing the number of upgrade levels requires modifying MAX_REFINE in src/map/status.h.
-// For Renewal Armors, there may or may not be another bonus, according to iRO wiki: Every upgrade gives floor[( 3 + current upgrade ) / 4] equipment DEF)
-

+ 20 - 0
db/import-tmpl/refine_db.yml

@@ -0,0 +1,20 @@
+# This file is a part of rAthena++.
+#   Copyright(C) 2017 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/>.
+#
+###########################################################################
+# Custom Refine Database
+###########################################################################

+ 0 - 41
db/pre-re/refine_db.txt

@@ -1,41 +0,0 @@
-// Refine Database [Pre-Renewal]
-//
-// Structure of Database:
-// Type,Stats per level,Random bonus start level,Random bonus value,Chance+1:Bonus+1,Chance+2:Bonus+2,Chance+3:Bonus+3,...
-//
-// For armors, values of 100 add 1 armor defense.
-// For weapons, values of 100 add 1 ATK.
-//
-// Type:
-//	0 - Armors
-//	1 - Level 1 weapons
-//	2 - Level 2 weapons
-//	3 - Level 3 weapons
-//	4 - Level 4 weapons
-//
-// Stats per level:
-// This value is applied for every upgrade level.
-//
-// Random bonus start level:
-// This value specifies the start point for those levels that give a random bonus value.
-//
-// Random bonus value:
-// A random number between 0 and (Random bonus start level - Upgrade level + 1) * this value is applied for all upgrades past
-// Random bonus start level (usually the first unsafe upgrade). This is only applied for weapons, and not displayed client-side.
-//
-// Chance:
-// 100 = 100%
-//
-// Notes:
-// Changing the number of upgrade levels requires modifying MAX_REFINE in src/map/status.h.
-
-// Armors
-0,70,0,0,100:0,100:0,100:0,100:0,60:0,40:0,40:0,20:0,20:0,10:0
-// Level 1 weapons
-1,200,8,300,100:0,100:0,100:0,100:0,100:0,100:0,100:0,60:0,40:0,20:0
-// Level 2 weapons
-2,300,7,500,100:0,100:0,100:0,100:0,100:0,100:0,60:0,40:0,20:0,20:0
-// Level 3 weapons
-3,500,6,800,100:0,100:0,100:0,100:0,100:0,60:0,50:0,20:0,20:0,20:0
-// Level 4 weapons
-4,700,5,1300,100:0,100:0,100:0,100:0,60:0,40:0,40:0,20:0,20:0,10:0

+ 235 - 0
db/pre-re/refine_db.yml

@@ -0,0 +1,235 @@
+# This file is a part of rAthena++.
+#   Copyright(C) 2017 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/>.
+#
+###########################################################################
+# Pre-Renewal Refine Database
+###########################################################################
+Armor:
+  StatsPerLevel: 66
+  RandomBonusStartLevel: 0
+  RandomBonusValue: 0
+  Costs:
+    - Type: REFINE_COST_NORMAL
+      Price: 2000
+      Material: 985
+    - Type: REFINE_COST_ENRICHED
+      Price: 2000
+      Material: 7619
+  Rates:
+    - Level: 5
+      NormalChance: 60
+      EnrichedChance: 90
+      EventNormalChance: 60
+      EventEnrichedChance: 95
+    - Level: 6
+      NormalChance: 40
+      EnrichedChance: 70
+      EventNormalChance: 40
+      EventEnrichedChance: 80
+    - Level: 7
+      NormalChance: 40
+      EnrichedChance: 70
+      EventNormalChance: 40
+      EventEnrichedChance: 80
+    - Level: 8
+      NormalChance: 20
+      EnrichedChance: 40
+      EventNormalChance: 20
+      EventEnrichedChance: 50
+    - Level: 9
+      NormalChance: 20
+      EnrichedChance: 40
+      EventNormalChance: 20
+      EventEnrichedChance: 50
+    - Level: 10
+      NormalChance: 9
+      EnrichedChance: 20
+      EventNormalChance: 9
+      EventEnrichedChance: 35
+WeaponLv1:
+  StatsPerLevel: 200
+  RandomBonusStartLevel: 8
+  RandomBonusValue: 300
+  Costs:
+    - Type: REFINE_COST_NORMAL
+      Price: 50
+      Material: 1010
+    - Type: REFINE_COST_ENRICHED
+      Price: 2000
+      Material: 7620
+  Rates:
+    - Level: 8
+      NormalChance: 60
+      EnrichedChance: 90
+      EventNormalChance: 60
+      EventEnrichedChance: 95
+    - Level: 9
+      NormalChance: 40
+      EnrichedChance: 70
+      EventNormalChance: 40
+      EventEnrichedChance: 85
+    - Level: 10
+      NormalChance: 19
+      EnrichedChance: 30
+      EventNormalChance: 19
+      EventEnrichedChance: 55
+WeaponLv2:
+  StatsPerLevel: 300
+  RandomBonusStartLevel: 7
+  RandomBonusValue: 500
+  Costs:
+    - Type: REFINE_COST_NORMAL
+      Price: 200
+      Material: 1011
+    - Type: REFINE_COST_ENRICHED
+      Price: 2000
+      Material: 7620
+  Rates:
+    - Level: 7
+      NormalChance: 60
+      EnrichedChance: 90
+      EventNormalChance: 60
+      EventEnrichedChance: 95
+    - Level: 8
+      NormalChance: 40
+      EnrichedChance: 70
+      EventNormalChance: 40
+      EventEnrichedChance: 85
+    - Level: 9
+      NormalChance: 20
+      EnrichedChance: 40
+      EventNormalChance: 20
+      EventEnrichedChance: 60
+    - Level: 10
+      NormalChance: 19
+      EnrichedChance: 30
+      EventNormalChance: 19
+      EventEnrichedChance: 45
+WeaponLv3:
+  StatsPerLevel: 500
+  RandomBonusStartLevel: 6
+  RandomBonusValue: 800
+  Costs:
+    - Type: REFINE_COST_NORMAL
+      Price: 5000
+      Material: 984
+    - Type: REFINE_COST_ENRICHED
+      Price: 2000
+      Material: 7620
+  Rates:
+    - Level: 6
+      NormalChance: 60
+      EnrichedChance: 90
+      EventNormalChance: 60
+      EventEnrichedChance: 95
+    - Level: 7
+      NormalChance: 50
+      EnrichedChance: 80
+      EventNormalChance: 50
+      EventEnrichedChance: 90
+    - Level: 8
+      NormalChance: 20
+      EnrichedChance: 40
+      EventNormalChance: 20
+      EventEnrichedChance: 70
+    - Level: 9
+      NormalChance: 20
+      EnrichedChance: 40
+      EventNormalChance: 20
+      EventEnrichedChance: 60
+    - Level: 10
+      NormalChance: 19
+      EnrichedChance: 30
+      EventNormalChance: 19
+      EventEnrichedChance: 45
+WeaponLv4:
+  StatsPerLevel: 700
+  RandomBonusStartLevel: 5
+  RandomBonusValue: 1300
+  Costs:
+    - Type: REFINE_COST_NORMAL
+      Price: 20000
+      Material: 984
+    - Type: REFINE_COST_ENRICHED
+      Price: 2000
+      Material: 7620
+  Rates:
+    - Level: 5
+      NormalChance: 60
+      EnrichedChance: 90
+      EventNormalChance: 60
+      EventEnrichedChance: 95
+    - Level: 6
+      NormalChance: 40
+      EnrichedChance: 70
+      EventNormalChance: 40
+      EventEnrichedChance: 80
+    - Level: 7
+      NormalChance: 40
+      EnrichedChance: 70
+      EventNormalChance: 40
+      EventEnrichedChance: 80
+    - Level: 8
+      NormalChance: 20
+      EnrichedChance: 40
+      EventNormalChance: 20
+      EventEnrichedChance: 60
+    - Level: 9
+      NormalChance: 20
+      EnrichedChance: 40
+      EventNormalChance: 20
+      EventEnrichedChance: 50
+    - Level: 10
+      NormalChance: 9
+      EnrichedChance: 20
+      EventNormalChance: 9
+      EventEnrichedChance: 35
+Shadow:
+  StatsPerLevel: 0
+  RandomBonusStartLevel: 0
+  RandomBonusValue: 0
+  Rates:
+    - Level: 5
+      NormalChance: 60
+      EnrichedChance: 90
+      EventNormalChance: 60
+      EventEnrichedChance: 95
+    - Level: 6
+      NormalChance: 40
+      EnrichedChance: 70
+      EventNormalChance: 40
+      EventEnrichedChance: 80
+    - Level: 7
+      NormalChance: 40
+      EnrichedChance: 70
+      EventNormalChance: 40
+      EventEnrichedChance: 80
+    - Level: 8
+      NormalChance: 20
+      EnrichedChance: 40
+      EventNormalChance: 20
+      EventEnrichedChance: 50
+    - Level: 9
+      NormalChance: 20
+      EnrichedChance: 40
+      EventNormalChance: 20
+      EventEnrichedChance: 50
+    - Level: 10
+      NormalChance: 9
+      EnrichedChance: 20
+      EventNormalChance: 9
+      EventEnrichedChance: 35

+ 0 - 41
db/re/refine_db.txt

@@ -1,41 +0,0 @@
-// Refine Database [Renewal]
-//
-// Structure of Database:
-// Type,Stats per level,Random bonus start level,Random bonus value,Chance+1:Bonus+1,Chance+2:Bonus+2,Chance+3:Bonus+3,...
-//
-// For armors, values of 100 add 1 armor defense.
-// For weapons, values of 100 add 1 ATK&MATK.
-//
-// Type:
-//	0 - Armors
-//	1 - Level 1 weapons
-//	2 - Level 2 weapons
-//	3 - Level 3 weapons
-//	4 - Level 4 weapons
-//
-// Stats per level:
-// This value is applied for every upgrade level.
-//
-// Random bonus start level:
-// This value specifies the start point for those levels that give a random bonus value (usually the first unsafe upgrade).
-//
-// Random bonus value:
-// A random number between 0 and (Random bonus start level - Upgrade level + 1) * this value is applied for all upgrades past
-// Random bonus start level. This is only applied for weapons, and not displayed client-side.
-//
-// Chance:
-// 100 = 100%
-//
-// Notes:
-// Changing the number of upgrade levels requires modifying MAX_REFINE in src/map/status.h.
-// For Renewal Armors, there may or may not be another bonus, according to iRO wiki: Every upgrade gives floor[( 3 + current upgrade ) / 4] equipment DEF)
-
-0,0,0,0,100:100,100:100,100:100,100:100,60:200,40:200,40:200,20:200,20:300,9:300,8:300,8:300,8:400,8:400,7:400,7:400,7:500,7:500,5:500,5:500
-// Level 1 weapons
-1,200,8,300,100:0,100:0,100:0,100:0,100:0,100:0,100:0,60:0,40:0,19:0,18:0,18:0,18:0,18:0,18:0,17:300,17:300,17:300,15:300,15:300
-// Level 2 weapons
-2,300,7,500,100:0,100:0,100:0,100:0,100:0,100:0,60:0,40:0,20:0,19:0,18:0,18:0,18:0,18:0,18:0,17:600,17:600,17:600,15:600,15:600
-// Level 3 weapons
-3,500,6,800,100:0,100:0,100:0,100:0,100:0,60:0,50:0,20:0,20:0,19:0,18:0,18:0,18:0,18:0,18:0,17:900,17:900,17:900,15:900,15:900
-// Level 4 weapons
-4,700,5,1400,100:0,100:0,100:0,100:0,60:0,40:0,40:0,20:0,20:0,9:0,8:0,8:0,8:0,8:0,7:0,7:1200,7:1200,7:1200,5:1200,5:1200

+ 584 - 0
db/re/refine_db.yml

@@ -0,0 +1,584 @@
+# This file is a part of rAthena++.
+#   Copyright(C) 2017 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/>.
+#
+###########################################################################
+# Renewal Refine Database
+###########################################################################
+Armor:
+  StatsPerLevel: 0
+  RandomBonusStartLevel: 0
+  RandomBonusValue: 0
+  Costs:
+    - Type: REFINE_COST_NORMAL
+      Price: 2000
+      Material: 985
+    - Type: REFINE_COST_OVER10
+      Price: 100000
+      Material: 6223
+    - Type: REFINE_COST_HD
+      Price: 20000
+      Material: 6241
+    - Type: REFINE_COST_ENRICHED
+      Price: 2000
+      Material: 7619
+    - Type: REFINE_COST_OVER10_HD
+      Price: 100000
+      Material: 6225
+  Rates:
+    - Level: 1
+      Bonus: 100
+    - Level: 2
+      Bonus: 100
+    - Level: 3
+      Bonus: 100
+    - Level: 4
+      Bonus: 100
+    - Level: 5
+      NormalChance: 60
+      EnrichedChance: 90
+      EventNormalChance: 60
+      EventEnrichedChance: 95
+      Bonus: 200
+    - Level: 6
+      NormalChance: 40
+      EnrichedChance: 70
+      EventNormalChance: 40
+      EventEnrichedChance: 80
+      Bonus: 200
+    - Level: 7
+      NormalChance: 40
+      EnrichedChance: 70
+      EventNormalChance: 40
+      EventEnrichedChance: 80
+      Bonus: 200
+    - Level: 8
+      NormalChance: 20
+      EnrichedChance: 40
+      EventNormalChance: 20
+      EventEnrichedChance: 50
+      Bonus: 200
+    - Level: 9
+      NormalChance: 20
+      EnrichedChance: 40
+      EventNormalChance: 20
+      EventEnrichedChance: 50
+      Bonus: 300
+    - Level: 10
+      NormalChance: 9
+      EnrichedChance: 20
+      EventNormalChance: 9
+      EventEnrichedChance: 35
+      Bonus: 300
+    - Level: 11
+      NormalChance: 8
+      EnrichedChance: 8
+      EventNormalChance: 20
+      EventEnrichedChance: 20
+      Bonus: 300
+    - Level: 12
+      NormalChance: 8
+      EnrichedChance: 8
+      EventNormalChance: 20
+      EventEnrichedChance: 20
+      Bonus: 300
+    - Level: 13
+      NormalChance: 8
+      EnrichedChance: 8
+      EventNormalChance: 16
+      EventEnrichedChance: 16
+      Bonus: 400
+    - Level: 14
+      NormalChance: 8
+      EnrichedChance: 8
+      EventNormalChance: 16
+      EventEnrichedChance: 16
+      Bonus: 400
+    - Level: 15
+      NormalChance: 7
+      EnrichedChance: 7
+      EventNormalChance: 15
+      EventEnrichedChance: 15
+      Bonus: 400
+    - Level: 16
+      NormalChance: 7
+      EnrichedChance: 7
+      EventNormalChance: 15
+      EventEnrichedChance: 15
+      Bonus: 400
+    - Level: 17
+      NormalChance: 7
+      EnrichedChance: 7
+      EventNormalChance: 14
+      EventEnrichedChance: 14
+      Bonus: 500
+    - Level: 18
+      NormalChance: 7
+      EnrichedChance: 7
+      EventNormalChance: 14
+      EventEnrichedChance: 14
+      Bonus: 500
+    - Level: 19
+      NormalChance: 5
+      EnrichedChance: 5
+      EventNormalChance: 10
+      EventEnrichedChance: 10
+      Bonus: 500
+    - Level: 20
+      NormalChance: 5
+      EnrichedChance: 5
+      EventNormalChance: 10
+      EventEnrichedChance: 10
+      Bonus: 500
+WeaponLv1:
+  StatsPerLevel: 200
+  RandomBonusStartLevel: 8
+  RandomBonusValue: 300
+  Costs:
+    - Type: REFINE_COST_NORMAL
+      Price: 50
+      Material: 1010
+    - Type: REFINE_COST_OVER10
+      Price: 100000
+      Material: 6224
+    - Type: REFINE_COST_HD
+      Price: 20000
+      Material: 6240
+    - Type: REFINE_COST_ENRICHED
+      Price: 2000
+      Material: 7620
+    - Type: REFINE_COST_OVER10_HD
+      Price: 100000
+      Material: 6226
+  Rates:
+    - Level: 8
+      NormalChance: 60
+      EnrichedChance: 90
+      EventNormalChance: 60
+      EventEnrichedChance: 95
+    - Level: 9
+      NormalChance: 40
+      EnrichedChance: 70
+      EventNormalChance: 40
+      EventEnrichedChance: 85
+    - Level: 10
+      NormalChance: 19
+      EnrichedChance: 30
+      EventNormalChance: 19
+      EventEnrichedChance: 55
+    - Level: 11
+      NormalChance: 18
+      EnrichedChance: 18
+      EventNormalChance: 40
+      EventEnrichedChance: 40
+    - Level: 12
+      NormalChance: 18
+      EnrichedChance: 18
+      EventNormalChance: 40
+      EventEnrichedChance: 40
+    - Level: 13
+      NormalChance: 18
+      EnrichedChance: 18
+      EventNormalChance: 35
+      EventEnrichedChance: 35
+    - Level: 14
+      NormalChance: 18
+      EnrichedChance: 18
+      EventNormalChance: 35
+      EventEnrichedChance: 35
+    - Level: 15
+      NormalChance: 18
+      EnrichedChance: 18
+      EventNormalChance: 30
+      EventEnrichedChance: 30
+    - Level: 16
+      NormalChance: 17
+      EnrichedChance: 17
+      EventNormalChance: 30
+      EventEnrichedChance: 30
+      Bonus: 300
+    - Level: 17
+      NormalChance: 17
+      EnrichedChance: 17
+      EventNormalChance: 20
+      EventEnrichedChance: 20
+      Bonus: 300
+    - Level: 18
+      NormalChance: 17
+      EnrichedChance: 17
+      EventNormalChance: 20
+      EventEnrichedChance: 20
+      Bonus: 300
+    - Level: 19
+      NormalChance: 15
+      EnrichedChance: 15
+      EventNormalChance: 15
+      EventEnrichedChance: 15
+      Bonus: 300
+    - Level: 20
+      NormalChance: 15
+      EnrichedChance: 15
+      EventNormalChance: 15
+      EventEnrichedChance: 15
+      Bonus: 300
+WeaponLv2:
+  StatsPerLevel: 300
+  RandomBonusStartLevel: 7
+  RandomBonusValue: 500
+  Costs:
+    - Type: REFINE_COST_NORMAL
+      Price: 200
+      Material: 1011
+    - Type: REFINE_COST_OVER10
+      Price: 100000
+      Material: 6224
+    - Type: REFINE_COST_HD
+      Price: 20000
+      Material: 6240
+    - Type: REFINE_COST_ENRICHED
+      Price: 2000
+      Material: 7620
+    - Type: REFINE_COST_OVER10_HD
+      Price: 100000
+      Material: 6226
+  Rates:
+    - Level: 7
+      NormalChance: 60
+      EnrichedChance: 90
+      EventNormalChance: 60
+      EventEnrichedChance: 95
+    - Level: 8
+      NormalChance: 40
+      EnrichedChance: 70
+      EventNormalChance: 40
+      EventEnrichedChance: 85
+    - Level: 9
+      NormalChance: 20
+      EnrichedChance: 40
+      EventNormalChance: 20
+      EventEnrichedChance: 60
+    - Level: 10
+      NormalChance: 19
+      EnrichedChance: 30
+      EventNormalChance: 19
+      EventEnrichedChance: 45
+    - Level: 11
+      NormalChance: 18
+      EnrichedChance: 18
+      EventNormalChance: 40
+      EventEnrichedChance: 40
+    - Level: 12
+      NormalChance: 18
+      EnrichedChance: 18
+      EventNormalChance: 40
+      EventEnrichedChance: 40
+    - Level: 13
+      NormalChance: 18
+      EnrichedChance: 18
+      EventNormalChance: 35
+      EventEnrichedChance: 35
+    - Level: 14
+      NormalChance: 18
+      EnrichedChance: 18
+      EventNormalChance: 35
+      EventEnrichedChance: 35
+    - Level: 15
+      NormalChance: 18
+      EnrichedChance: 18
+      EventNormalChance: 30
+      EventEnrichedChance: 30
+    - Level: 16
+      NormalChance: 17
+      EnrichedChance: 17
+      EventNormalChance: 30
+      EventEnrichedChance: 30
+      Bonus: 600
+    - Level: 17
+      NormalChance: 17
+      EnrichedChance: 17
+      EventNormalChance: 20
+      EventEnrichedChance: 20
+      Bonus: 600
+    - Level: 18
+      NormalChance: 17
+      EnrichedChance: 17
+      EventNormalChance: 20
+      EventEnrichedChance: 20
+      Bonus: 600
+    - Level: 19
+      NormalChance: 15
+      EnrichedChance: 15
+      EventNormalChance: 15
+      EventEnrichedChance: 15
+      Bonus: 600
+    - Level: 20
+      NormalChance: 15
+      EnrichedChance: 15
+      EventNormalChance: 15
+      EventEnrichedChance: 15
+      Bonus: 600
+WeaponLv3:
+  StatsPerLevel: 500
+  RandomBonusStartLevel: 6
+  RandomBonusValue: 800
+  Costs:
+    - Type: REFINE_COST_NORMAL
+      Price: 5000
+      Material: 984
+    - Type: REFINE_COST_OVER10
+      Price: 100000
+      Material: 6224
+    - Type: REFINE_COST_HD
+      Price: 20000
+      Material: 6240
+    - Type: REFINE_COST_ENRICHED
+      Price: 2000
+      Material: 7620
+    - Type: REFINE_COST_OVER10_HD
+      Price: 100000
+      Material: 6226
+  Rates:
+    - Level: 6
+      NormalChance: 60
+      EnrichedChance: 90
+      EventNormalChance: 60
+      EventEnrichedChance: 95
+    - Level: 7
+      NormalChance: 50
+      EnrichedChance: 80
+      EventNormalChance: 50
+      EventEnrichedChance: 90
+    - Level: 8
+      NormalChance: 20
+      EnrichedChance: 40
+      EventNormalChance: 20
+      EventEnrichedChance: 70
+    - Level: 9
+      NormalChance: 20
+      EnrichedChance: 40
+      EventNormalChance: 20
+      EventEnrichedChance: 60
+    - Level: 10
+      NormalChance: 19
+      EnrichedChance: 30
+      EventNormalChance: 19
+      EventEnrichedChance: 45
+    - Level: 11
+      NormalChance: 18
+      EnrichedChance: 18
+      EventNormalChance: 40
+      EventEnrichedChance: 40
+    - Level: 12
+      NormalChance: 18
+      EnrichedChance: 18
+      EventNormalChance: 40
+      EventEnrichedChance: 40
+    - Level: 13
+      NormalChance: 18
+      EnrichedChance: 18
+      EventNormalChance: 35
+      EventEnrichedChance: 35
+    - Level: 14
+      NormalChance: 18
+      EnrichedChance: 18
+      EventNormalChance: 35
+      EventEnrichedChance: 35
+    - Level: 15
+      NormalChance: 18
+      EnrichedChance: 18
+      EventNormalChance: 30
+      EventEnrichedChance: 30
+    - Level: 16
+      NormalChance: 17
+      EnrichedChance: 17
+      EventNormalChance: 30
+      EventEnrichedChance: 30
+      Bonus: 900
+    - Level: 17
+      NormalChance: 17
+      EnrichedChance: 17
+      EventNormalChance: 20
+      EventEnrichedChance: 20
+      Bonus: 900
+    - Level: 18
+      NormalChance: 17
+      EnrichedChance: 17
+      EventNormalChance: 20
+      EventEnrichedChance: 20
+      Bonus: 900
+    - Level: 19
+      NormalChance: 15
+      EnrichedChance: 15
+      EventNormalChance: 15
+      EventEnrichedChance: 15
+      Bonus: 900
+    - Level: 20
+      NormalChance: 15
+      EnrichedChance: 15
+      EventNormalChance: 15
+      EventEnrichedChance: 15
+      Bonus: 900
+WeaponLv4:
+  StatsPerLevel: 700
+  RandomBonusStartLevel: 5
+  RandomBonusValue: 1400
+  Costs:
+    - Type: REFINE_COST_NORMAL
+      Price: 20000
+      Material: 984
+    - Type: REFINE_COST_OVER10
+      Price: 100000
+      Material: 6224
+    - Type: REFINE_COST_HD
+      Price: 20000
+      Material: 6240
+    - Type: REFINE_COST_ENRICHED
+      Price: 2000
+      Material: 7620
+    - Type: REFINE_COST_OVER10_HD
+      Price: 100000
+      Material: 6226
+  Rates:
+    - Level: 5
+      NormalChance: 60
+      EnrichedChance: 90
+      EventNormalChance: 60
+      EventEnrichedChance: 95
+    - Level: 6
+      NormalChance: 40
+      EnrichedChance: 70
+      EventNormalChance: 40
+      EventEnrichedChance: 80
+    - Level: 7
+      NormalChance: 40
+      EnrichedChance: 70
+      EventNormalChance: 40
+      EventEnrichedChance: 80
+    - Level: 8
+      NormalChance: 20
+      EnrichedChance: 40
+      EventNormalChance: 20
+      EventEnrichedChance: 60
+    - Level: 9
+      NormalChance: 20
+      EnrichedChance: 40
+      EventNormalChance: 20
+      EventEnrichedChance: 50
+    - Level: 10
+      NormalChance: 9
+      EnrichedChance: 20
+      EventNormalChance: 9
+      EventEnrichedChance: 35
+    - Level: 11
+      NormalChance: 8
+      EnrichedChance: 8
+      EventNormalChance: 20
+      EventEnrichedChance: 20
+    - Level: 12
+      NormalChance: 8
+      EnrichedChance: 8
+      EventNormalChance: 20
+      EventEnrichedChance: 20
+    - Level: 13
+      NormalChance: 8
+      EnrichedChance: 8
+      EventNormalChance: 16
+      EventEnrichedChance: 16
+    - Level: 14
+      NormalChance: 8
+      EnrichedChance: 8
+      EventNormalChance: 16
+      EventEnrichedChance: 16
+    - Level: 15
+      NormalChance: 7
+      EnrichedChance: 7
+      EventNormalChance: 15
+      EventEnrichedChance: 15
+    - Level: 16
+      NormalChance: 7
+      EnrichedChance: 7
+      EventNormalChance: 15
+      EventEnrichedChance: 15
+      Bonus: 1200
+    - Level: 17
+      NormalChance: 7
+      EnrichedChance: 7
+      EventNormalChance: 14
+      EventEnrichedChance: 14
+      Bonus: 1200
+    - Level: 18
+      NormalChance: 7
+      EnrichedChance: 7
+      EventNormalChance: 14
+      EventEnrichedChance: 14
+      Bonus: 1200
+    - Level: 19
+      NormalChance: 5
+      EnrichedChance: 5
+      EventNormalChance: 10
+      EventEnrichedChance: 10
+      Bonus: 1200
+    - Level: 20
+      NormalChance: 5
+      EnrichedChance: 5
+      EventNormalChance: 10
+      EventEnrichedChance: 10
+      Bonus: 1200
+Shadow:
+  StatsPerLevel: 0
+  RandomBonusStartLevel: 0
+  RandomBonusValue: 0
+  Costs:
+    - Type: REFINE_COST_NORMAL
+      Price: 20000
+      Material: 985
+    - Type: REFINE_COST_HD
+      Price: 20000
+      Material: 6241
+    - Type: REFINE_COST_ENRICHED
+      Price: 20000
+      Material: 7619
+  Rates:
+    - Level: 5
+      NormalChance: 60
+      EnrichedChance: 90
+      EventNormalChance: 60
+      EventEnrichedChance: 95
+    - Level: 6
+      NormalChance: 40
+      EnrichedChance: 70
+      EventNormalChance: 40
+      EventEnrichedChance: 80
+    - Level: 7
+      NormalChance: 40
+      EnrichedChance: 70
+      EventNormalChance: 40
+      EventEnrichedChance: 80
+    - Level: 8
+      NormalChance: 20
+      EnrichedChance: 40
+      EventNormalChance: 20
+      EventEnrichedChance: 50
+    - Level: 9
+      NormalChance: 20
+      EnrichedChance: 40
+      EventNormalChance: 20
+      EventEnrichedChance: 50
+    - Level: 10
+      NormalChance: 9
+      EnrichedChance: 20
+      EventNormalChance: 9
+      EventEnrichedChance: 35

+ 27 - 2
doc/script_commands.txt

@@ -2719,14 +2719,17 @@ Examples:
 
 ---------------------------------------
 
-*getequippercentrefinery(<equipment slot>{,<char_id>})
+*getequippercentrefinery(<equipment slot>{,<enriched>,<char_id>})
 
 This function calculates and returns the percent value chance to successfully
 refine the item found in the specified equipment slot of the invoking character
 by +1. There is no actual formula, the success rate for a given weapon level of
-a certain refine level is found in the db/refine_db.txt file. For a list of
+a certain refine level is found in the db/(pre-)re/refine_db.yml file. For a list of
 equipment slots see 'getequipid'.
 
+If enriched parameter is set to true, chance to successfully refine the item with
+enriched material is returned instead.
+
 These values can be displayed for the player to see, or used to calculate the
 random change of a refine succeeding or failing and then going through with it
 (which is what the official NPC refinery scripts use it for)
@@ -2737,6 +2740,28 @@ random change of a refine succeeding or failing and then going through with it
 
 ---------------------------------------
 
+*getequiprefinecost(<equipment slot>,<type>,<information>{,<char id>})
+
+This function returns refine cost for equipment in <equipment slot> based on
+passed arguments <type> and <information>.
+
+Valid cost types are:
+
+REFINE_COST_NORMAL     - For normal refining
+REFINE_COST_OVER10     - For refining over +10
+REFINE_COST_HD         - For refining with HD ores
+REFINE_COST_ENRICHED   - For refining with enriched ores
+REFINE_COST_OVER10_HD  - For refining over +10 with HD ores
+
+This function will return required cost for refining based on <information> argument.
+
+Valid information types are:
+
+REFINE_ZENY_COST       - Zeny
+REFINE_MATERIAL_ID     - Material Item ID
+
+---------------------------------------
+
 *getareadropitem("<map name>",<x1>,<y1>,<x2>,<y2>,<item>)
 
 This function will count all the items with the specified ID number lying on the

+ 5 - 22
npc/merchants/advanced_refiner.txt

@@ -1,22 +1,11 @@
 //===== rAthena Script =======================================
 //= Advanced Refiner
-//===== By: ==================================================
-//= L0ne_W0lf
-//===== Current Version: =====================================
-//= 1.6
-//===== Compatible With: =====================================
-//= rAthena Project
 //===== Description: =========================================
 //= [Official Conversion]
 //= Refiner that uses Enriched ores to increase upgrade success.
-//= After a conversation with Doddler, it's been established that
-//= the advanced refiner works similar the the "Bubble Gum" item.
-//= The success percentage is not "increased" however, if it fails
-//= You get a second try. This tries twice at the same time,
-//= effectively giving you a re-roll on your attempt.
 //= - Dialog is only partly official to iRO.
 //= - Uses the iRO position for this NPC.
-//===== Additional Comments: =================================
+//===== Changelog: ===========================================
 //= 1.0 First Version. [L0ne_W0lf]
 //= 1.1 Fixed a weird carriage return. o_o [L0ne_W0lf]
 //= 1.2 Optimizing refine method [Zephyrus]
@@ -26,6 +15,7 @@
 //= 1.4b Fixed coordinates. [Euphy]
 //= 1.5 Some official script updates. [Euphy]
 //= 1.6 Added VIP features. [Euphy]
+//= 1.7 Removed re-roll behavior. [Secret]
 //============================================================
 
 payon,157,146,6	script	Suhnbi#cash	85,{
@@ -65,19 +55,12 @@ payon,157,146,6	script	Suhnbi#cash	85,{
 		close;
 	}
 
-	// Make sure you have the neccessary items and Zeny to refine your items
-	// Determines chance of failure and verifies that you want to continue.
-	switch(getequipweaponlv(.@part)) {
-		case 1: callsub S_RefineValidate,1,7620,50,.@part; break;
-		case 2: callsub S_RefineValidate,2,7620,200,.@part; break;
-		case 3: callsub S_RefineValidate,3,7620,5000,.@part; break;
-		case 4: callsub S_RefineValidate,4,7620,20000,.@part; break;
-		default: callsub S_RefineValidate,0,7619,2000,.@part; break;
-	}
+	.@price = getequiprefinecost(.@part, REFINE_COST_ENRICHED, REFINE_ZENY_COST);
+	.@material = getequiprefinecost(.@part, REFINE_COST_ENRICHED, REFINE_MATERIAL_ID);
 
 	mes "[Suhnbi]";
 	mes "Clang! Clang! Clang!";
-	if (getequippercentrefinery(.@part) > rand(100) || getequippercentrefinery(.@part) > rand(100)) {
+	if (getequippercentrefinery(.@part, true) > rand(100)) {
 		successrefitem .@part;
 		next;
 		emotion e_no1;

+ 81 - 111
npc/merchants/refine.txt

@@ -38,7 +38,7 @@ geffen_in,110,172,0	script	Christopher#1	63,{
 				close;
 			}
 			getitem 986,1; // Anvil
-			set Zeny, Zeny-30000;
+			Zeny = Zeny-30000;
 			mes "[Christopher Guillenrow]";
 			mes "This is the cheapest one, but efficient enough to forge most items. Thank ye fer shopping at me workshop.  Feel free to come anytime, whenever ye need.";
 			close;
@@ -49,7 +49,7 @@ geffen_in,110,172,0	script	Christopher#1	63,{
 				close;
 			}
 			getitem 987,1; // Oridecon_Anvil
-			set Zeny, Zeny-120000;
+			Zeny = Zeny-120000;
 			mes "[Christopher Guillenrow]";
 			mes "Aye, friend ye have an eye for the anvil. This must be the proper anvil for a Blacksmith, eh? Thank ye fer shopping at me workshop.  Feel free to come anytime, whenever ye need.";
 			close;
@@ -60,7 +60,7 @@ geffen_in,110,172,0	script	Christopher#1	63,{
 				close;
 			}
 			getitem 988,1; // Golden_Anvil
-			set Zeny, Zeny-300000;
+			Zeny = Zeny-300000;
 			mes "[Christopher Guillenrow]";
 			mes "This one is the best among all me stuffs in me workshop! With this, ye can rule the Blacksmith world! Thank ye fer shopping at me workshop.  Feel free to come anytime, whenever ye need.";
 			close;
@@ -101,7 +101,7 @@ geffen_in,110,172,0	script	Christopher#1	63,{
 					break;
 				}
 			}
-			set .@sell,.@input * 150;
+			.@sell = .@input * 150;
 			if (Zeny < .@sell) {
 				mes "[Christopher Guillenrow]";
 				mes "I don't think I can let ye have this with the zeny ye have. I can't lose me money because of ye.";
@@ -113,7 +113,7 @@ geffen_in,110,172,0	script	Christopher#1	63,{
 				close;
 			}
 			getitem 612,.@input; // Portable_Furnace
-			set Zeny, Zeny-.@sell;
+			Zeny = Zeny-.@sell;
 			mes "[Christopher Guillenrow]";
 			mes "Thank ye fer shopping at me workshop. Feel free to come anytime, whenever ye need.";
 			close;
@@ -124,7 +124,7 @@ geffen_in,110,172,0	script	Christopher#1	63,{
 				close;
 			}
 			getitem 613,1; // Iron_Hammer
-			set Zeny, Zeny-1000;
+			Zeny = Zeny-1000;
 			mes "[Christopher Guillenrow]";
 			mes "Thank ye fer shopping at me workshop. Feel free to come anytime, whenever ye need.";
 			close;
@@ -135,7 +135,7 @@ geffen_in,110,172,0	script	Christopher#1	63,{
 				close;
 			}
 			getitem 614,1; // Golden_Hammer
-			set Zeny, Zeny-3000;
+			Zeny = Zeny-3000;
 			mes "[Christopher Guillenrow]";
 			mes "Thank ye fer shopping at me workshop. Feel free to come anytime, whenever ye need.";
 			close;
@@ -146,7 +146,7 @@ geffen_in,110,172,0	script	Christopher#1	63,{
 				close;
 			}
 			getitem 615,1; // Oridecon_Hammer
-			set Zeny, Zeny-5000;
+			Zeny = Zeny-5000;
 			mes "[Christopher Guillenrow]";
 			mes "Thank ye fer shopping at me workshop. Feel free to come anytime, whenever ye need.";
 			close;
@@ -182,7 +182,7 @@ geffen_in,110,172,0	script	Christopher#1	63,{
 					break;
 				}
 			}
-			set .@sell,.@input * 200;
+			.@sell = .@input * 200;
 			if (Zeny < .@sell) {
 				mes "[Christopher Guillenrow]";
 				mes "Ye don't have enough money. Ye know I can't sell this at a lower price... You know how the wifey nags about Zeny.";
@@ -194,7 +194,7 @@ geffen_in,110,172,0	script	Christopher#1	63,{
 				close;
 			}
 			getitem 1010,.@input; // Phracon
-			set Zeny, Zeny-.@sell;
+			Zeny = Zeny-.@sell;
 			mes "[Christopher Guillenrow]";
 			mes "Thank ye fer shopping at me workshop. Feel free to come anytime, whenever ye need.";
 			close;
@@ -220,7 +220,7 @@ geffen_in,110,172,0	script	Christopher#1	63,{
 					break;
 				}
 			}
-			set .@sell,.@input * 1000;
+			.@sell = .@input * 1000;
 			if (Zeny < .@sell) {
 				mes "[Christopher Guillenrow]";
 				mes "I don't think I can let ye have this with the zeny ye have. I can't lose me money because of ye.";
@@ -232,7 +232,7 @@ geffen_in,110,172,0	script	Christopher#1	63,{
 				close;
 			}
 			getitem 1011,.@input; // Emveretarcon
-			set Zeny, Zeny-.@sell;
+			Zeny = Zeny-.@sell;
 			mes "[Christopher Guillenrow]";
 			mes "Thank ye fer shopping at me workshop. Feel free to come anytime, whenever ye need, whenever ye want.";
 			close;
@@ -314,7 +314,7 @@ ein_in01,38,29,0	script	Paul Spanner	63,{
 				close;
 			}
 			getitem 986,1; //Anvil
-			set Zeny, Zeny-30000;
+			Zeny = Zeny-30000;
 			mes "[Paul Spanner]";
 			mes "It is the cheapest anvil which has the most basic ability.";
 			mes "Thank you for using my shop. If you need anything, just let me know.";
@@ -326,7 +326,7 @@ ein_in01,38,29,0	script	Paul Spanner	63,{
 				close;
 			}
 			getitem 987,1; //Oridecon_Anvil
-			set Zeny, Zeny-120000;
+			Zeny = Zeny-120000;
 			mes "[Paul Spanner]";
 			mes "Ah, you have an eye for anvil. A Blacksmith needs an anvil at least as good as this.";
 			mes "Thank you for using my shop. If you need anything, just let me know.";
@@ -338,7 +338,7 @@ ein_in01,38,29,0	script	Paul Spanner	63,{
 				close;
 			}
 			getitem 988,1; //Golden_Anvil
-			set Zeny, Zeny-300000;
+			Zeny = Zeny-300000;
 			mes "[Paul Spanner]";
 			mes "I can tell your ambition to become a good Blacksmith just by looking at you to choose this Golden Anvil!";
 			mes "This anvil will surely aid you in creating the best weapons.";
@@ -360,27 +360,27 @@ ein_in01,38,29,0	script	Paul Spanner	63,{
 		next;
 		switch(select("Mini Furnace - 150z.:Iron Hammer - 1,000z.:Golden Hammer - 3,000z.:Oridecon Hammer - 5,000z.:Cancel.")) {
 		case 1:
-			set .@item,612;
-			set .@item_cost,150;
-			set .@item_weight,200;
+			.@item = 612;
+			.@item_cost = 150;
+			.@item_weight = 200;
 			mes "[Paul Spanner]";
 			mes "You definately need this furnce to process ores!";
 			next;
 			break;
 		case 2:
-			set .@item,613;
-			set .@item_cost,1000;
-			set .@item_weight,200;
+			.@item = 613;
+			.@item_cost = 1000;
+			.@item_weight = 200;
 			break;
 		case 3:
-			set .@item,614;
-			set .@item_cost,3000;
-			set .@item_weight,300;
+			.@item = 614;
+			.@item_cost = 3000;
+			.@item_weight = 300;
 			break;
 		case 4:
-			set .@item,615;
-			set .@item_cost,5000;
-			set .@item_weight,400;
+			.@item = 615;
+			.@item_cost = 5000;
+			.@item_weight = 400;
 			break;
 		case 5:
 			mes "[Paul Spanner]";
@@ -406,7 +406,7 @@ ein_in01,38,29,0	script	Paul Spanner	63,{
 				break;
 			}
 		}
-		set .@sell,.@input * .@item_cost;
+		.@sell = .@input * .@item_cost;
 		if (Zeny < .@sell) {
 			mes "[Paul Spanner]";
 			mes "You don't have enough money. Sorry, I cannot sell them at a loss.";
@@ -417,7 +417,7 @@ ein_in01,38,29,0	script	Paul Spanner	63,{
 			mes "Hey, you look pale. Why don't you go lighten your weight first.";
 			close;
 		}
-		set Zeny, Zeny-.@sell;
+		Zeny = Zeny-.@sell;
 		getitem .@item,.@input;
 		mes "[Paul Spanner]";
 		mes "Thank you for using my shop. If you need anything, just let me know.";
@@ -429,12 +429,12 @@ ein_in01,38,29,0	script	Paul Spanner	63,{
 		next;
 		switch(select("Phracon - 200z.:Emveretarcon - 1,000z.:Quit.")) {
 		case 1:
-			set .@item,1010;
-			set .@item_price,200;
+			.@item = 1010;
+			.@item_price = 200;
 			break;
 		case 2:
-			set .@item,1011;
-			set .@item_price,1000;
+			.@item = 1011;
+			.@item_price = 1000;
 			break;
 		case 3:
 			mes "[Paul Spanner]";
@@ -460,7 +460,7 @@ ein_in01,38,29,0	script	Paul Spanner	63,{
 				break;
 			}
 		}
-		set .@sell,.@input * .@item_price;
+		.@sell = .@input * .@item_price;
 		if (Zeny < .@sell) {
 			mes "[Paul Spanner]";
 			mes "You don't have enough money. Sorry, I cannot sell them at a loss.";
@@ -472,7 +472,7 @@ ein_in01,38,29,0	script	Paul Spanner	63,{
 			close;
 		}
 		getitem .@item,.@input;
-		set Zeny, Zeny-.@sell;
+		Zeny = Zeny-.@sell;
 		mes "[Paul Spanner]";
 		mes "Thank you for using my shop. If you need anything, just let me know.";
 		close;
@@ -562,7 +562,7 @@ lhz_in02,282,20,7	script	Fulerr	869,{
 function	script	refinemain	{
 	disable_items;
 	.@npc_name$ = getarg(0);
-	set .@features,getarg(1);
+	.@features = getarg(1);
 	mes "["+ .@npc_name$ +"]";
 	mes "I'm the Armsmith.";
 	mes "I can refine all kinds of weapons, armor and equipment, so let me";
@@ -570,19 +570,19 @@ function	script	refinemain	{
 	next;
 
 	setarray .@indices[1], EQI_HEAD_TOP, EQI_ARMOR, EQI_HAND_L, EQI_HAND_R, EQI_GARMENT, EQI_SHOES, EQI_ACC_L, EQI_ACC_R, EQI_HEAD_MID, EQI_HEAD_LOW;
-	for(set .@i,1; .@i<getarraysize(.@indices); set .@i,.@i+1) {
+	for(.@i = 1; .@i<getarraysize(.@indices); ++.@i) {
 		if(getequipisequiped(.@indices[.@i])) {
-			set .@menu$, .@menu$ + F_getpositionname(.@indices[.@i]) + "-[" + getequipname(.@indices[.@i]) + "]";
-			set .@equipped,1;
+			.@menu$ = .@menu$ + F_getpositionname(.@indices[.@i]) + "-[" + getequipname(.@indices[.@i]) + "]";
+			.@equipped = 1;
 		}
-		set .@menu$, .@menu$ + ":";
+		.@menu$ = .@menu$ + ":";
 	}
 	if (.@equipped == 0) {
 		mes "["+ .@npc_name$ +"]";
 		mes "I don't think I can refine any items you have...";
 		close;
 	}
-	set .@part, .@indices[select(.@menu$)];
+	.@part = .@indices[select(.@menu$)];
 
 	if(!getequipisequiped(.@part)) { //custom check
 		mes "["+ .@npc_name$ +"]";
@@ -607,50 +607,20 @@ function	script	refinemain	{
 		mes "refined as it gets!";
 		close;
 	}
-	set .@refineitemid, getequipid(.@part); // save id of the item
-	set .@refinerycnt, getequiprefinerycnt(.@part); //save refinery count
-	switch(getequipweaponlv(.@part)){
-	case 0: 	//Refine Armor
-		set .@price,2000;
-		set .@material,985; //Elunium
-		set .@safe,4;
-		break;
-	case 1: 	//Refine Level 1 Weapon
-		set .@price,50;
-		set .@material,1010; //Phracon
-		set .@safe,7;
-		break;
-	case 2: 	//Refine Level 2 Weapon
-		set .@price,200;
-		set .@material,1011; //Emveretarcon
-		set .@safe,6;
-		break;
-	case 3: 	//Refine Level 3 Weapon
-		set .@price,5000;
-		set .@material,984; //Oridecon
-		set .@safe,5;
-		break;
-	case 4: 	//Refine Level 4 Weapon
-		set .@price,20000;
-		set .@material,984; //Oridecon
-		set .@safe,4;
-		break;
-	case 5: 	//Refine other stuff?
-		set .@price,2000;
-		set .@material,985; //Elunium
-		set .@safe,4;
-		break;
-	}
+	.@refineitemid = getequipid(.@part); // save id of the item
+	.@refinerycnt = getequiprefinerycnt(.@part); //save refinery count
+	.@price = getequiprefinecost(.@part, REFINE_COST_NORMAL, REFINE_ZENY_COST);
+	.@material = getequiprefinecost(.@part, REFINE_COST_NORMAL, REFINE_MATERIAL_ID);
 
 	// If the VIP system is enabled, the prices for non-VIP players are considerably higher.
 	if (VIP_SCRIPT && !vip_status(VIP_STATUS_ACTIVE)) {
 		switch(getequipweaponlv(.@part)) {
-			case 0: set .@price, .@price * 10; break;
-			case 1: set .@price, .@price * 40; break;
-			case 2: set .@price, .@price * 50; break;
-			case 3: set .@price, .@price * 2; break;
-			case 4: set .@price, .@price * 2; break;
-			case 5: set .@price, .@price * 10; break;
+			case 0: .@price = .@price * 10; break;
+			case 1: .@price = .@price * 40; break;
+			case 2: .@price = .@price * 50; break;
+			case 3: .@price = .@price * 2; break;
+			case 4: .@price = .@price * 2; break;
+			case 5: .@price = .@price * 10; break;
 		}
 	}
 
@@ -705,7 +675,7 @@ function	script	refinemain	{
 			mes "here all day if you need me.";
 			close;
 		}
-		set Zeny, Zeny-.@price;
+		Zeny = Zeny-.@price;
 		delitem .@material,1;
 
 		// anti-hack
@@ -723,7 +693,7 @@ function	script	refinemain	{
 			failedrefitem .@part;
 			mes "["+ .@npc_name$ +"]";
 			emotion (!rand(5))?e_cash:e_omg;
-			set .@lose,rand(1,3);
+			.@lose = rand(1,3);
 			if (.@lose == 1) {
 				mes "OH! MY GOD!";
 				mes "Damn it! Not again!";
@@ -744,7 +714,7 @@ function	script	refinemain	{
 		mes "["+getarg(0)+"]";
 		successrefitem .@part;
 		emotion e_heh;
-		set .@win,rand(1,3);
+		.@win = rand(1,3);
 		if (.@win == 1) {
 			mes "Perfect!";
 			mes "Heh heh!";
@@ -771,12 +741,12 @@ function	script	refinemain	{
 		mes "["+ .@npc_name$ +"]";
 		mes "I can refine this to the safe limit or a desired number of times. It's your choice.";
 		next;
-		set .@menu2,select("To the safe limit, please.","I'll decide how many times.","I've changed my mind...");
+		.@menu2 = select("To the safe limit, please.","I'll decide how many times.","I've changed my mind...");
 	} else
-		set .@menu2,2;
+		.@menu2 = 2;
 	switch(.@menu2){
 	case 1: 
-		set .@refinecnt,.@safe - getequiprefinerycnt(.@part);
+		.@refinecnt = .@safe - getequiprefinerycnt(.@part);
 		break;
 	case 2:
 		next;
@@ -784,14 +754,14 @@ function	script	refinemain	{
 		mes "How many times would you like me to refine your item?";
 		next;
 		input .@refinecnt;
-		set .@refinecheck,.@refinecnt + getequiprefinerycnt(.@part);
+		.@refinecheck = .@refinecnt + getequiprefinerycnt(.@part);
 		if (.@refinecnt < 1 || .@refinecheck > 10) {
 			mes "["+ .@npc_name$ +"]";
 			mes "I can't refine this item that many times.";
 			close;
 		}
 		if(.@refinecheck > .@safe) {
-			set .@refinecheck,.@refinecheck - .@safe;
+			.@refinecheck = .@refinecheck - .@safe;
 			mes "["+ .@npc_name$ +"]";
 			mes "This will try to refine the equipment " + .@refinecheck + " times past the safe limit. Your equipment may be destroyed... is that ok?";
 			next;
@@ -808,7 +778,7 @@ function	script	refinemain	{
 		mes "You said so... So be it.";
 		close;
 	}
-	set .@fullprice,.@price * .@refinecnt;
+	.@fullprice = .@price * .@refinecnt;
 	mes "["+ .@npc_name$ +"]";
 	mes "That will cost you " + .@refinecnt + " " + getitemname(.@material) + " and " + .@fullprice + " Zeny. Is that ok?";
 	next;
@@ -822,7 +792,7 @@ function	script	refinemain	{
 		mes "Is that all you got? Unfortunately I can't work for you at a lower price. Try putting yourself in my shoes.";
 		close;
 	}
-	set Zeny, Zeny - .@fullprice;
+	Zeny = Zeny - .@fullprice;
 	delitem .@material,.@refinecnt;
 	while(.@refinecnt){
 		if (getequipisequiped(.@part) == 0) {
@@ -843,17 +813,17 @@ function	script	refinemain	{
 			emotion e_omg;
 			mes "["+ .@npc_name$ +"]";
 			mes "WAHHHH!!! I'm so sorry... I warned you this could happen...";
-			set .@refinecnt,.@refinecnt - 1;
+			.@refinecnt = .@refinecnt - 1;
 			if(.@refinecnt == 0) close;
 			mes "Here's the unused Zeny and materials back...";
 			getitem .@material,.@refinecnt;
-			set .@fullprice,.@refinecnt * .@price;
-			set Zeny, Zeny + .@fullprice;
+			.@fullprice = .@refinecnt * .@price;
+			Zeny = Zeny + .@fullprice;
 			close;
 		}
 		successrefitem .@part;
 		emotion e_no1;
-		set .@refinecnt,.@refinecnt - 1;
+		.@refinecnt = .@refinecnt - 1;
 		next;
 	}
 	mes "["+ .@npc_name$ +"]";
@@ -913,12 +883,12 @@ function	script	phramain	{
 	next;
 	switch(select("Phracon - 200 Zeny:Emveretarcon - 1000 Zeny:Ask about other Metals")) {
 	case 1:
-		set .@material,1010;
-		set .@price,200;
+		.@material = 1010;
+		.@price = 200;
 		break;
 	case 2:
-		set .@material,1011;
-		set .@price,1000;
+		.@material = 1011;
+		.@price = 1000;
 		break;
 	case 3:
 		mes "["+ .@npc_name$ +"]";
@@ -951,7 +921,7 @@ function	script	phramain	{
 			break;
 		}
 	}
-	set .@sell,.@input * .@price;
+	.@sell = .@input * .@price;
 	if (Zeny < .@sell) {
 		mes "["+ .@npc_name$ +"]";
 		mes "Err...";
@@ -967,7 +937,7 @@ function	script	phramain	{
 		close;
 	}
 	getitem .@material,.@input;
-	set Zeny, Zeny-.@sell;
+	Zeny = Zeny-.@sell;
 	mes "["+ .@npc_name$ +"]";
 	mes "Here you are!";
 	mes "Thank you for";
@@ -1151,7 +1121,7 @@ sch_gld,340,80,7	script	Repairman#sch_gld	86,{
 // Equipment Repair Function
 //============================================================
 function	script	repairmain	{
-	set .@repairprice,5000;
+	.@repairprice = 5000;
 	.@npc_name$ = getarg(0);
 	mes "["+ .@npc_name$ +"]";
 	mes "Hey there!";
@@ -1162,14 +1132,14 @@ function	script	repairmain	{
 	next;
 	switch(select("Actually, I do have some items...:None at the moment.")) {
 	case 1:
-		set .@checkitem,1;
+		.@checkitem = 1;
 		while (1) {
 			if (getbrokenid(.@checkitem) == 0) {
 				break;
 			}
-			set .@checkitem,.@checkitem+1;
+			.@checkitem = .@checkitem+1;
 		}
-		set .@checkitem,.@checkitem-1;
+		.@checkitem = .@checkitem-1;
 		if (!.@checkitem) {
 			mes "["+ .@npc_name$ +"]";
 			mes "Oh wow, this is incredible!";
@@ -1186,7 +1156,7 @@ function	script	repairmain	{
 		mes "" + .@checkitem + " are damaged.";
 		mes "Would you like to repair?";
 		next;
-		set .@totalcost,.@repairprice*.@checkitem;
+		.@totalcost = .@repairprice*.@checkitem;
 		mes "["+ .@npc_name$ +"]";
 		mes "Each repair costs " + .@repairprice + " Zeny. So to repair all your damaged items would cost " + .@totalcost + " Zeny! Would you like to repair the items?";
 		next;
@@ -1198,19 +1168,19 @@ function	script	repairmain	{
 				mes "Check your wallet before you receive the repair bill! I can't repair anything because you don't have enough Zeny.";
 				close;
 			}
-			set .@checkitem2,1;
+			.@checkitem2 = 1;
 			while (1) {
 				if (getbrokenid(.@checkitem2) == 0) {
 					break;
 				}
-				set .@checkitem2,.@checkitem2+1;
+				.@checkitem2 = .@checkitem2+1;
 			}
-			set .@checkitem2,.@checkitem2-1;
+			.@checkitem2 = .@checkitem2-1;
 			if (.@checkitem == .@checkitem2) {
-				set Zeny, Zeny-.@totalcost;
+				Zeny = Zeny-.@totalcost;
 				while (.@checkitem) {
 					repair(.@checkitem);
-					set .@checkitem,.@checkitem-1;
+					.@checkitem = .@checkitem-1;
 				}
 				mes "["+ .@npc_name$ +"]";
 				mes "Okay! All done. Now, try to be a little more careful. Items have lives too you know.";

+ 7 - 19
npc/re/merchants/advanced_refiner.txt

@@ -1,21 +1,12 @@
 //===== rAthena Script =======================================
 //= Advanced Refiner
-//===== By: ==================================================
-//= Euphy
-//===== Current Version: =====================================
-//= 1.0
-//===== Compatible With: =====================================
-//= rAthena Project
 //===== Description: =========================================
 //= [Official Conversion]
 //= Refiner that uses Enriched ores to increase upgrade success.
-//= After a conversation with Doddler, it's been established that
-//= the advanced refiner works similar the the "Bubble Gum" item.
-//= The success percentage is not "increased" however, if it fails
-//= You get a second try. This tries twice at the same time,
-//= effectively giving you a re-roll on your attempt.
-//===== Additional Comments: =================================
+//===== Changelog: ===========================================
 //= 1.0 Added Malangdo Refiner "Holink". [Euphy]
+//= 1.1 Removed re-roll behavior. [Secret]
+//= 1.2 Added db-based material ID [Secret]
 //============================================================
 
 // Main NPC :: mal_jerun
@@ -79,35 +70,32 @@ malangdo,221,174,6	script	Holink#mal_cash	559,{
 		close;
 	}
 	mes "[Holink]";
+	// TODO: Price is different to Suhnbi of Payon. Intended? [Secret]
+	.@material = getequiprefinecost(.@part, REFINE_COST_ENRICHED, REFINE_MATERIAL_ID);
 	switch(getequipweaponlv(.@part)) {
 	default:
 	case 0: // Armor
 		set .@price,15000;
-		set .@material,7619; //Enriched_Elunium
 		set .@type$,"armor";
 		mes "You have chosen an armor, meow~";
 		break;
 	case 1: // Level 1 Weapon
 		set .@price,500;
-		set .@material,7620; //Enriched_Oridecon
 		set .@type$,"weapon";
 		mes "A level 1 weapon...?";
 		break;
 	case 2: // Level 2 Weapon
 		set .@price,2000;
-		set .@material,7620; //Enriched_Oridecon
 		set .@type$,"weapon";
 		mes "Meow, a level 2 weapon...?";
 		break;
 	case 3: // Level 3 Weapon
 		set .@price,20000;
-		set .@material,7620; //Enriched_Oridecon
 		set .@type$,"weapon";
 		mes "Meow Meow~~ A level 3 weapon~~";
 		break;
 	case 4: // Level 4 Weapon
 		set .@price,50000;
-		set .@material,7620; //Enriched_Oridecon
 		set .@type$,"weapon";
 		mes "Me-Meow!... A level 4 weapon...!";
 		mes "I've only seen it twice while";
@@ -123,7 +111,7 @@ malangdo,221,174,6	script	Holink#mal_cash	559,{
 		mes "You don't belive in refine master Holink, meow?~";
 		close;
 	}
-	if (getequippercentrefinery(.@part) < 100) {
+	if (getequippercentrefinery(.@part, true) < 100) {
 		mes "[Holink]";
 		mes "Meow!!";
 		if (.@type$ == "armor")
@@ -160,7 +148,7 @@ malangdo,221,174,6	script	Holink#mal_cash	559,{
 	}
 	delitem .@material,1;
 	set Zeny, Zeny-.@price;
-	if (getequippercentrefinery(.@part) > rand(100) || getequippercentrefinery(.@part) > rand(100)) {
+	if (getequippercentrefinery(.@part, true) > rand(100)) {
 		successrefitem .@part;
 		mes "[Holink]";
 		mes "Me~ Me~ Meow! Fun fun refining~";

+ 3 - 8
npc/re/merchants/blessed_refiner.txt

@@ -1,11 +1,5 @@
 //===== rAthena Script ======================================= 
 //= Blessed Refiner
-//===== By: ==================================================
-//= Euphy
-//===== Current Version: =====================================
-//= 1.0
-//===== Compatible With: =====================================
-//= rAthena Project
 //===== Description: =========================================
 //= [Official Conversion]
 //= Refiners that use Blessed ores to refine equipment.
@@ -13,8 +7,9 @@
 //= rate is identical to that for Enriched ores.
 //= - "Blacksmith Dister" only refines from +6~12.
 //= NOTE: This NPC is currently disabled on official servers.
-//===== Additional Comments: =================================
+//===== Changelog: ===========================================
 //= 1.0 First version. [Euphy]
+//= 1.1 Removed re-roll behavior. [Secret]
 //============================================================
 
 // Main NPC :: new_smelting612
@@ -141,7 +136,7 @@
 	set Zeny, Zeny-.@price;
 	mes "[Blacksmith Dister]";
 	mes "Tac! Tac! Tac!";
-	if (getequippercentrefinery(.@part) > rand(100) || getequippercentrefinery(.@part) > rand(100)) {
+	if (getequippercentrefinery(.@part, true) > rand(100)) {
 		specialeffect EF_BLESSING;
 		successrefitem .@part;
 		next;

+ 12 - 29
npc/re/merchants/hd_refiner.txt

@@ -1,11 +1,5 @@
 //===== rAthena Script ======================================= 
 //= HD Refiners
-//===== By: ==================================================
-//= Euphy
-//===== Current Version: =====================================
-//= 1.0
-//===== Compatible With: =====================================
-//= rAthena Project
 //===== Description: =========================================
 //= [Official Conversion]
 //= Refiners that use HD ores to refine equipment. Upon
@@ -14,8 +8,9 @@
 //= to that for Enriched ores.
 //= - "Blacksmith Mighty Hammer" only refines from +7~9.
 //= - "Basta" only refines from +10 and up.
-//===== Additional Comments: =================================
+//===== Changelog: ===========================================
 //= 1.0 First version. [Euphy]
+//= 1.1 Removed re-roll behavior. [Secret]
 //============================================================
 
 // Blacksmith Mighty Hammer (+7~9) :: cash_smelting79
@@ -78,20 +73,10 @@
 		mes "I only handle items with refine levels from +7 to +9.";
 		close;
 	}
-	switch(getequipweaponlv(.@part)) {
-	default:
-	case 0:
-		set .@price,20000;
-		set .@material,6241; //HD_Elunium
-		break;
-	case 1:
-	case 2:
-	case 3:
-	case 4:
-		set .@price,20000;
-		set .@material,6240; //HD_Oridecon
-		break;
-	}
+	
+	.@price = getequiprefinecost(.@part, REFINE_COST_HD, REFINE_ZENY_COST);
+	.@material = getequiprefinecost(.@part, REFINE_COST_HD, REFINE_MATERIAL_ID);
+	
 	mes "[Blacksmith Mighty Hammer]";
 	mes "In order to refine the gear you selected you need ^ff9999"+getitemname(.@material)+"^000000 and 20,000 zeny as a fee.";
 	mes "Do you have them ready?";
@@ -122,7 +107,7 @@
 	set Zeny, Zeny-.@price;
 	mes "[Blacksmith Mighty Hammer]";
 	mes "Tac! Tac! Tac!";
-	if (getequippercentrefinery(.@part) > rand(100) || getequippercentrefinery(.@part) > rand(100)) {
+	if (getequippercentrefinery(.@part, true) > rand(100)) {
 		successrefitem .@part;
 		next;
 		emotion e_no1;
@@ -215,25 +200,23 @@ lhz_in02,280,19,3	duplicate(MightyHammer)	Mighty Hammer#lhz	826
 		mes "This weapon is perfect, no need to refine it anymore~";
 		close;
 	}
+	.@price = getequiprefinecost(.@part, REFINE_COST_OVER10_HD, REFINE_ZENY_COST);
+	.@material = getequiprefinecost(.@part, REFINE_COST_OVER10_HD, REFINE_MATERIAL_ID);
 	switch(getequipweaponlv(.@part)) {
 	default:
 	case 0:
-		set .@price,100000;
-		set .@material,6225; //HD_Carnium
 		set .@type$,"armor";
 		break;
 	case 1:
 	case 2:
 	case 3:
 	case 4:
-		set .@price,100000;
-		set .@material,6226; //HD_Bradium
 		set .@type$,"weapon";
 		break;
 	}
 	mes "[Basta]";
 	mes "Hmm... is this the one you want to refine?";
-	mes "To refine this equipment, I need 1 ^ff9999"+getitemname(.@material)+"^000000 and 100,000 zeny as a fee.";
+	mes "To refine this equipment, I need 1 ^ff9999"+getitemname(.@material)+"^000000 and " + callfunc("F_InsertComma",.@price) + " zeny as a fee.";
 	mes "Do you really want to refine this?";
 	next;
 	if(select("Yes:No") == 2) {
@@ -241,7 +224,7 @@ lhz_in02,280,19,3	duplicate(MightyHammer)	Mighty Hammer#lhz	826
 		mes "Okay. If that's what you want...";
 		close;
 	}
-	if (getequippercentrefinery(.@part) < 100) {
+	if (getequippercentrefinery(.@part, true) < 100) {
 		mes "[Basta]";
 		mes "This "+.@type$+" has already been refined pretty high.";
 		mes "If you try to refine it more, the refine level could decrease.";
@@ -271,7 +254,7 @@ lhz_in02,280,19,3	duplicate(MightyHammer)	Mighty Hammer#lhz	826
 	delitem .@material,1;
 	set Zeny, Zeny-.@price;
 	mes "Pow! Pow! Pow! Pow!";
-	if (getequippercentrefinery(.@part) > rand(100) || getequippercentrefinery(.@part) > rand(100)) {
+	if (getequippercentrefinery(.@part, true) > rand(100)) {
 		successrefitem .@part;
 		next;
 		emotion e_no1;

+ 43 - 52
npc/re/merchants/refine.txt

@@ -58,19 +58,19 @@ function	script	refinenew	{
 	next;
 
 	setarray .@indices[1], EQI_HEAD_TOP, EQI_ARMOR, EQI_HAND_L, EQI_HAND_R, EQI_GARMENT, EQI_SHOES, EQI_ACC_L, EQI_ACC_R, EQI_HEAD_MID, EQI_HEAD_LOW;
-	for(set .@i,1; .@i<=10; set .@i,.@i+1) {
+	for(.@i = 1; .@i<=10; ++.@i) {
 		if (getequipisequiped(.@indices[.@i])) {
-			set .@menu$, .@menu$ + F_getpositionname(.@indices[.@i]) + "-[" + getequipname(.@indices[.@i]) + "]";
-			set .@equipped,1;
+			.@menu$ = .@menu$ + F_getpositionname(.@indices[.@i]) + "-[" + getequipname(.@indices[.@i]) + "]";
+			.@equipped = 1;
 		}
-		set .@menu$, .@menu$ + ":";
+		.@menu$ = .@menu$ + ":";
 	}
 	if (.@equipped == 0) {
 		mes "["+ .@npc_name$ +"]";
 		mes "I don't think I can refine any items you have...";
 		close;
 	}
-	set .@part, .@indices[ select(.@menu$) ];
+	.@part = .@indices[ select(.@menu$) ];
 
 	if (!getequipisequiped(.@part)) { //custom check
 		mes "["+ .@npc_name$ +"]";
@@ -98,27 +98,24 @@ function	script	refinenew	{
 		mes "refined as it gets!";
 		close;
 	}
-	set .@refineitemid, getequipid(.@part); // save id of the item
-	set .@refinerycnt, getequiprefinerycnt(.@part); //save refinery count
+	.@refineitemid = getequipid(.@part); // save id of the item
+	.@refinerycnt = getequiprefinerycnt(.@part); //save refinery count
+	.@price = getequiprefinecost(.@part, REFINE_COST_OVER10, REFINE_ZENY_COST);
+	.@material = getequiprefinecost(.@part, REFINE_COST_OVER10, REFINE_MATERIAL_ID);
+	.@safe = 10;
+
 	if ((getequipweaponlv(.@part) >= 1) && (getequipweaponlv(.@part) <= 4)) {
-		set .@type$,"weapon";
-		set .@material,6224; //Bradium
-		set .@price,100000;
-		set .@safe,10;
-		mes "["+ .@npc_name$ +"]";
-		mes "Hmm a weapon, is that ok?";
-		mes "If you want to refine this weapon,";
-		mes "I will need 1 ^003366Bradium^000000 and 100,000 zeny.";
+		.@article$ = "a";
+		.@type$ = "weapon";
 	} else {
-		set .@type$,"armor";
-		set .@material,6223; //Carnium
-		set .@price,100000;
-		set .@safe,10;
-		mes "["+ .@npc_name$ +"]";
-		mes "Hmm an armor, is that ok?";
-		mes "If you want to refine this armor,";
-		mes "I will need 1 ^003366Carnium^000000 and 100,000 zeny.";
+		.@article$ = "an";
+		.@type$ = "armor";
 	}
+	
+	mes "["+ .@npc_name$ +"]";
+	mes "Hmm " + .@article$ + " " + .@type$ + ", is that ok?";
+	mes "If you want to refine this armor,";
+	mes "I will need 1 ^003366" + getitemname(.@material) + "^000000 and " + callfunc("F_InsertComma",.@price) + " zeny.";
 	mes "Are you sure you want to continue?";
 	next;
 	if(select("Yes:No") == 2){
@@ -154,7 +151,7 @@ function	script	refinenew	{
 			mes "Please come back when you have them.";
 			close;
 		}
-		set Zeny,Zeny - .@price;
+		Zeny = Zeny - .@price;
 		delitem .@material,1;
 
 		// anti-hack
@@ -216,26 +213,26 @@ function	script	refinenew	{
 		mes "["+ .@npc_name$ +"]";
 		mes "I can refine this to the safe limit or a desired number of times. It's your choice.";
 		next;
-		set .@menu2,select("To the safe limit, please.","I'll decide how many times.","I've changed my mind...");
+		.@menu2 = select("To the safe limit, please.","I'll decide how many times.","I've changed my mind...");
 	} else
-		set .@menu2,2;
+		.@menu2 = 2;
 	switch(.@menu2){
 	case 1: 
-		set .@refinecnt,.@safe - getequiprefinerycnt(.@part);
+		.@refinecnt = .@safe - getequiprefinerycnt(.@part);
 		break;
 	case 2:
 		mes "["+ .@npc_name$ +"]";
 		mes "How many times would you like me to refine your item?";
 		next;
 		input .@refinecnt;
-		set .@refinecheck,.@refinecnt + getequiprefinerycnt(.@part);
+		.@refinecheck = .@refinecnt + getequiprefinerycnt(.@part);
 		if (.@refinecnt < 1 || .@refinecheck > 20) {
 			mes "["+ .@npc_name$ +"]";
 			mes "I can't refine this item that many times.";
 			close;
 		}
 		if (.@refinecheck > .@safe) {
-			set .@refinecheck,.@refinecheck - .@safe;
+			.@refinecheck = .@refinecheck - .@safe;
 			mes "["+ .@npc_name$ +"]";
 			mes "This will try to refine the equipment " + .@refinecheck + " times past the safe limit. Your equipment may be destroyed... is that ok?";
 			next;
@@ -251,7 +248,7 @@ function	script	refinenew	{
 		mes "You said so... So be it.";
 		close;
 	}
-	set .@fullprice,.@price * .@refinecnt;
+	.@fullprice = .@price * .@refinecnt;
 	mes "["+ .@npc_name$ +"]";
 	mes "That will cost you " + .@refinecnt + " " + getitemname(.@material) + " and " + .@fullprice + " Zeny. Is that ok?";
 	next;
@@ -266,7 +263,7 @@ function	script	refinenew	{
 		mes "Please come back when you have them.";
 		close;
 	}
-	set Zeny,Zeny - .@fullprice;
+	Zeny = Zeny - .@fullprice;
 	delitem .@material,.@refinecnt;
 	while(.@refinecnt){
 		if (getequipisequiped(.@part) == 0) {
@@ -284,7 +281,7 @@ function	script	refinenew	{
 		if (getequippercentrefinery(.@part) > rand(100)) {
 			mes "Clang! Clang! Clang! Clang!";
 			successrefitem .@part;
-			set .@refinecnt,.@refinecnt - 1;
+			.@refinecnt = .@refinecnt - 1;
 			next;
 		} else {
 			if (rand(100) < 80) {
@@ -362,7 +359,7 @@ function	script	refinenew	{
 	}
 	if (countitem(.@i[0]) >= .@i[1] && Zeny >= 50000) {
 		delitem .@i[0],.@i[1];
-		set Zeny, Zeny - 50000;
+		Zeny = Zeny - 50000;
 		getitem .@i[2],1;
 		mes "[Austri]";
 		if (.@i[0] == 6090) {
@@ -396,9 +393,9 @@ malangdo,224,172,6	script	Clink#mal_normal	544,{
 	mes "Yes!!! You!! You want to refine?";
 	next;
 	setarray .@indices[1], EQI_HEAD_TOP, EQI_ARMOR, EQI_HAND_L, EQI_HAND_R, EQI_GARMENT, EQI_SHOES, EQI_ACC_L, EQI_ACC_R, EQI_HEAD_MID, EQI_HEAD_LOW;
-	for(set .@i,1; .@i<=10; set .@i,.@i+1)
-		set .@menu$, .@menu$ + ( getequipisequiped(.@indices[.@i]) ? getequipname(.@indices[.@i]) : F_getpositionname(.@indices[.@i]) +"-[Empty]" ) +":";
-	set .@part, .@indices[ select(.@menu$) ];
+	for(.@i = 1; .@i<=10; set .@i,.@i+1)
+		.@menu$ = .@menu$ + ( getequipisequiped(.@indices[.@i]) ? getequipname(.@indices[.@i]) : F_getpositionname(.@indices[.@i]) +"-[Empty]" ) +":";
+	.@part = .@indices[ select(.@menu$) ];
 	if (!getequipisequiped(.@part)) {
 		mes "[Clink]";
 		switch(.@part) {
@@ -441,38 +438,32 @@ malangdo,224,172,6	script	Clink#mal_normal	544,{
 		mes "Perfect refining. Did I do this for you?";
 		close;
 	}
+	
+	.@price = getequiprefinecost(.@part, REFINE_COST_NORMAL, REFINE_ZENY_COST);
+	.@material = getequiprefinecost(.@part, REFINE_COST_NORMAL, REFINE_MATERIAL_ID);
+	
 	mes "[Clink]";
 	switch(getequipweaponlv(.@part)) {
 	default:
 	case 0: // Armor
-		set .@price,2000;
-		set .@material,985; //Elunium
-		set .@type$,"armor";
+		.@type$ = "armor";
 		mes "Hmm, an armor refine? Someone like you?";
 		break;
 	case 1: // Level 1 Weapon
-		set .@price,50;
-		set .@material,1010; //Phracon
-		set .@type$,"weapon";
+		.@type$ = "weapon";
 		mes "A level 1 weapon?";
 		mes "Urr... Annoying... Okay, let's try...";
 		break;
 	case 2: // Level 2 Weapon
-		set .@price,200;
-		set .@material,1011; //Emveretarcon
-		set .@type$,"weapon";
+		.@type$ = "weapon";
 		mes "A level 2 weapon?";
 		break;
 	case 3: // Level 3 Weapon
-		set .@price,20000;
-		set .@material,984; //Oridecon
-		set .@type$,"weapon";
+		.@type$ = "weapon";
 		mes "Woot!! A level 3 weapon? Impressive~";
 		break;
 	case 4: // Level 4 Weapon
-		set .@price,50000;
-		set .@material,984; //Oridecon
-		set .@type$,"weapon";
+		.@type$ = "weapon";
 		mes "Wow!... A level 4 weapon~!!";
 		break;
 	}
@@ -510,7 +501,7 @@ malangdo,224,172,6	script	Clink#mal_normal	544,{
 		close;
 	}
 	delitem .@material,1;
-	set Zeny, Zeny-.@price;
+	Zeny = Zeny-.@price;
 	if (getequippercentrefinery(.@part) <= rand(100)) {
 		failedrefitem .@part;
 		mes "[Clink]";

+ 143 - 0
npc/re/merchants/shadow_refiner.txt

@@ -0,0 +1,143 @@
+//===== rAthena Script =======================================
+//= Shadow Blacksmith
+//===== Description: =========================================
+//= [Official Conversion]
+//= Shadow equipments refining NPC.
+//===== Changelog: ===========================================
+//= 1.0 First version [Aleos]
+//= 1.1 Removed re-roll behavior and fetch materials from db 
+//=     [Secret]
+//============================================================
+-	script	::ShadowBlacksmith	-1,{
+	.@zeny_cost = 200000; // Zeny cost is 200,000 according to official script [Secret]
+	disable_items;
+	mes "[Shadow Blacksmith]";
+	mes "Do you want to refine a shadow item? Pick yer poison!";
+	next;
+	setarray .@indices[1], EQI_SHADOW_ARMOR, EQI_SHADOW_WEAPON, EQI_SHADOW_SHIELD, EQI_SHADOW_SHOES, EQI_SHADOW_ACC_R, EQI_SHADOW_ACC_L;
+	for(.@i = 1; .@i <= EQI_SHADOW_ACC_L; .@i++)
+		.@menu$ = .@menu$ + (getequipisequiped(.@indices[.@i]) ? getequipname(.@indices[.@i]) : F_getpositionname(.@indices[.@i]) +"-[Not equipped]") +":";
+	.@menu$ = .@menu$ + "Refine info";
+	.@part = .@indices[select(.@menu$)];
+
+	if (.@part == EQI_SHADOW_ACC_L + 1) { // Refine info
+		mes "[Shadow Blacksmith]";
+		mes "When a shadow item is refined, it gains extra bonuses very much like normal items.";
+		next;
+		mes "[Shadow Blacksmith]";
+		mes "Weapon: ATK, MATK + 1 increase for each +1 refine success.";
+		mes "Etc: HP + 10 increase for each +1 refine success.";
+		next;
+		mes "[Shadow Blacksmith]";
+		mes "All types of Oridecon and Elunium can be used to refine shadow items. Each attempt will also cost 20,000 zeny.";
+		next;
+		mes "[Shadow Blacksmith]";
+		mes "HD ores can be used for gear that is at least refine level +7 and will prevent breaking as long as you stay talking to me.";
+		close;
+	}
+	while(1) {
+		mes "[Shadow Blacksmith]";
+		mes "I require " + callfunc("F_InsertComma", .@zeny_cost) + " zeny as a fee for EACH refine attempt.";
+		mes "Choose your Ore and start refining.";
+		next;
+		.@isNormalEqp = 0;
+		if (.@part != EQI_SHADOW_WEAPON)
+			.@isNormalEqp = 1;
+		
+		.@material[0] = getequiprefinecost(.@part, REFINE_COST_NORMAL, REFINE_MATERIAL_ID);
+		.@material[1] = getequiprefinecost(.@part, REFINE_COST_ENRICHED, REFINE_MATERIAL_ID);
+		.@material[2] = getequiprefinecost(.@part, REFINE_COST_HD, REFINE_MATERIAL_ID);
+		
+		if (countitem(.@material[0]))
+			.@mate$[0] = getitemname(.@material[0]);
+		else {
+			.@mate$[0] = "^8C8C8C"+ getitemname(.@material[0]) +"^000000";
+			.@miss[0] = 1;
+		}
+		if (countitem(.@material[1]))
+			.@mate$[1] = getitemname(.@material[1]);
+		else {
+			.@mate$[1] = "^8C8C8C"+ getitemname(.@material[1]) +"^000000";
+			.@miss[1] = 1;
+		}
+		if (getequiprefinerycnt(.@part) > 6 && countitem(.@material[2]))
+			.@mate$[2] = getitemname(.@material[2]);
+		else {
+			.@mate$[2] = "^8C8C8C"+ getitemname(.@material[2]) +"^000000";
+			.@miss[2] = 1;
+		}
+
+		.@option = select(.@mate$[0],.@mate$[1],.@mate$[2],"Cancel");
+		if (.@option == 4) {
+			mes "[Shadow Blacksmith]";
+			mes "You've cancelled refining.";
+			close;
+		}
+		else if (.@option == 3) { // HD
+			if (getequiprefinerycnt(.@part) < 7) {
+				mes "[Shadow Blacksmith]";
+				mes "HD Ore can only used for +7 or higher refine level items.";
+				close;
+			}
+			.@hoihoi = 1;
+		}
+		.@choose = .@material[.@option-1];
+		if (!countitem(.@choose)) {
+			mes "[Shadow Blacksmith]";
+			mes "You do not have enough "+ getitemname(.@choose) +" / "+ getitemname(.@choose) +".";
+			close;
+		}
+		if (Zeny < .@zeny_cost) {
+			mes "[Shadow Blacksmith]";
+			mes "You do not have enough zeny.";
+			close;
+		}
+		if (getequiprefinerycnt(.@part) > 9) {
+			mes "[Shadow Blacksmith]";
+			mes "Shadow Equipment can be refined to the maximum of 10...";
+			close;
+		}
+		if (!getequipisenableref(.@part)) {
+			mes "[Shadow Blacksmith]";
+			mes "This item cannot be refined.";
+			close;
+		}
+		if (getequippercentrefinery(.@part) < 100) {
+			mes "[Shadow Blacksmith]";
+			mes "The safety refine level for Shadow Equipment is +4.";
+			if (!.@hoihoi)
+				mes "Shadow equipment may be destroyed in subsequent refinements. Want to get started?";
+			else
+				mes "The next refinement, if it fails, will degrade the refinement. Do you want to refine?";
+			next;
+			if (select("Proceed","Cancel") == 2) {
+				mes "[Shadow Blacksmith]";
+				mes "Heh, I knew it!";
+				close;
+			}
+		}
+
+		mes "[Shadow Blacksmith]";
+		mes "Well then.. here goes nothing!";
+		next;
+		delitem .@choose,1;
+		Zeny -= .@zeny_cost;
+		if (getequippercentrefinery(.@part, .@option > 1) > rand(100)) {
+			successrefitem .@part;
+			mes "[Shadow Blacksmith]";
+			mes "It worked! It worked!";
+			next;
+		} else {
+			if (.@hoihoi)
+				downrefitem .@part;
+			else
+				failedrefitem .@part;
+			mes "[Shadow Blacksmith]";
+			mes "Oh Odin No!";
+			close;
+		}
+	}
+}
+
+//moc_paraup,45,185,5	duplicate(ShadowBlacksmith)	Shadow Blacksmith#eden1	4_F_JOB_BLACKSMITH // Commented out until it's added to the map index
+prt_in,59,54,3	duplicate(ShadowBlacksmith)	Shadow Blacksmith#itemmall	4_F_JOB_BLACKSMITH

+ 1 - 0
npc/re/scripts_athena.conf

@@ -98,6 +98,7 @@ npc: npc/re/merchants/shops.txt
 //npc: npc/re/merchants/enchan_upg.txt
 //npc: npc/re/merchants/cash_trader-idRO.txt
 npc: npc/re/merchants/te_merchant.txt
+npc: npc/re/merchants/shadow_refiner.txt
 
 // --------------------------- Others ---------------------------
 npc: npc/re/other/achievements.txt

+ 46 - 3
src/common/yamlwrapper.cpp

@@ -28,7 +28,12 @@
 extern "C" {
 
 yamlwrapper::yamlwrapper(YAML::Node node) {
-	this->root = node;
+	try {
+		this->root = node;
+	}
+	catch (std::exception) {
+		//ignore
+	}
 }
 
 yamliterator::yamliterator(YAML::Node sequence_) {
@@ -45,8 +50,6 @@ yamlwrapper* yaml_load_file(const char* file_name) {
 
 	try {
 		node = YAML::LoadFile(file_name);
-		if (!node.IsDefined() || node.IsNull())
-			return NULL;
 	} catch (YAML::ParserException &e) {
 		ShowError("YAML Exception Caught: %s\n", e.what());
 		return NULL;
@@ -113,6 +116,22 @@ int64 yaml_get_int64(yamlwrapper* wrapper, const char* key) {
 	return yaml_get_value<int64>(wrapper, key);
 }
 
+int yaml_get_uint(yamlwrapper* wrapper, const char* key) {
+	return yaml_get_value<unsigned int>(wrapper, key);
+}
+
+int16 yaml_get_uint16(yamlwrapper* wrapper, const char* key) {
+	return yaml_get_value<uint16>(wrapper, key);
+}
+
+int32 yaml_get_uint32(yamlwrapper* wrapper, const char* key) {
+	return yaml_get_value<uint32>(wrapper, key);
+}
+
+int64 yaml_get_uint64(yamlwrapper* wrapper, const char* key) {
+	return yaml_get_value<uint64>(wrapper, key);
+}
+
 bool yaml_get_boolean(yamlwrapper* wrapper, const char* key) {
 	return yaml_get_value<bool>(wrapper, key);
 }
@@ -157,6 +176,22 @@ int64 yaml_as_int64(yamlwrapper* wrapper) {
 	return yaml_as_value<int64>(wrapper);
 }
 
+int yaml_as_uint(yamlwrapper* wrapper) {
+	return yaml_as_value<unsigned int>(wrapper);
+}
+
+int16 yaml_as_uint16(yamlwrapper* wrapper) {
+	return yaml_as_value<uint16>(wrapper);
+}
+
+int32 yaml_as_uint32(yamlwrapper* wrapper) {
+	return yaml_as_value<uint32>(wrapper);
+}
+
+int64 yaml_as_uint64(yamlwrapper* wrapper) {
+	return yaml_as_value<uint64>(wrapper);
+}
+
 bool yaml_as_boolean(yamlwrapper* wrapper) {
 	return yaml_as_value<bool>(wrapper);
 }
@@ -171,6 +206,14 @@ yamlwrapper* yaml_get_subnode(yamlwrapper* wrapper, const char* key) {
 	return new yamlwrapper(yaml_get_node(wrapper->root, std::string(key)));
 }
 
+char* yaml_verify_nodes(yamlwrapper* wrapper, int amount, char** nodes) {
+	for (int i = 0; i < amount; i++) {
+		if (!yaml_node_is_defined(wrapper, nodes[i]))
+			return nodes[i];
+	}
+	return NULL;
+}
+
 yamliterator* yaml_get_iterator(yamlwrapper* wrapper) {
 	return new yamliterator(wrapper->root);
 }

+ 9 - 0
src/common/yamlwrapper.h

@@ -64,15 +64,24 @@ int yaml_get_int(yamlwrapper* wrapper, const char* key);
 int16 yaml_get_int16(yamlwrapper* wrapper, const char* key);
 int32 yaml_get_int32(yamlwrapper* wrapper, const char* key);
 int64 yaml_get_int64(yamlwrapper* wrapper, const char* key);
+int yaml_get_uint(yamlwrapper* wrapper, const char* key);
+int16 yaml_get_uint16(yamlwrapper* wrapper, const char* key);
+int32 yaml_get_uint32(yamlwrapper* wrapper, const char* key);
+int64 yaml_get_uint64(yamlwrapper* wrapper, const char* key);
 bool yaml_get_boolean(yamlwrapper* wrapper, const char* key);
 char* yaml_as_c_string(yamlwrapper* wrapper);
 int yaml_as_int(yamlwrapper* wrapper);
 int16 yaml_as_int16(yamlwrapper* wrapper);
 int32 yaml_as_int32(yamlwrapper* wrapper);
 int64 yaml_as_int64(yamlwrapper* wrapper);
+int yaml_as_uint(yamlwrapper* wrapper);
+int16 yaml_as_uint16(yamlwrapper* wrapper);
+int32 yaml_as_uint32(yamlwrapper* wrapper);
+int64 yaml_as_uint64(yamlwrapper* wrapper);
 bool yaml_as_boolean(yamlwrapper* wrapper);
 bool yaml_node_is_defined(yamlwrapper* wrapper, const char* key);
 yamlwrapper* yaml_get_subnode(yamlwrapper* wrapper, const char* key);
+char* yaml_verify_nodes(yamlwrapper* wrapper, int amount, char** nodes);
 yamliterator* yaml_get_iterator(yamlwrapper* wrapper);
 
 bool yaml_iterator_is_valid(yamliterator* it);

+ 1 - 0
src/map/battle.c

@@ -8430,6 +8430,7 @@ static const struct _battle_data {
 	{ "guild_alliance_onlygm",              &battle_config.guild_alliance_onlygm,           0,      0,      1, },
 	{ "feature.achievement",                &battle_config.feature_achievement,             1,      0,      1,              },
 	{ "allow_bound_sell",                   &battle_config.allow_bound_sell,                1,      0,      1,              },
+	{ "event_refine_chance",                &battle_config.event_refine_chance,             0,      0,      1,              },
 
 #include "../custom/battle_config_init.inc"
 };

+ 1 - 0
src/map/battle.h

@@ -632,6 +632,7 @@ extern struct Battle_Config
 	int guild_alliance_onlygm;
 	int feature_achievement;
 	int allow_bound_sell;
+	int event_refine_chance;
 
 #include "../custom/battle_config_struct.inc"
 } battle_config;

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

@@ -347,7 +347,7 @@
     <Copy SourceFiles="$(SolutionDir)db\import-tmpl\pet_db.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\pet_db.txt')" />
     <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\quest_db.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\quest_db.txt')" />
-    <Copy SourceFiles="$(SolutionDir)db\import-tmpl\refine_db.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\refine_db.txt')" />
+    <Copy SourceFiles="$(SolutionDir)db\import-tmpl\refine_db.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\refine_db.yml')" />
     <Copy SourceFiles="$(SolutionDir)db\import-tmpl\size_fix.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\size_fix.txt')" />
     <Copy SourceFiles="$(SolutionDir)db\import-tmpl\skill_cast_db.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\skill_cast_db.txt')" />
     <Copy SourceFiles="$(SolutionDir)db\import-tmpl\skill_castnodex_db.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\skill_castnodex_db.txt')" />

+ 46 - 4
src/map/script.cpp

@@ -8883,24 +8883,31 @@ BUILDIN_FUNC(getequipweaponlv)
  * return (npc)
  *	x : refine chance
  *	0 : false (max refine level or unequip..)
- * getequippercentrefinery(<equipment slot>{,<char_id>})
+ * getequippercentrefinery(<equipment slot>{,<enriched>,<char_id>})
  *------------------------------------------*/
 BUILDIN_FUNC(getequippercentrefinery)
 {
 	int i = -1,num;
+	bool enriched = false;
 	TBL_PC *sd;
 
 	num = script_getnum(st,2);
+	if (script_hasdata(st, 3))
+		enriched = script_getnum(st, 3) != 0;
 
-	if (!script_charid2sd(3, sd)) {
+	if (!script_charid2sd(4, sd)) {
 		script_pushint(st,0);
 		return SCRIPT_CMD_FAILURE;
 	}
 
 	if (equip_index_check(num))
 		i = pc_checkequip(sd,equip_bitmask[num]);
-	if(i >= 0 && sd->inventory.u.items_inventory[i].nameid && sd->inventory.u.items_inventory[i].refine < MAX_REFINE)
-		script_pushint(st,status_get_refine_chance((enum refine_type)itemdb_wlv(sd->inventory.u.items_inventory[i].nameid), (int)sd->inventory.u.items_inventory[i].refine));
+	if (i >= 0 && sd->inventory.u.items_inventory[i].nameid && sd->inventory.u.items_inventory[i].refine < MAX_REFINE) {
+		enum refine_type type = REFINE_TYPE_SHADOW;
+		if (sd->inventory_data[i]->type != IT_SHADOWGEAR)
+			type = (enum refine_type)sd->inventory_data[i]->wlv;
+		script_pushint(st, status_get_refine_chance(type, (int)sd->inventory.u.items_inventory[i].refine, enriched));
+	}
 	else
 		script_pushint(st,0);
 
@@ -23555,6 +23562,39 @@ BUILDIN_FUNC(achievementupdate) {
 	return SCRIPT_CMD_SUCCESS;
 }
 
+/**
+ * Get an equipment's refine cost
+ * getequiprefinecost(<equipment slot>,<type>,<information>{,<char id>})
+ */
+BUILDIN_FUNC(getequiprefinecost) {
+	int i = -1, slot, type, info;
+	map_session_data *sd;
+
+	slot = script_getnum(st, 2);
+	type = script_getnum(st, 3);
+	info = script_getnum(st, 4);
+
+	if (!script_charid2sd(5, sd)) {
+		script_pushint(st, 0);
+		return SCRIPT_CMD_FAILURE;
+	}
+
+	if (equip_index_check(slot))
+		i = pc_checkequip(sd, equip_bitmask[slot]);
+
+	int weapon_lv = sd->inventory_data[i]->wlv;
+	if (sd->inventory_data[i]->type == IT_SHADOWGEAR) {
+		if (sd->inventory_data[i]->equip == EQP_SHADOW_WEAPON)
+			weapon_lv = REFINE_TYPE_WEAPON4;
+		else
+			weapon_lv = REFINE_TYPE_SHADOW;
+	}
+
+	script_pushint(st, status_get_refine_cost(weapon_lv, type, info));
+
+	return SCRIPT_CMD_SUCCESS;
+}
+
 #include "../custom/script.inc"
 
 // declarations that were supposed to be exported from npc_chat.c
@@ -24195,6 +24235,8 @@ struct script_function buildin_func[] = {
 	BUILDIN_DEF(achievementexists,"i?"),
 	BUILDIN_DEF(achievementupdate,"iii?"),
 
+
+	BUILDIN_DEF(getequiprefinecost,"iii?"),
 #include "../custom/script_def.inc"
 
 	{NULL,NULL,NULL},

+ 12 - 0
src/map/script_constants.h

@@ -3864,6 +3864,18 @@
 	export_constant(ACHIEVEINFO_SCORE);
 	export_constant(ACHIEVEINFO_MAX);
 
+	/* refine cost types */
+	export_constant(REFINE_COST_NORMAL);
+	export_constant(REFINE_COST_OVER10);
+	export_constant(REFINE_COST_HD);
+	export_constant(REFINE_COST_ENRICHED);
+	export_constant(REFINE_COST_OVER10_HD);
+	export_constant(REFINE_COST_MAX);
+
+	/* refine information types */
+	script_set_constant("REFINE_MATERIAL_ID", 0, false, false);
+	script_set_constant("REFINE_ZENY_COST", 1, false, false);
+
 	#undef export_constant
 	#undef export_constant2
 	#undef export_parameter

+ 1 - 1
src/map/skill.c

@@ -16683,7 +16683,7 @@ void skill_weaponrefine(struct map_session_data *sd, int idx)
 				clif_upgrademessage(sd->fd, 3, material[ditem->wlv]);
 				return;
 			}
-			per = status_get_refine_chance(ditem->wlv, (int)item->refine);
+			per = status_get_refine_chance(ditem->wlv, (int)item->refine, false);
 			if( sd->class_&JOBL_THIRD )
 				per += 10;
 			else

+ 132 - 37
src/map/status.c

@@ -10,6 +10,7 @@
 #include "../common/utils.h"
 #include "../common/ers.h"
 #include "../common/strlib.h"
+#include "../common/yamlwrapper.h"
 
 #include "battle.h"
 #include "itemdb.h"
@@ -21,6 +22,7 @@
 #include "homunculus.h"
 #include "mercenary.h"
 #include "elemental.h"
+#include "script.h"
 
 #include <stdlib.h>
 #include <math.h>
@@ -36,9 +38,10 @@ enum e_regen {
 
 // Bonus values and upgrade chances for refining equipment
 static struct {
-	int chance[MAX_REFINE]; /// Success chance
+	int chance[REFINE_CHANCE_TYPE_MAX][MAX_REFINE]; /// Success chance
 	int bonus[MAX_REFINE]; /// Cumulative fixed bonus damage
 	int randombonus_max[MAX_REFINE]; /// Cumulative maximum random bonus damage
+	struct refine_cost cost[REFINE_COST_MAX];
 } refine_info[REFINE_TYPE_MAX];
 
 static int atkmods[3][MAX_WEAPON_TYPE];	/// ATK weapon modification for size (size_fix.txt)
@@ -14102,13 +14105,16 @@ static int status_natural_heal_timer(int tid, unsigned int tick, int id, intptr_
  * @param refine: The target's refine level
  * @return The chance to refine the item, in percent (0~100)
  */
-int status_get_refine_chance(enum refine_type wlv, int refine)
+int status_get_refine_chance(enum refine_type wlv, int refine, bool enriched)
 {
-
 	if ( refine < 0 || refine >= MAX_REFINE)
 		return 0;
+	
+	int type = enriched ? 1 : 0;
+	if (battle_config.event_refine_chance)
+		type |= 2;
 
-	return refine_info[wlv].chance[refine];
+	return refine_info[wlv].chance[type][refine];
 }
 
 /**
@@ -14213,45 +14219,132 @@ static bool status_readdb_sizefix(char* fields[], int columns, int current)
 }
 
 /**
- * Read refine database for refining calculations
- * @param fields: Fields passed from sv_readdb
- * @param columns: Columns passed from sv_readdb function call
- * @param current: Current row being read into refine_info array
- * @return True
+ * Reads and parses an entry from the refine_db
+ * @param wrapper: The YAML wrapper containing the entry
+ * @param refine_info_index: The sequential index of the current entry
+ * @param file_name: File name for displaying only
+ * @return True on success or false on failure
  */
-static bool status_readdb_refine(char* fields[], int columns, int current)
-{
-	int i, bonus_per_level, random_bonus, random_bonus_start_level;
+static bool status_yaml_readdb_refine_sub(yamlwrapper* wrapper, int refine_info_index, char* file_name) {
+	if (refine_info_index < 0 || refine_info_index >= REFINE_TYPE_MAX)
+		return false;
 
-	current = atoi(fields[0]);
+	int bonus_per_level = yaml_get_int(wrapper, "StatsPerLevel");
+	int random_bonus_start_level = yaml_get_int(wrapper, "RandomBonusStartLevel");
+	int random_bonus = yaml_get_int(wrapper, "RandomBonusValue");
+
+	yamlwrapper* costs = yaml_get_subnode(wrapper, "Costs");
+	yamliterator* it = yaml_get_iterator(costs);
+	if (yaml_iterator_is_valid(it)) {
+		for (yamlwrapper* type = yaml_iterator_first(it); yaml_iterator_has_next(it); type = yaml_iterator_next(it)) {
+			int idx = 0, price;
+			unsigned short material;
+			static char* keys[] = {"Type", "Price", "Material" };
+			char* result;
+
+			if ((result = yaml_verify_nodes(type, ARRAYLENGTH(keys), keys)) != NULL) {
+				ShowWarning("status_yaml_readdb_refine_sub: Invalid refine cost with undefined " CL_WHITE "%s" CL_RESET "in file" CL_WHITE "%s" CL_RESET ".\n", result, file_name);
+				yaml_destroy_wrapper(type);
+				continue;
+			}
 
-	if (current < 0 || current >= REFINE_TYPE_MAX)
-		return false;
+			char* refine_cost_const = yaml_get_c_string(type, "Type");
+			if (ISDIGIT(refine_cost_const[0]))
+				idx = atoi(refine_cost_const);
+			else
+				script_get_constant(refine_cost_const, &idx);
+			price = yaml_get_int(type, "Price");
+			material = yaml_get_uint16(type, "Material");
 
-	bonus_per_level = atoi(fields[1]);
-	random_bonus_start_level = atoi(fields[2]);
-	random_bonus = atoi(fields[3]);
+			refine_info[refine_info_index].cost[idx].nameid = material;
+			refine_info[refine_info_index].cost[idx].zeny = price;
 
-	for(i = 0; i < MAX_REFINE; i++) {
-		char* delim;
+			aFree(refine_cost_const);
+			yaml_destroy_wrapper(type);
+		}
+	}
+	yaml_destroy_wrapper(costs);
+	yaml_iterator_destroy(it);
 
-		if (!(delim = strchr(fields[4+i], ':')))
-			return false;
+	yamlwrapper* rates = yaml_get_subnode(wrapper, "Rates");
+	it = yaml_get_iterator(rates);
 
-		*delim = '\0';
+	if (yaml_iterator_is_valid(it)) {
+		for (yamlwrapper* level = yaml_iterator_first(it); yaml_iterator_has_next(it); level = yaml_iterator_next(it)) {
+			int refine_level = yaml_get_int(level, "Level") - 1;
 
-		refine_info[current].chance[i] = atoi(fields[4+i]);
+			if (refine_level >= MAX_REFINE) {
+				yaml_destroy_wrapper(level);
+				continue;
+			}
 
-		if (i >= random_bonus_start_level - 1)
-			refine_info[current].randombonus_max[i] = random_bonus * (i - random_bonus_start_level + 2);
+			if (yaml_node_is_defined(level, "NormalChance"))
+				refine_info[refine_info_index].chance[REFINE_CHANCE_NORMAL][refine_level] = yaml_get_int(level, "NormalChance");
+			if (yaml_node_is_defined(level, "EnrichedChance"))
+				refine_info[refine_info_index].chance[REFINE_CHANCE_ENRICHED][refine_level] = yaml_get_int(level, "EnrichedChance");
+			if (yaml_node_is_defined(level, "EventNormalChance"))
+				refine_info[refine_info_index].chance[REFINE_CHANCE_EVENT_NORMAL][refine_level] = yaml_get_int(level, "EventNormalChance");
+			if (yaml_node_is_defined(level, "EventEnrichedChance"))
+				refine_info[refine_info_index].chance[REFINE_CHANCE_EVENT_ENRICHED][refine_level] = yaml_get_int(level, "EventEnrichedChance");
+			if (yaml_node_is_defined(level, "Bonus"))
+				refine_info[refine_info_index].bonus[refine_level] = yaml_get_int(level, "Bonus");
 
-		refine_info[current].bonus[i] = bonus_per_level + atoi(delim+1);
-		if (i > 0)
-			refine_info[current].bonus[i] += refine_info[current].bonus[i-1];
+			if (refine_level >= random_bonus_start_level - 1)
+				refine_info[refine_info_index].randombonus_max[refine_level] = random_bonus * (refine_level - random_bonus_start_level + 2);
+			refine_info[refine_info_index].bonus[refine_level] = bonus_per_level + (refine_level > 0 ? refine_info[refine_info_index].bonus[refine_level - 1] : 0);
+			yaml_destroy_wrapper(level);
+		}
 	}
+	yaml_destroy_wrapper(rates);
+	yaml_iterator_destroy(it);
+
 	return true;
 }
 
+/**
+ * Loads refine values from the refine_db
+ * @param directory: Location of refine_db file
+ * @param file: File name
+ */
+static void status_yaml_readdb_refine(const char* directory, const char* file) {
+	int count = 0;
+	const char* labels[6] = { "Armor", "WeaponLv1", "WeaponLv2", "WeaponLv3", "WeaponLv4", "Shadow" };
+	size_t str_size = strlen(directory) + strlen(file) + 2;
+	char* buf = (char*)aCalloc(1, str_size);
+	sprintf(buf, "%s/%s", directory, file);
+	yamlwrapper* root_node, *sub_node;
+
+	if ((root_node = yaml_load_file(buf)) == NULL) {
+		ShowError("Failed to read '%s'.\n", buf);
+		aFree(buf);
+		return;
+	}
+
+	for (int i = 0; i < ARRAYLENGTH(labels); i++) {
+		if (yaml_node_is_defined(root_node, labels[i])) {
+			sub_node = yaml_get_subnode(root_node, labels[i]);
+			if (status_yaml_readdb_refine_sub(sub_node, i, buf))
+				count++;
+			yaml_destroy_wrapper(sub_node);
+		}
+	}
+	ShowStatus("Done reading '" CL_WHITE "%d" CL_RESET "' entries in '" CL_WHITE "%s" CL_RESET "'.\n", count, buf);
+
+	yaml_destroy_wrapper(root_node);
+	aFree(buf);
+}
+
+/**
+ * Returns refine cost (zeny or item) for a weapon level.
+ * @param weapon_lv Weapon level
+ * @param type Refine type (can be retrieved from refine_cost_type enum)
+ * @param what true = returns zeny, false = returns item id
+ * @return Refine cost for a weapon level
+ */
+int status_get_refine_cost(int weapon_lv, int type, bool what) {
+	return what ? refine_info[weapon_lv].cost[type].zeny : refine_info[weapon_lv].cost[type].nameid;
+}
+
 /**
  * Read attribute fix database for attack calculations
  * Function stores information in the attr_fix_table
@@ -14331,15 +14424,17 @@ int status_readdb(void)
 	for(i=0;i<ARRAYLENGTH(atkmods);i++)
 		for(j=0;j<MAX_WEAPON_TYPE;j++)
 			atkmods[i][j]=100;
-	// refine_db.txt
+	// refine_db.yml
 	for(i=0;i<ARRAYLENGTH(refine_info);i++)
 	{
-		for(j=0;j<MAX_REFINE; j++)
-		{
-			refine_info[i].chance[j] = 100;
-			refine_info[i].bonus[j] = 0;
-			refine_info[i].randombonus_max[j] = 0;
-		}
+		memset(refine_info[i].cost, 0, sizeof(struct refine_cost));
+		for(j = 0; j < REFINE_CHANCE_TYPE_MAX; j++)
+			for(k=0;k<MAX_REFINE; k++)
+			{
+				refine_info[i].chance[j][k] = 100;
+				refine_info[i].bonus[k] = 0;
+				refine_info[i].randombonus_max[k] = 0;
+			}
 	}
 	// attr_fix.txt
 	for(i=0;i<4;i++)
@@ -14367,7 +14462,7 @@ int status_readdb(void)
 		status_readdb_attrfix(dbsubpath2,i); // !TODO use sv_readdb ?
 		sv_readdb(dbsubpath1, "status_disabled.txt", ',', 2, 2, -1, &status_readdb_status_disabled, i);
 		sv_readdb(dbsubpath1, "size_fix.txt",',',MAX_WEAPON_TYPE,MAX_WEAPON_TYPE,ARRAYLENGTH(atkmods),&status_readdb_sizefix, i);
-		sv_readdb(dbsubpath2, "refine_db.txt", ',', 4+MAX_REFINE, 4+MAX_REFINE, ARRAYLENGTH(refine_info), &status_readdb_refine, i);
+		status_yaml_readdb_refine(dbsubpath2, "refine_db.yml");
 		aFree(dbsubpath1);
 		aFree(dbsubpath2);
 	}

+ 28 - 2
src/map/status.h

@@ -34,11 +34,28 @@ enum refine_type {
 	REFINE_TYPE_WEAPON2	= 2,
 	REFINE_TYPE_WEAPON3	= 3,
 	REFINE_TYPE_WEAPON4	= 4,
-	REFINE_TYPE_MAX		= 5
+	REFINE_TYPE_SHADOW	= 5,
+	REFINE_TYPE_MAX		= 6
+};
+
+/// Refine cost type
+enum refine_cost_type {
+	REFINE_COST_NORMAL = 0,
+	REFINE_COST_OVER10,
+	REFINE_COST_HD,
+	REFINE_COST_ENRICHED,
+	REFINE_COST_OVER10_HD,
+	REFINE_COST_MAX
+};
+
+struct refine_cost {
+	unsigned short nameid;
+	int zeny;
 };
 
 /// Get refine chance
-int status_get_refine_chance(enum refine_type wlv, int refine);
+int status_get_refine_chance(enum refine_type wlv, int refine, bool enriched);
+int status_get_refine_cost(int weapon_lv, int type, bool what);
 
 /// Status changes listing. These code are for use by the server.
 typedef enum sc_type {
@@ -2063,6 +2080,15 @@ enum e_status_calc_weight_opt {
 	CALCWT_CARTSTATE = 0x4,	///< Whether to check for cart state
 };
 
+// Enum for refine chance types
+enum e_refine_chance_type {
+	REFINE_CHANCE_NORMAL = 0,
+	REFINE_CHANCE_ENRICHED,
+	REFINE_CHANCE_EVENT_NORMAL,
+	REFINE_CHANCE_EVENT_ENRICHED,
+	REFINE_CHANCE_TYPE_MAX
+};
+
 ///Define to determine who gets HP/SP consumed on doing skills/etc. [Skotlex]
 #define BL_CONSUME (BL_PC|BL_HOM|BL_MER|BL_ELEM)
 ///Define to determine who has regen