Actions

Configs/LocType

From RuneWiki

Structure

Regardless of the revision, the packing process has some basic rules.

  1. Loc names must be unique. They can have + symbols in the name.
  2. Configs are a purely text format with a custom parser. True/false values are written as yes/no.
  3. Opcodes are written in the order they're read in. This means the packing process is writing immediately as it parses, with a few exceptions for properties that are "collected" and written at the end (typically arrays or complex properties). If you decode to memory or a standard intermediate format, you will lose this information, not that it matters much for the end result. Only bother with this if you care to match the checksum exactly.

Because of #2 you'll also be able to see when they copy-paste lines and/or forget to remove old properties!

[example]
name=Example
desc=This is an example
model=example
length=4
width=2
length=2
recol1s=5
recol1d=1234

RS2

Changes based on decompiling available clients. If a revision is off by a couple, it's because we were missing those clients or they were not auto-decompilable (yet) to narrow the revision down further. I'll refine this again later.

Names are an attempt to be authentic and correct, if you have any more information definitely reach out.

Property Opcode History Notes
model 1 Added 186 (2003-12-02)

Changed 300 (2005-03-07)

Changed 581 (2010-01-29)

Written at the end of a config.
name 2 Added 186 (2003-12-02) Written at the end of a config.
desc 3 Added 186 (2003-12-02)

Removed 410 (2006-05-25)

Examine text, written at the end of a config. Later transmitted from the server.
model 5 Added 249 (2004-08-09)

Changed 300 (2005-03-07)

Changed 581 (2010-01-29)

Written at the end of a config. This opcode is used to save bytes in the list of models.
width 14 Added 186 (2003-12-02)
length 15 Added 186 (2003-12-02)
blockwalk=no 17 Added 186 (2003-12-02)
blockrange=no 18 Added 186 (2003-12-02)
active 19 Added 186 (2003-12-02)
hillskew=yes 21 Added 186 (2003-12-02) hillskew mode 1
sharelight=yes 22 Added 186 (2003-12-02)
occlude=yes 23 Added 186 (2003-12-02)
anim 24 Added 186 (2003-12-02)
- 25 Added 186 (2003-12-02)

Removed 249 (2004-08-09)

This opcode was used internally for disposing of alpha data between animation frames.

It was not manually defined and comes from a linked anim.

blockwalk=yes 27 Added 454 (2007-03-26)
wallwidth 28 Added 186 (2003-12-02)
ambient 29 Added 186 (2003-12-02)
contrast 39 Added 186 (2003-12-02)
op 30-35 Added 186 (2003-12-02) Originally this reserved opcodes >= 30 & < 39 (likely copy-pasted).
recol 40 Added 186 (2003-12-02)
retex 41 Added 465 (2007-07-19)
recoldpalette 42 Added 494 (2008-04-15)
mapfunction 60 Added 186 (2003-12-02)
mirror=yes 62 Added 186 (2003-12-02)
shadow=no 64 Added 186 (2003-12-02)
resizex 65 Added 186 (2003-12-02)
resizey 66 Added 186 (2003-12-02)
resizez 67 Added 186 (2003-12-02)
mapscene 68 Added 186 (2003-12-02)

Removed 530 (2009-01-28)

