Link Search Menu Expand Document

Hit Mask

Hit mask refers to the updating mask used by both player updating and NPC updating to display head bars and/or hit splats on an entity. The mask is made up out of two sections - hits splats and head bars.


Table of contents

Hits

The first half of the mask covers hits. Up to 255 hits can be transmitted to the client per updated entity in one game tick. While the amount of hits that can be transmitted is quite high, the number of hits that can render on one entity is capped to the four first ones.

Supported Variables

The OldSchool RuneScape hit mask is a direct 1:1 match with the one found in today’s RuneScape 3. Because of that, the hits can support a lot more than what they’re currently being utilized for in OldSchool RuneScape. All the variables covered below are written as small short smarts, meaning their minimum value is 0, and the maximum value is 32,767.

  • The type of the hit. The type indicates the config that will be used for the given hit splat.
    • You can read about all the different types of hits in the hit types section below.
    • The types 0x7FFF(32,767) and 0x7FFE(32,766) are used to inform the client to read the hit info differently. A breakdown of this can be found below in ways of writing hits.
  • The amount displayed on the hit.
  • The delay until the hit is rendered. The duration is in client ticks.
  • Unused variables(They are supported by the mask, but never used in OldSchool RuneScape):
    • Soak type. The type indicates the config that will be used for the soak splat that appears next to the normal hit splat.
    • Soak amount displayed on the soak hit splat.

Ways of Writing Hits

There are three possible ways to write a hit splat to the client:

  • An ignored hit. While the client will appropriately read the hit, it will not process it. The code returns early for this type.
    • Must write the hit type as the value 0x7FFE(32,766). This informs the client that it is about to read an ignored hit.
    • Only the delay is written alongside the ignored hit. Nothing about soaking or the amount is sent.
  • A basic hit. This covers all the hits you ever see in OldSchool RuneScape.
    • The hit type written must correspond to the id of the hitmark config.
    • Only the amount and delay are written alongside the basic hits. Soak information is not sent.
  • A soaked hit. While this is never used, it is supported:
    • Must write the hit type as the value 0x7FFF(32,767). This informs the client that it’s about to read a soaked hit.
    • The actual type of the hit is now written separately, which is followed by the amount shown on the hit splat.
    • The soak hit splat is written afterwards, along with its amount.

Hit Types

There are two types of hit configs - ones that always display the same sprite, and ones that show a tinted version if the hit was dealt by someone other than yourself.

  • Varbit-driven types. These types have two variations of the hit splat - an active and an inactive version. They all make use of varbit 10,236, which corresponds to the in-game setting “Hitsplat tinting”. If the varbit’s value is 0, the inactive version of the hit splat will be shown for the dynamic versions. The always active column indicates configs which will always display the active icon, regardless of the current value of the given varbit.
Active Icon Inactive Icon Always active id Dynamic id Name Description
Active block Inactive block 12 13 Block Indicates a hit of zero damage.
Active damage Inactive damage 16 17 Damage Indicates a successful hit that dealt damage. In the Nightmare Zone, drinking an absorption potion will cause all monster-inflicted damage to be zero, but will still use this red damage hit splat to indicate the successful hit.
Active shield Inactive shield placeholder 18 19 Shield Indicates damage dealt to Verzik Vitur’s, The Nightmare’s and Tempoross’ shields. While the inactive icon is defined in the config, it seems to be a placeholder.
Active armour Inactive armour 20 21 Armour Indicates damage dealt to Zalcano’s stone armour. The dynamic id is never actually used.
Active charge Inactive charge 22 23 Charge Indicates totems being healed while charging them during the fight against The Nightmare.
Active discharge Inactive discharge 24 25 Discharge Indicates totems being damaged while the parasites discharge them during the fight against The Nightmare. The dynamic is is never actually used.
  • Always active types. These will always display the same sprite, regardless of whom the hit splat is showing on. As such, they only have one sprite defined.
Icon Id Name Description
Corruption 0 Corruption Corruption has a chance to apply on the target of the player who is under the effects of either Lesser Corruption or Greater Corruption during a successful hit.
Poison 2 Poison Poison damages entities over time, lowering the damage by one every four hit splat cycles.
Unused Disease 3 Unknown The use case of this hit splat is currently unknown. While it resembles disease rather closely, it is not used for disease in OldSchool RuneScape.
Disease 4 Disease Indicates the player being under the effects of a disease, which periodically drains stats.
Venom 5 Venom Venom damages entities over time, increasing the damage by one every four hit splat cycles, capping out at 20.
Heal 6 Heal Indicates the entity healing for the number shown on the hit splat.

Client Code

The below piece of code is a refactored version of the hits section of the hit mask. Do note that the transformations applied to the hitCount variable may differ between the different versions of the client.

