Преглед изворни кода

Refactor out a lot of hard coded hit rates
* Moves skills that adjust hit rate into the skill database.

aleos пре 1 година
родитељ
комит
8fdac5ecfc
9 измењених фајлова са 596 додато и 91 уклоњено
  1. 5 1
      db/import-tmpl/skill_db.yml
  2. 180 1
      db/pre-re/skill_db.yml
  3. 299 1
      db/re/skill_db.yml
  4. 5 1
      db/skill_db.yml
  5. 22 1
      doc/skill_db.txt
  6. 4 0
      doc/yaml/db/skill_db.yml
  7. 38 85
      src/map/battle.cpp
  8. 34 0
      src/map/skill.cpp
  9. 9 1
      src/map/skill.hpp

+ 5 - 1
db/import-tmpl/skill_db.yml

@@ -37,6 +37,10 @@
 #   HitCount:                 Skill hit count. (Default: 0)
 #     - Level                 Skill level.
 #       Count                 Number of hits at specific skill level.
+#   HitRate                   Skill hit rate. (Default: 100)
+#     - Level                 Skill level.
+#       Rate                  Rate is a percent of hit rate added to hit rate.
+#       Skills:               Skill flagged as a requirement (players only). (Optional)
 #   Element:                  Skill element. (Default: Neutral)
 #     - Level                 Skill level.
 #       Element               Element at specific skill level.
@@ -140,4 +144,4 @@
 
 Header:
   Type: SKILL_DB
-  Version: 3
+  Version: 4

+ 180 - 1
db/pre-re/skill_db.yml

@@ -37,6 +37,10 @@
 #   HitCount:                 Skill hit count. (Default: 0)
 #     - Level                 Skill level.
 #       Count                 Number of hits at specific skill level.
+#   HitRate                   Skill hit rate. (Default: 100)
+#     - Level                 Skill level.
+#       Rate                  Rate is a percent of hit rate added to hit rate.
+#       Skills:               Skill flagged as a requirement (players only). (Optional)
 #   Element:                  Skill element. (Default: Neutral)
 #     - Level                 Skill level.
 #       Element               Element at specific skill level.
@@ -140,7 +144,7 @@
 
 Header:
   Type: SKILL_DB
-  Version: 3
+  Version: 4
 
 Body:
   - Id: 1
@@ -170,6 +174,27 @@ Body:
     Range: -1
     Hit: Single
     HitCount: 1
+    HitRate:
+      - Level: 1
+        Rate: 105
+      - Level: 2
+        Rate: 110
+      - Level: 3
+        Rate: 115
+      - Level: 4
+        Rate: 120
+      - Level: 5
+        Rate: 125
+      - Level: 6
+        Rate: 130
+      - Level: 7
+        Rate: 135
+      - Level: 8
+        Rate: 140
+      - Level: 9
+        Rate: 145
+      - Level: 10
+        Rate: 150
     Element: Weapon
     CopyFlags:
       Skill:
@@ -269,6 +294,27 @@ Body:
       TargetTrap: true
     Hit: Single
     HitCount: 1
+    HitRate:
+      - Level: 1
+        Rate: 110
+      - Level: 2
+        Rate: 120
+      - Level: 3
+        Rate: 130
+      - Level: 4
+        Rate: 140
+      - Level: 5
+        Rate: 150
+      - Level: 6
+        Rate: 160
+      - Level: 7
+        Rate: 170
+      - Level: 8
+        Rate: 180
+      - Level: 9
+        Rate: 190
+      - Level: 10
+        Rate: 200
     Element: Fire
     SplashArea:
       - Level: 1
@@ -2088,6 +2134,27 @@ Body:
     Range: -2
     Hit: Multi_Hit
     HitCount: 3
+    HitRate:
+      - Level: 1
+        Rate: 105
+      - Level: 2
+        Rate: 110
+      - Level: 3
+        Rate: 115
+      - Level: 4
+        Rate: 120
+      - Level: 5
+        Rate: 125
+      - Level: 6
+        Rate: 130
+      - Level: 7
+        Rate: 135
+      - Level: 8
+        Rate: 140
+      - Level: 9
+        Rate: 145
+      - Level: 10
+        Rate: 150
     Element: Weapon
     Requires:
       SpCost: 7
@@ -2232,6 +2299,7 @@ Body:
       Critical: true
     Hit: Single
     HitCount: 1
+    HitRate: 120
     Element: Weapon
     Duration1:
       - Level: 1
@@ -4768,6 +4836,29 @@ Body:
     Range: 1
     Hit: Multi_Hit
     HitCount: -8
+    HitRate:
+      - Level: 1
+        Rate: 50
+      - Level: 2
+        Rate: 50
+      - Level: 3
+        Rate: 50
+      - Level: 4
+        Rate: 50
+      - Level: 5
+        Rate: 50
+      - Level: 6
+        Rate: 50
+      - Level: 7
+        Rate: 50
+      - Level: 8
+        Rate: 50
+      - Level: 9
+        Rate: 50
+      - Level: 10
+        Rate: 50
+      Skills:
+        AS_SONICACCEL: true
     Element: Weapon
     AfterCastActDelay: 2000
     AfterCastWalkDelay: 2000