forceapproach 69 Added 186 (2003-12-02) This is a bitmask, one bit will be unset - the direction.
offsetx 70 Added 194 (2004-01-07)
offsety 71 Added 194 (2004-01-07)
offsetz 72 Added 194 (2004-01-07)
forcedecor=yes 73 Added 194 (2004-01-07)
breakroutefinding=yes 74 Added 245 (2004-07-13)
raiseobject 75 Added 249 (2004-08-09)
multiloc 77 Added 289 (2005-01-17)
bgsound 78 Added 417 (2006-06-27)
randomsound 79 Added 417 (2006-06-27)
treeskew* 81 Added 465 (2007-07-19) hillskew mode 2
82 Added 487 (2008-02-12) Related to whether it should render?
hardshadow=no* 88 Added 487 (2008-02-12) If this isn't hardshadow, it's something like sceneshadow?
randseq=no* 89 Added 487 (2008-02-12) Disable randomizing the initial seq frame.
90 Added 487 (2008-02-12)
members=yes 91 Added 494 (2008-04-15)
multiloc 92 Added 498 (2008-05-09) multiloc with a default value.
rotateskew* 93 Added 498 (2008-05-09) hillskew mode 3 - Same as previous but reads 2-bytes.
ceilingskew=yes* 94 Added 498 (2008-05-09) hillskew mode 4
skewtofit=yes* 95 Added 498 (2008-05-09) hillskew mode 5
96 Added 501 (2008-07-01) Related to having an animation?
mapscenerotates=yes 97 Added 506 (2008-07-28) Map scene icon rotates with the loc.
98 Added 530 (2009-01-28)
cursor1 99 Added 530 (2009-01-28)
cursor2 100 Added 530 (2009-01-28)
mapsceneangle* 101 Added 530 (2009-01-28) Map scene icon angle offset.
mapscene 102 Added 530 (2009-01-28) Replaces the earlier mapscene.
occlude=no 103 Added 535 (2009-03-16)
bgsoundvol 104 Added 535 (2009-03-16)
mapsceneflipy* 105 Added 535 (2009-03-16) Map scene icon flipped vertically.
anims 106 Added 542 (2009-04-02) Animation weights?
mel 107 Added 548 (2009-05-27) Map element.
memberop* 150-155 Added 548 (2009-05-27) Members-only ops.
quests* 160 Added 555 (2009-09-02)
rotateskew* 162 Added 581 (2010-01-29) Same as previous but reads 4-bytes.
tint 163 Added 581 (2010-01-29) Hue, saturation, luminance, weight values
postoffsetx 164 Added 593 (2010-03-02)
postoffsety 165 Added 593 (2010-03-02)
postoffsetz 166 Added 593 (2010-03-02)
decorheight* 167 Added 595 (2010-03-12)
168 Added 611 (2010-06-08)
169 Added 611 (2010-06-08)
occludewidth 170 Added 618 (2010-09-14)
occludeheight 171 Added 618 (2010-09-14)
bgsoundrate 173 Added 623 (2010-10-11)
177 Added 637 (2011-02-07)
bgsounddistance 178 Added 637 (2011-02-07)
189 667+ (todo)
param 249 Added 500 (2008-06-05) Map of params key -> value.

hillskew Types

enum HillSkewType {
    none = 0,
    floor_skew = 1,
    tree_skew = 2,
    rotate = 3,
    ceiling_skew = 4,
    skew_to_fit = 5
}

shape Names

enum LocShape {
    wall_straight = 0,
    wall_diagonalcorner = 1,
    wall_l = 2,
    wall_squarecorner = 3,
    wall_diagonal = 9,
    walldecor_straight_nooffset = 4,
    walldecor_straight_offset = 5,
    walldecor_diagonal_nooffset = 6,
    walldecor_diagonal_offset = 7,
    walldecor_diagonal_both = 8,
    centrepiece_straight = 10,
    centrepiece_diagonal = 11,
    grounddecor = 22,
    roof_straight = 12,
    roof_diagonal_with_roofedge = 13,
    roof_diagonal = 14,
    roof_l_concave = 15,
    roof_l_convex = 16,
    roof_flat = 17,
    roofedge_straight = 18,
    roofedge_diagonalcorner = 19,
    roofedge_l = 20,
    roofedge_squarecorner = 21,
}

shape Map Editor Hotkeys

