@abextm/cache2
Version:
Utilities for reading OSRS "caches"
196 lines (195 loc) • 6.41 kB
JavaScript
import { PerFileLoadable } from "../Loadable.js";
import { Typed } from "../reflect.js";
import { AnimRestartMode, PreAnimMoveMode, } from "../types.js";
export class FrameSound {
id;
weight;
loops;
retain;
constructor(id, weight, loops, location, retain) {
this.id = id;
this.weight = weight;
this.loops = loops;
this.retain = retain;
this.offsetX = (location >> 16) & 0xFF;
this.offsetY = (location >> 8) & 0xFF;
this.maxDistance = location & 0xFF;
this.isAreaSound = location === 0;
}
offsetX;
offsetY;
isAreaSound;
maxDistance;
}
export class Animation extends PerFileLoadable {
id;
constructor(id) {
super();
this.id = id;
}
static index = 2;
static archive = 12;
static gameval = 7;
frameLengths = undefined;
frameIDs = undefined;
chatheadFrameIDs = undefined;
animMayaID = undefined;
animMayaStart = 0;
animMayaEnd = 0;
masks = undefined;
debugName;
verticalOffset = 0;
frameStep = -1;
interleaveLeave = undefined;
stretches = true;
priority = 5;
leftHandItem = undefined;
rightHandItem = undefined;
maxLoops = undefined;
preAnimMove;
postAnimMove;
restartMode = AnimRestartMode.ResetLoops;
sounds = new Map();
static decode(r, id) {
const v = new Animation(id);
let [legacyFrameSounds, animMayaID, frameSounds, animMayaBounds, verticalOffset] = r.isAfter({ era: "osrs", indexRevision: 4470 })
? [-1, 13, 14, 15, 16]
: [13, 14, 15, 16, -1];
for (let opcode; (opcode = r.u8()) != 0;) {
switch (opcode) {
case 1: {
let len = r.u16();
v.frameLengths = new Array(len);
v.frameIDs = new Array(len);
for (let i = 0; i < len; i++) {
v.frameLengths[i] = r.u16();
}
for (let i = 0; i < len; i++) {
v.frameIDs[i] = [0, r.u16()];
}
for (let i = 0; i < len; i++) {
v.frameIDs[i][0] = r.u16();
}
break;
}
case 2:
v.frameStep = r.u16();
break;
case 3: {
let len = r.u8();
v.interleaveLeave = new Array(len + 1);
for (let i = 0; i < len; i++) {
v.interleaveLeave[i] = r.u8();
}
v.interleaveLeave[len] = 9999999;
break;
}
case 4:
v.stretches = true;
break;
case 5:
v.priority = r.u8();
break;
case 6:
v.leftHandItem = r.kit();
break;
case 7:
v.rightHandItem = r.kit();
break;
case 8:
v.maxLoops = r.u8();
break;
case 9:
v.preAnimMove = r.u8();
break;
case 10:
v.postAnimMove = r.u8();
break;
case 11:
v.restartMode = r.u8();
break;
case 12: {
let len = r.u8();
v.chatheadFrameIDs = new Array(len);
for (let i = 0; i < len; i++) {
v.chatheadFrameIDs[i] = [0, r.u16()];
}
for (let i = 0; i < len; i++) {
v.chatheadFrameIDs[i][0] = r.u16();
}
break;
}
case legacyFrameSounds: {
let len = r.u8();
for (let i = 0; i < len; i++) {
readFrameSound(v, r, i);
}
break;
}
case animMayaID:
v.animMayaID = r.i32();
break;
case frameSounds: {
let len = r.u16();
for (let i = 0; i < len; i++) {
let frame = r.u16();
readFrameSound(v, r, frame);
}
break;
}
case animMayaBounds:
v.animMayaStart = r.u16();
v.animMayaEnd = r.u16();
break;
case verticalOffset:
v.verticalOffset = r.i8();
break;
case 17: {
v.masks = new Array(256);
v.masks.fill(false);
let len = r.u8();
for (let i = 0; i < len; i++) {
v.masks[r.u8()] = true;
}
break;
}
case 18:
v.debugName = r.string();
break;
default:
throw new Error(`unknown animation opcode ${opcode}`);
}
}
let defaultAnimMode = v.interleaveLeave === undefined && v.masks == undefined
? PreAnimMoveMode.DelayMove
: PreAnimMoveMode.Merge;
v.preAnimMove ??= defaultAnimMode;
v.postAnimMove ??= defaultAnimMode;
return v;
}
}
function readFrameSound(v, r, frame) {
let sound;
if (r.isAfter({ era: "osrs", indexRevision: 4106 })) {
let id = r.u16();
let weight = r.isAfter({ era: "osrs", indexRevision: 4470 })
? r.u8()
: -1;
let loops = r.u8();
let location = r.u8();
let retain = r.u8();
sound = new FrameSound(id, weight, loops, location, retain);
}
else {
let bits = r.u24();
sound = new FrameSound((bits >> 8), -1, (bits >> 4) & 7, bits & 15, 0);
}
if (sound.id >= 1 && sound.loops >= 1) {
let list = v.sounds.get(frame);
if (!list) {
list = [];
v.sounds.set(frame, list);
}
list.push(sound);
}
}