@@ -5605,6 +5696,7 @@ Body:
     Range: -7
     Hit: Single
     HitCount: 1
+    HitRate: 120
     Element: Weapon
     Duration2: 60000
     Status: Poison
@@ -5619,6 +5711,7 @@ Body:
     Range: -7
     Hit: Single
     HitCount: 1
+    HitRate: 120
     Element: Weapon
     Duration2: 30000
     Status: Blind
@@ -5633,6 +5726,7 @@ Body:
     Range: -7
     Hit: Single
     HitCount: 1
+    HitRate: 120
     Element: Weapon
     Duration2: 30000
     Status: Silence
@@ -5647,6 +5741,7 @@ Body:
     Range: -7
     Hit: Single
     HitCount: 1
+    HitRate: 120
     Element: Weapon
     Duration2: 5000
     Status: Stun
@@ -5661,6 +5756,7 @@ Body:
     Range: -7
     Hit: Single
     HitCount: 1
+    HitRate: 120
     Element: Weapon
     Duration1: 100
     Duration2: 20000
@@ -5676,6 +5772,7 @@ Body:
     Range: -7
     Hit: Single
     HitCount: 1
+    HitRate: 120
     Element: Dark
     Duration2: 30000
     Status: Curse
@@ -5690,6 +5787,7 @@ Body:
     Range: -7
     Hit: Single
     HitCount: 1
+    HitRate: 120
     Element: Weapon
     Duration2: 30000
     Status: Sleep
@@ -5716,6 +5814,7 @@ Body:
     Range: -7
     Hit: Single
     HitCount: 1
+    HitRate: 120
     Element: Water
   - Id: 185
     Name: NPC_GROUNDATTACK
@@ -5729,6 +5828,7 @@ Body:
     Range: -7
     Hit: Single
     HitCount: 1
+    HitRate: 120
     Element: Earth
   - Id: 186
     Name: NPC_FIREATTACK
@@ -5741,6 +5841,7 @@ Body:
     Range: -7
     Hit: Single
     HitCount: 1
+    HitRate: 120
     Element: Fire
   - Id: 187
     Name: NPC_WINDATTACK
@@ -5753,6 +5854,7 @@ Body:
     Range: -7
     Hit: Single
     HitCount: 1
+    HitRate: 120
     Element: Wind
   - Id: 188
     Name: NPC_POISONATTACK
@@ -5765,6 +5867,7 @@ Body:
     Range: -7
     Hit: Single
     HitCount: 1
+    HitRate: 120
     Element: Poison
     Status: Poison
   - Id: 189
@@ -5778,6 +5881,7 @@ Body:
     Range: -7
     Hit: Single
     HitCount: 1
+    HitRate: 120
     Element: Holy
   - Id: 190
     Name: NPC_DARKNESSATTACK
@@ -5790,6 +5894,7 @@ Body:
     Range: -7
     Hit: Single
     HitCount: 1
+    HitRate: 120
     Element: Dark
   - Id: 191
     Name: NPC_TELEKINESISATTACK
@@ -5802,6 +5907,7 @@ Body:
     Range: -7
     Hit: Single
     HitCount: 1
+    HitRate: 120
     Element: Ghost
   - Id: 192
     Name: NPC_MAGICALATTACK
@@ -9380,6 +9486,7 @@ Body:
     Range: -7
     Hit: Single
     HitCount: 1
+    HitRate: 120
     Element: Undead
   - Id: 348
     Name: NPC_CHANGEUNDEAD
@@ -9392,6 +9499,7 @@ Body:
     Range: -2
     Hit: Single
     HitCount: 1
+    HitRate: 120
     Element: Undead
     Duration2: 60000
     Status: ChangeUndead
@@ -13089,6 +13197,7 @@ Body:
     Range: 4
     Hit: Multi_Hit
     HitCount: 5
+    HitRate: 120
     CastTime: 1000
     AfterCastActDelay: 1000
     Requires:
@@ -15599,6 +15708,7 @@ Body:
       IgnoreLandProtector: true
     Hit: Multi_Hit
     HitCount: 1
+    HitRate: 120
     SplashArea:
       - Level: 1
         Area: 5
@@ -15659,6 +15769,7 @@ Body:
     Range: 6
     Hit: Single
     HitCount: 1
+    HitRate: 200
     Element: Fire
     SplashArea: 3
     ActiveInstance: 14
@@ -15673,6 +15784,7 @@ Body:
     Range: 6
     Hit: Single
     HitCount: 1
+    HitRate: 200
     Element: Water
     SplashArea: 3
     ActiveInstance: 14
@@ -15689,6 +15801,7 @@ Body:
     Range: 6
     Hit: Single
     HitCount: 1
+    HitRate: 200
     Element: Wind
     SplashArea: 3
     ActiveInstance: 14
@@ -15703,6 +15816,7 @@ Body:
     Range: 6
     Hit: Single
     HitCount: 1
+    HitRate: 200
     Element: Poison
     SplashArea: 3
     ActiveInstance: 14