// hotkeys in jagex's map editor are used as the extension for loc models so they know which shape to inherit
enum LocShapeHotkey {
    _1 = 0, // 'wall_straight',
    _2 = 1, // 'wall_diagonalcorner',
    _3 = 2, // 'wall_l',
    _4 = 3, // 'wall_squarecorner',
    _5 = 9, // 'wall_diagonal',
    //
    _q = 4, // 'walldecor_straight_nooffset',
    _w = 5, // 'walldecor_straight_offset',
    _e = 6, // 'walldecor_diagonal_nooffset',
    _r = 7, // 'walldecor_diagonal_offset',
    _t = 8, // 'walldecor_diagonal_both',
    //
    _8 = 10, // 'centrepiece_straight',
    _9 = 11, // 'centrepiece_diagonal',
    _0 = 22, // 'grounddecor',
    //
    _a = 12, // 'roof_straight',
    _s = 13, // 'roof_diagonal_with_roofedge',
    _d = 14, // 'roof_diagonal',
    _f = 15, // 'roof_l_concave',
    _g = 16, // 'roof_l_convex',
    _h = 17, // 'roof_flat',
    //
    _z = 18, // 'roofedge_straight',
    _x = 19, // 'roofedge_diagonalcorner',
    _c = 20, // 'roofedge_l',
    _v = 21, // 'roofedge_squarecorner',
}

model Property

This property is used to render a specific model based on the shape. The shape to use comes from the map data and zone protocol.

This opcode is packed at the end of the config when we receive it in the cache.

Config
[example]
model=example

They only need to define this as a single model=name, the shape is derived by looking for suffixes on file names in their src/models/ directory. The suffixes are not the shape numbers here but rather their map editor's hotkeys!

Scenario 1: a model example_8.ob3 and they have model=example in their loc config. It sees _8 and then knows to add shape=10.

Scenario 2: two models, example_8.ob3 and example_0.ob3 and they have model=example in their loc config. It sees both suffixes and knows to add shape=10 and shape=22 with those model IDs.

Scenario 3: two models, example_8.ob3 and example_0.ob3 again, but this time they have model=example_0 in their loc config. It sees that it's a specific suffix and adds that grounddecor model using shape=10 instead. This is a very particular feature used to override the appearance of the standard centrepiece_straight shape.

186
if (opcode == 1) {
    int count = buf.g1();

    this.shapes = new int[count];
    this.models = new int[count];

    for (int i = 0; i < count; i++) {
        this.models[i] = buf.g2();
        this.shapes[i] = buf.g1();
    }
}
249

Opcode 5 was added (in addition to 1) for models that are solely shape 10.

if (opcode == 5) {
    int count = buf.g1();

    if (this.models == null || lowmem) {
        this.shapes = null;
        this.models = new int[count];

        for (int i = 0; i < count; i++) {
            this.models[i] = buf.g2();
        }
    }
}
300

Locs are able to change their appearance for lowmem (low detail) mode. I have no clue what this looks like on their end -- maybe another key like ldmodel, or maybe it just assumes one of the model= values is lowmem inherently?

if (opcode == 1) {
    int count = buf.g1();

    if (count > 0) {
        // this opcode can be packed twice -- the first instance is the standard models
        // the second instance is the low-detail model

        if (this.models == null || lowmem) {
            this.shapes = new int[count];
            this.models = new int[count];

            for (int i = 0; i < count; i++) {
                this.models[i] = buf.g2();
                this.shapes[i] = buf.g1();
            }
        } else {
            buf.pos += count * 2;
        }
    }
} else if (opcode == 5) {
    int count = buf.g1();

    if (count > 0) {
        // same as above

        if (this.models == null || lowmem) {
            this.shapes = null;
            this.models = new int[count];

            for (int i = 0; i < count; i++) {
                this.models[i] = buf.g2();
            }
        } else {
            buf.pos += count * 2;
        }
    }
}
581

Models is now a 2d array so multiple models can be merged when rendering a loc shape.

Opcode 5 is now used to differentiate the lowmem models (not limited to shape 10).

