const entryListDisplayMax = 6; const titleOffsetY = 22; const perkImageXMaxSize = 167; const perkImageYMaxSize = 153; const colourBlack = 0; const colourGray1 = 1; const colourGray2 = 2; const colourWhite = 3; const maxScreen = 2; const perkScreen = 2; const statScreen = 1; const SPECIALScreen = 0; Graphics.prototype.setFontMonofonto14 = function () { // Actual height 14 (13 - 0) // 1 BPP return this.setFontCustom( E.toString( require('heatshrink').decompress( atob( 'AB0D/uP/0/7AICh+AnwNC8AGBAoMBwFnw4UB/H/8f/h4ZDgHxw/nn/e+/55/DEIV88P/w/4g/4v/j7+MvwNBu4iBx/2FIPz8EfwEyKAwjB/BZGgH/5///kPLQcD///n/whgIBAQMzgARB+E/wE/gHMMwUAgkAiEBJgPgAwQyFgPgg+AjAIDsCCBg0ABINgCwoKBnAKDgahBFYN+h/gnkA4BTCUAkBXgX4n4OCgEcgCSBRYP+HQUjweOn0zDYNj+ODG4INB4YNBt0zzDKCwZYCIIN+XQLYEMwkD/cP90/zHO8c/ZQZxBj+DJgOY/1jz+IBoXAkcHxhhDgfgWwUAmODLQU7zHusZhEnED/GP805/Hn8f+g/wWwuYg9wjOABQkZ8F3wOYWIakB+EHsAUB4cDH4UJgEkgGQgVAAwgNBmHAWwIwB8EPEQTUCsEDwOO9033H8kfggY+Cj5xB+f95v7m3s/+x/zVBgPgN4U/+H/AwOAjyuDBof4UAKEEv/DAwUwjHg8eDwUIBoLRCBoM4nDmD/ANGmOY41jSggNFwHGgbyCh5KBBoOOg0z/Hv8e/DYLfCBoOAsAGFFIXALQYNBAwMBBoQtBsEBxkODYZtCIowNB/fjgZTIEQhFGOwJFIDYfwh4NFN4yZEG5E54H/gKlCDYsHnE+//7cIIbHnY3C+YpDvHD+eP80z7Hn8efBoMwTIL7FAwIZCn43DwEGPoJTEng3BwYGBDYQGB4AbBnxFDwf+Po0ghHxAwOH/iZDwZFD/BFBDYINB/jCDmEY4fjn5TCzH4dogADh//AAJXCiEAnApBgH8AIV+QoLhBIoIfBg4ZCLoQMBh+AN4PwgPgGIkEFIVAgIGFBoMCgEMG4QtBDIcwhvgm6SBgfYcIM/ehEDjANF8EH4AGB8wNBh3gmINBgPwCgfGUAauCDYvWgdYCgM9BoLqBhj0F5j0DDYMPY4Ow43D/4GC8BTIWQJhFhljn+O/0zWgJ+BAAMDgcMh8//3/+f/aIY+C/4iC90CjAlDgBoGgf4G4Y+BAwgmDBohMGoCgF3ANBj53DN4Xw//DXgquGSwIUDG43AG4MOeAIpDh1AWoJTCfYMXSQiiBwf+h/4hlgcwUDXgIpCg0AIosDwEPMIU+PoXAnCuCKYUfRYs8BoMChEMEQV+BocgFInENAMfegQpDKYVgm4pEKYYADhB4Bn////+PwqOC/+/BYIVDCYP//h/BkAKBOQUAsEBPIYGBBoI', ), ), ), 32, atob( 'BwYHCAgICAYHBggIBgcGCAgGCAgICAgICAgGBggICAgICAgICAcICAgICAgICAgICAgICAgICAgICAgICAUICAcICAgICAgICAcHCAYICAgICAgICAgICAgICAgGBwg=', ), 14 | 65536, ); }; function draw() { if (drawing) return; drawing = true; bC.clear(); if (screenSelected == perkScreen) { buildScreen('USER/StatsDisplay/PERKS/ENABLED'); } else if (screenSelected == statScreen) { buildScreen('USER/StatsDisplay/SKILLS'); } else if (screenSelected == SPECIALScreen) { buildScreen('USER/StatsDisplay/SPECIAL'); } bH.flip(); bF.flip(); bC.flip(); drawing = false; } function buildScreen(directory) { let files = require('fs').readdirSync(directory); loadedListMax = files.length; let entryListMax = Math.min(entryListDisplayMax, loadedListMax); let a = 0; while (entrySelected >= entryListMax) { a++; //We're beyond the number of entries we can see on one page. //We need to get the next set of files and display them entryListMax = Math.min(entryListDisplayMax * (a + 1), loadedListMax); } for (i = a * entryListDisplayMax; i < entryListMax; i++) { let file = files[i]; let fileString = require('fs').readFileSync(directory + '/' + file); let fileObj = JSON.parse(fileString); if (i == entrySelected) { drawEntry(fileObj); drawSelectedEntryOutline(i % entryListDisplayMax); } drawEntryTitle(fileObj.title, i % entryListDisplayMax, i == entrySelected); if (screenSelected != perkScreen) { drawEntryPoints( fileObj.points, i % entryListDisplayMax, i == entrySelected, ); } } } function drawEntry(perkObj) { drawEntryImage(perkObj.img, perkObj.xSize, perkObj.ySize); drawEntryDesc(perkObj.description); } function drawEntryImage(imgStr, xSize, ySize) { //so we want to try and draw as central as possible. //our 'window' for how big the perk can be is 167x153 (y truncated for the desc at the bottom) //to figure out how to centre the image we need to get the difference //between the size of the image and our window, halve it, and add it on //to the location. let xOffset = Math.floor((perkImageXMaxSize - xSize) / 2); let yOffset = Math.floor((perkImageYMaxSize - ySize) / 2); bC.setColor(colourGray2); bC.drawImage( { width: xSize, height: ySize, bpp: 1, buffer: require('heatshrink').decompress(atob(imgStr)), }, 200 + xOffset, 0 + yOffset, ); } function drawEntryTitle(title, i, selected) { bC.setFontMonofonto18(); if (selected) { bC.setColor(colourBlack); } else { bC.setColor(colourWhite); } bC.drawString(title, 10, titleOffsetY * i + 5); } function drawEntryPoints(points, i, selected) { bC.setFontMonofonto18(); if (selected) { bC.setColor(colourBlack); } else { bC.setColor(colourWhite); } bC.drawString(points, 160, titleOffsetY * i + 5); } function drawEntryDesc(desc) { bC.setFontMonofonto14(); bC.setColor(colourWhite); bC.drawString(desc, 10, 150); } function drawSelectedEntryOutline(i) { bC.setColor(colourWhite); bC.fillRect(5, titleOffsetY * i + 1, 190, titleOffsetY * i + 23); } function handleKnob1(dir) { //first, play the click. Pip.knob1Click(dir); //then, we need to change our position in the list. entrySelected -= dir; //-1 is scroll down, but our list increases numerically. so we need to subtract if (entrySelected < 0) { entrySelected = loadedListMax - 1; } else if (entrySelected >= loadedListMax) { entrySelected = 0; } draw(); } function handleKnob2(dir) { //first, play the click. Pip.knob2Click(dir); log('knob2 direction: ' + dir); //then switch stats screen. screenSelected += dir; entrySelected = 0; //reset to top of list if (screenSelected > maxScreen) { screenSelected = 0; } else if (screenSelected < 0) { screenSelected = maxScreen; } draw(); } function handleTorch() { gracefulClose(); torchButtonHandler(); } function gracefulClose() { //shut down interval triggers first in case one fires while we're tearing down clearInterval(intervalId); clearInterval(modeCheck); Pip.removeListener('knob1', handleKnob1); Pip.removeListener('knob2', handleKnob2); Pip.removeListener('torch', handleTorch); showMainMenu(); //this causes a brief flicker but if we don't do it the controls stop working. } function ourModeHandler() { checkMode(); if (Pip.mode != 2) { gracefulClose(); } } let loadedListMax = 0; let entrySelected = 0; let screenSelected = 0; let drawing = false; Pip.on('knob1', handleKnob1); Pip.on('knob2', handleKnob2); Pip.on('torch', handleTorch); draw(); let modeCheck = setInterval(ourModeHandler, 100); let intervalId = setInterval(() => { if (Pip.mode == 2) { draw(); } else { gracefulClose(); } }, 1000);