hitCount = buffer.readUnsignedByte();
if (hitCount > 0) {
    for (int i = 0; i < hitCount; i++) {
        int soakType = -1;
        int amount = -1;
        int soakedAmount = -1;
        int hitType = buffer.readSmallSmart();
        if (hitType == 0x7FFF) {
            hitType = buffer.readSmallSmart();
            amount = buffer.readSmallSmart();
            soakType = buffer.readSmallSmart();
            soakedAmount = buffer.readSmallSmart();
        } else if (hitType == 0x7FFE) {
            hitType = -1;
        } else {
            amount = buffer.readSmallSmart();
        }
        int delay = buffer.readSmallSmart();
        updatedEntity.applyActorHitsplat(hitType, amount, soakType, soakedAmount, Client.gameCycle, delay);
    }
}

Head Bars

The second half of the hit mask covers head bars. Contrary to popular belief, head bars are not linked to hits themselves. Nothing prevents the client from showing head bars - or hits for that matter - individually, without the other half. Although up to 255 head bars can be transmitted to the client per updated entity in one game tick, only the first head bar will actually render.

Supported Variables

Below is a list of supported variables for head bars. Even though the mask itself is a direct copy of that found in RuneScape 3 today, only one head bar can display in OldSchool RuneScape. The code responsible for finding the respective current head bar stops at the very first head bar that is active at the moment, regardless of if it actually matches the one that is being updated.

  • The type of the head bar. See types here.
  • The time span of the head bar. The number written informs the client to gradually progress the head bar towards the destination provided further below. Each value corresponds to one client tick. If the time span is written as 0x7FFF(32,767), the head bar will instead be removed instantly. If that’s the case, none of the below will be written for this head bar.
  • The delay until the head bar becomes visible. The value corresponds to one client tick.
  • The number of pixels to fill the head bar with.
  • If the time span is between 1 and 32,766(inclusive), the number of pixels at which the gradual progression stops.

Head Bar Types

Below is a table of different head bar types. The types cannot be resized dynamically by the client, and as such, a lot of duplicate types are made to fill every possible width that might be used.

  • The duration variable is the total duration of the head bar in client ticks.
  • The disposal variable refers to the client tick at which the head bar begins gradually vanishing.
  • The width refers to the width of the head bar sprite.

The table is sorted according to the internal head bar type ids.