if (opcode == 1 || opcode == 5) {
    if (opcode == 5 && LocTypeList.lowmem) {
        this.skipModels(buf);
    }

    int shapeCount = buf.g1();
    this.shapes = new byte[shapeCount];
    this.models = new int[shapeCount][];

    for (int i = 0; i < shapeCount; i++) {
        this.shapes[i] = buf.g1();

        int modelCount = buf.g1();
        this.models[i] = new int[modelCount];

        for (int j = 0; j < modelCount; j++) {
            this.models[i][j] = buf.g2();
        }
    }

    if (opcode == 5 && !LocTypeList.lowmem) {
        this.skipModels(buf);
    }
}

void skipModels(Buffer buf) {
    int shapeCount = buf.g1();
    for (int i = 0; i < shapeCount; i++) {
        buf.pos++;

        int modelCount = buf.g1();
        buf.pos += modelCount * 2;
    }
}

name Property

This property is the visible tooltip name. Occasionally, the internal debug name can slip in here, but that isn't visible unless the loc is "active" (based on shape or explicitly defined).

This opcode is packed at the end of the config when we receive it in the cache.

Config
[example]
name=Example
186
if (opcode == 2) {
    this.name = buf.gjstr();
}

desc Property

This property is the examine text. After 2006 this was no longer stored in the cache and is transmitted on-demand when a player examines something.

This opcode is packed at the end of the config when we receive it in the cache.

Config
[example]
desc=This is an example
186
if (opcode == 3) {
    this.desc = buf.gjstr();
}

width Property

Number of tiles a loc takes on the east/west axis.

186
if (opcode == 14) {
    this.width = buf.g1();
}

length Property

Number of tiles a loc takes on the north/south axis.

186
if (opcode == 15) {
    this.length = buf.g1();
}

blockwalk Property

Pathfinder property - controls line-of-walk checks through this tile.

186
if (opcode == 17) {
    this.blockwalk = false;
}

blockrange Property

Pathfinder property - controls line-of-sight checks through this tile.

186
if (opcode == 18) {
    this.blockrange = false;
}

active Property

Overrides if a loc can be examined and/or interacted with. There is a default value based on the available shapes/ops.

Config
[door]
active=yes
op1=Open

This door example is good because doors use wall shapes, so they wouldn't be set to active (able to use) without this.

186
if (opcode == 19) {
    active = dat.g1();

    if (active == 1) {
        this.active = true;
    }
}

// after all decoding
if (active == -1) {
    this.active = this.shapes.length > 0 && this.shapes[0] == 10;

    if (this.ops != null) {
        this.active = true;
    }
}

hillskew Property

Stretch the loc model based on the tile height.

if (opcode == 21) {
    this.hillskew = true;
}

sharelight Property

Allows vertex lighting to be shared between neighboring locs.

if (opcode == 22) {
    this.sharelight = true;
}

occlude Property

if (opcode == 23) {
    this.occlude = true;
}
if (opcode == 103) {
    this.occlude = false;
}

anim Property

if (opcode == 24) {
    this.anim = 65535;

    if (this.anim != 65535) {
        this.anim = -1;
    }
}

wallwidth Property

if (code == 28) {
    this.wallwidth = dat.g1();
}

ambient Property

if (code == 29) {
    this.ambient = dat.g1b();
}

contrast Property

if (code == 39) {
    this.contrast = dat.g1b();
}

op Properties

op1-5 directly correlates to the server-script triggers for oploc1 through oploc5.

There are options labelled "hidden" which are used for the server-side triggers to repeat oploc interactions.

if (code >= 30 && code < 39) {
    if (this.ops == null) {
        this.ops = new String[5];
    }

    this.ops[code - 30] = dat.gjstr();
    if (this.ops[code - 30].equalsIgnoreCase("hidden")) {
        this.ops[code - 30] = null;
    }
}

recol Properties

Recolor part of a model.

if (code == 40) {
    int count = dat.g1();
    this.recol_s = new int[count];
    this.recol_d = new int[count];

    for (int i = 0; i < count; i++) {
        this.recol_s[i] = dat.g2();
        this.recol_d[i] = dat.g2();
    }
}

retex Properties

Retexture part of a model.

recol_dpalette Properties

mapfunction Property

