UNPKG

@bitsy/hecks

Version:

a collection of re-usable scripts for bitsy game maker

188 lines (167 loc) 5.75 kB
/** ➿ @file corrupt @summary corrupts gamedata at runtime @license MIT @version 3.0.4 @requires 5.5 @author Sean S. LeBlanc @description Corrupts gamedata at runtime Corruptions include: position of tiles in current room pixels of tiles in current room pixels of sprites in current room pixels of items in current room colours of palette in current room pixels of fontdata In the provided code, corruptions occur each time the player moves, but this can be changed by calling `corrupt()` in different scenarios. e.g. `setInterval(corrupt, 1000)` would corrupt once per second. When the game is reset, the corruptions will be reset as well. HOW TO USE: 1. Copy-paste into a script tag after the bitsy source 2. Edit `hackOptions` below as needed Options ending in `Freq` are a combination of iterations and probabilities: Given the value X.Y, it will corrupt X times, and may corrupt once more with a probability of Y e.g. 0.0 = won't ever corrupt 0.1 = will corrupt with a probability of one in ten 1.0 = will corrupt once 2.0 = will corrupt twice 3.5 = will corrupt thrice, and corrupt a fourth time with a probability of one in two */ import bitsy from "bitsy"; import { getSpriteData, getTileData, getItemData, setSpriteData, setTileData, setItemData } from "./helpers/edit image at runtime"; import { after } from "./helpers/kitsy-script-toolkit"; /////////// // setup // /////////// export var hackOptions = { tilemapFreq: 1, tilePixelsFreq: 1, spritePixelsFreq: 1, itemPixelsFreq: 1, fontPixelsFreq: 1, paletteFreq: 1, globalFreq: 1, // multiplier for all the other `Freq` options paletteAmplitude: 10, // how much to corrupt palette by (0-128) }; // hook corruption to player movement after('onPlayerMoved', corrupt); ////////////////// // corrupt code // ////////////////// // get a reference to the fontdata var fontdata; after('dialogRenderer.SetFont', function(font) { fontdata = Object.values(font.getData()).map(function(char){ return char.data; }); }); function corrupt() { var i; var currentRoom = bitsy.room[bitsy.curRoom]; // corrupt pixels of visible tiles var visibleTiles = {}; for (var y = 0; y < bitsy.mapsize; ++y) { for (var x = 0; x < bitsy.mapsize; ++x) { visibleTiles[currentRoom.tilemap[y][x]] = true; } } delete visibleTiles["0"]; // empty tile doesn't actually exist visibleTiles = Object.keys(visibleTiles); if (visibleTiles.length > 0) { iterate(hackOptions.tilePixelsFreq * hackOptions.globalFreq, function () { var t = rndItem(visibleTiles); var frame = Math.floor(Math.random() * bitsy.tile[t].animation.frameCount); var tdata = getTileData(t, frame); var y = Math.floor(Math.random() * bitsy.tilesize); var x = Math.floor(Math.random() * bitsy.tilesize); tdata[y][x] = Math.abs(tdata[y][x] - 1); setTileData(t, frame, tdata); }); } // corrupt pixels of visible sprites var visibleSprites = {}; for (i in bitsy.sprite) { if (Object.prototype.hasOwnProperty.call(bitsy.sprite, i)) { if (bitsy.sprite[i].room === bitsy.curRoom) { visibleSprites[i] = true; } } } visibleSprites = Object.keys(visibleSprites); iterate(hackOptions.spritePixelsFreq * hackOptions.globalFreq, function () { var t = rndItem(visibleSprites); var frame = Math.floor(Math.random() * bitsy.sprite[t].animation.frameCount); var tdata = getSpriteData(t, frame); var y = Math.floor(Math.random() * bitsy.tilesize); var x = Math.floor(Math.random() * bitsy.tilesize); tdata[y][x] = Math.abs(tdata[y][x] - 1); setSpriteData(t, frame, tdata); }); // corrupt pixels of visible items var visibleItems = {}; for (i = 0; i < currentRoom.items.length; ++i) { visibleItems[currentRoom.items[i].id] = true; } visibleItems = Object.keys(visibleItems); if (visibleItems.length > 0) { iterate(hackOptions.itemPixelsFreq * hackOptions.globalFreq, function () { var t = rndItem(visibleItems); var frame = Math.floor(Math.random() * bitsy.item[t].animation.frameCount); var tdata = getItemData(t, frame); var y = Math.floor(Math.random() * bitsy.tilesize); var x = Math.floor(Math.random() * bitsy.tilesize); tdata[y][x] = Math.abs(tdata[y][x] - 1); setItemData(t, frame, tdata); }); } // corrupt current room's tilemap var possibleTiles = Object.keys(bitsy.tile); possibleTiles.push("0"); // empty tile iterate(hackOptions.tilemapFreq * hackOptions.globalFreq, function () { // pick a tile at random in the current room and assign it a random tile y = Math.floor(Math.random() * bitsy.mapsize); x = Math.floor(Math.random() * bitsy.mapsize); currentRoom.tilemap[y][x] = rndItem(possibleTiles); }); // corrupt visible palette colours var visibleColors = bitsy.getPal(bitsy.curPal()); iterate(hackOptions.paletteFreq * hackOptions.globalFreq, function () { var c = rndItem(visibleColors); var i = rndIndex(c); c[i] = Math.round((c[i] + (Math.random() * 2 - 1) * hackOptions.paletteAmplitude) % 256); }); if (hackOptions.paletteImmediate) { bitsy.renderImages(); } // corrupt pixels of font data iterate(hackOptions.fontPixelsFreq * hackOptions.globalFreq, function () { var char = rndItem(fontdata); var i = rndIndex(char); char[i] = Math.abs(char[i] - 1); }); } ///////////// // helpers // ///////////// // helper for iteratively calling a function function iterate(i, fn) { while (Math.random() < i--) { fn(); } } // RNG array helpers function rndIndex(array) { return Math.floor(Math.random() * array.length); } function rndItem(array) { return array[rndIndex(array)]; }