@@ -15719,6 +15833,7 @@ Body:
     Range: 6
     Hit: Single
     HitCount: 1
+    HitRate: 200
     Element: Dark
     SplashArea: 3
     ActiveInstance: 14
@@ -15766,6 +15881,7 @@ Body:
     Range: -9
     Hit: Single
     HitCount: 1
+    HitRate: 120
     Element: Weapon
     Duration2: 120000
     Status: Bleeding
@@ -32261,6 +32377,27 @@ Body:
     Range: -1
     Hit: Single
     HitCount: 1
+    HitRate:
+      - Level: 1
+        Rate: 105
+      - Level: 2
+        Rate: 110
+      - Level: 3
+        Rate: 115
+      - Level: 4
+        Rate: 120
+      - Level: 5
+        Rate: 125
+      - Level: 6
+        Rate: 130
+      - Level: 7
+        Rate: 135
+      - Level: 8
+        Rate: 140
+      - Level: 9
+        Rate: 145
+      - Level: 10
+        Rate: 150
     Element: Weapon
     Requires:
       SpCost:
@@ -32319,6 +32456,27 @@ Body:
       TargetTrap: true
     Hit: Single
     HitCount: 1
+    HitRate:
+      - Level: 1
+        Rate: 110
+      - Level: 2
+        Rate: 120
+      - Level: 3
+        Rate: 130
+      - Level: 4
+        Rate: 140
+      - Level: 5
+        Rate: 150
+      - Level: 6
+        Rate: 160
+      - Level: 7
+        Rate: 170
+      - Level: 8
+        Rate: 180
+      - Level: 9
+        Rate: 190
+      - Level: 10
+        Rate: 200
     Element: Fire
     SplashArea: 2
     Knockback: 2
@@ -32773,6 +32931,27 @@ Body:
     Range: -2
     Hit: Multi_Hit
     HitCount: 3
+    HitRate:
+      - Level: 1
+        Rate: 105
+      - Level: 2
+        Rate: 110
+      - Level: 3
+        Rate: 115
+      - Level: 4
+        Rate: 120
+      - Level: 5
+        Rate: 125
+      - Level: 6
+        Rate: 130
+      - Level: 7
+        Rate: 135
+      - Level: 8
+        Rate: 140
+      - Level: 9
+        Rate: 145
+      - Level: 10
+        Rate: 150
     Element: Weapon
     Requires:
       SpCost: 7

+ 299 - 1
db/re/skill_db.yml

@@ -37,6 +37,10 @@
 #   HitCount:                 Skill hit count. (Default: 0)
 #     - Level                 Skill level.
 #       Count                 Number of hits at specific skill level.
+#   HitRate                   Skill hit rate. (Default: 100)
+#     - Level                 Skill level.
+#       Rate                  Rate is a percent of hit rate added to hit rate.
+#       Skills:               Skill flagged as a requirement (players only). (Optional)
 #   Element:                  Skill element. (Default: Neutral)
 #     - Level                 Skill level.
 #       Element               Element at specific skill level.
@@ -140,7 +144,7 @@
 
 Header:
   Type: SKILL_DB
-  Version: 3
+  Version: 4
 
 Body:
   - Id: 1
@@ -170,6 +174,27 @@ Body:
     Range: -1
     Hit: Single
     HitCount: 1
+    HitRate:
+      - Level: 1
+        Rate: 105
+      - Level: 2
+        Rate: 110
+      - Level: 3
+        Rate: 115
+      - Level: 4
+        Rate: 120
+      - Level: 5
+        Rate: 125
+      - Level: 6
+        Rate: 130
+      - Level: 7
+        Rate: 135
+      - Level: 8
+        Rate: 140
+      - Level: 9
+        Rate: 145
+      - Level: 10
+        Rate: 150
     Element: Weapon
     CopyFlags:
       Skill:
@@ -268,6 +293,27 @@ Body:
       TargetTrap: true
     Hit: Single
     HitCount: 1
+    HitRate:
+      - Level: 1
+        Rate: 110
+      - Level: 2
+        Rate: 120
+      - Level: 3
+        Rate: 130
+      - Level: 4
+        Rate: 140
+      - Level: 5
+        Rate: 150
+      - Level: 6
+        Rate: 160
+      - Level: 7
+        Rate: 170
+      - Level: 8
+        Rate: 180
+      - Level: 9
+        Rate: 190
+      - Level: 10
+        Rate: 200
     Element: Fire
     SplashArea:
       - Level: 1
@@ -2102,6 +2148,27 @@ Body:
     Range: -2
     Hit: Multi_Hit
     HitCount: 3
+    HitRate:
+      - Level: 1
+        Rate: 105
+      - Level: 2
+        Rate: 110
+      - Level: 3
+        Rate: 115
+      - Level: 4
+        Rate: 120
+      - Level: 5
+        Rate: 125
+      - Level: 6
+        Rate: 130
+      - Level: 7
+        Rate: 135
+      - Level: 8
+        Rate: 140
+      - Level: 9
+        Rate: 145
+      - Level: 10
+        Rate: 150
     Element: Weapon
     Requires:
       SpCost: 7
