Ranking
Original Post
Replay File Specification
This is (more or less) a full description of the events in a replay file (.rpl) and what they mean. I'm still uncertain on some things (designated by orange question marks), so any help filling in those cracks would be very appreciated!

This covers RPL spec versions 10 and 12, which are used in modern versions of Toribash. Earlier versions might differ.

Oh, and before you ask:


Types
  • Int (Whole number, 32 bits, -2,147,483,648 <= x <= 2,147,483,647)
  • Fix (Decimal number with 6 digits after decimal point)
  • Long Fix (Decimal number with 8 digits after decimal point)
  • String (Plain text)
  • Bool (On/Off)
  • Unsigned Quartchar (Positive whole number, 2 bits, 0 <= x <= 4)


Coordinates
In the classic.tbm mod on default rules, and from Tori's perspective:
  • +X: Left
  • +Y: Backwards, away from Uke
  • +Z: Up
  • +Pitch: Pitch Down
  • +Roll: Roll Counterclockwise
  • +Yaw: Yaw Left


Events

VERSION {version number}
Specifies the PRL spec version the file uses.
  • version number: (Int) PRL spec version.


FIGHTNAME 0; [replay name]
Specifies the replay's name. Shows up in the ToriUI replay browser.
  • replay name: (String) Name of the replay.


BOUT {player ID}; {player name}
Specifies the usernames of the players.
  • player ID: (Unsigned Quartchar) Internal ID of the player. 0 for "Tori", 1 for "Uke". 2 and 3 can only be used via replay file hacking.
  • player name: (String) Username of the player.

Note
Tori and Uke have the internal "usernames" of tori and uke, respectively.

AUTHOR 0; [author name]
Specifies the author of the replay.
  • author name: (String) Name of the replay author.


