RF455-097 RF 4.55: class attack skills (Bash Explosion, Force Impact, Fatal Step…) deal the wrong damage: the server looks their index up in the general `skill` table
Game: RF 4.55 (Dragonborn), server v0.3.1, Windows build (stock gameserver.exe).
Client: the supported Taiwan build, RF_Online.bin SHA-256 46528aac…2bbc558 (2025-07-16), Language=Taiwan.
Data: the shipped db\gamedata_rf455.db.
Summary
The client sends a damaging class skill as 05/02 attack_skill_request, the same message as a general attack
skill, with the class-skill row index. GoMMO looks that index up in the skill table (84 general skills),
never in classskill. So no class attack skill gets its own damage:
- an index past 83 has no
skillrow, and gets a default multiplier (about +63% at level 1 GM); - an index under 84 picks up an unrelated general skill's row. Bellato's and Cora's Bash Explosion (rows 16, 57), Judgment (9) and Full Swing (48) land on rows with formula −1 and attack constant 0, which gives a zero damage band. Double Crash (6) gets Death Blow's 155%.
Their own data (and rfdatabase.net) says 218–596%. Read from the code and data (static); not live-tested.
The client (read, RF_Online.bin)
- The skill-use dispatch
0x413a80tests the category byte ([action+0x5c], 2 = class skill;0x4070f0) and "attackable" (0x4638f0→0x463960). A skill is attackable when, on any level, the per-level byte atSkillForce.edfrecord+0x90 + 0x28·Lis 0 or 4. - Attackable → 05/02, sender
0x5a4ac0. Not attackable → 11/07, sender0x5a0790. - The 05/02 body has the category byte (2) at offset 3 and the u16 skill index at offset 4, taken from
action[+4](0x40b200). The 11/07 sender takes its index from the same field, and live 11/07 requests inhistory.logcarryclassskillrow indices (217, 228). So 05/02 carries theclassskillrow index too (inferred from the shared field; no class-skill 05/02 was captured). - 22 class skills pass the test: every row in the table below.
The server (read, v0.3.1)
handleAttackSkill0x1407d9d60passes the index toSkillAttackFor0x140525660→loadSkillAttack0x1405258a0, a query on theskilltable bym_dwIndex.- The category byte goes only to
resolveSFEffectOK. There is no branch for class skills, and no loader that readsclassskill'sm_nAttConstant/m_fAttFormulaConstant(loadClassSkillGroupsFrom0x1407c21e0andbuildSFEffectColumns0x140527f40take neither). skillAttackPoint0x1408d5ac0:- with a row:
formula × attConst[L] / 788 × (0.847 + 0.86472·(0.5L+3.5)/7 + 0.28824·M/99)(row+0x40,+8); - with no row (
test r8, r8/je 0x1408d5b30): formula 1.0 (0x140d7ca94) and attConst 788.0 (0x140d7cb2c).
- with a row:
handleClassSkillCast(11/07) computes no damage at all.
Every class skill the client sends as 05/02 (Credit to RFDB for http://rfdatabase.net)
"data" is the class skill's own multiplier (its formula constant, attack constant taken as 788, level 1, GM). It
equals rfdatabase.net's "Skill damage output". "server" is what skillAttackPoint computes for the index it
receives. −100% is a zero band (formula −1 × attConst 0); how much a zero band finally hits for wasn't traced.
code row name data (attConst as 788) server (level 1, GM) 7001E 6 DoubleCrash 218% 155% skill row 6 Death Blow (formula 1.5625, attConst 788) 70021 9 Judgment 218% -100% skill row 9 Aid Stretching (formula -1, attConst 0) 70008 16 BashExplosion 377% -100% skill row 16 Slam (formula -1, attConst 0) 80048 48 FullSwing 298% -100% skill row 48 Booster (formula -1, attConst 0) 80008 57 BashExplosion 377% -100% skill row 57 Offence wave (formula -1, attConst 0) 4006C 84 Mangle 218% 63% no skill row, default 1.0/788 40008 100 BashExplosion 377% 63% no skill row, default 1.0/788 71099 132 EagleCrusher 298% 63% no skill row, default 1.0/788 700A2 138 FatalStep 596% 63% no skill row, default 1.0/788 7100C 141 SDFiring 298% 63% no skill row, default 1.0/788 810C1 169 FirstStrikeShot 218% 63% no skill row, default 1.0/788 800CC 180 SilenceStep 596% 63% no skill row, default 1.0/788 8100C 183 SDFiring 298% 63% no skill row, default 1.0/788 410EB 211 AminingLauncher 218% 63% no skill row, default 1.0/788 410EC 212 CompoundSiege 298% 63% no skill row, default 1.0/788 410ED 216 DesperationLauncher 298% 63% no skill row, default 1.0/788 410EF 218 MightblastSiege 397% 63% no skill row, default 1.0/788 400F6 222 IllusionAttack 596% 63% no skill row, default 1.0/788 4100C 225 SDFiring 298% 63% no skill row, default 1.0/788 7011B 259 DeadlyStaff 218% 63% no skill row, default 1.0/788 7111C 260 ForceImpact 397% 63% no skill row, default 1.0/788 81146 302 StrikingForce 397% 63% no skill row, default 1.0/788
Three of these rows carry attack constant 7880, not 788 (Deadly Staff, Force Impact, Striking Force). Read as-is, that would be ten times the site's value, so it may need checking too if class skills get their own loader.
How to reproduce
On one monster, compare a few normal hits with a few casts of:
- Bash Explosion as Accretia Mercenary (row 100): about a weak skill, far below 3.8×;
- Bash Explosion as Bellato Shield Miller (row 16) or Cora Black Knight (row 57): next to nothing.
Related reports
- RF455-093New: class skills sent as 11/07 lose their instant effects. This report is the other path: class skills the client sends as 05/02.
- RF455-030Released (released 0.1.2) rebuilt 12 class skills in
classskilland RF455-092New follows it up (names). Neither touches class-skill damage. - RF455-051Released (splash targets on 05/02) and RF455-046Released (the damage number's display) are about the same message, but not about where the damage values come from.
Suggested fix
In handleAttackSkill, when the category byte at offset 3 is 2 (class skill), load the attack row from
classskill (the same columns loadSkillAttack reads from skill) instead of skill.