@@ -2247,6 +2314,7 @@ Body:
       Critical: true
     Hit: Single
     HitCount: 1
+    HitRate: 120
     Element: Weapon
     Duration1:
       - Level: 1
@@ -5013,6 +5081,29 @@ Body:
     Range: 1
     Hit: Multi_Hit
     HitCount: -8
+    HitRate:
+      - Level: 1
+        Rate: 90
+      - Level: 2
+        Rate: 90
+      - Level: 3
+        Rate: 90
+      - Level: 4
+        Rate: 90
+      - Level: 5
+        Rate: 90
+      - Level: 6
+        Rate: 90
+      - Level: 7
+        Rate: 90
+      - Level: 8
+        Rate: 90
+      - Level: 9
+        Rate: 90
+      - Level: 10
+        Rate: 90
+      Skills:
+        AS_SONICACCEL: true
     Element: Weapon
     Duration2: 4500
     Cooldown: 1000
@@ -5875,6 +5966,7 @@ Body:
     Range: -7
     Hit: Single
     HitCount: 1
+    HitRate: 120
     Element: Weapon
     Duration2: 18000
     Status: Poison
@@ -5889,6 +5981,7 @@ Body:
     Range: -7
     Hit: Single
     HitCount: 1
+    HitRate: 120
     Element: Weapon
     Duration2: 18000
     Status: Blind
@@ -5903,6 +5996,7 @@ Body:
     Range: -7
     Hit: Single
     HitCount: 1
+    HitRate: 120
     Element: Weapon
     Duration2: 18000
     Status: Silence
@@ -5917,6 +6011,7 @@ Body:
     Range: -7
     Hit: Single
     HitCount: 1
+    HitRate: 120
     Element: Weapon
     Duration2: 4500
     Status: Stun
@@ -5931,6 +6026,7 @@ Body:
     Range: -7
     Hit: Single
     HitCount: 1
+    HitRate: 120
     Element: Weapon
     Duration1: 100
     Duration2: 17000
@@ -5946,6 +6042,7 @@ Body:
     Range: -7
     Hit: Single
     HitCount: 1
+    HitRate: 120
     Element: Dark
     Duration2: 28000
     Status: Curse
@@ -5960,6 +6057,7 @@ Body:
     Range: -7
     Hit: Single
     HitCount: 1
+    HitRate: 120
     Element: Weapon
     Duration2: 18000
     Status: Sleep
@@ -5986,6 +6084,7 @@ Body:
     Range: -7
     Hit: Single
     HitCount: 1
+    HitRate: 120
     Element: Water
   - Id: 185
     Name: NPC_GROUNDATTACK
@@ -5999,6 +6098,7 @@ Body:
     Range: -7
     Hit: Single
     HitCount: 1
+    HitRate: 120
     Element: Earth
   - Id: 186
     Name: NPC_FIREATTACK
@@ -6011,6 +6111,7 @@ Body:
     Range: -7
     Hit: Single
     HitCount: 1
+    HitRate: 120
     Element: Fire
   - Id: 187
     Name: NPC_WINDATTACK
@@ -6023,6 +6124,7 @@ Body:
     Range: -7
     Hit: Single
     HitCount: 1
+    HitRate: 120
     Element: Wind
   - Id: 188
     Name: NPC_POISONATTACK
@@ -6035,6 +6137,7 @@ Body:
     Range: -7
     Hit: Single
     HitCount: 1
+    HitRate: 120
     Element: Poison
     Status: Poison
   - Id: 189
@@ -6048,6 +6151,7 @@ Body:
     Range: -7
     Hit: Single
     HitCount: 1
+    HitRate: 120
     Element: Holy
   - Id: 190
     Name: NPC_DARKNESSATTACK
@@ -6060,6 +6164,7 @@ Body:
     Range: -7
     Hit: Single
     HitCount: 1
+    HitRate: 120
     Element: Dark
   - Id: 191
     Name: NPC_TELEKINESISATTACK
@@ -6072,6 +6177,7 @@ Body:
     Range: -7
     Hit: Single
     HitCount: 1
+    HitRate: 120
     Element: Ghost
   - Id: 192
     Name: NPC_MAGICALATTACK
@@ -6386,6 +6492,27 @@ Body:
     Range: -1
     Hit: Single
     HitCount: 1
+    HitRate:
+      - Level: 1
+        Rate: 105
+      - Level: 2
+        Rate: 110
+      - Level: 3
+        Rate: 115
+      - Level: 4
+        Rate: 120
+      - Level: 5
+        Rate: 125
+      - Level: 6
+        Rate: 130
+      - Level: 7
+        Rate: 135
+      - Level: 8
+        Rate: 140
+      - Level: 9
+        Rate: 145
+      - Level: 10
+        Rate: 150
     Element: Weapon
     CopyFlags:
       Skill:
@@ -9690,6 +9817,7 @@ Body:
     Range: -7
     Hit: Single
     HitCount: 1
+    HitRate: 120
     Element: Undead
   - Id: 348
     Name: NPC_CHANGEUNDEAD