ENGAGE {player ID}; {x} {y} {z} {pitch} {roll} {yaw} (v12)
Manually specify the starting position of a player. Overrides engageheight, engagedistance, and engagerotation. Position is evaluated first, then rotation.
  • x/y/z (Fix) The world position of the player (point between the player's feet).
  • roll/pitch/yaw (Int) The 3D angle the player is facing (center of the player's head).


NEWGAME {?};{matchframes} {turnframes} {reactiontime} 0 0 {flags} {engagedistance} {damage} {sumo} {mod} 0 {dojosize} {dismemberthreshold} {fracturethreshold} {engageheight} 0 1 0 2 {engagerotation} 0 {engagespace} {dqtimeout} 0 {dojotype} {gravity x} {gravity y} {gravity z} {dqflag} 0 {drawwinner} {pointthreshold} {maxcontacts} {winpoint}
Specifies the match rules (Ctrl+G).
  • matchframes: (Int) Match time limit in frames.
  • turnframes: (Int) How long a turn lasts, in frames.
  • reactiontime: (Int) Used in multiplayer, timer length between turns in seconds. No effect in replays.
  • flags: (Halfchar) The state of 4 flags represented as binary places in a number:
    • Ones place: Enable body-part disqualification.
    • Twos place: Enable dismemberment.
    • Fours place: Disable grabbing.
    • Eights place: Enable fracturing.
  • engagedistance: (Int) Distance between the players.
  • damage: (Int) Determines if self-damage is enabled.
    • 0: Self-damage is disabled.
    • 1: Self-damage is enabled.
    • 2: Self-damage is enabled exclusively.
  • sumo: (Bool) If enabled, wrists/ankles count as part of hands/feet for body-part disqualification. No effect if disqualification is set to false.
  • mod: (String) Filename of the mod file.
  • dojosize: (Int) Size of the dojo bounds.
  • dismemberthreshold: (Int) Damage threshold to dismember a joint. No effect if dismemberment is set to false.
  • fracturethreshold: (Int) Damage threshold to fracture a joint. No effect if fracture is set to false.
  • engageheight: (Int) Height of the players above the ground.
  • engagerotation: (Int) Rotation of the two players, relative to the point between them.
  • engagespace: (Int) No effect?
  • dqtimeout: (Int) How long a player can touch the ground (dojo/body-part) before disqualification.
  • dojotype: (Int) Shape of the dojo.
    • 0: Square
    • 1: Circle
    • 2+: Disable Dojo
  • gravity *: (Fix) World's gravity.
  • dqflag: (Bool) If enabled, dojo disqualification will bypass dqtimeout.
  • drawwinner: (Int) This player will win instead of a draw?
  • pointthreshold: (Int) If a hit is below this threshold, it won't count towards damage dealt?
  • maxcontacts: (?) How many grabballs that a player can have at once? (8 <= x <= 12
  • winpoint: (Int) If greater than 0, first player to reach this amount of damage dealt will instantly win.


WORLD_SHADER 0;{shader}
Specifies the world shaders to use.
  • shader: (String) Filename of the shader file.


FRAME {frame no.}; {?} {?} {?} {?}
Indicates the start of a frame. All following events will belong to this frame until the next FRAME event or EOF.
  • frame no.: (Int) The frame number.


JOINT {player ID}; {{joint ID} {state ID}} [...]
Sets the state of a player's joints.
  • player ID: (Unsigned Quartchar) Internal ID of the player. 0 for "Tori", 1 for "Uke". 2 and 3 can only be used via replay file hacking.
  • joint ID: As follows:
    • 0: neck
    • 1: chest
    • 2: lumbar
    • 3: abs
    • 4: right pec
    • 5: right shoulder
    • 6: right elbow
    • 7: left pec
    • 8: left shoulder
    • 9: left elbow
    • 10: right wrist
    • 11: left wrist
    • 12: right glute
    • 13: left glute
    • 14: right hip
    • 15: left hip
    • 16: right knee
    • 17: left knee
    • 18: right ankle
    • 19: left ankle
  • state ID As follows:
    • 1: extend/right rotate/right bend
    • 2: contract/left rotate/left bend
    • 3: hold
    • 4: relax


GRIP {player ID}; {left hand} {right hand}
Sets the grab state of a player's joints.
  • player ID: (Unsigned Quartchar) Internal ID of the player. 0 for "Tori", 1 for "Uke". 2 and 3 can only be used via replay file hacking.
  • left/right hand: The state of this hand. 1 for grabbing, 2 for ungrabbing.


POS {player ID}; {{x} {y} {z}} {x21}
Sets the world position of a player's body parts. Order is as follows:
  • Head
  • Breast
  • Chest
  • Stomach
  • Thorax
  • Right Pecs
  • Right Biceps
  • Right Triceps
  • Left Pecs
  • Left Biceps
  • Left Triceps
  • Right Hand
  • Left Hand
  • Right Butt
  • Left Butt
  • Right Thigh
  • Left Thigh
  • Left Leg
  • Right Leg
  • Right Foot
  • Left Foot

  • player ID: (Unsigned Quartchar) Internal ID of the player. 0 for "Tori", 1 for "Uke". 2 and 3 can only be used via replay file hacking.
  • x/y/z: (Long Fix) The coordinate value of this body part.


QAT {player ID}; {{a} {b} {c} {d}} {x21}
Sets the rotation of a player's body parts. Same order as in POS.
  • player ID: (Unsigned Quartchar) Internal ID of the player. 0 for "Tori", 1 for "Uke". 2 and 3 can only be used via replay file hacking.
  • a/b/c/d: (Fix) The quaternion values of this body part.

Note
Explaining quaternions is outside the scope of this thread. The reason Toribash and many other games use them to represent rotation is to avoid a problem called gimbal lock.

LINVEL {player ID}; {{x} {y} {z}} {x21}
Sets the linear velocity of a player's body parts. Same order as in POS.
  • player ID: (Unsigned Quartchar) Internal ID of the player. 0 for "Tori", 1 for "Uke". 2 and 3 can only be used via replay file hacking.
  • x/y/z: (Long Fix) The velocity of this body part.


ANGVEL {player id}; {{p} {r} {y}} {x21}
Sets the angular velocity of a player's body parts. Same order as in POS.
  • player id: (Unsigned Quartchar) Internal ID of the player. 0 for "Tori", 1 for "Uke". 2 and 3 can only be used via replay file hacking.
  • p/r/y: (Long Fix) The velocity of this body part.


CRUSH {player ID}; {joint ID} [...]
Dismembers a player's joint.
  • player ID: (Unsigned Quartchar) Internal ID of the player. 0 for "Tori", 1 for "Uke". 2 and 3 can only be used via replay file hacking.
  • joint ID: The ID of the dismembered joint. Same as in JOINT.


FRACT {player ID}; {joint ID} [...]
Fractures a player's joint.
  • player ID: (Unsigned Quartchar) Internal ID of the player. 0 for "Tori", 1 for "Uke". 2 and 3 can only be used via replay file hacking.
  • joint ID: The ID of the fractured joint. Same as in JOINT.


EPOS 0; {{x} {y} {z}} {x entities}
Sets the world position of the movable objects in the world.
  • x/y/z: (Long Fix) The coordinate value of this object.


EQAT 0; {{a} {b} {c} {d}} {x entities}
Sets the rotation of the movable objects in the world.
  • a/b/c/d: (Long Fix) The quaternion values of this object.


ELINVEL 0; {{x} {y} {z}} {x entities}
Sets the linear velocity of the movable objects in the world.
  • x/y/z: (Long Fix) The velocity of this object.


EANGVEL 0; {{p} {r} {y}} {x entities}
Sets the angular velocity of the movable objects in the world.
  • p/r/y: (Long Fix) The velocity of this object.


EMOTE {player ID}; {text}
Displays a message above a player's head. (/em)
  • player ID: (Unsigned Quartchar) Internal ID of the player. 0 for "Tori", 1 for "Uke". 2 and 3 can only be used via replay file hacking.
  • text: (String) Text to display.
Attached Images
okay.png (11.4 KB, 35 views)
The first two values after FRAME are score corresponding to Uke and Tori respectively. The third and fourth values are a little stranger, I've done some testing in the past and the most I could figure out is the following.
If Tori and Uke do not suffer dismemberments, v1=v4 and v2=v3 (value 3 and value 4 are the same as Uke and Tori's scores, but mirrored). In Toribash, a dismemberment penalises the player that suffered it by giving the other player a certain amount of points (I think usually 2000 or 5000 depending on the body part). If Tori is dismembered, v3 decreases by the amount of points that Uke gained from the dismemberment, and if Uke is dismembered, v4 decreases by the amount of points Tori gained. v3 and v4 differ from v2 and v1 in that they subtract the score that each player lost from being dismembered. The values can be negative if a player suffers a lot of dms.

FRAME x; {UkeScore} {ToriScore} {ToriScore - DMsToriSuffered} {UkeScore - DMsUkeSuffered}

Note that UkeScore and ToriScore consist of the sum of the damage dealt both by hitting and dismembering.
Cool thread. If you haven't seen Moltex's hacking tutorial it might have something useful: https://forum.toribash.com/showthread.php?t=19742 However it is quite old and the replay file structure might have changed since then.
Last edited by pusga; Jul 19, 2020 at 04:47 PM.
oh yeah