1/* The Torchbearer â game config and run state. 2 * 3 * Run state is a single object rebuilt wholesale by SK.resetRun(), which is 4 * what guarantees a restart is truly clean: shards, HP, floor, score and 5 * stats all come back from one place. 6 */ 7window.SK = window.SK || {}; 8 9// Defaults in case a scene reads settings before MenuScene has loaded. 10SK.settings = SK.settings || { muted:false, music:true, shake:true, 11 shader:true, damageNumbers:true, minimap:true }; 12 13SK.BUILD = '27Jul-TB8'; 14SK.HIGH_KEY = 'shadowKingCrownfall.highScore'; 15SK.DAILY_KEY = 'shadowKingCrownfall.daily.'; 16 17/* Playtest shortcut, off unless ?dev=1 is in the URL. */ 18SK.DEV = /[?&]dev=1/.test(window.location.search); 19 20SK.newRun = function (mode, classId) { 21 mode = mode || 'free'; 22 var seedKey = SK.installRng(mode); 23 var cls = SK.CLASSES[classId || SK.chosenClass || SK.DEFAULT_CLASS]; 24 var mods = SK.computeMods([], [], cls.id); 25 var maxHp = Math.max(1, cls.hp + mods.maxHpBonus - mods.startHpPenalty); 26 return { 27 mode: mode, 28 seedKey: seedKey, 29 floor: 0, 30 loop: 0, 31 score: 0, 32 hp: maxHp, 33 maxHp: maxHp, 34 shardIds: [], 35 pool: SK.SHARDS.map(function (s) { return s.id; }), 36 mods: mods, 37 classId: cls.id, 38 weaponId: cls.weapon, 39 weaponLevels: (function () { var o = {}; o[cls.weapon] = 1; return o; })(), 40 // id -> index into SK.RARITIES. You start with plain gear. 41 weaponRarities: (function () { var o = {}; o[cls.weapon] = 0; return o; })(), 42 weaponSuffixes: {}, // weapon id -> suffix id 43 power: 0, // rises as you clear; see SK.powerMods 44 armourId: 'none', armourRarity: 0, 45 trinketId: 'none', trinketRarity: 0, 46 inventory: [], // consumable ids, up to SK.INVENTORY_SLOTS 47 artifactIds: [], // permanent Sovereign drops 48 quirkIds: [], // what the crypt did to you 49 coins: 0, 50 buffs: {}, // active timed effects, keyed by kind 51 bought: [], // one-time shop purchases already made 52 shopFuryStart: 0, // Wrath Sigil 53 shopCoinMult: 1, // Greedy Palm 54 stats: { 55 kills: 0, elites: 0, bosses: 0, bestChain: 0, parries: 0, ultimates: 0, 56 roomsCleared: 0, damageTaken: 0, startedAt: Date.now() 57 } 58 }; 59}; 60 61SK.resetRun = function (mode, classId) { 62 SK.run = SK.newRun(mode, classId); 63 if (SK.game) SK.game.registry.set('run', SK.run); 64 return SK.run; 65}; 66 67/* Taking a shard recomputes mods from the FULL shard list â never 68 * incremental, so an effect can't be applied twice across scenes. */ 69SK.takeShard = function (run, id) { 70 if (run.shardIds.indexOf(id) !== -1) return run; 71 72 run.shardIds.push(id); 73 var at = run.pool.indexOf(id); 74 if (at !== -1) run.pool.splice(at, 1); 75 76 // Single recompute path (see SK.refreshRun): folds shards, artifacts, quirks 77 // AND worn gear. Iron Heart heals as it is taken; Ember Pact bites, but 78 // never to zero. 79 return SK.refreshRun(run); 80}; 81 82/* ---- localStorage: never allowed to throw (private mode) ---------------- */ 83 84SK.getHigh = function () { 85 try { 86 return parseInt(window.localStorage.getItem(SK.HIGH_KEY), 10) || 0; 87 } catch (e) { return 0; } 88}; 89 90SK.setHigh = function (v) { 91 try {
92 window.localStorage.setItem(SK.HIGH_KEY, String(v)); 93 return true; 94 } catch (e) { return false; } 95}; 96 97SK.getDailyHigh = function (dayKey) { 98 try { 99 return parseInt(window.localStorage.getItem(SK.DAILY_KEY + dayKey), 10) || 0; 100 } catch (e) { return 0; } 101}; 102 103SK.setDailyHigh = function (dayKey, v) { 104 try { 105 window.localStorage.setItem(SK.DAILY_KEY + dayKey, String(v)); 106 return true; 107 } catch (e) { return false; } 108}; 109 110/* ---- Phaser ------------------------------------------------------------ */ 111 112SK.WIDTH = 800; 113SK.HEIGHT = 600; 114 115/* Boot integrity check. 116 * 117 * The scripts are separate files with no bundler, so a browser can serve a 118 * fresh DungeonScene.js next to a cached juice.js. The game then half-works 119 * and throws several seconds into play, which reads as a game bug and is not. 120 * Check the API surface up front and say plainly what is wrong. 121 */ 122SK.REQUIRED_API = [ 123 ['juice.coach', function () { return SK.juice && SK.juice.coach; }], 124 ['juice.telegraph', function () { return SK.juice && SK.juice.telegraph; }], 125 ['ui.panel', function () { return SK.ui && SK.ui.panel; }], 126 ['ui.keycap', function () { return SK.ui && SK.ui.keycap; }], 127 ['Sheet', function () { return SK.Sheet; }], 128 ['refreshRun', function () { return SK.refreshRun; }], 129 ['gearMods', function () { return SK.gearMods; }], 130 ['safeConsumable', function () { return SK.safeConsumable; }], 131 ['weaponFullName', function () { return SK.weaponFullName; }], 132 ['enemyName', function () { return SK.enemyName; }], 133 ['rollRarity', function () { return SK.rollRarity; }] 134]; 135 136SK.checkApi = function () { 137 return SK.REQUIRED_API 138 .filter(function (r) { return !r[1](); }) 139 .map(function (r) { return r[0]; }); 140}; 141 142window.addEventListener('load', function () { 143 if (!window.Phaser) return; // CDN fallback message already shown 144 145 var missing = SK.checkApi(); 146 if (missing.length) { 147 var el = document.createElement('div'); 148 el.style.cssText = 'position:fixed;inset:0;z-index:9999;background:#1a0f0c;' + 149 'color:#ffd45e;font:15px/1.6 system-ui,sans-serif;padding:40px;'; 150 el.innerHTML = '<b style="font-size:20px">Stale files in the browser cache</b>' + 151 '<p>These scripts are out of date: <code>' + missing.join(', ') + '</code></p>' + 152 '<p>Hard-refresh to fix: <b>Cmd+Shift+R</b> (Mac) or <b>Ctrl+F5</b> (Windows).</p>' + 153 '<p style="color:#a8977d">Build ' + SK.BUILD + '. This is a caching problem, ' + 154 'not a fault in the game.</p>'; 155 document.body.appendChild(el); 156 return; 157 } 158 159 160 SK.settings = SK.loadSettings(); 161 SK.run = SK.newRun('free'); 162 163 SK.game = new Phaser.Game({ 164 type: Phaser.AUTO, 165 width: SK.WIDTH, 166 height: SK.HEIGHT, 167 backgroundColor: SK.CSS.void, 168 parent: 'game', 169 physics: { 170 default: 'arcade', 171 arcade: { debug: false } 172 }, 173 scale: { 174 mode: Phaser.Scale.FIT, 175 autoCenter: Phaser.Scale.CENTER_BOTH 176 }, 177 // Crisp pixel art: nearest-neighbour scaling, no smoothing. 178 pixelArt: true, 179 render: { 180 pixelArt: true, 181 antialias: false, 182 antialiasGL: false, 183 roundPixels: true 184 }, 185 scene: [ 186 SK.BootScene, 187 SK.TitleScene, 188 SK.LoadScene, 189 SK.DungeonScene, 190 SK.AspirantScene, 191 SK.ClassScene, 192 SK.MenuScene, 193 SK.LeaderScene, 194 SK.NameScene, 195 SK.ShardScene, 196 SK.ShopScene, 197 SK.EndScene 198 ] 199 }); 200 201 SK.game.registry.set('run', SK.run); 202 203 // WebGL-only post-processing; silently absent under Canvas. 204 SK.game.events.once('ready', function () { 205 SK.registerShaders(SK.game); 206 }); 207});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.