@@ -9702,6 +9830,7 @@ Body:
     Range: -2
     Hit: Single
     HitCount: 1
+    HitRate: 120
     Element: Undead
     Duration2: 60000
     Status: ChangeUndead
@@ -13412,6 +13541,7 @@ Body:
         Size: 11
     Hit: Multi_Hit
     HitCount: 5
+    HitRate: 120
     Element: Weapon
     CastTime: 800
     AfterCastActDelay: 1000
@@ -15985,6 +16115,7 @@ Body:
       IgnoreLandProtector: true
     Hit: Multi_Hit
     HitCount: 1
+    HitRate: 120
     SplashArea:
       - Level: 1
         Area: 5
@@ -16046,6 +16177,7 @@ Body:
     Range: 6
     Hit: Single
     HitCount: 1
+    HitRate: 200
     Element: Fire
     SplashArea: 3
     ActiveInstance: 14
@@ -16060,6 +16192,7 @@ Body:
     Range: 6
     Hit: Single
     HitCount: 1
+    HitRate: 200
     Element: Water
     SplashArea: 3
     ActiveInstance: 14
@@ -16076,6 +16209,7 @@ Body:
     Range: 6
     Hit: Single
     HitCount: 1
+    HitRate: 200
     Element: Wind
     SplashArea: 3
     ActiveInstance: 14
@@ -16090,6 +16224,7 @@ Body:
     Range: 6
     Hit: Single
     HitCount: 1
+    HitRate: 200
     Element: Poison
     SplashArea: 3
     ActiveInstance: 14
@@ -16106,6 +16241,7 @@ Body:
     Range: 6
     Hit: Single
     HitCount: 1
+    HitRate: 200
     Element: Dark
     SplashArea: 3
     ActiveInstance: 14
@@ -16153,6 +16289,7 @@ Body:
     Range: -9
     Hit: Single
     HitCount: 1
+    HitRate: 120
     Element: Weapon
     Duration2: 108000
     Status: Bleeding
@@ -18229,6 +18366,7 @@ Body:
     Range: -9
     Hit: Single
     HitCount: 1
+    HitRate: 120
     Element: Neutral
     Duration2: 108000
     Status: Bleeding
@@ -18243,6 +18381,7 @@ Body:
     Range: 6
     Hit: Single
     HitCount: 1
+    HitRate: 200
     Element: Water
     SplashArea: 4
     ActiveInstance: 14
@@ -18857,6 +18996,27 @@ Body:
         Size: 11
     Hit: Single
     HitCount: 3
+    HitRate: # TODO: Confirm rate
+      - Level: 1
+        Rate: 103
+      - Level: 2
+        Rate: 106
+      - Level: 3
+        Rate: 109
+      - Level: 4
+        Rate: 112
+      - Level: 5
+        Rate: 115
+      - Level: 6
+        Rate: 118
+      - Level: 7
+        Rate: 121
+      - Level: 8
+        Rate: 124
+      - Level: 9
+        Rate: 127
+      - Level: 10
+        Rate: 130
     Element: Weapon
     CopyFlags:
       Skill:
@@ -20781,6 +20941,17 @@ Body:
     Range: 1
     Hit: Single
     HitCount: 1
+    HitRate:
+      - Level: 1
+        Rate: 114
+      - Level: 2
+        Rate: 118
+      - Level: 3
+        Rate: 122
+      - Level: 4
+        Rate: 126
+      - Level: 5
+        Rate: 130
     Element: Weapon
     AfterCastActDelay: 1000
     Requires:
@@ -23466,6 +23637,27 @@ Body:
     Range: 2
     Hit: Single
     HitCount: 1
+    HitRate:
+      - Level: 1
+        Rate: 70
+      - Level: 2
+        Rate: 75
+      - Level: 3
+        Rate: 80
+      - Level: 4
+        Rate: 85
+      - Level: 5
+        Rate: 90
+      - Level: 6
+        Rate: 100
+      - Level: 7
+        Rate: 105
+      - Level: 8
+        Rate: 110
+      - Level: 9
+        Rate: 115
+      - Level: 10
+        Rate: 120
     Element: Weapon
     SplashArea:
       - Level: 1
@@ -24443,6 +24635,27 @@ Body:
     Range: 7
     Hit: Single
     HitCount: 1
+    HitRate:
+      - Level: 1
+        Rate: 105
+      - Level: 2
+        Rate: 110
+      - Level: 3
+        Rate: 115
+      - Level: 4
+        Rate: 120
+      - Level: 5
+        Rate: 125
+      - Level: 6
+        Rate: 130
+      - Level: 7
+        Rate: 135
+      - Level: 8
+        Rate: 140
+      - Level: 9
+        Rate: 145
+      - Level: 10
+        Rate: 150
     Element: Weapon
     Requires:
       SpCost:
@@ -28738,6 +28951,17 @@ Body:
     Name: GN_REMODELING_CART
     Description: Cart Remodeling
     MaxLevel: 5
