UNPKG

@2003scape/rsc-client

Version:
1,377 lines (1,185 loc) 187 kB
const Color = require('./lib/graphics/color'); const Font = require('./lib/graphics/font'); const GameBuffer = require('./game-buffer'); const GameCharacter = require('./game-character'); const GameConnection = require('./game-connection'); const GameData = require('./game-data'); const GameModel = require('./game-model'); const Long = require('long'); const Panel = require('./panel'); const Scene = require('./scene'); const StreamAudioPlayer = require('./stream-audio-player'); const Surface = require('./surface'); const Utility = require('./utility'); const WordFilter = require('./word-filter'); const World = require('./world'); const applyUIComponents = require('./ui'); const getPacketHandlers = require('./packet-handlers'); const keycodes = require('./lib/keycodes'); const clientOpcodes = require('./opcodes/client'); const version = require('./version'); const ZOOM_MIN = 450; const ZOOM_MAX = 1250; const ZOOM_INDOORS = 550; const ZOOM_OUTDOORS = 750; const MENU_MAX = 250; const PATH_STEPS_MAX = 8000; const PLAYERS_MAX = 500; const NPCS_MAX = 500; const GAME_OBJECTS_MAX = 1000; const WALL_OBJECTS_MAX = 500; const PLAYERS_SERVER_MAX = 4000; const GROUND_ITEMS_MAX = 5000; const NPCS_SERVER_MAX = 5000; const OBJECTS_MAX = 1500; const PLAYER_STAT_COUNT = 18; const QUEST_COUNT = 50; const PLAYER_STAT_EQUIPMENT_COUNT = 5; const ANIMATED_MODELS = [ 'torcha2', 'torcha3', 'torcha4', 'skulltorcha2', 'skulltorcha3', 'skulltorcha4', 'firea2', 'firea3', 'fireplacea2', 'fireplacea3', 'firespell2', 'firespell3', 'lightning2', 'lightning3', 'clawspell2', 'clawspell3', 'clawspell4', 'clawspell5', 'spellcharge2', 'spellcharge3' ]; class mudclient extends GameConnection { constructor(canvas) { super(canvas); // attach methods and properties from files in ./ui/ applyUIComponents(this); // { opcode: function handler (data) { } } this.packetHandlers = getPacketHandlers(this); this.localRegionX = 0; this.localRegionY = 0; this.messageTabSelected = 0; this.mouseClickXX = 0; this.mouseClickXY = 0; this.privateMessageTarget = new Long(0); this.controlListQuest = 0; this.controlListMagic = 0; this.packetErrorCount = 0; this.mouseButtonDownTime = 0; this.mouseButtonItemCountIncrement = 0; this.animationIndex = 0; this.cameraRotationX = 0; this.tradeConfirmAccepted = false; this.appearanceHeadType = 0; this.appearanceSkinColour = 0; this.anInt707 = 0; this.deathScreenTimeout = 0; this.cameraRotationY = 0; this.welcomeUnreadMessages = 0; this.logoutTimeout = 0; this.tradeRecipientConfirmHash = new Long(0); this.loginTimer = 0; this.npcCombatModelArray1 = new Int32Array([0, 1, 2, 1, 0, 0, 0, 0]); this.npcCombatModelArray2 = new Int32Array([0, 0, 0, 0, 0, 1, 2, 1]); this.systemUpdate = 0; this.graphics = null; this.regionX = 0; this.regionY = 0; this.welcomScreenAlreadyShown = false; this.mouseButtonClick = 0; this.healthBarCount = 0; this.spriteMedia = 0; this.spriteUtil = 0; this.spriteItem = 0; this.spriteProjectile = 0; this.spriteTexture = 0; this.spriteTextureWorld = 0; this.spriteLogo = 0; this.teleportBubbleCount = 0; this.mouseClickCount = 0; this.shopSellPriceMod = 0; this.shopBuyPriceMod = 0; this.duelOptionRetreat = 0; this.duelOptionMagic = 0; this.duelOptionPrayer = 0; this.duelOptionWeapons = 0; this.groundItemCount = 0; this.receivedMessagesCount = 0; this.messageTabFlashAll = 0; this.messageTabFlashHistory = 0; this.messageTabFlashQuest = 0; this.messageTabFlashPrivate = 0; this.bankItemCount = 0; this.objectAnimationNumberFireLightningSpell = 0; this.objectAnimationNumberTorch = 0; this.objectAnimationNumberClaw = 0; this.loggedIn = 0; this.npcCount = 0; this.npcCacheCount = 0; this.objectAnimationCount = 0; this.tradeConfirmItemsCount = 0; this.mouseClickXStep = 0; this.newBankItemCount = 0; // the orders of the NPC animation slots at different angles this.npcAnimationArray = [ new Int32Array([11, 2, 9, 7, 1, 6, 10, 0, 5, 8, 3, 4]), new Int32Array([11, 2, 9, 7, 1, 6, 10, 0, 5, 8, 3, 4]), new Int32Array([11, 3, 2, 9, 7, 1, 6, 10, 0, 5, 8, 4]), new Int32Array([3, 4, 2, 9, 7, 1, 6, 10, 8, 11, 0, 5]), new Int32Array([3, 4, 2, 9, 7, 1, 6, 10, 8, 11, 0, 5]), new Int32Array([4, 3, 2, 9, 7, 1, 6, 10, 8, 11, 0, 5]), new Int32Array([11, 4, 2, 9, 7, 1, 6, 10, 0, 5, 8, 3]), new Int32Array([11, 2, 9, 7, 1, 6, 10, 0, 5, 8, 4, 3])]; this.npcWalkModel = new Int32Array([0, 1, 2, 1]); this.referID = 0; this.combatTimeout = 0; this.optionMenuCount = 0; this.errorLoadingCodebase = false; this.cameraRotationTime = 0; this.duelOpponentItemsCount = 0; this.duelItemsCount = 0; this.duelOfferOpponentItemCount = 0; this.characterHairColours = new Int32Array([ 0xffc030, 0xffa040, 0x805030, 0x604020, 0x303030, 0xff6020, 0xff4000, 0xffffff, 65280, 65535 ]); this.characterTopBottomColours = new Int32Array([ 0xff0000, 0xff8000, 0xffe000, 0xa0e000, 0x00e000, 0x008000, 0x00a080, 0x00b0ff, 0x0080ff, 0x0030f0, 0xe000e0, 0x303030, 0x604000, 0x805000, 0xffffff ]); this.characterSkinColours = new Int32Array([ 0xecded0, 0xccb366, 0xb38c40, 0x997326, 0x906020 ]); this.itemsAboveHeadCount = 0; this.statFatigue = 0; this.fatigueSleeping = 0; this.tradeRecipientConfirmItemsCount = 0; this.tradeRecipientItemsCount = 0; this.showDialogServerMessage = false; this.menuX = 0; this.menuY = 0; this.menuWidth = 0; this.menuHeight = 0; this.menuItemsCount = 0; this.showUITab = 0; this.tradeItemsCount = 0; this.planeWidth = 0; this.planeHeight = 0; this.planeMultiplier = 0; this.playerQuestPoints = 0; this.welcomeLastLoggedInDays = 0; this.inventoryItemsCount = 0; this.duelOpponentNameHash = new Long(0); this.minimapRandom1 = 0; this.minimapRandom2 = 0; this.objectCount = 0; this.duelOfferItemCount = 0; this.cameraAutoRotatePlayerX = 0; this.cameraAutoRotatePlayerY = 0; this.playerCount = 0; this.knownPlayerCount = 0; this.spriteCount = 0; this.wallObjectCount = 0; this.welcomeRecoverySetDays = 0; this.localLowerX = 0; this.localLowerY = 0; this.localUpperX = 0; this.localUpperY = 0; this.world = null; this.welcomeLastLoggedInIP = 0; this.sleepWordDelayTimer = 0; this.menuIndices = new Int32Array(MENU_MAX); this.cameraAutoAngleDebug = false; this.wallObjectDirection = new Int32Array(WALL_OBJECTS_MAX); this.wallObjectId = new Int32Array(WALL_OBJECTS_MAX); this.cameraRotationXIncrement = 2; this.inventoryMaxItemCount = 30; this.bankItemsMax = 48; this.optionMenuEntry = []; this.optionMenuEntry.length = 5; this.optionMenuEntry.fill(null); this.newBankItems = new Int32Array(256); this.newBankItemsCount = new Int32Array(256); this.teleportBubbleTime = new Int32Array(50); this.receivedMessageX = new Int32Array(50); this.receivedMessageY = new Int32Array(50); this.receivedMessageMidPoint = new Int32Array(50); this.receivedMessageHeight = new Int32Array(50); this.localPlayer = new GameCharacter(); this.localPlayerServerIndex = -1; this.menuItemX = new Int32Array(MENU_MAX); this.menuItemY = new Int32Array(MENU_MAX); this.bankItems = new Int32Array(256); this.bankItemsCount = new Int32Array(256); this.appearanceBodyGender = 1; this.appearance2Colour = 2; this.appearanceHairColour = 2; this.appearanceTopColour = 8; this.appearanceBottomColour = 14; this.appearanceHeadGender = 1; this.loginUser = ''; this.loginPass = ''; this.cameraAngle = 1; this.members = false; this.optionSoundDisabled = false; this.showRightClickMenu = false; this.cameraRotationYIncrement = 2; this.objectAlreadyInMenu = new Int8Array(OBJECTS_MAX); this.menuItemText1 = []; this.menuItemText1.length = MENU_MAX; this.menuItemText1.fill(null); this.duelOpponentName = ''; this.lastObjectAnimationNumberFireLightningSpell = -1; this.lastObjectAnimationNumberTorch = -1; this.lastObjectAnimationNumberClaw = -1; this.planeIndex = -1; this.cameraRotation = 128; this.teleportBubbleX = new Int32Array(50); this.errorLoadingData = false; this.playerExperience = new Int32Array(PLAYER_STAT_COUNT); this.tradeRecipientAccepted = false; this.tradeAccepted = false; this.mouseClickXHistory = new Int32Array(8192); this.mouseClickYHistory = new Int32Array(8192); this.playerServerIndexes = new Int32Array(PLAYERS_MAX); this.teleportBubbleY = new Int32Array(50); this.receivedMessages = []; this.receivedMessages.length = 50; this.receivedMessages.fill(null); this.showDialogDuelConfirm = false; this.duelAccepted = false; this.players = []; this.players.length = PLAYERS_MAX; this.players.fill(null); this.prayerOn = new Int8Array(50); this.menuIndex = new Int32Array(MENU_MAX); this.menuSourceIndex = new Int32Array(MENU_MAX); this.menuTargetIndex = new Int32Array(MENU_MAX); this.wallObjectAlreadyInMenu = new Int8Array(WALL_OBJECTS_MAX); this.magicLoc = 128; this.errorLoadingMemory = false; this.fogOfWar = false; this.gameWidth = 512; this.gameHeight = 334; this.tradeConfirmItems = new Int32Array(14); this.tradeConfirmItemCount = new Int32Array(14); this.tradeRecipientName = ''; this.selectedSpell = -1; this.showOptionMenu = false; this.playerStatCurrent = new Int32Array(PLAYER_STAT_COUNT); this.teleportBubbleType = new Int32Array(50); this.showDialogShop = false; this.shopItem = new Int32Array(256); this.shopItemCount = new Int32Array(256); this.shopItemPrice = new Int32Array(256); this.duelOfferOpponentAccepted = false; this.duelOfferAccepted = false; this.gameModels = []; this.gameModels.length = GAME_OBJECTS_MAX; this.gameModels.fill(null); this.showDialogDuel = false; this.serverMessage = ''; this.duelOpponentItems = new Int32Array(8); this.duelOpponentItemCount = new Int32Array(8); this.duelItems = new Int32Array(8); this.duelItemCount = new Int32Array(8); this.playerStatBase = new Int32Array(PLAYER_STAT_COUNT); this.npcsCache = []; this.npcsCache.length = NPCS_MAX; this.npcsCache.fill(null); this.groundItemX = new Int32Array(GROUND_ITEMS_MAX); this.groundItemY = new Int32Array(GROUND_ITEMS_MAX); this.groundItemID = new Int32Array(GROUND_ITEMS_MAX); this.groundItemZ = new Int32Array(GROUND_ITEMS_MAX); this.bankSelectedItemSlot = -1; this.bankSelectedItem = -2; this.duelOfferOpponentItemId = new Int32Array(8); this.duelOfferOpponentItemStack = new Int32Array(8); this.messageHistoryTimeout = new Int32Array(5); this.optionCameraModeAuto = true; this.objectX = new Int32Array(OBJECTS_MAX); this.objectY = new Int32Array(OBJECTS_MAX); this.objectId = new Int32Array(OBJECTS_MAX); this.objectDirection = new Int32Array(OBJECTS_MAX); this.selectedItemInventoryIndex = -1; this.selectedItemName = ''; this.loadingArea = false; this.tradeRecipientConfirmItems = new Int32Array(14); this.tradeRecipientConfirmItemCount = new Int32Array(14); this.tradeRecipientItems = new Int32Array(14); this.tradeRecipientItemCount = new Int32Array(14); this.showDialogServerMessage = false; this.menuType = new Int32Array(MENU_MAX); this.questComplete = new Int8Array(QUEST_COUNT); this.wallObjectModel = []; this.wallObjectModel.length = WALL_OBJECTS_MAX; this.wallObjectModel.fill(null); this.actionBubbleX = new Int32Array(50); this.actionBubbleY = new Int32Array(50); this.cameraZoom = ZOOM_INDOORS; // 400-1250 this.tradeItems = new Int32Array(14); this.tradeItemCount = new Int32Array(14); this.lastHeightOffset = -1; this.duelSettingsRetreat = false; this.duelSettingsMagic = false; this.duelSettingsPrayer = false; this.duelSettingsWeapons = false; this.showDialogBank = false; this.loginUserDesc = ''; this.loginUserDisp = ''; this.optionMouseButtonOne = false; this.inventoryItemId = new Int32Array(35); this.inventoryItemStackCount = new Int32Array(35); this.inventoryEquipped = new Int32Array(35); this.knownPlayers = []; this.knownPlayers.length = PLAYERS_MAX; this.knownPlayers.fill(null); this.messageHistory = []; this.messageHistory.length = 5; this.messageHistory.fill(null); this.duelOfferItemId = new Int32Array(8); this.duelOfferItemStack = new Int32Array(8); this.actionBubbleScale = new Int32Array(50); this.actionBubbleItem = new Int32Array(50); this.sleepWordDelay = true; this.showAppearanceChange = false; this.shopSelectedItemIndex = -1; this.shopSelectedItemType = -2; this.projectileMaxRange = 40; this.npcs = []; this.npcs.length = NPCS_MAX; this.npcs.fill(null); this.experienceArray = new Int32Array(99); this.healthBarX = new Int32Array(50); this.healthBarY = new Int32Array(50); this.healthBarMissing = new Int32Array(50); this.playerServer = []; this.playerServer.length = PLAYERS_SERVER_MAX; this.playerServer.fill(null); this.walkPathX = new Int32Array(PATH_STEPS_MAX); this.walkPathY = new Int32Array(PATH_STEPS_MAX); this.wallObjectX = new Int32Array(WALL_OBJECTS_MAX); this.wallObjectY = new Int32Array(WALL_OBJECTS_MAX); this.menuItemText2 = []; this.menuItemText2.length = MENU_MAX; this.menuItemText2.fill(null); this.npcsServer = []; this.npcsServer.length = NPCS_SERVER_MAX; this.npcsServer.fill(null); this.playerStatEquipment = new Int32Array(PLAYER_STAT_EQUIPMENT_COUNT); this.objectModel = []; this.objectModel.length = OBJECTS_MAX; this.objectModel.fill(null); // message scrollback this.playerMsgHistory = []; this.playerMsgPtr = 0; this.recoveryQuestions = [ 'Where were you born?', 'What was your first teachers name?', 'What is your fathers middle name?', 'Who was your first best friend?', 'What is your favourite vacation spot?', 'What is your mothers middle name?', 'What was your first pets name?', 'What was the name of your first school?', 'What is your mothers maiden name?', 'Who was your first boyfriend/girlfriend?', 'What was the first computer game you purchased?', 'Who is your favourite actor/actress?', 'Who is your favourite author?', 'Who is your favourite musician?', 'Who is your favourite cartoon character?', 'What is your favourite book?', 'What is your favourite food?', 'What is your favourite movie?' ]; this.showRecoverChange = false; this.recoverCustomQuestionIndex = -1; this.showChangePasswordStep = 0; this.changePasswordOld = ''; this.changePasswordNew = ''; this.welcomeTipDay = 0; } playSoundFile(soundName) { if (!this.audioPlayer || this.optionSoundDisabled) { return; } const filename = `${soundName}.pcm`; this.audioPlayer.writeStream( this.soundData, Utility.getDataFileOffset(filename, this.soundData), Utility.getDataFileLength(filename, this.soundData) ); } _walkToActionSource_from8(startX, startY, x1, y1, x2, y2, checkObjects, walkToAction) { let steps = this.world.route(startX, startY, x1, y1, x2, y2, this.walkPathX, this.walkPathY, checkObjects); if (steps === -1) { if (walkToAction) { steps = 1; this.walkPathX[0] = x1; this.walkPathY[0] = y1; } else { return false; } } steps--; startX = this.walkPathX[steps]; startY = this.walkPathY[steps]; steps--; if (walkToAction) { this.packetStream.newPacket(clientOpcodes.WALK_ACTION); } else { this.packetStream.newPacket(clientOpcodes.WALK); } this.packetStream.putShort(startX + this.regionX); this.packetStream.putShort(startY + this.regionY); if (walkToAction && steps === -1 && (startX + this.regionX) % 5 === 0) { steps = 0; } for (let i = steps; i >= 0 && i > steps - 25; i--) { this.packetStream.putByte(this.walkPathX[i] - startX); this.packetStream.putByte(this.walkPathY[i] - startY); } this.packetStream.sendPacket(); this.mouseClickXStep = -24; this.mouseClickXX = this.mouseX; this.mouseClickXY = this.mouseY; return true; } walkTo(startX, startY, x1, y1, x2, y2, checkObjects, walkToAction) { let steps = this.world.route(startX, startY, x1, y1, x2, y2, this.walkPathX, this.walkPathY, checkObjects); if (steps === -1) { return false; } steps--; startX = this.walkPathX[steps]; startY = this.walkPathY[steps]; steps--; if (walkToAction) { this.packetStream.newPacket(clientOpcodes.WALK_ACTION); } else { this.packetStream.newPacket(clientOpcodes.WALK); } this.packetStream.putShort(startX + this.regionX); this.packetStream.putShort(startY + this.regionY); if (walkToAction && steps === -1 && (startX + this.regionX) % 5 === 0) { steps = 0; } for (let i = steps; i >= 0 && i > steps - 25; i--) { this.packetStream.putByte(this.walkPathX[i] - startX); this.packetStream.putByte(this.walkPathY[i] - startY); } this.packetStream.sendPacket(); this.mouseClickXStep = -24; this.mouseClickXX = this.mouseX; this.mouseClickXY = this.mouseY; return true; } updateBankItems() { this.bankItemCount = this.newBankItemCount; for (let i = 0; i < this.newBankItemCount; i++) { this.bankItems[i] = this.newBankItems[i]; this.bankItemsCount[i] = this.newBankItemsCount[i]; } for (let invIdx = 0; invIdx < this.inventoryItemsCount; invIdx++) { if (this.bankItemCount >= this.bankItemsMax) { break; } const inventoryID = this.inventoryItemId[invIdx]; let hasItemInInventory = false; for (let i = 0; i < this.bankItemCount; i++) { if (this.bankItems[i] === inventoryID) { hasItemInInventory = true; break; } } if (!hasItemInInventory) { this.bankItems[this.bankItemCount] = inventoryID; this.bankItemsCount[this.bankItemCount] = 0; this.bankItemCount++; } } } drawAboveHeadStuff() { for (let i = 0; i < this.receivedMessagesCount; i++) { const textHeight = this.surface.textHeight(1); const x = this.receivedMessageX[i]; let y = this.receivedMessageY[i]; const messageMid = this.receivedMessageMidPoint[i]; const messageHeight = this.receivedMessageHeight[i]; let flag = true; while (flag) { flag = false; for (let j = 0; j < i; j++) { if (y + messageHeight > this.receivedMessageY[j] - textHeight && y - textHeight < this.receivedMessageY[j] + this.receivedMessageHeight[j] && x - messageMid < this.receivedMessageX[j] + this.receivedMessageMidPoint[j] && x + messageMid > this.receivedMessageX[j] - this.receivedMessageMidPoint[j] && this.receivedMessageY[j] - textHeight - messageHeight < y) { y = this.receivedMessageY[j] - textHeight - messageHeight; flag = true; } } } this.receivedMessageY[i] = y; this.surface.drawParagraph(this.receivedMessages[i], x, y, 1, 0xffff00, 300); } for (let i = 0; i < this.itemsAboveHeadCount; i++) { const x = this.actionBubbleX[i]; const y = this.actionBubbleY[i]; const scale = this.actionBubbleScale[i]; const id = this.actionBubbleItem[i]; const scaleX = ((39 * scale) / 100) | 0; const scaleY = ((27 * scale) / 100) | 0; this.surface.drawActionBubble(x - ((scaleX / 2) | 0), y - scaleY, scaleX, scaleY, this.spriteMedia + 9, 85); const scaleXClip = ((36 * scale) / 100) | 0; const scaleYClip = ((24 * scale) / 100) | 0; this.surface._spriteClipping_from9(x - ((scaleXClip / 2) | 0), (y - scaleY + ((scaleY / 2) | 0)) - ((scaleYClip / 2) | 0), scaleXClip, scaleYClip, GameData.itemPicture[id] + this.spriteItem, GameData.itemMask[id], 0, 0, false); } for (let i = 0; i < this.healthBarCount; i++) { const x = this.healthBarX[i]; const y = this.healthBarY[i]; const missing = this.healthBarMissing[i]; this.surface.drawBoxAlpha(x - 15, y - 3, missing, 5, 65280, 192); this.surface.drawBoxAlpha((x - 15) + missing, y - 3, 30 - missing, 5, 0xff0000, 192); } } _walkToActionSource_from5(sx, sy, dx, dy, action) { this._walkToActionSource_from8(sx, sy, dx, dy, dx, dy, false, action); } disposeAndCollect() { if (this.surface) { this.surface.clear(); this.surface.pixels = null; this.surface = null; } if (this.scene) { this.scene.dispose(); this.scene = null; } this.gameModels = null; this.objectModel = null; this.wallObjectModel = null; this.playerServer = null; this.players = null; this.npcsServer = null; this.npcs = null; this.localPlayer = null; if (this.world) { this.world.terrainModels = null; this.world.wallModels = null; this.world.roofModels = null; this.world.parentModel = null; this.world = null; } } drawUI() { if (this.logoutTimeout !== 0) { this.drawDialogLogout(); } else if (this.showDialogWelcome) { this.drawDialogWelcome(); } else if (this.showDialogServerMessage) { this.drawDialogServerMessage(); } else if (this.showUiWildWarn === 1) { this.drawDialogWildWarn(); } else if (this.showDialogBank && this.combatTimeout === 0) { this.drawDialogBank(); } else if (this.showDialogShop && this.combatTimeout === 0) { this.drawDialogShop(); } else if (this.showDialogTradeConfirm) { this.drawDialogTradeConfirm(); } else if (this.showDialogTrade) { this.drawDialogTrade(); } else if (this.showDialogDuelConfirm) { this.drawDialogDuelConfirm(); } else if (this.showDialogDuel) { this.drawDialogDuel(); } else if (this.showDialogReportAbuseStep === 1) { this.drawDialogReportAbuse(); } else if (this.showDialogReportAbuseStep === 2) { this.drawDialogReportAbuseInput(); } else if (this.showChangePasswordStep !== 0) { this.drawDialogChangePassword(); } else if (this.showDialogSocialInput !== 0) { this.drawDialogSocialInput(); } else { if (this.showOptionMenu) { this.drawOptionMenu(); if (this.options.mobile) { this.showUITab = 0; } } if (this.localPlayer.animationCurrent === 8 || this.localPlayer.animationCurrent === 9) { this.drawDialogCombatStyle(); } if (this.options.mobile) { if (!this.showOptionMenu) { this.setActiveMobileUITab(); } } else { this.setActiveUITab(); } const noMenus = !this.showOptionMenu && !this.showRightClickMenu; if (noMenus) { this.menuItemsCount = 0; } if (this.showUITab === 0 && noMenus) { this.createRightClickMenu(); } if (this.showUITab === 1) { this.drawUiTabInventory(noMenus); } else if (this.showUITab === 2) { this.drawUiTabMinimap(noMenus); } else if (this.showUITab === 3) { this.drawUiTabPlayerInfo(noMenus); } else if (this.showUITab === 4) { this.drawUiTabMagic(noMenus); } else if (this.showUITab === 5) { this.drawUiTabSocial(noMenus); } else if (this.showUITab === 6) { this.drawUiTabOptions(noMenus); } if (!this.showOptionMenu) { if (!this.showRightClickMenu) { this.createTopMouseMenu(); } else { this.drawRightClickMenu(); } } // draw menu action box on mobile if (this.menuActionTimeout) { const offsetX = this.menuX <= this.gameWidth / 2 ? 8 : -this.menuTextWidth - 8; this.surface.drawBoxAlpha( offsetX + this.menuX - 4, this.menuY - 4, this.menuTextWidth + 4, 18, 0xbebebe, 192 ); this.surface.drawString( this.menuText, offsetX + this.menuX - 2, this.menuY + 10, 1, 0xffffff ); this.menuActionTimeout -= 1; } } this.mouseButtonClick = 0; } resetGame() { this.systemUpdate = 0; this.combatStyle = 0; this.logoutTimeout = 0; this.loginScreen = 0; this.loggedIn = 1; this.resetPMText(); this.surface.blackScreen(); this.surface.draw(this.graphics, 0, 0); for (let i = 0; i < this.objectCount; i++) { this.scene.removeModel(this.objectModel[i]); this.world.removeObject(this.objectX[i], this.objectY[i], this.objectId[i]); } for (let i = 0; i < this.wallObjectCount; i++) { this.scene.removeModel(this.wallObjectModel[i]); this.world.removeWallObject(this.wallObjectX[i], this.wallObjectY[i], this.wallObjectDirection[i], this.wallObjectId[i]); } this.objectCount = 0; this.wallObjectCount = 0; this.groundItemCount = 0; this.playerCount = 0; for (let i = 0; i < PLAYERS_SERVER_MAX; i++) { this.playerServer[i] = null; } for (let i = 0; i < PLAYERS_MAX; i++) { this.players[i] = null; } this.npcCount = 0; for (let i = 0; i < NPCS_SERVER_MAX; i++) { this.npcsServer[i] = null; } for (let i = 0; i < NPCS_MAX; i++) { this.npcs[i] = null; } for (let i = 0; i < this.prayerOn.length; i++) { this.prayerOn[i] = false; } this.mouseButtonClick = 0; this.lastMouseButtonDown = 0; this.mouseButtonDown = 0; this.showDialogShop = false; this.showDialogBank = false; this.isSleeping = false; this.friendListCount = 0; } handleKeyPress(keyCode) { if (this.loggedIn === 0) { if (this.loginScreen === 0 && this.panelLoginWelcome) { this.panelLoginWelcome.keyPress(keyCode); } if (this.loginScreen === 1 && this.panelLoginNewUser) { this.panelLoginNewUser.keyPress(keyCode); } if (this.loginScreen === 2 && this.panelLoginExistingUser) { this.panelLoginExistingUser.keyPress(keyCode); } if (this.loginScreen === 3 && this.panelRecoverUser) { this.panelRecoverUser.keyPress(keyCode); } } if (this.loggedIn === 1) { if (this.showAppearanceChange && this.panelAppearance) { this.panelAppearance.keyPress(keyCode); return; } if ( this.showChangePasswordStep === 0 && this.showDialogSocialInput === 0 && this.showDialogReportAbuseStep === 0 && !this.isSleeping && this.panelMessageTabs ) { this.panelMessageTabs.keyPress(keyCode); } if ( this.showChangePasswordStep === 3 || this.showChangePasswordStep === 4 ) { this.showChangePasswordStep = 0; } } } sendLogout() { if (this.loggedIn === 0) { return; } if (this.combatTimeout > 450) { this.showMessage( "@cya@You can't logout during combat!", 3 ); return; } if (this.combatTimeout > 0) { this.showMessage( "@cya@You can't logout for 10 seconds after combat", 3 ); return; } else { this.packetStream.newPacket(clientOpcodes.LOGOUT); this.packetStream.sendPacket(); this.logoutTimeout = 1000; return; } } createPlayer(serverIndex, x, y, anim) { if (this.playerServer[serverIndex] === null) { this.playerServer[serverIndex] = new GameCharacter(); this.playerServer[serverIndex].serverIndex = serverIndex; this.playerServer[serverIndex].serverId = 0; } const player = this.playerServer[serverIndex]; let flag = false; for (let i = 0; i < this.knownPlayerCount; i++) { if (this.knownPlayers[i].serverIndex !== serverIndex) { continue; } flag = true; break; } if (flag) { player.animationNext = anim; let j1 = player.waypointCurrent; if (x !== player.waypointsX[j1] || y !== player.waypointsY[j1]) { player.waypointCurrent = j1 = (j1 + 1) % 10; player.waypointsX[j1] = x; player.waypointsY[j1] = y; } } else { player.serverIndex = serverIndex; player.movingStep = 0; player.waypointCurrent = 0; player.waypointsX[0] = player.currentX = x; player.waypointsY[0] = player.currentY = y; player.animationNext = player.animationCurrent = anim; player.stepCount = 0; } this.players[this.playerCount++] = player; return player; } drawItem(x, y, w, h, id) { const picture = GameData.itemPicture[id] + this.spriteItem; const mask = GameData.itemMask[id]; this.surface._spriteClipping_from9(x, y, w, h, picture, mask, 0, 0, false); } async handleGameInput() { if (this.systemUpdate > 1) { this.systemUpdate--; } await this.checkConnection(); if (this.logoutTimeout > 0) { this.logoutTimeout--; } if (this.mouseActionTimeout > 4500 && this.combatTimeout === 0 && this.logoutTimeout === 0) { this.mouseActionTimeout -= 500; this.sendLogout(); return; } if (this.localPlayer.animationCurrent === 8 || this.localPlayer.animationCurrent === 9) { this.combatTimeout = 500; } if (this.combatTimeout > 0) { this.combatTimeout--; } if (this.showAppearanceChange) { this.handleAppearancePanelInput(); return; } for (let i = 0; i < this.playerCount; i++) { const player = this.players[i]; // TODO figure out why this is happening if (!player) { console.log('null character at ', i, this.playerCount); return; } let k = (player.waypointCurrent + 1) % 10; if (player.movingStep !== k) { let i1 = -1; let l2 = player.movingStep; let j4; if (l2 < k) { j4 = k - l2; } else { j4 = (10 + k) - l2; } let j5 = 4; if (j4 > 2) { j5 = (j4 - 1) * 4; } if (player.waypointsX[l2] - player.currentX > this.magicLoc * 3 || player.waypointsY[l2] - player.currentY > this.magicLoc * 3 || player.waypointsX[l2] - player.currentX < -this.magicLoc * 3 || player.waypointsY[l2] - player.currentY < -this.magicLoc * 3 || j4 > 8) { player.currentX = player.waypointsX[l2]; player.currentY = player.waypointsY[l2]; } else { if (player.currentX < player.waypointsX[l2]) { player.currentX += j5; player.stepCount++; i1 = 2; } else if (player.currentX > player.waypointsX[l2]) { player.currentX -= j5; player.stepCount++; i1 = 6; } if (player.currentX - player.waypointsX[l2] < j5 && player.currentX - player.waypointsX[l2] > -j5) { player.currentX = player.waypointsX[l2]; } if (player.currentY < player.waypointsY[l2]) { player.currentY += j5; player.stepCount++; if (i1 === -1) { i1 = 4; } else if (i1 === 2) { i1 = 3; } else { i1 = 5; } } else if (player.currentY > player.waypointsY[l2]) { player.currentY -= j5; player.stepCount++; if (i1 === -1) { i1 = 0; } else if (i1 === 2) { i1 = 1; } else { i1 = 7; } } if (player.currentY - player.waypointsY[l2] < j5 && player.currentY - player.waypointsY[l2] > -j5) { player.currentY = player.waypointsY[l2]; } } if (i1 !== -1) { player.animationCurrent = i1; } if (player.currentX === player.waypointsX[l2] && player.currentY === player.waypointsY[l2]) { player.movingStep = (l2 + 1) % 10; } } else { player.animationCurrent = player.animationNext; } if (player.messageTimeout > 0) { player.messageTimeout--; } if (player.bubbleTimeout > 0) { player.bubbleTimeout--; } if (player.combatTimer > 0) { player.combatTimer--; } if (this.deathScreenTimeout > 0) { this.deathScreenTimeout--; if (this.deathScreenTimeout === 0) { this.showMessage('You have been granted another life. Be more careful this time!', 3); this.showMessage('You retain your skills. Your objects land where you died', 3); } } } for (let i = 0; i < this.npcCount; i++) { const npc = this.npcs[i]; let j1 = (npc.waypointCurrent + 1) % 10; if (npc.movingStep !== j1) { let i3 = -1; let k4 = npc.movingStep; let k5; if (k4 < j1) { k5 = j1 - k4; } else { k5 = (10 + j1) - k4; } let l5 = 4; if (k5 > 2) { l5 = (k5 - 1) * 4; } if (npc.waypointsX[k4] - npc.currentX > this.magicLoc * 3 || npc.waypointsY[k4] - npc.currentY > this.magicLoc * 3 || npc.waypointsX[k4] - npc.currentX < -this.magicLoc * 3 || npc.waypointsY[k4] - npc.currentY < -this.magicLoc * 3 || k5 > 8) { npc.currentX = npc.waypointsX[k4]; npc.currentY = npc.waypointsY[k4]; } else { if (npc.currentX < npc.waypointsX[k4]) { npc.currentX += l5; npc.stepCount++; i3 = 2; } else if (npc.currentX > npc.waypointsX[k4]) { npc.currentX -= l5; npc.stepCount++; i3 = 6; } if (npc.currentX - npc.waypointsX[k4] < l5 && npc.currentX - npc.waypointsX[k4] > -l5) { npc.currentX = npc.waypointsX[k4]; } if (npc.currentY < npc.waypointsY[k4]) { npc.currentY += l5; npc.stepCount++; if (i3 === -1) { i3 = 4; } else if (i3 === 2) { i3 = 3; } else { i3 = 5; } } else if (npc.currentY > npc.waypointsY[k4]) { npc.currentY -= l5; npc.stepCount++; if (i3 === -1) { i3 = 0; } else if (i3 === 2) { i3 = 1; } else { i3 = 7; } } if (npc.currentY - npc.waypointsY[k4] < l5 && npc.currentY - npc.waypointsY[k4] > -l5) { npc.currentY = npc.waypointsY[k4]; } } if (i3 !== -1) { npc.animationCurrent = i3; } if (npc.currentX === npc.waypointsX[k4] && npc.currentY === npc.waypointsY[k4]) { npc.movingStep = (k4 + 1) % 10; } } else { npc.animationCurrent = npc.animationNext; if (npc.npcId === 43) { npc.stepCount++; } } if (npc.messageTimeout > 0) { npc.messageTimeout--; } if (npc.bubbleTimeout > 0) { npc.bubbleTimeout--; } if (npc.combatTimer > 0) { npc.combatTimer--; } } if (this.showUITab !== 2) { if (Surface.anInt346 > 0) { this.sleepWordDelayTimer++; } if (Surface.anInt347 > 0) { this.sleepWordDelayTimer = 0; } Surface.anInt346 = 0; Surface.anInt347 = 0; } for (let i = 0; i < this.playerCount; i++) { const player = this.players[i]; if (player.projectileRange > 0) { player.projectileRange--; } } if (this.cameraAutoAngleDebug) { if (this.cameraAutoRotatePlayerX - this.localPlayer.currentX < -500 || this.cameraAutoRotatePlayerX - this.localPlayer.currentX > 500 || this.cameraAutoRotatePlayerY - this.localPlayer.currentY < -500 || this.cameraAutoRotatePlayerY - this.localPlayer.currentY > 500) { this.cameraAutoRotatePlayerX = this.localPlayer.currentX; this.cameraAutoRotatePlayerY = this.localPlayer.currentY; } } else { if (this.cameraAutoRotatePlayerX - this.localPlayer.currentX < -500 || this.cameraAutoRotatePlayerX - this.localPlayer.currentX > 500 || this.cameraAutoRotatePlayerY - this.localPlayer.currentY < -500 || this.cameraAutoRotatePlayerY - this.localPlayer.currentY > 500) { this.cameraAutoRotatePlayerX = this.localPlayer.currentX; this.cameraAutoRotatePlayerY = this.localPlayer.currentY; } if (this.cameraAutoRotatePlayerX !== this.localPlayer.currentX) { this.cameraAutoRotatePlayerX += ((this.localPlayer.currentX - this.cameraAutoRotatePlayerX) / (16 + (((this.cameraZoom - 500) / 15) | 0))) | 0; } if (this.cameraAutoRotatePlayerY !== this.localPlayer.currentY) { this.cameraAutoRotatePlayerY += ((this.localPlayer.currentY - this.cameraAutoRotatePlayerY) / (16 + (((this.cameraZoom - 500) / 15) | 0))) | 0; } if (this.optionCameraModeAuto) { let k1 = this.cameraAngle * 32; let j3 = k1 - this.cameraRotation; let byte0 = 1; if (j3 !== 0) { this.anInt707++; if (j3 > 128) { byte0 = -1; j3 = 256 - j3; } else if (j3 > 0) byte0 = 1; else if (j3 < -128) { byte0 = 1; j3 = 256 + j3; } else if (j3 < 0) { byte0 = -1; j3 = -j3; } this.cameraRotation += (((this.anInt707 * j3 + 255) / 256) | 0) * byte0; this.cameraRotation &= 0xff; } else { this.anInt707 = 0; } } } if (this.sleepWordDelayTimer > 20) { this.sleepWordDelay = false; this.sleepWordDelayTimer = 0; } if (this.isSleeping) { this.handleSleepInput(); return; } await this.handleMesssageTabsInput(); if (this.deathScreenTimeout !== 0) { this.lastMouseButtonDown = 0; } if (this.showDialogTrade || this.showDialogDuel) { if (this.mouseButtonDown !== 0) { this.mouseButtonDownTime++; } else { this.mouseButtonDownTime = 0; } if (this.mouseButtonDownTime > 600) { this.mouseButtonItemCountIncrement += 5000; } else if (this.mouseButtonDownTime > 450) { this.mouseButtonItemCountIncrement += 500; } else if (this.mouseButtonDownTime > 300) { this.mouseButtonItemCountIncrement += 50; } else if (this.mouseButtonDownTime > 150) { this.mouseButtonItemCountIncrement += 5; } else if (this.mouseButtonDownTime > 50) { this.mouseButtonItemCountIncrement++; } else if (this.mouseButtonDownTime > 20 && (this.mouseButtonDownTime & 5) === 0) { this.mouseButtonItemCountIncrement++; } } else { this.mouseButtonDownTime = 0; this.mouseButtonItemCountIncrement = 0; } if (this.lastMouseButtonDown === 1) { this.mouseButtonClick = 1; } else if (this.lastMouseButtonDown === 2) { this.mouseButtonClick = 2; } this.scene.setMouseLoc(this.mouseX, this.mouseY); this.lastMouseButtonDown = 0; if (this.optionCameraModeAuto) { if (this.anInt707 === 0 || this.cameraAutoAngleDebug) { if (this.keyLeft) { this.cameraAngle = this.cameraAngle + 1 & 7; this.keyLeft = false; if (!this.fogOfWar) { if ((this.cameraAngle & 1) === 0) { this.cameraAngle = this.cameraAngle + 1 & 7; } for (let i2 = 0; i2 < 8; i2++) { if (this.isValidCameraAngle(this.cameraAngle)) { break; } this.cameraAngle = this.cameraAngle + 1 & 7; } } } if (this.keyRight) { this.cameraAngle = this.cameraAngle + 7 & 7; this.keyRight = false; if (!this.fogOfWar) { if ((this.cameraAngle & 1) === 0) { this.cameraAngle = this.cameraAngle + 7 & 7; } for (let j2 = 0; j2 < 8; j2++) { if (this.isValidCameraAngle(this.cameraAngle)) { break; } this.cameraAngle = this.cameraAngle + 7 & 7; } } } } } else if (this.keyLeft) { this.cameraRotation = this.cameraRotation + 2 & 0xff; } else if (this.keyRight) { this.cameraRotation = this.cameraRotation - 2 & 0xff; } if (!this.optionCameraModeAuto && this.options.middleClickCamera && this.middleButtonDown) { this.cameraRotation = (this.originRotation + ((this.mouseX - this.originMouseX) / 2)) & 0xff; } if (this.options.zoomCamera) { this.handleCameraZoom(); } else { if (this.fogOfWar && this.cameraZoom > ZOOM_INDOORS) { this.cameraZoom -= 4; } else if (!this.fogOfWar && this.cameraZoom < ZOOM_OUTDOORS) { this.cameraZoom += 4; } } if (this.mouseClickXStep > 0) { this.mouseClickXStep--; } else if (this.mouseClickXStep < 0) { this.mouseClickXStep++; } this.scene.doSOemthingWithTheFuckinFountainFuck(17); this.objectAnimationCount++; if (this.objectAnimationCount > 5) { this.objectAnimationCount = 0; this.objectAnimationNumberFireLightningSpell = (this.objectAnimationNumberFireLightningSpell + 1) % 3; this.objectAnimationNumberTorch = (this.objectAnimationNumberTorch + 1) % 4; this.objectAnimationNumberClaw = (this.objectAnimationNumberClaw + 1) % 5; } for (let i = 0; i < this.objectCount; i++) { const x = this.objectX[i]; const y = this.objectY[i]; if (x >= 0 && y >= 0 && x < 96 && y < 96 && this.objectId[i] === 74) { this.objectModel[i].rotate(1, 0, 0); } } for (let i = 0; i < this.teleportBubbleCount; i++) { this.teleportBubbleTime[i]++; if (this.teleportBubbleTime[i] > 50) { this.teleportBubbleCount--; for (let j = i; j < this.teleportBubbleCount; j++) { this.teleportBubbleX[j] = this.teleportBubbleX[j + 1]; this.teleportBubbleY[j] = this.teleportBubbleY[j + 1]; this.teleportBubbleTime[j] = this.teleportBubbleTime[j + 1]; this.teleportBubbleType[j] = this.teleportBubbleType[j + 1]; } } } } handleCameraZoom() { if (this.keyUp && !this.ctrl) { this.cameraZoom -= 16; } else if (this.keyDown &&