Id Filled sprite Empty sprite Name Duration Disposal Width Description
0 Full health_30 Empty health_30 Health 300 N/A 30 Indicates the current health of the entity.
1 Full blue_50 Empty blue_50 N/A 300 280 50 Indicates the remaining stardust in a shooting star.
2 Full health_40 Empty health_40 Health 300 280 40 Indicates the current health of the entity.
3 Full shield_30 Empty shield_30 Shield 300 280 30 Indicates the current level of shield for Verzik Vitur, The Nightmare and Tempoross.
4 Full shield_40 Empty shield_40 Shield 300 280 40 Indicates the current level of shield for Verzik Vitur, The Nightmare and Tempoross.
5 Full shield_50 Empty shield_50 Shield 300 280 50 Indicates the current level of shield for Verzik Vitur, The Nightmare and Tempoross.
6 Full shield_60 Empty shield_60 Shield 300 280 60 Indicates the current level of shield for Verzik Vitur, The Nightmare and Tempoross.
7 Full cox_puzzle_timer Empty cox_puzzle_timer N/A 60 40 100 Indicates the progress made towards the unfreezing of the Ice Demon, and feeding of the Corrupted Scavenger in Chambers of Xeric.
8 Full cox_olm_claw_timer Empty cox_olm_claw_timer N/A 60 40 120 Indicates the time until the restoration of the Great Olm’s claws in Chambers of Xeric.
9 Full shield_80 Empty shield_80 Shield 300 280 80 Indicates the current level of shield for Verzik Vitur, The Nightmare and Tempoross.
10 Full shield_100 Empty shield_100 Shield 300 280 100 Indicates the current level of shield for Verzik Vitur, The Nightmare and Tempoross.
11 Full shield_120 Empty shield_120 Shield 300 280 120 Indicates the current level of shield for Verzik Vitur, The Nightmare and Tempoross.
12 Full health_70 Empty health_70 Shield 300 280 70 Indicates the current level of shield for Verzik Vitur, The Nightmare and Tempoross.
13 Full shield_140 Empty shield_140 Shield 300 280 140 Indicates the current level of shield for Verzik Vitur, The Nightmare and Tempoross.
14 Full shield_160 Empty shield_160 Shield 300 280 160 Indicates the current level of shield for Verzik Vitur, The Nightmare and Tempoross.
15 Full armour_30 Empty armour_30 Armour 300 280 30 Indicates the current level of Zalcano’s shield armour.
16 Full health_50 Empty health_50 Health 300 280 50 Indicates the current health of the entity.
17 Full health_60 Empty health_60 Health 300 280 60 Indicates the current health of the entity.
18 Full health_80 Empty health_80 Health 300 280 80 Indicates the current health of the entity.
19 Full health_100 Empty health_100 Health 300 280 100 Indicates the current health of the entity.
20 Full health_120 Empty health_120 Health 300 280 120 Indicates the current health of the entity.
21 Full health_140 Empty health_140 Health 300 280 140 Indicates the current health of the entity.
22 Full health_160 Empty health_160 Health 300 280 160 Indicates the current health of the entity.
23 Full armour_40 Empty armour_40 Armour 300 280 40 Indicates the current level of Zalcano’s shield armour.
24 Full armour_50 Empty armour_50 Armour 300 280 50 Indicates the current level of Zalcano’s shield armour.
25 Full armour_60 Empty armour_60 Armour 300 280 60 Indicates the current level of Zalcano’s shield armour.
26 Full armour_80 Empty armour_80 Armour 300 280 80 Indicates the current level of Zalcano’s shield armour.
27 Full armour_100 Empty armour_100 Armour 300 280 100 Indicates the current level of Zalcano’s shield armour.
28 Full armour_120 Empty armour_120 Armour 300 280 120 Indicates the current level of Zalcano’s shield armour.
29 Full armour_140 Empty armour_140 Armour 300 280 140 Indicates the current level of Zalcano’s shield armour.
30 Full armour_160 Empty armour_160 Armour 300 280 160 Indicates the current level of Zalcano’s shield armour.
31 Full charge_30 Empty charge_30 Charge 300 280 30 Indicates the current charge of the totems at The Nightmare.
32 Full charge_40 Empty charge_40 Charge 300 280 40 Indicates the current charge of the totems at The Nightmare.
33 Full charge_50 Empty charge_50 Charge 300 280 50 Indicates the current charge of the totems at The Nightmare.
34 Full charge_60 Empty charge_60 Charge 300 280 60 Indicates the current charge of the totems at The Nightmare.
35 Full charge_80 Empty charge_80 Charge 300 280 80 Indicates the current charge of the totems at The Nightmare.
36 Full charge_100 Empty charge_100 Charge 300 280 100 Indicates the current charge of the totems at The Nightmare.
37 Full charge_120 Empty charge_120 Charge 300 280 120 Indicates the current charge of the totems at The Nightmare.
38 Full charge_140 Empty charge_140 Charge 300 280 140 Indicates the current charge of the totems at The Nightmare.
39 Full charge_160 Empty charge_160 Charge 300 280 160 Indicates the current charge of the totems at The Nightmare.
40 Full shield_70 Empty shield_70 Shield 300 280 70 Indicates the current level of shield for Verzik Vitur, The Nightmare and Tempoross.
41 Full armour_70 Empty armour_70 Armour 300 280 70 Indicates the current level of Zalcano’s shield armour.
42 Full charge_70 Empty charge_70 Charge 300 280 70 Indicates the current charge of the totems at The Nightmare.

Client Code

The below piece of code is a refactored version of the head bars section of the hit mask. Do note that the transformations applied to the hitCount, fillAmount and destinationFillAmount variables may differ between the different versions of the client.

headbarCount = buffer.readUnsignedByte();
if (headbarCount > 0) {
    for (int i = 0; i < headbarCount; i++) {
        int headbarType = buffer.readSmallSmart();
        int timespan = buffer.readSmallSmart();
        if (timespan == 0x7FFF) {
            updatedEntity.removeHeadbar(headbarType);
        } else {
            int delay = buffer.readSmallSmart();
            int fillAmount = buffer.readUnsignedByte();
            int destinationFillAmount = timespan > 0 ? var0.readUnsignedByte() : fillAmount;
            updatedEntity.updateHeadbar(headbarType, Client.gameCycle, timespan, delay, fillAmount, destinationFillAmount);
        }
    }
}

Media

The below gif demonstrates sending an individual poison hit splat, without any associated head bars. Individual hitsplat


The below gif demonstrates sending an individual head bar without any associated hits. It also shows the gradual progression from 100% down to 25%, over a time span of 90 client ticks.

Individual headbar


The below gif demonstrates sending two hit splats, each with a soak hit splat. Note that the hit splat shown is configurable for everything. For this demonstration, I’ve specifically used the inactive and active versions of the respective hit splats. The reason behind capping it to two hit splats is due to overlapping. Since OldSchool RuneScape does not technically support soaking, the positioning of the hit splats is done in a way that makes any more than two hit splats begin overlapping.

Soaking


References

  1. Hitsplat - OS Wikia