+    HitRate:
+      - Level: 1
+        Rate: 104
+      - Level: 2
+        Rate: 108
+      - Level: 3
+        Rate: 112
+      - Level: 4
+        Rate: 116
+      - Level: 5
+        Rate: 120
   - Id: 2476
     Name: GN_CART_TORNADO
     Description: Cart Tornado
@@ -30438,6 +30662,17 @@ Body:
     Range: -9
     Hit: Single
     HitCount: 1
+    HitRate:
+      - Level: 1
+        Rate: 10
+      - Level: 2
+        Rate: 9
+      - Level: 3
+        Rate: 8
+      - Level: 4
+        Rate: 7
+      - Level: 5
+        Rate: 6
     Knockback: 6
     CastTime:
       - Level: 1
@@ -44015,6 +44250,27 @@ Body:
     Range: -1
     Hit: Single
     HitCount: 1
+    HitRate:
+      - Level: 1
+        Rate: 105
+      - Level: 2
+        Rate: 110
+      - Level: 3
+        Rate: 115
+      - Level: 4
+        Rate: 120
+      - Level: 5
+        Rate: 125
+      - Level: 6
+        Rate: 130
+      - Level: 7
+        Rate: 135
+      - Level: 8
+        Rate: 140
+      - Level: 9
+        Rate: 145
+      - Level: 10
+        Rate: 150
     Element: Weapon
     Requires:
       SpCost:
@@ -44073,6 +44329,27 @@ Body:
       TargetTrap: true
     Hit: Single
     HitCount: 1
+    HitRate:
+      - Level: 1
+        Rate: 110
+      - Level: 2
+        Rate: 120
+      - Level: 3
+        Rate: 130
+      - Level: 4
+        Rate: 140
+      - Level: 5
+        Rate: 150
+      - Level: 6
+        Rate: 160
+      - Level: 7
+        Rate: 170
+      - Level: 8
+        Rate: 180
+      - Level: 9
+        Rate: 190
+      - Level: 10
+        Rate: 200
     Element: Fire
     SplashArea: 2
     Knockback: 2
@@ -44566,6 +44843,27 @@ Body:
     Range: -2
     Hit: Multi_Hit
     HitCount: 3
+    HitRate:
+      - Level: 1
+        Rate: 15
+      - Level: 2
+        Rate: 110
+      - Level: 3
+        Rate: 115
+      - Level: 4
+        Rate: 120
+      - Level: 5
+        Rate: 125
+      - Level: 6
+        Rate: 130
+      - Level: 7
+        Rate: 135
+      - Level: 8
+        Rate: 140
+      - Level: 9
+        Rate: 145
+      - Level: 10
+        Rate: 150
     Element: Weapon
     Requires:
       SpCost: 7

+ 5 - 1
db/skill_db.yml

@@ -37,6 +37,10 @@
 #   HitCount:                 Skill hit count. (Default: 0)
 #     - Level                 Skill level.
 #       Count                 Number of hits at specific skill level.
+#   HitRate                   Skill hit rate. (Default: 100)
+#     - Level                 Skill level.
+#       Rate                  Rate is a percent of hit rate added to hit rate.
+#       Skills:               Skill flagged as a requirement (players only). (Optional)
 #   Element:                  Skill element. (Default: Neutral)
 #     - Level                 Skill level.
 #       Element               Element at specific skill level.
@@ -140,7 +144,7 @@
 
 Header:
   Type: SKILL_DB
-  Version: 3
+  Version: 4
 
 Footer:
   Imports:

+ 22 - 1
doc/skill_db.txt

@@ -3,7 +3,7 @@
 //===== By: ==================================================
 //= rAthena Dev Team
 //===== Last Updated: ========================================
-//= 20220126
+//= 20230803
 //===== Description: =========================================
 //= Explanation of the skill_db.yml file and structure.
 //============================================================
@@ -157,6 +157,27 @@ Sequence Map Form
 
 ---------------------------------------
 
+HitRate: Skill hit rate. Rate is 100 by default.
+
+Can be defined in scalar form or sequence map form:
+Scalar Form
+  HitRate: 120
+
+Sequence Map Form
+  HitRate:
+    - Level: 1
+      Count: 120
+    - Level: 2
+      Count: 140
+    - Level: 3
+      Count: 160
+    - Level: 4
+      Count: 180
+    - Level: 5
+      Count: 200
+
+---------------------------------------
+
 Element: Skill element.
 
 Neutral (Default)

+ 4 - 0
doc/yaml/db/skill_db.yml

@@ -20,6 +20,10 @@
 #   HitCount:                 Skill hit count. (Default: 0)
 #     - Level                 Skill level.
 #       Count                 Number of hits at specific skill level.
+#   HitRate                   Skill hit rate. (Default: 100)
+#     - Level                 Skill level.
+#       Rate                  Rate is a percent of hit rate added to hit rate.
+#       Skills:               Skill flagged as a requirement (players only). (Optional)
 #   Element:                  Skill element. (Default: Neutral)
 #     - Level                 Skill level.
 #       Element               Element at specific skill level.

+ 38 - 85
src/map/battle.cpp

@@ -34,6 +34,8 @@
 #include "pc_groups.hpp"
 #include "pet.hpp"
 
