UNPKG

@2003scape/rsc-client

Version:
1,823 lines (1,499 loc) 85.5 kB
const Utility = require('./utility'); const SLEEP_WIDTH = 255; const SLEEP_HEIGHT = 40; const BLACK = 0; const DARK_GREY = 0xa0a0a0; const LIGHT_GREY = 0xdcdcdc; const C_0 = '0'.charCodeAt(0); const C_9 = '9'.charCodeAt(0); class Surface { constructor(width, height, limit, mudclient) { this.mudclient = mudclient; this.image = null; this.anIntArray340 = null; this.anIntArray341 = null; this.anIntArray342 = null; this.anIntArray343 = null; this.anIntArray344 = null; this.anIntArray345 = null; this.boundsTopY = 0; this.boundsTopX = 0; this.interlace = false; this.loggedIn = false; this.boundsBottomY = height; this.boundsBottomX = width; this.width1 = this.width2 = width; this.height1 = this.height2 = height; this.area = width * height; this.pixels = new Int32Array(width * height); this.surfacePixels = []; this.surfacePixels.length = limit; this.surfacePixels.fill(null); this.spriteColoursUsed = []; this.spriteColoursUsed.length = limit; this.spriteColoursUsed.fill(null); this.spriteColourList = []; this.spriteColourList.length = limit; this.spriteColourList.fill(null); this.spriteTranslate = new Int8Array(limit); this.spriteWidth = new Int32Array(limit); this.spriteHeight = new Int32Array(limit); this.spriteWidthFull = new Int32Array(limit); this.spriteHeightFull = new Int32Array(limit); this.spriteTranslateX = new Int32Array(limit); this.spriteTranslateY = new Int32Array(limit); this.rgbPixels = new Uint8Array( this.pixels.buffer, this.pixels.byteOffset ); this.imageData = mudclient._graphics.ctx.createImageData(width, height); this.setComplete(); } static rgbToInt(red, green, blue) { return (red << 16) + (green << 8) + blue; } static createFont(bytes, id) { Surface.gameFonts[id] = bytes; } setComplete() { for (let i = 0; i < this.area * 4; i += 4) { const blue = this.rgbPixels[i]; this.rgbPixels[i] = this.rgbPixels[i + 2]; this.rgbPixels[i + 2] = blue; this.rgbPixels[i + 3] = 255; } this.imageData.data.set(this.rgbPixels); } setBounds(x1, y1, x2, y2) { if (x1 < 0) { x1 = 0; } if (y1 < 0) { y1 = 0; } if (x2 > this.width2) { x2 = this.width2; } if (y2 > this.height2) { y2 = this.height2; } this.boundsTopX = x1; this.boundsTopY = y1; this.boundsBottomX = x2; this.boundsBottomY = y2; } resetBounds() { this.boundsTopX = 0; this.boundsTopY = 0; this.boundsBottomX = this.width2; this.boundsBottomY = this.height2; } draw(graphics, x, y) { this.setComplete(); graphics.drawImage(this.imageData, x, y); } blackScreen() { const area = this.width2 * this.height2; if (!this.interlace) { for (let i = 0; i < area; i++) { this.pixels[i] = 0; } return; } let pixelIdx = 0; for (let y = -this.height2; y < 0; y += 2) { for (let x = -this.width2; x < 0; x++) { this.pixels[pixelIdx++] = 0; } pixelIdx += this.width2; } } drawCircle(x, y, radius, colour, alpha) { const bgAlpha = 256 - alpha; const red = ((colour >> 16) & 0xff) * alpha; const green = ((colour >> 8) & 0xff) * alpha; const blue = (colour & 0xff) * alpha; let top = y - radius; if (top < 0) { top = 0; } let bottom = y + radius; if (bottom >= this.height2) { bottom = this.height2 - 1; } let vertInc = 1; if (this.interlace) { vertInc = 2; if ((top & 1) !== 0) { top++; } } for (let yy = top; yy <= bottom; yy += vertInc) { const l3 = yy - y; const i4 = Math.sqrt(radius * radius - l3 * l3) | 0; let j4 = x - i4; if (j4 < 0) { j4 = 0; } let k4 = x + i4; if (k4 >= this.width2) { k4 = this.width2 - 1; } let index = j4 + yy * this.width2; for (let i = j4; i <= k4; i++) { const bgRed = ((this.pixels[index] >> 16) & 0xff) * bgAlpha; const bgGreen = ((this.pixels[index] >> 8) & 0xff) * bgAlpha; const bgBlue = (this.pixels[index] & 0xff) * bgAlpha; const newColour = (((red + bgRed) >> 8) << 16) + (((green + bgGreen) >> 8) << 8) + ((blue + bgBlue) >> 8); this.pixels[index++] = newColour; } } } drawBoxAlpha(x, y, width, height, colour, alpha) { if (x < this.boundsTopX) { width -= this.boundsTopX - x; x = this.boundsTopX; } if (y < this.boundsTopY) { height -= this.boundsTopY - y; y = this.boundsTopY; } if (x + width > this.boundsBottomX) { width = this.boundsBottomX - x; } if (y + height > this.boundsBottomY) { height = this.boundsBottomY - y; } const backgroundAlpha = 256 - alpha; const red = ((colour >> 16) & 0xff) * alpha; const green = ((colour >> 8) & 0xff) * alpha; const blue = (colour & 0xff) * alpha; let j3 = this.width2 - width; // wat let vertInc = 1; if (this.interlace) { vertInc = 2; j3 += this.width2; if ((y & 1) !== 0) { y++; height--; } } let pixelIdx = x + y * this.width2; for (let i = 0; i < height; i += vertInc) { for (let j = -width; j < 0; j++) { const backgroundRed = ((this.pixels[pixelIdx] >> 16) & 0xff) * backgroundAlpha; const backgroundGreen = ((this.pixels[pixelIdx] >> 8) & 0xff) * backgroundAlpha; const backgroundBlue = (this.pixels[pixelIdx] & 0xff) * backgroundAlpha; const newColour = (((red + backgroundRed) >> 8) << 16) + (((green + backgroundGreen) >> 8) << 8) + ((blue + backgroundBlue) >> 8); this.pixels[pixelIdx++] = newColour; } pixelIdx += j3; } } drawGradient(x, y, width, height, colourTop, colourBottom) { if (x < this.boundsTopX) { width -= this.boundsTopX - x; x = this.boundsTopX; } if (x + width > this.boundsBottomX) { width = this.boundsBottomX - x; } const bottomRed = (colourBottom >> 16) & 0xff; const bottomGreen = (colourBottom >> 8) & 0xff; const bottomBlue = colourBottom & 0xff; const topRed = (colourTop >> 16) & 0xff; const topGreen = (colourTop >> 8) & 0xff; const topBlue = colourTop & 0xff; let i3 = this.width2 - width; // wat let vertInc = 1; if (this.interlace) { vertInc = 2; i3 += this.width2; if ((y & 1) !== 0) { y++; height--; } } let pixelIdx = x + y * this.width2; for (let i = 0; i < height; i += vertInc) { if (i + y >= this.boundsTopY && i + y < this.boundsBottomY) { const newColour = (((bottomRed * i + topRed * (height - i)) / height) << 16) + (((bottomGreen * i + topGreen * (height - i)) / height) << 8) + (((bottomBlue * i + topBlue * (height - i)) / height) | 0); for (let j = -width; j < 0; j++) { this.pixels[pixelIdx++] = newColour; } pixelIdx += i3; } else { pixelIdx += this.width2; } } } drawBox(x, y, w, h, colour) { if (x < this.boundsTopX) { w -= this.boundsTopX - x; x = this.boundsTopX; } if (y < this.boundsTopY) { h -= this.boundsTopY - y; y = this.boundsTopY; } if (x + w > this.boundsBottomX) { w = this.boundsBottomX - x; } if (y + h > this.boundsBottomY) { h = this.boundsBottomY - y; } let j1 = this.width2 - w; // wat let vertInc = 1; if (this.interlace) { vertInc = 2; j1 += this.width2; if ((y & 1) !== 0) { y++; h--; } } let pixelIdx = x + y * this.width2; for (let l1 = -h; l1 < 0; l1 += vertInc) { for (let i2 = -w; i2 < 0; i2++) { this.pixels[pixelIdx++] = colour; } pixelIdx += j1; } } drawBoxEdge(x, y, width, height, colour) { this.drawLineHoriz(x, y, width, colour); this.drawLineHoriz(x, y + height - 1, width, colour); this.drawLineVert(x, y, height, colour); this.drawLineVert(x + width - 1, y, height, colour); } drawLineHoriz(x, y, width, colour) { if (y < this.boundsTopY || y >= this.boundsBottomY) { return; } if (x < this.boundsTopX) { width -= this.boundsTopX - x; x = this.boundsTopX; } if (x + width > this.boundsBottomX) { width = this.boundsBottomX - x; } let i1 = x + y * this.width2; for (let j1 = 0; j1 < width; j1++) { this.pixels[i1 + j1] = colour; } } drawLineVert(x, y, height, colour) { if (x < this.boundsTopX || x >= this.boundsBottomX) { return; } if (y < this.boundsTopY) { height -= this.boundsTopY - y; y = this.boundsTopY; } if (y + height > this.boundsBottomX) { height = this.boundsBottomY - y; } let i1 = x + y * this.width2; for (let j1 = 0; j1 < height; j1++) { this.pixels[i1 + j1 * this.width2] = colour; } } setPixel(x, y, colour) { if ( x < this.boundsTopX || y < this.boundsTopY || x >= this.boundsBottomX || y >= this.boundsBottomY ) { return; } this.pixels[x + y * this.width2] = colour; } fadeToBlack() { const area = this.width2 * this.height2; for (let j = 0; j < area; j++) { let i = this.pixels[j] & 0xffffff; this.pixels[j] = ((i >>> 1) & 0x7f7f7f) + ((i >>> 2) & 0x3f3f3f) + ((i >>> 3) & 0x1f1f1f) + ((i >>> 4) & 0xf0f0f); } } drawLineAlpha(i, j, x, y, width, height) { for (let xx = x; xx < x + width; xx++) { for (let yy = y; yy < y + height; yy++) { let i2 = 0; let j2 = 0; let k2 = 0; let l2 = 0; for (let i3 = xx - i; i3 <= xx + i; i3++) if (i3 >= 0 && i3 < this.width2) { for (let j3 = yy - j; j3 <= yy + j; j3++) { if (j3 >= 0 && j3 < this.height2) { let k3 = this.pixels[i3 + this.width2 * j3]; i2 += (k3 >> 16) & 0xff; j2 += (k3 >> 8) & 0xff; k2 += k3 & 0xff; l2++; } } } this.pixels[xx + this.width2 * yy] = ((i2 / l2) << 16) + ((j2 / l2) << 8) + ((k2 / l2) | 0); } } } clear() { for (let i = 0; i < this.surfacePixels.length; i++) { this.surfacePixels[i] = null; this.spriteWidth[i] = 0; this.spriteHeight[i] = 0; this.spriteColoursUsed[i] = null; this.spriteColourList[i] = null; } } parseSprite(spriteID, spriteData, indexData, frameCount) { let indexOffset = Utility.getUnsignedShort(spriteData, 0); const fullWidth = Utility.getUnsignedShort(indexData, indexOffset); indexOffset += 2; const fullHeight = Utility.getUnsignedShort(indexData, indexOffset); indexOffset += 2; const colourCount = indexData[indexOffset++] & 0xff; const colours = new Int32Array(colourCount); colours[0] = 0xff00ff; for (let i = 0; i < colourCount - 1; i++) { colours[i + 1] = ((indexData[indexOffset] & 0xff) << 16) + ((indexData[indexOffset + 1] & 0xff) << 8) + (indexData[indexOffset + 2] & 0xff); indexOffset += 3; } let spriteOffset = 2; for (let id = spriteID; id < spriteID + frameCount; id++) { this.spriteTranslateX[id] = indexData[indexOffset++] & 0xff; this.spriteTranslateY[id] = indexData[indexOffset++] & 0xff; this.spriteWidth[id] = Utility.getUnsignedShort( indexData, indexOffset ); indexOffset += 2; this.spriteHeight[id] = Utility.getUnsignedShort( indexData, indexOffset ); indexOffset += 2; const unknown = indexData[indexOffset++] & 0xff; const size = this.spriteWidth[id] * this.spriteHeight[id]; this.spriteColoursUsed[id] = new Int8Array(size); this.spriteColourList[id] = colours; this.spriteWidthFull[id] = fullWidth; this.spriteHeightFull[id] = fullHeight; this.surfacePixels[id] = null; this.spriteTranslate[id] = false; if ( this.spriteTranslateX[id] !== 0 || this.spriteTranslateY[id] !== 0 ) { this.spriteTranslate[id] = true; } if (unknown === 0) { for (let pixel = 0; pixel < size; pixel++) { this.spriteColoursUsed[id][pixel] = spriteData[spriteOffset++]; if (this.spriteColoursUsed[id][pixel] === 0) { this.spriteTranslate[id] = true; } } } else if (unknown === 1) { for (let x = 0; x < this.spriteWidth[id]; x++) { for (let y = 0; y < this.spriteHeight[id]; y++) { this.spriteColoursUsed[id][ x + y * this.spriteWidth[id] ] = spriteData[spriteOffset++]; if ( this.spriteColoursUsed[id][ x + y * this.spriteWidth[id] ] === 0 ) { this.spriteTranslate[id] = true; } } } } } } readSleepWord(spriteID, spriteData) { const pixels = (this.surfacePixels[spriteID] = new Int32Array( SLEEP_WIDTH * SLEEP_HEIGHT )); this.spriteWidth[spriteID] = SLEEP_WIDTH; this.spriteHeight[spriteID] = SLEEP_HEIGHT; this.spriteTranslateX[spriteID] = 0; this.spriteTranslateY[spriteID] = 0; this.spriteWidthFull[spriteID] = SLEEP_WIDTH; this.spriteHeightFull[spriteID] = SLEEP_HEIGHT; this.spriteTranslate[spriteID] = false; let colour = 0; let packetOffset = 1; let pixelOffset = 0; for (pixelOffset = 0; pixelOffset < 255; ) { const length = spriteData[packetOffset++] & 0xff; for (let i = 0; i < length; i++) { pixels[pixelOffset++] = colour; } // alternate between black and white colour = 0xffffff - colour; } for (let y = 1; y < 40; y++) { for (let x = 0; x < 255; ) { const length = spriteData[packetOffset++] & 0xff; for (let i = 0; i < length; i++) { pixels[pixelOffset] = pixels[pixelOffset - 255]; pixelOffset++; x++; } if (x < 255) { pixels[pixelOffset] = 0xffffff - pixels[pixelOffset - 255]; pixelOffset++; x++; } } } } drawWorld(spriteId) { let spriteSize = this.spriteWidth[spriteId] * this.spriteHeight[spriteId]; let spritePixels = this.surfacePixels[spriteId]; let ai1 = new Int32Array(32768); for (let k = 0; k < spriteSize; k++) { let l = spritePixels[k]; ai1[ ((l & 0xf80000) >> 9) + ((l & 0xf800) >> 6) + ((l & 0xf8) >> 3) ]++; } let ai2 = new Int32Array(256); ai2[0] = 0xff00ff; let ai3 = new Int32Array(256); for (let i1 = 0; i1 < 32768; i1++) { let j1 = ai1[i1]; if (j1 > ai3[255]) { for (let k1 = 1; k1 < 256; k1++) { if (j1 <= ai3[k1]) { continue; } for (let i2 = 255; i2 > k1; i2--) { ai2[i2] = ai2[i2 - 1]; ai3[i2] = ai3[i2 - 1]; } ai2[k1] = ((i1 & 0x7c00) << 9) + ((i1 & 0x3e0) << 6) + ((i1 & 0x1f) << 3) + 0x40404; ai3[k1] = j1; break; } } ai1[i1] = -1; } let abyte0 = new Int8Array(spriteSize); for (let l1 = 0; l1 < spriteSize; l1++) { let j2 = spritePixels[l1]; let k2 = ((j2 & 0xf80000) >> 9) + ((j2 & 0xf800) >> 6) + ((j2 & 0xf8) >> 3); let l2 = ai1[k2]; if (l2 === -1) { let i3 = 999999999; let j3 = (j2 >> 16) & 0xff; let k3 = (j2 >> 8) & 0xff; let l3 = j2 & 0xff; for (let i4 = 0; i4 < 256; i4++) { let j4 = ai2[i4]; let k4 = (j4 >> 16) & 0xff; let l4 = (j4 >> 8) & 0xff; let i5 = j4 & 0xff; let j5 = (j3 - k4) * (j3 - k4) + (k3 - l4) * (k3 - l4) + (l3 - i5) * (l3 - i5); if (j5 < i3) { i3 = j5; l2 = i4; } } ai1[k2] = l2; } abyte0[l1] = l2 & 0xff; // << 24 >> 24 } this.spriteColoursUsed[spriteId] = abyte0; this.spriteColourList[spriteId] = ai2; this.surfacePixels[spriteId] = null; } loadSprite(spriteID) { if (this.spriteColoursUsed[spriteID] === null) { return; } const size = this.spriteWidth[spriteID] * this.spriteHeight[spriteID]; const idx = this.spriteColoursUsed[spriteID]; const cols = this.spriteColourList[spriteID]; const pixels = new Int32Array(size); for (let pixel = 0; pixel < size; pixel++) { let colour = cols[idx[pixel] & 0xff]; if (colour === 0) { colour = 1; } else if (colour === 0xff00ff) { colour = 0; } pixels[pixel] = colour; } this.surfacePixels[spriteID] = pixels; this.spriteColoursUsed[spriteID] = null; this.spriteColourList[spriteID] = null; } // used from World drawSpriteMinimap(sprite, x, y, width, height) { this.spriteWidth[sprite] = width; this.spriteHeight[sprite] = height; this.spriteTranslate[sprite] = false; this.spriteTranslateX[sprite] = 0; this.spriteTranslateY[sprite] = 0; this.spriteWidthFull[sprite] = width; this.spriteHeightFull[sprite] = height; this.surfacePixels[sprite] = new Int32Array(width * height); let pixel = 0; for (let xx = x; xx < x + width; xx++) { for (let yy = y; yy < y + height; yy++) { this.surfacePixels[sprite][pixel++] = this.pixels[ xx + yy * this.width2 ]; } } } // used from mudclient _drawSprite_from5(sprite, x, y, width, height) { this.spriteWidth[sprite] = width; this.spriteHeight[sprite] = height; this.spriteTranslate[sprite] = false; this.spriteTranslateX[sprite] = 0; this.spriteTranslateY[sprite] = 0; this.spriteWidthFull[sprite] = width; this.spriteHeightFull[sprite] = height; this.surfacePixels[sprite] = new Int32Array(width * height); let pixel = 0; for (let yy = y; yy < y + height; yy++) { for (let xx = x; xx < x + width; xx++) { this.surfacePixels[sprite][pixel++] = this.pixels[ xx + yy * this.width2 ]; } } } _drawSprite_from3(x, y, id) { if (this.spriteTranslate[id]) { x += this.spriteTranslateX[id]; y += this.spriteTranslateY[id]; } let rY = x + y * this.width2; let rX = 0; let height = this.spriteHeight[id]; let width = this.spriteWidth[id]; let w2 = this.width2 - width; let h2 = 0; if (y < this.boundsTopY) { let j2 = this.boundsTopY - y; height -= j2; y = this.boundsTopY; rX += j2 * width; rY += j2 * this.width2; } if (y + height >= this.boundsBottomY) { height -= y + height - this.boundsBottomY + 1; } if (x < this.boundsTopX) { let k2 = this.boundsTopX - x; width -= k2; x = this.boundsTopX; rX += k2; rY += k2; h2 += k2; w2 += k2; } if (x + width >= this.boundsBottomX) { let l2 = x + width - this.boundsBottomX + 1; width -= l2; h2 += l2; w2 += l2; } if (width <= 0 || height <= 0) { return; } let inc = 1; if (this.interlace) { inc = 2; w2 += this.width2; h2 += this.spriteWidth[id]; if ((y & 1) !== 0) { rY += this.width2; height--; } } if (this.surfacePixels[id] === null) { this._drawSprite_from10A( this.pixels, this.spriteColoursUsed[id], this.spriteColourList[id], rX, rY, width, height, w2, h2, inc ); } else { this._drawSprite_from10( this.pixels, this.surfacePixels[id], 0, rX, rY, width, height, w2, h2, inc ); } } _spriteClipping_from5(x, y, width, height, spriteId) { try { const spriteWidth = this.spriteWidth[spriteId]; const spriteHeight = this.spriteHeight[spriteId]; let l1 = 0; let i2 = 0; let j2 = ((spriteWidth << 16) / width) | 0; let k2 = ((spriteHeight << 16) / height) | 0; if (this.spriteTranslate[spriteId]) { let l2 = this.spriteWidthFull[spriteId]; let j3 = this.spriteHeightFull[spriteId]; j2 = ((l2 << 16) / width) | 0; k2 = ((j3 << 16) / height) | 0; x += ((this.spriteTranslateX[spriteId] * width + l2 - 1) / l2) | 0; y += ((this.spriteTranslateY[spriteId] * height + j3 - 1) / j3) | 0; if ((this.spriteTranslateX[spriteId] * width) % l2 !== 0) { l1 = (((l2 - ((this.spriteTranslateX[spriteId] * width) % l2)) << 16) / width) | 0; } if ((this.spriteTranslateY[spriteId] * height) % j3 !== 0) { i2 = (((j3 - ((this.spriteTranslateY[spriteId] * height) % j3)) << 16) / height) | 0; } width = ((width * (this.spriteWidth[spriteId] - (l1 >> 16))) / l2) | 0; height = ((height * (this.spriteHeight[spriteId] - (i2 >> 16))) / j3) | 0; } let i3 = x + y * this.width2; let k3 = this.width2 - width; if (y < this.boundsTopY) { let l3 = this.boundsTopY - y; height -= l3; y = 0; i3 += l3 * this.width2; i2 += k2 * l3; } if (y + height >= this.boundsBottomY) { height -= y + height - this.boundsBottomY + 1; } if (x < this.boundsTopX) { let i4 = this.boundsTopX - x; width -= i4; x = 0; i3 += i4; l1 += j2 * i4; k3 += i4; } if (x + width >= this.boundsBottomX) { let j4 = x + width - this.boundsBottomX + 1; width -= j4; k3 += j4; } let yInc = 1; if (this.interlace) { yInc = 2; k3 += this.width2; k2 += k2; if ((y & 1) !== 0) { i3 += this.width2; height--; } } this._plotScale_from13( this.pixels, this.surfacePixels[spriteId], 0, l1, i2, i3, k3, width, height, j2, k2, spriteWidth, yInc ); } catch (e) { console.error(e); } } _spriteClipping_from7(x, y, w, h, id, tx, ty) { if (id >= 50000) { this.mudclientref.drawTeleportBubble( x, y, w, h, id - 50000, tx, ty ); return; } if (id >= 40000) { this.mudclientref.drawItem(x, y, w, h, id - 40000, tx, ty); return; } if (id >= 20000) { this.mudclientref.drawNpc(x, y, w, h, id - 20000, tx, ty); return; } if (id >= 5000) { this.mudclientref.drawPlayer(x, y, w, h, id - 5000, tx, ty); return; } this._spriteClipping_from5(x, y, w, h, id); } _drawSpriteAlpha_from4(x, y, spriteId, alpha) { if (this.spriteTranslate[spriteId]) { x += this.spriteTranslateX[spriteId]; y += this.spriteTranslateY[spriteId]; } let size = x + y * this.width2; let j1 = 0; let height = this.spriteHeight[spriteId]; let width = this.spriteWidth[spriteId]; let extraXSpace = this.width2 - width; let j2 = 0; if (y < this.boundsTopY) { let k2 = this.boundsTopY - y; height -= k2; y = this.boundsTopY; j1 += k2 * width; size += k2 * this.width2; } if (y + height >= this.boundsBottomY) { height -= y + height - this.boundsBottomY + 1; } if (x < this.boundsTopX) { let l2 = this.boundsTopX - x; width -= l2; x = this.boundsTopX; j1 += l2; size += l2; j2 += l2; extraXSpace += l2; } if (x + width >= this.boundsBottomX) { let i3 = x + width - this.boundsBottomX + 1; width -= i3; j2 += i3; extraXSpace += i3; } if (width <= 0 || height <= 0) { return; } let yInc = 1; if (this.interlace) { yInc = 2; extraXSpace += this.width2; j2 += this.spriteWidth[spriteId]; if ((y & 1) !== 0) { size += this.width2; height--; } } if (this.surfacePixels[spriteId] === null) { this._drawSpriteAlpha_from11A( this.pixels, this.spriteColoursUsed[spriteId], this.spriteColourList[spriteId], j1, size, width, height, extraXSpace, j2, yInc, alpha ); } else { this._drawSpriteAlpha_from11( this.pixels, this.surfacePixels[spriteId], 0, j1, size, width, height, extraXSpace, j2, yInc, alpha ); } } drawActionBubble(x, y, scaleX, scaleY, sprite, alpha) { try { const spriteWidth = this.spriteWidth[sprite]; const spriteHeight = this.spriteHeight[sprite]; let i2 = 0; let j2 = 0; let k2 = ((spriteWidth << 16) / scaleX) | 0; let l2 = ((spriteHeight << 16) / scaleY) | 0; if (this.spriteTranslate[sprite]) { const i3 = this.spriteWidthFull[sprite]; const k3 = this.spriteHeightFull[sprite]; k2 = ((i3 << 16) / scaleX) | 0; l2 = ((k3 << 16) / scaleY) | 0; x += ((this.spriteTranslateX[sprite] * scaleX + i3 - 1) / i3) | 0; y += ((this.spriteTranslateY[sprite] * scaleY + k3 - 1) / k3) | 0; if ((this.spriteTranslateX[sprite] * scaleX) % i3 !== 0) { i2 = (((i3 - ((this.spriteTranslateX[sprite] * scaleX) % i3)) << 16) / scaleX) | 0; } if ((this.spriteTranslateY[sprite] * scaleY) % k3 !== 0) { j2 = (((k3 - ((this.spriteTranslateY[sprite] * scaleY) % k3)) << 16) / scaleY) | 0; } scaleX = ((scaleX * (this.spriteWidth[sprite] - (i2 >> 16))) / i3) | 0; scaleY = ((scaleY * (this.spriteHeight[sprite] - (j2 >> 16))) / k3) | 0; } let j3 = x + y * this.width2; let l3 = this.width2 - scaleX; if (y < this.boundsTopY) { let i4 = this.boundsTopY - y; scaleY -= i4; y = 0; j3 += i4 * this.width2; j2 += l2 * i4; } if (y + scaleY >= this.boundsBottomY) scaleY -= y + scaleY - this.boundsBottomY + 1; if (x < this.boundsTopX) { let j4 = this.boundsTopX - x; scaleX -= j4; x = 0; j3 += j4; i2 += k2 * j4; l3 += j4; } if (x + scaleX >= this.boundsBottomX) { let k4 = x + scaleX - this.boundsBottomX + 1; scaleX -= k4; l3 += k4; } let yInc = 1; if (this.interlace) { yInc = 2; l3 += this.width2; l2 += l2; if ((y & 1) !== 0) { j3 += this.width2; scaleY--; } } this.transparentScale( this.pixels, this.surfacePixels[sprite], 0, i2, j2, j3, l3, scaleX, scaleY, k2, l2, spriteWidth, yInc, alpha ); } catch (e) { console.error(e); } } _spriteClipping_from6(x, y, width, height, spriteId, colour) { try { let k1 = this.spriteWidth[spriteId]; let l1 = this.spriteHeight[spriteId]; let i2 = 0; let j2 = 0; let k2 = ((k1 << 16) / width) | 0; let l2 = ((l1 << 16) / height) | 0; if (this.spriteTranslate[spriteId]) { let i3 = this.spriteWidthFull[spriteId]; let k3 = this.spriteHeightFull[spriteId]; k2 = ((i3 << 16) / width) | 0; l2 = ((k3 << 16) / height) | 0; x += ((this.spriteTranslateX[spriteId] * width + i3 - 1) / i3) | 0; y += ((this.spriteTranslateY[spriteId] * height + k3 - 1) / k3) | 0; if ((this.spriteTranslateX[spriteId] * width) % i3 !== 0) { i2 = (((i3 - ((this.spriteTranslateX[spriteId] * width) % i3)) << 16) / width) | 0; } if ((this.spriteTranslateY[spriteId] * height) % k3 !== 0) { j2 = (((k3 - ((this.spriteTranslateY[spriteId] * height) % k3)) << 16) / height) | 0; } width = ((width * (this.spriteWidth[spriteId] - (i2 >> 16))) / i3) | 0; height = ((height * (this.spriteHeight[spriteId] - (j2 >> 16))) / k3) | 0; } let j3 = x + y * this.width2; let l3 = this.width2 - width; if (y < this.boundsTopY) { let i4 = this.boundsTopY - y; height -= i4; y = 0; j3 += i4 * this.width2; j2 += l2 * i4; } if (y + height >= this.boundsBottomY) { height -= y + height - this.boundsBottomY + 1; } if (x < this.boundsTopX) { let j4 = this.boundsTopX - x; width -= j4; x = 0; j3 += j4; i2 += k2 * j4; l3 += j4; } if (x + width >= this.boundsBottomX) { let k4 = x + width - this.boundsBottomX + 1; width -= k4; l3 += k4; } let yInc = 1; if (this.interlace) { yInc = 2; l3 += this.width2; l2 += l2; if ((y & 1) !== 0) { j3 += this.width2; height--; } } this._plotScale_from14( this.pixels, this.surfacePixels[spriteId], 0, i2, j2, j3, l3, width, height, k2, l2, k1, yInc, colour ); } catch (e) { console.error(e); } } _drawSprite_from10( dest, src, i, srcPos, destPos, width, height, j1, k1, yInc ) { let i2 = -(width >> 2); width = -(width & 3); for (let j2 = -height; j2 < 0; j2 += yInc) { for (let k2 = i2; k2 < 0; k2++) { i = src[srcPos++]; if (i !== 0) { dest[destPos++] = i; } else { destPos++; } i = src[srcPos++]; if (i !== 0) { dest[destPos++] = i; } else { destPos++; } i = src[srcPos++]; if (i !== 0) { dest[destPos++] = i; } else { destPos++; } i = src[srcPos++]; if (i !== 0) { dest[destPos++] = i; } else { destPos++; } } for (let l2 = width; l2 < 0; l2++) { i = src[srcPos++]; if (i !== 0) { dest[destPos++] = i; } else { destPos++; } } destPos += j1; srcPos += k1; } } _drawSprite_from10A( target, colourIdx, colours, srcPos, destPos, width, height, w2, h2, rowInc ) { let l1 = -(width >> 2); width = -(width & 3); for (let i2 = -height; i2 < 0; i2 += rowInc) { for (let j2 = l1; j2 < 0; j2++) { let byte0 = colourIdx[srcPos++]; if (byte0 !== 0) { target[destPos++] = colours[byte0 & 0xff]; } else { destPos++; } byte0 = colourIdx[srcPos++]; if (byte0 !== 0) { target[destPos++] = colours[byte0 & 0xff]; } else { destPos++; } byte0 = colourIdx[srcPos++]; if (byte0 !== 0) { target[destPos++] = colours[byte0 & 0xff]; } else { destPos++; } byte0 = colourIdx[srcPos++]; if (byte0 !== 0) { target[destPos++] = colours[byte0 & 0xff]; } else { destPos++; } } for (let k2 = width; k2 < 0; k2++) { let byte1 = colourIdx[srcPos++]; if (byte1 !== 0) { target[destPos++] = colours[byte1 & 0xff]; } else { destPos++; } } destPos += w2; srcPos += h2; } } _plotScale_from13(dest, src, i, j, k, destPos, i1, j1, k1, l1, i2, j2, k2) { try { let l2 = j; for (let i3 = -k1; i3 < 0; i3 += k2) { let j3 = (k >> 16) * j2; for (let k3 = -j1; k3 < 0; k3++) { i = src[(j >> 16) + j3]; if (i !== 0) { dest[destPos++] = i; } else { destPos++; } j += l1; } k += i2; j = l2; destPos += i1; } } catch (e) { console.error(e); } } _drawSpriteAlpha_from11( dest, src, i, srcPos, size, width, height, extraXSpace, k1, yInc, alpha ) { let j2 = 256 - alpha; for (let k2 = -height; k2 < 0; k2 += yInc) { for (let l2 = -width; l2 < 0; l2++) { i = src[srcPos++]; if (i !== 0) { let i3 = dest[size]; dest[size++] = ((((i & 0xff00ff) * alpha + (i3 & 0xff00ff) * j2) & -16711936) + (((i & 0xff00) * alpha + (i3 & 0xff00) * j2) & 0xff0000)) >> 8; } else { size++; } } size += extraXSpace; srcPos += k1; } } _drawSpriteAlpha_from11A( dest, coloursUsed, colourList, listPos, size, width, height, extraXSpace, j1, yInc, alpha ) { let i2 = 256 - alpha; for (let j2 = -height; j2 < 0; j2 += yInc) { for (let k2 = -width; k2 < 0; k2++) { let l2 = coloursUsed[listPos++]; if (l2 !== 0) { l2 = colourList[l2 & 0xff]; let i3 = dest[size]; dest[size++] = ((((l2 & 0xff00ff) * alpha + (i3 & 0xff00ff) * i2) & -16711936) + (((l2 & 0xff00) * alpha + (i3 & 0xff00) * i2) & 0xff0000)) >> 8; } else { size++; } } size += extraXSpace; listPos += j1; } } transparentScale( dest, src, i, j, k, destPos, i1, j1, k1, l1, i2, j2, yInc, alpha ) { let i3 = 256 - alpha; try { let j3 = j; for (let k3 = -k1; k3 < 0; k3 += yInc) { let l3 = (k >> 16) * j2; for (let i4 = -j1; i4 < 0; i4++) { i = src[(j >> 16) + l3]; if (i !== 0) { let j4 = dest[destPos]; dest[destPos++] = ((((i & 0xff00ff) * alpha + (j4 & 0xff00ff) * i3) & -0xff0100) + (((i & 0xff00) * alpha + (j4 & 0xff00) * i3) & 0xff0000)) >> 8; } else { destPos++; } j += l1; } k += i2; j = j3; destPos += i1; } } catch (e) { console.error(e); } } _plotScale_from14( target, pixels, i, j, k, l, i1, width, height, l1, i2, j2, yInc, colour ) { let i3 = (colour >> 16) & 0xff; let j3 = (colour >> 8) & 0xff; let k3 = colour & 0xff; try { let l3 = j; for (let i4 = -height; i4 < 0; i4 += yInc) { let j4 = (k >> 16) * j2; for (let k4 = -width; k4 < 0; k4++) { i = pixels[(j >> 16) + j4]; if (i !== 0) { let l4 = (i >> 16) & 0xff; let i5 = (i >> 8) & 0xff; let j5 = i & 0xff; if (l4 === i5 && i5 === j5) { target[l++] = (((l4 * i3) >> 8) << 16) + (((i5 * j3) >> 8) << 8) + ((j5 * k3) >> 8); } else { target[l++] = i; } } else { l++; } j += l1; } k += i2; j = l3; l += i1; } } catch (e) { console.error(e); } } // "scale" is not actually scaling when it comes to the landscape drawMinimapSprite(x, y, sprite, rotation, scale) { let j1 = this.width2; let k1 = this.height2; if (!this.sinCosCache) { this.sinCosCache = new Int32Array(512); for (let i = 0; i < 256; i++) { this.sinCosCache[i] = (Math.sin(i * 0.02454369) * 32768) | 0; this.sinCosCache[i + 256] = (Math.cos(i * 0.02454369) * 32768) | 0; } } let i2 = -((this.spriteWidthFull[sprite] / 2) | 0); let j2 = -((this.spriteHeightFull[sprite] / 2) | 0); if (this.spriteTranslate[sprite]) { i2 += this.spriteTranslateX[sprite]; j2 += this.spriteTranslateY[sprite]; } let k2 = i2 + this.spriteWidth[sprite]; let l2 = j2 + this.spriteHeight[sprite]; let i3 = k2; let j3 = j2; let k3 = i2; let l3 = l2; rotation &= 0xff; let i4 = this.sinCosCache[rotation] * scale; let j4 = this.sinCosCache[rotation + 256] * scale; let k4 = x + ((j2 * i4 + i2 * j4) >> 22); let l4 = y + ((j2 * j4 - i2 * i4) >> 22); let i5 = x + ((j3 * i4 + i3 * j4) >> 22); let j5 = y + ((j3 * j4 - i3 * i4) >> 22); let k5 = x + ((l2 * i4 + k2 * j4) >> 22); let l5 = y + ((l2 * j4 - k2 * i4) >> 22); let i6 = x + ((l3 * i4 + k3 * j4) >> 22); let j6 = y + ((l3 * j4 - k3 * i4) >> 22); if (scale === 192 && (rotation & 0x3f) === (Surface.anInt348 & 0x3f)) { Surface.anInt346++; } else if (scale === 128) { Surface.anInt348 = rotation; } else { Surface.anInt347++; } let k6 = l4; let l6 = l4; if (j5 < k6) { k6 = j5; } else if (j5 > l6) { l6 = j5; } if (l5 < k6) { k6 = l5; } else if (l5 > l6) { l6 = l5; } if (j6 < k6) { k6 = j6; } else if (j6 > l6) { l6 = j6; } if (k6 < this.boundsTopY) { k6 = this.boundsTopY; } if (l6 > this.boundsBottomY) { l6 = this.boundsBottomY; } if ( this.anIntArray340 === null || this.anIntArray340.length !== k1 + 1 ) { this.anIntArray340 = new Int32Array(k1 + 1); this.anIntArray341 = new Int32Array(k1 + 1); this.anIntArray342 = new Int32Array(k1 + 1); this.anIntArray343 = new Int32Array(k1 + 1); this.anIntArray344 = new Int32Array(k1 + 1); this.anIntArray345 = new Int32Array(k1 + 1); } for (let i7 = k6; i7 <= l6; i7++) { this.anIntArray340[i7] = 99999999; this.anIntArray341[i7] = -99999999; } let i8 = 0; let k8 = 0; let i9 = 0; let j9 = this.spriteWidth[sprite]; let k9 = this.spriteHeight[sprite]; i2 = 0; j2 = 0; i3 = j9 - 1; j3 = 0; k2 = j9 - 1; l2 = k9 - 1; k3 = 0; l3 = k9 - 1; if (j6 !== l4) { i8 = (((i6 - k4) << 8) / (j6 - l4)) | 0; i9 = (((l3 - j2) << 8) / (j6 - l4)) | 0; } let j7 = 0; let k7 = 0; let l7 = 0; let l8 = 0; if (l4 > j6) { l7 = i6 << 8; l8 = l3 << 8; j7 = j6; k7 = l4; } else { l7 = k4 << 8; l8 = j2 << 8; j7 = l4; k7 = j6; } if (j7 < 0) { l7 -= i8 * j7; l8 -= i9 * j7; j7 = 0; } if (k7 > k1 - 1) { k7 = k1 - 1; } for (let i = j7; i <= k7; i++) { this.anIntArray340[i] = this.anIntArray341[i] = l7; l7 += i8; this.anIntArray342[i] = this.anIntArray343[i] = 0; this.anIntArray344[i] = this.anIntArray345[i] = l8; l8 += i9; } if (j5 !==