Configs/LocType: Difference between revisions
From RuneWiki
Tags: Reverted Visual edit |
No edit summary |
||
(48 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
Loc means “Location” and represents all of the game objects in the world. | |||
=== Structure === | |||
Regardless of the revision, the packing process has some basic rules. | |||
# Loc names must be unique. They can have + symbols in the name. | |||
# Configs are a purely text format with a custom parser. True/false values are written as yes/no. | |||
# 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!<syntaxhighlight lang="ini"> | |||
[example] | |||
name=Example | |||
desc=This is an example | |||
model=example | |||
length=4 | |||
width=2 | |||
length=2 | |||
recol1s=5 | |||
recol1d=1234 | |||
</syntaxhighlight> | |||
=== RS2 === | === 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. | 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. | Names are an attempt to be authentic and correct, if you have any more information definitely reach out. | ||
{| class="wikitable" | {| class="wikitable" | ||
|+ | |+ | ||
Line 19: | Line 34: | ||
|1 | |1 | ||
|Added 186 (2003-12-02) | |Added 186 (2003-12-02) | ||
Changed 300 (2005-03-07) | |||
Changed 581 (2010-01-29) | Changed 581 (2010-01-29) | ||
| | |Written at the end of a config. | ||
|- | |- | ||
|name | |name | ||
|2 | |2 | ||
|Added 186 (2003-12-02) | |Added 186 (2003-12-02) | ||
| | |Written at the end of a config. | ||
|- | |- | ||
|desc | |desc | ||
Line 31: | Line 48: | ||
|Added 186 (2003-12-02) | |Added 186 (2003-12-02) | ||
Removed 410 (2006-05-25) | Removed 410 (2006-05-25) | ||
|Examine text. Later transmitted from the server. | |Examine text, written at the end of a config. Later transmitted from the server. | ||
|- | |- | ||
|model | |model | ||
|5 | |5 | ||
|Added 249 (2004-08-09) | |Added 249 (2004-08-09) | ||
Changed 300 (2005-03-07) | |||
Changed 581 (2010-01-29) | Changed 581 (2010-01-29) | ||
|This opcode is used to save bytes in the list of models. | |Written at the end of a config. This opcode is used to save bytes in the list of models. | ||
|- | |- | ||
|width | |width | ||
Line 52: | Line 71: | ||
|17 | |17 | ||
|Added 186 (2003-12-02) | |Added 186 (2003-12-02) | ||
Changed 454 (2007-03-05) | |||
| | | | ||
|- | |- | ||
Line 93: | Line 113: | ||
|blockwalk=yes | |blockwalk=yes | ||
|27 | |27 | ||
|Added | |Added 451 (2007-03-05) | ||
| | |Forces blockwalk to be on. Ground decor is clipped with FLOOR_DECORATION | ||
|- | |- | ||
|wallwidth | |wallwidth | ||
Line 170: | Line 190: | ||
|69 | |69 | ||
|Added 186 (2003-12-02) | |Added 186 (2003-12-02) | ||
|This is a bitmask, one bit will be | |This is a bitmask, one bit will be unset - the direction. | ||
|- | |- | ||
|offsetx | |offsetx | ||
Line 232: | Line 252: | ||
|If this isn't hardshadow, it's something like sceneshadow? | |If this isn't hardshadow, it's something like sceneshadow? | ||
|- | |- | ||
| | |randomanimframe=false | ||
|89 | |89 | ||
|Added 487 (2008-02-12) | |Added 487 (2008-02-12) | ||
Line 414: | Line 434: | ||
==== hillskew Types ==== | ==== hillskew Types ==== | ||
0 | <syntaxhighlight lang="ts"> | ||
enum HillSkewType { | |||
none = 0, | |||
floor_skew = 1, | |||
tree_skew = 2, | |||
rotate = 3, | |||
ceiling_skew = 4, | |||
skew_to_fit = 5 | |||
} | |||
</syntaxhighlight> | |||
==== | ==== shape Names ==== | ||
<syntaxhighlight lang="ts"> | <syntaxhighlight lang="ts"> | ||
enum LocShape { | enum LocShape { | ||
Line 445: | Line 474: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
==== | ==== shape Map Editor Hotkeys ==== | ||
<syntaxhighlight lang="ts"> | <syntaxhighlight lang="ts"> | ||
// hotkeys in jagex's map editor are used as the extension for loc models so they know which shape to inherit | // hotkeys in jagex's map editor are used as the extension for loc models so they know which shape to inherit | ||
Line 480: | Line 509: | ||
==== model Property ==== | ==== model Property ==== | ||
This property is used to render a specific model based on the shape. The shape to use | 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 ===== | ===== Config ===== | ||
They only need to define this as <code>model=name</code>, the shape is derived by looking for suffixes on file names in their <code>src/models/</code> directory. The suffixes are not the shape numbers here but rather their map editor's hotkeys! | <syntaxhighlight lang="ini"> | ||
[example] | |||
model=example | |||
</syntaxhighlight>They only need to define this as a single <code>model=name</code>, the shape is derived by looking for suffixes on file names in their <code>src/models/</code> directory. The suffixes are not the shape numbers here but rather their map editor's hotkeys! | |||
Scenario 1: a model <code>example_8.ob3</code> and they have <code>model=example</code> in their loc config. It sees <code>_8</code> and then knows to add shape=10. | |||
Scenario 2: two models, <code>example_8.ob3</code> and <code>example_0.ob3</code> and they have <code>model=example</code> 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, <code>example_8.ob3</code> and <code>example_0.ob3</code> again, but this time they have <code>model=example_0</code> 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 ===== | ===== 186 ===== | ||
Line 496: | Line 530: | ||
int count = buf.g1(); | 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(); | |||
} | } | ||
} | } | ||
Line 509: | Line 541: | ||
===== 249 ===== | ===== 249 ===== | ||
<syntaxhighlight lang="java" line="1"> | Opcode 5 was added (in addition to 1) for models that are solely shape 10.<syntaxhighlight lang="java" line="1"> | ||
if (opcode == 5) { | if (opcode == 5) { | ||
int count = buf.g1(); | int count = buf.g1(); | ||
Line 519: | Line 551: | ||
for (int i = 0; i < count; i++) { | for (int i = 0; i < count; i++) { | ||
this.models[i] = buf.g2(); | this.models[i] = buf.g2(); | ||
} | |||
} | |||
} | |||
</syntaxhighlight> | |||
===== 300 ===== | |||
Locs are able to change their appearance for lowmem (low detail) mode. I have no clue what this looks like on their end -- but I suspect models might just have a low-detail suffix they check for?<syntaxhighlight lang="java" line="1"> | |||
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; | |||
} | } | ||
} | } | ||
Line 525: | Line 598: | ||
===== 581 ===== | ===== 581 ===== | ||
Models is now a 2d array so multiple models can be merged when rendering a loc shape.<syntaxhighlight lang="java" line="1"> | 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).<syntaxhighlight lang="java" line="1"> | |||
if (opcode == 1 || opcode == 5) { | if (opcode == 1 || opcode == 5) { | ||
if (opcode == 5 && LocTypeList. | if (opcode == 5 && LocTypeList.lowmem) { | ||
this.skipModels(buf); | this.skipModels(buf); | ||
} | } | ||
Line 546: | Line 621: | ||
} | } | ||
if (opcode == 5 && !LocTypeList. | if (opcode == 5 && !LocTypeList.lowmem) { | ||
this.skipModels(buf); | this.skipModels(buf); | ||
} | } | ||
Line 558: | Line 633: | ||
int modelCount = buf.g1(); | int modelCount = buf.g1(); | ||
buf.pos += modelCount * 2; | buf.pos += modelCount * 2; | ||
} | |||
} | |||
</syntaxhighlight> | |||
===== 700+ ===== | |||
<syntaxhighlight lang="java" line="1"> | |||
if (opcode == 1) { | |||
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.gSmart2or4(); | |||
} | |||
} | |||
} | |||
</syntaxhighlight> | |||
==== 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 ===== | |||
<syntaxhighlight lang="ini"> | |||
[example] | |||
name=Example | |||
</syntaxhighlight> | |||
===== 186 ===== | |||
<syntaxhighlight lang="java" line="1"> | |||
if (opcode == 2) { | |||
this.name = buf.gjstr(); | |||
} | |||
</syntaxhighlight> | |||
==== 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 ===== | |||
<syntaxhighlight lang="ini"> | |||
[example] | |||
desc=This is an example | |||
</syntaxhighlight> | |||
===== 186 ===== | |||
<syntaxhighlight lang="java" line="1"> | |||
if (opcode == 3) { | |||
this.desc = buf.gjstr(); | |||
} | |||
</syntaxhighlight> | |||
==== width Property ==== | |||
Number of tiles a loc takes on the east/west axis. | |||
===== 186 ===== | |||
<syntaxhighlight lang="java" line="1"> | |||
if (opcode == 14) { | |||
this.width = buf.g1(); | |||
} | |||
</syntaxhighlight> | |||
==== length Property ==== | |||
Number of tiles a loc takes on the north/south axis. | |||
===== 186 ===== | |||
<syntaxhighlight lang="java" line="1"> | |||
if (opcode == 15) { | |||
this.length = buf.g1(); | |||
} | |||
</syntaxhighlight> | |||
==== blockwalk Property ==== | |||
Pathfinder property - controls line-of-walk checks through this tile. | |||
===== 186 ===== | |||
<syntaxhighlight lang="java" line="1"> | |||
if (opcode == 17) { | |||
this.blockwalk = false; | |||
} | |||
</syntaxhighlight> | |||
===== 451 ===== | |||
<syntaxhighlight lang="java" line="1"> | |||
if (opcode == 17) { | |||
this.blockrange = false; | |||
this.blockwalk = false; | |||
} | |||
</syntaxhighlight> | |||
==== blockrange Property ==== | |||
Pathfinder property - controls line-of-sight checks through this tile. | |||
===== 186 ===== | |||
<syntaxhighlight lang="java" line="1"> | |||
if (opcode == 18) { | |||
this.blockrange = false; | |||
} | |||
</syntaxhighlight> | |||
==== 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 ===== | |||
<syntaxhighlight lang="ini"> | |||
[door] | |||
active=yes | |||
op1=Open | |||
</syntaxhighlight>This door example is good because doors use wall shapes, so they wouldn't be set to active (able to use) without this. | |||
===== 186 ===== | |||
<syntaxhighlight lang="java" line="1"> | |||
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; | |||
} | |||
} | |||
</syntaxhighlight> | |||
==== hillskew Property ==== | |||
Stretch the loc model based on the tile height.<syntaxhighlight lang="java" line="1"> | |||
if (opcode == 21) { | |||
this.hillskew = true; | |||
} | |||
</syntaxhighlight> | |||
==== sharelight Property ==== | |||
Allows vertex lighting to be shared between neighboring locs.<syntaxhighlight lang="java" line="1"> | |||
if (opcode == 22) { | |||
this.sharelight = true; | |||
} | |||
</syntaxhighlight> | |||
==== occlude Property ==== | |||
<syntaxhighlight lang="java" line="1"> | |||
if (opcode == 23) { | |||
this.occlude = true; | |||
} | |||
</syntaxhighlight><syntaxhighlight lang="java" line="1"> | |||
if (opcode == 103) { | |||
this.occlude = false; | |||
} | |||
</syntaxhighlight> | |||
==== anim Property ==== | |||
<syntaxhighlight lang="java" line="1"> | |||
if (opcode == 24) { | |||
this.anim = 65535; | |||
if (this.anim != 65535) { | |||
this.anim = -1; | |||
} | |||
} | |||
</syntaxhighlight> | |||
==== wallwidth Property ==== | |||
<syntaxhighlight lang="java" line="1"> | |||
if (code == 28) { | |||
this.wallwidth = dat.g1(); | |||
} | |||
</syntaxhighlight> | |||
==== ambient Property ==== | |||
<syntaxhighlight lang="java" line="1"> | |||
if (code == 29) { | |||
this.ambient = dat.g1b(); | |||
} | |||
</syntaxhighlight> | |||
==== contrast Property ==== | |||
<syntaxhighlight lang="java" line="1"> | |||
if (code == 39) { | |||
this.contrast = dat.g1b(); | |||
} | |||
</syntaxhighlight> | |||
==== 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.<syntaxhighlight lang="java" line="1"> | |||
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; | |||
} | |||
} | |||
</syntaxhighlight> | |||
==== recol Properties ==== | |||
Recolor part of a model.<syntaxhighlight lang="java" line="1"> | |||
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(); | |||
} | |||
} | |||
</syntaxhighlight> | |||
==== retex Properties ==== | |||
Retexture part of a model. | |||
==== recol_dpalette Properties ==== | |||
==== mapfunction Property ==== | |||
Draws a mapfunction sprite on the minimap where this loc is.<syntaxhighlight lang="java" line="1"> | |||
if (code == 60) { | |||
this.mapfunction = dat.g2(); | |||
} | |||
</syntaxhighlight> | |||
==== mirror Property ==== | |||
<syntaxhighlight lang="java" line="1"> | |||
if (code == 62) { | |||
this.mirror = true; | |||
} | |||
</syntaxhighlight> | |||
==== shadow Property ==== | |||
<syntaxhighlight lang="java" line="1"> | |||
if (code == 64) { | |||
this.shadow = false; | |||
} | |||
</syntaxhighlight> | |||
==== resize Properties ==== | |||
<syntaxhighlight lang="java" line="1"> | |||
if (code == 65) { | |||
this.resizex = dat.g2(); | |||
} else if (code == 66) { | |||
this.resizey = dat.g2(); | |||
} else if (code == 67) { | |||
this.resizez = dat.g2(); | |||
} | |||
</syntaxhighlight> | |||
==== mapscene Property ==== | |||
Draws a mapscene sprite on the minimap where this loc is.<syntaxhighlight lang="java" line="1"> | |||
if (code == 68) { | |||
this.mapscene = dat.g2(); | |||
} | |||
</syntaxhighlight> | |||
==== 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 ===== | |||
<syntaxhighlight lang="java" line="1"> | |||
if (code == 69) { | |||
this.forceapproach = dat.g1(); | |||
} | |||
</syntaxhighlight> | |||
==== offset Properties ==== | |||
<syntaxhighlight lang="java" line="1"> | |||
if (code == 70) { | |||
this.offsetx = dat.g2s(); | |||
} else if (code == 71) { | |||
this.offsety = dat.g2s(); | |||
} else if (code == 72) { | |||
this.offsetz = dat.g2s(); | |||
} | |||
</syntaxhighlight> | |||
==== forcedecor Property ==== | |||
<syntaxhighlight lang="java" line="1"> | |||
if (code == 73) { | |||
this.forcedecor=true | |||
} | |||
</syntaxhighlight> | |||
==== 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.<syntaxhighlight lang="java" line="1"> | |||
if (code === 74) { | |||
this.breakroutefinding = true; | |||
} | |||
</syntaxhighlight> | |||
==== raiseobject Property ==== | |||
<syntaxhighlight lang="java" line="1"> | |||
if (code === 75) { | |||
this.raiseobject = buf.g1(); | |||
} | |||
</syntaxhighlight> | |||
==== multiloc Property ==== | |||
==== bgsound Property ==== | |||
<syntaxhighlight lang="java" line="1"> | |||
if (code === 78) { | |||
this.bgsound = buf.g2(); | |||
this.bgsoundrange = buf.g1(); | |||
} | |||
</syntaxhighlight> | |||
==== randomsound Property ==== | |||
<syntaxhighlight lang="java" line="1"> | |||
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(); | |||
} | |||
} | |||
</syntaxhighlight> | |||
==== hardshadow Property ==== | |||
<syntaxhighlight lang="java" line="1"> | |||
if (code === 88) { | |||
this.hardshadow = false; | |||
} | |||
</syntaxhighlight> | |||
==== randseq Property ==== | |||
<syntaxhighlight lang="java" line="1"> | |||
if (code === 89) { | |||
this.randseq = false; | |||
} | |||
</syntaxhighlight> | |||
==== members Property ==== | |||
<syntaxhighlight lang="java" line="1"> | |||
if (code === 91) { | |||
this.members = true; | |||
} | |||
</syntaxhighlight> | |||
==== mapscenerotates Property ==== | |||
==== cursor Properties ==== | |||
==== mapsceneangle Property ==== | |||
==== bgsoundvol Property ==== | |||
==== mapsceneflipy Property ==== | |||
==== anims Properties ==== | |||
==== mel Property ==== | |||
==== memberop Property ==== | |||
==== quests Property ==== | |||
==== tint Property ==== | |||
==== postoffset Properties ==== | |||
<syntaxhighlight lang="java" line="1"> | |||
if (code == 164) { | |||
this.postoffsetx = dat.g2s(); | |||
} else if (code == 165) { | |||
this.postoffsety = dat.g2s(); | |||
} else if (code == 166) { | |||
this.postoffsetz = dat.g2s(); | |||
} | |||
</syntaxhighlight> | |||
==== decorheight Property ==== | |||
<syntaxhighlight lang="java" line="1"> | |||
if (code == 167) { | |||
this.decorheight = dat.g2(); | |||
} | |||
</syntaxhighlight> | |||
==== occludewidth Property ==== | |||
<syntaxhighlight lang="java" line="1"> | |||
if (code == 170) { | |||
this.occludewidth = dat.gSmart1or2(); | |||
} | |||
</syntaxhighlight> | |||
==== occludeheight Property ==== | |||
<syntaxhighlight lang="java" line="1"> | |||
if (code == 171) { | |||
this.occludeheight = dat.gSmart1or2(); | |||
} | |||
</syntaxhighlight> | |||
==== bgsoundrate Property ==== | |||
==== bgsounddistance Property ==== | |||
==== param Properties ==== | |||
<syntaxhighlight lang="java"> | |||
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); | |||
} | } | ||
} | } |
Latest revision as of 17:26, 28 March 2024
Loc means “Location” and represents all of the game objects in the world.
Structure
Regardless of the revision, the packing process has some basic rules.
- Loc names must be unique. They can have + symbols in the name.
- Configs are a purely text format with a custom parser. True/false values are written as yes/no.
- 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)
Changed 454 (2007-03-05) |
|
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 451 (2007-03-05) | Forces blockwalk to be on. Ground decor is clipped with FLOOR_DECORATION |
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? |
randomanimframe=false | 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 (count > 0) {
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 -- but I suspect models might just have a low-detail suffix they check for?
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;
}
}
700+
if (opcode == 1) {
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.gSmart2or4();
}
}
}
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;
}
451
if (opcode == 17) {
this.blockrange = false;
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;
}
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