+using namespace rathena;
+
 struct Battle_Config battle_config;
 static struct eri *delay_damage_ers; //For battle delay damage structures.
 
@@ -3097,98 +3099,49 @@ static bool is_attack_hitting(struct Damage* wd, struct block_list *src, struct
 		hitrate += pc_checkskill(sd,AC_VULTURE);
 #endif
 
-	if(skill_id) {
-		switch(skill_id) { //Hit skill modifiers
+	if (skill_id > 0) {
+		switch (skill_id) { //Hit skill modifiers
 			//It is proven that bonus is applied on final hitrate, not hit.
-			case SM_BASH:
-			case MS_BASH:
-				hitrate += hitrate * 5 * skill_lv / 100;
-				break;
-			case MS_MAGNUM:
-			case SM_MAGNUM:
-				hitrate += hitrate * 10 * skill_lv / 100;
-				break;
-			case KN_AUTOCOUNTER:
-			case PA_SHIELDCHAIN:
-			case NPC_WATERATTACK:
-			case NPC_GROUNDATTACK:
-			case NPC_FIREATTACK:
-			case NPC_WINDATTACK:
-			case NPC_POISONATTACK:
-			case NPC_HOLYATTACK:
-			case NPC_DARKNESSATTACK:
-			case NPC_TELEKINESISATTACK:
-			case NPC_UNDEADATTACK:
-			case NPC_CHANGEUNDEAD:
-			case NPC_EARTHQUAKE:
-			case NPC_POISON:
-			case NPC_BLINDATTACK:
-			case NPC_SILENCEATTACK:
-			case NPC_STUNATTACK:
-			case NPC_PETRIFYATTACK:
-			case NPC_CURSEATTACK:
-			case NPC_SLEEPATTACK:
-			case NPC_BLEEDING:
-			case NPC_BLEEDING2:
-				hitrate += hitrate * 20 / 100;
-				break;
-			case NPC_FIREBREATH:
-			case NPC_ICEBREATH:
-			case NPC_ICEBREATH2:
-			case NPC_THUNDERBREATH:
-			case NPC_ACIDBREATH:
-			case NPC_DARKNESSBREATH:
-				hitrate *= 2;
-				break;
-			case KN_PIERCE:
-			case ML_PIERCE:
-				hitrate += hitrate * 5 * skill_lv / 100;
-				break;
-			case AS_SONICBLOW:
-				if(sd && pc_checkskill(sd,AS_SONICACCEL) > 0)
-#ifdef RENEWAL
-					hitrate += hitrate * 90 / 100;
-#else
-					hitrate += hitrate * 50 / 100;
-#endif
-				break;
-#ifdef RENEWAL
-			case RG_BACKSTAP:
-				hitrate += skill_lv; // !TODO: What's the rate increase?
-				break;
-#endif
-			case RK_SONICWAVE:
-				hitrate += hitrate * 3 * skill_lv / 100; // !TODO: Confirm the hitrate bonus
-				break;
 			case MC_CARTREVOLUTION:
 			case GN_CART_TORNADO:
 			case GN_CARTCANNON:
-				if (sd && pc_checkskill(sd, GN_REMODELING_CART))
-					hitrate += pc_checkskill(sd, GN_REMODELING_CART) * 4;
-				break;
-			case LG_BANISHINGPOINT:
-				hitrate += 5 * skill_lv;
-				break;
-			case GC_VENOMPRESSURE:
-				hitrate += 10 + 4 * skill_lv;
-				break;
-			case SC_FATALMENACE:
-				if (skill_lv < 6)
-					hitrate -= 35 - 5 * skill_lv;
-				else if (skill_lv > 6)
-					hitrate += 5 * skill_lv - 30;
-				break;
+			{
+				uint16 cart_remodel_lv = pc_checkskill(sd, GN_REMODELING_CART);
+
+				if (sd && cart_remodel_lv > 0)
+					hitrate = hitrate * skill_get_hitrate(GN_REMODELING_CART, cart_remodel_lv) / 100;
+			}
+			break;
 			case RL_SLUGSHOT:
-				{
-					int8 dist = distance_bl(src, target);
-					if (dist > 3) {
-						// Reduce n hitrate for each cell after initial 3 cells. Different each level
-						// -10:-9:-8:-7:-6
-						dist -= 3;
-						hitrate -= ((11 - skill_lv) * dist);
+			{
+				uint32 dist = distance_bl(src, target);
+
+				if (dist > 3) {
+					// Reduce n hitrate for each cell after initial 3 cells.
+					hitrate -= (skill_get_hitrate(RL_SLUGSHOT, skill_lv) * (dist - 3));
+				}
+			}
+			break;
+			default:
+			{
+				struct s_skill_hitrate skill_hitrate = skill_db.find(skill_id)->hitrate;
+
+				if (skill_hitrate.rate[skill_lv] != 100) { // Hit skill modifiers
+					bool req_fail = false;
+
+					// List of skills required to be learned before adjusting hitrate (players only).
+					for (uint16 skill_req : skill_hitrate.skills) {
+						if (sd && pc_checkskill(sd, skill_req) == 0) {
+							req_fail = true;
+							break;
+						}
 					}
+
+					if (!req_fail)
+						hitrate = hitrate * skill_hitrate.rate[skill_lv] / 100;
 				}
-				break;
+			}
+			break;
 		}
 	} else if (sd && wd->type&DMG_MULTI_HIT && wd->div_ == 2) // +1 hit per level of Double Attack on a successful double attack (making sure other multi attack skills do not trigger this) [helvetica]
 		hitrate += pc_checkskill(sd,TF_DOUBLE);

+ 34 - 0
src/map/skill.cpp

@@ -172,6 +172,7 @@ static bool skill_check(uint16 id) {
 
 // Skill DB
 e_damage_type skill_get_hit( uint16 skill_id )                     { if (!skill_check(skill_id)) return DMG_NORMAL; return skill_db.find(skill_id)->hit; }
+int skill_get_hitrate( uint16 skill_id, uint16 skill_lv )          { skill_get_lv(skill_id, skill_lv, skill_db.find(skill_id)->hitrate.rate); }
 int skill_get_inf( uint16 skill_id )                               { skill_get(skill_id, skill_db.find(skill_id)->inf); }
 int skill_get_ele( uint16 skill_id , uint16 skill_lv )             { skill_get_lv(skill_id, skill_lv, skill_db.find(skill_id)->element); }
 int skill_get_max( uint16 skill_id )                               { skill_get(skill_id, skill_db.find(skill_id)->max); }
@@ -23641,6 +23642,39 @@ uint64 SkillDatabase::parseBodyNode(const ryml::NodeRef& node) {
 			memset(skill->num, 0, sizeof(skill->num));
 	}
 
+	if (this->nodeExists(node, "HitRate")) {
+		if (!this->parseNode("HitRate", "Rate", node, skill->hitrate.rate))
+			return 0;
+
+		const auto &skillsNode = node["HitRate"];
+
+		if (this->nodeExists(skillsNode, "Skills")) {
+			for (const auto &it : skillsNode) {
+				std::string req_skill_name;
+				c4::from_chars(it.key(), &req_skill_name);
+				uint16 req_skill_id = skill_name2id(req_skill_name.c_str());
+
+				if (skill_id == 0) {
+					this->invalidWarning(skillsNode, "HitRate requires skill %s is invalid.\n", req_skill_name.c_str());
+					return 0;
+				}
+
+				bool active;
+
+				if (!this->asBool(skillsNode, req_skill_name, active))
+					return 0;
+
+				if (active)
+					skill->hitrate.skills.push_back(req_skill_id);
+				else
+					util::vector_erase_if_exists(skill->hitrate.skills, req_skill_id);
+			}
+		}
+	} else {
+		if (!exists)
+			memset(skill->hitrate.rate, 100, sizeof(skill->hitrate.rate));
+	}
+
 	if (this->nodeExists(node, "Element")) {
 		const auto elementNode = node["Element"];
 		std::string element;

+ 9 - 1
src/map/skill.hpp

@@ -246,6 +246,12 @@ struct s_skill_copyable { // [Cydh]
 	uint16 req_opt;
 };
 
+/// Skill HitRate structure.
+struct s_skill_hitrate{
+	int32 rate[MAX_SKILL_LEVEL];
+	std::vector<uint16> skills;
+};
+
 /// Database skills
 struct s_skill_db {
 	uint16 nameid;								///< Skill ID
@@ -259,6 +265,7 @@ struct s_skill_db {
 	int32 splash[MAX_SKILL_LEVEL];				///< Splash effect
 	uint16 max;									///< Max level
 	int32 num[MAX_SKILL_LEVEL];					///< Number of hit
+	struct s_skill_hitrate hitrate;				///< Hitrate
 	bool castcancel;							///< Cancel cast when being hit
 	uint16 cast_def_rate;						///< Def rate during cast a skill
 	e_battle_flag skill_type;					///< Skill type
@@ -315,7 +322,7 @@ private:
 	template<typename T, size_t S> bool parseNode(const std::string& nodeName, const std::string& subNodeName, const ryml::NodeRef& node, T(&arr)[S]);
 
 public:
-	SkillDatabase() : TypesafeCachedYamlDatabase("SKILL_DB", 3, 1) {
+	SkillDatabase() : TypesafeCachedYamlDatabase("SKILL_DB", 4, 1) {
 		this->clear();
 	}
 
@@ -498,6 +505,7 @@ int skill_tree_get_max( uint16 skill_id, int b_class );	// Celest
 #define skill_get_index(skill_id) skill_db.get_index((skill_id), false, __FUNCTION__, __FILE__, __LINE__) /// Get skill index from skill_id (common usage on source)
 int skill_get_type( uint16 skill_id );
 e_damage_type skill_get_hit( uint16 skill_id );
+int skill_get_hitrate( uint16 skill_id, uint16 skill_lv );
 int skill_get_inf( uint16 skill_id );
 int skill_get_ele( uint16 skill_id , uint16 skill_lv );
 int skill_get_max( uint16 skill_id );