Draws a mapfunction sprite on the minimap where this loc is.

if (code == 60) {
    this.mapfunction = dat.g2();
}

mirror Property

if (code == 62) {
    this.mirror = true;
}

shadow Property

if (code == 64) {
    this.shadow = false;
}

resize Properties

if (code == 65) {
    this.resizex = dat.g2();
} else if (code == 66) {
    this.resizey = dat.g2();
} else if (code == 67) {
    this.resizez = dat.g2();
}

mapscene Property

Draws a mapscene sprite on the minimap where this loc is.

if (code == 68) {
    this.mapscene = dat.g2();
}

forceapproach Property

Pathfinder property - forces the player to approach the loc from a specific side.

if bit 1 == 0: top (north)

if bit 2 == 0: right (east)

if bit 3 == 0: bottom (south)

if bit 4 == 0: left (west)

186
if (code == 69) {
    this.forceapproach = dat.g1();
}

offset Properties

if (code == 70) {
    this.offsetx = dat.g2s();
} else if (code == 71) {
    this.offsety = dat.g2s();
} else if (code == 72) {
    this.offsetz = dat.g2s();
}

forcedecor Property

if (code == 73) {
    this.forcedecor=true
}

breakroutefinding Property

Pathfinder property - allow the pathfinder to route through this loc.

Scenario: interacting with a NPC behind a bank booth from an outside wall, so the player walks around to be within operable range.

if (code === 74) {
    this.breakroutefinding = true;
}

raiseobject Property

if (code === 75) {
    this.raiseobject = buf.g1();
}

multiloc Property

bgsound Property

if (code === 78) {
    this.bgsound = buf.g2();
    this.bgsoundrange = buf.g1();
}

randomsound Property

if (code === 79) {
    this.bgsoundmin = buf.g1();
    this.bgsoundmax = bug.g1();
    this.bgsoundrange = buf.g1();

    int count = buf.g1();
    this.bgsounds = new int[count];

    for (int i = 0; i < count; i++) {
        this.bgsounds[i] = buf.g2();
    }
}

hardshadow Property

if (code === 88) {
    this.hardshadow = false;
}

randseq Property

if (code === 89) {
    this.randseq = false;
}

members Property

if (code === 91) {
    this.members = true;
}

mapscenerotates Property

cursor Properties

mapsceneangle Property

bgsoundvol Property

mapsceneflipy Property

anims Properties

mel Property

memberop Property

quests Property

tint Property

postoffset Properties

if (code == 164) {
    this.postoffsetx = dat.g2s();
} else if (code == 165) {
    this.postoffsety = dat.g2s();
} else if (code == 166) {
    this.postoffsetz = dat.g2s();
}

decorheight Property

if (code == 167) {
    this.decorheight = dat.g2();
}

occludewidth Property

if (code == 170) {
    this.occludewidth = dat.gSmart1or2();
}

occludeheight Property

if (code == 171) {
    this.occludeheight = dat.gSmart1or2();
}

bgsoundrate Property

bgsounddistance Property

param Properties

if (code == 249) {
    int count = buf.g1();

    if (this.params == null) {
        int buckets = IntUtils.clp2(count);
        this.params = new HashTable(buckets);
    }

    for (int i = 0; i < count; i++) {
        boolean string = buffer.g1() == 1;
        int id = buffer.g3();

        Node node;
        if (string) {
            node = new StringNode(buf.gjstr());
        } else {
            node = new IntNode(buf.g4());
        }

        this.params.put(id, node);
    }
}

RS3

Very little time spent on RS3 (little-to-no tools). Here's some ones that existed in 2016.

Property Opcode History Notes
44
45
179
186
188
196
197
198
199
200
201
250
251
252
253
254
255

OSRS

OSRS is pretty similar, it forked from 468 but they can also backport stuff - here's the known additions

Property Opcode History Notes
category 61 Added 197 (2021-06-16) Originally only server-sided.

External Credits

* Walied for reviewing the list afterwards and advising on some properties