From dd10236b2281d4a3c47eca07a5ead693f154768c Mon Sep 17 00:00:00 2001 From: "Eevee (Evelyn Woods)" Date: Mon, 8 Mar 2021 21:04:23 -0700 Subject: [PATCH] Implement "hide logic", and actually save options (fixes #52) --- js/format-base.js | 1 + js/format-c2g.js | 25 ++++++++++++++++++++----- js/main-editor.js | 18 ++++++++++++++---- js/main.js | 2 ++ js/renderer-canvas.js | 3 ++- js/tileset.js | 15 ++++++++++----- 6 files changed, 49 insertions(+), 15 deletions(-) diff --git a/js/format-base.js b/js/format-base.js index e661cef..087b6a3 100644 --- a/js/format-base.js +++ b/js/format-base.js @@ -113,6 +113,7 @@ export class StoredLevel extends LevelInterface { // 1 - 4 patterns (default; PRNG + rotating through 0-3) // 2 - extra random (like deterministic, but initial seed is "actually" random) this.blob_behavior = 1; + this.hide_logic = false; // Lazy-loading that allows for checking existence (see methods below) // TODO this needs a better interface, these get accessed too much atm diff --git a/js/format-c2g.js b/js/format-c2g.js index 29e6a78..50c243d 100644 --- a/js/format-c2g.js +++ b/js/format-c2g.js @@ -1130,11 +1130,11 @@ export function parse_level(buf, number = 1) { if (view.byteLength <= 22) continue; - //options.hide_logic = view.getUint8(22, true); + level.hide_logic = !! view.getUint8(22, true); if (view.byteLength <= 23) continue; - level.use_cc1_boots = view.getUint8(23, true); + level.use_cc1_boots = !! view.getUint8(23, true); if (view.byteLength <= 24) continue; @@ -1482,17 +1482,32 @@ export function synthesize_level(stored_level) { } // Options block - let options = new Uint8Array(3); + let options = new Uint8Array(25); // max possible size + let options_length = 0; new DataView(options.buffer).setUint16(0, stored_level.time_limit, true); if (stored_level.viewport_size === 10) { options[2] = 0; } else if (stored_level.viewport_size === 9) { options[2] = 1; + options_length = 3; + } + if (stored_level.hide_logic) { + options[22] = 1; + options_length = 23; + } + if (stored_level.use_cc1_boots) { + options[23] = 1; + options_length = 24; + } + if (stored_level.blob_behavior !== 0) { + options[24] = stored_level.blob_behavior; + options_length = 25; } // TODO split - // TODO for size purposes, omit the block entirely if all options are defaults? - c2m.add_section('OPTN', options); + if (options_length > 0) { + c2m.add_section('OPTN', options.slice(0, options_length)); + } // Store camera regions // TODO LL feature, should be distinguished somehow diff --git a/js/main-editor.js b/js/main-editor.js index 6b2f0a9..b0ae46f 100644 --- a/js/main-editor.js +++ b/js/main-editor.js @@ -141,17 +141,24 @@ class EditorLevelMetaOverlay extends DialogOverlay { mk('br'), mk('label', mk('input', {name: 'blob_behavior', type: 'radio', value: '1'}), - " 4 patterns (default; PRNG + rotating offset)"), + " 4 patterns (CC2 default; PRNG + rotating offset)"), mk('br'), mk('label', mk('input', {name: 'blob_behavior', type: 'radio', value: '2'}), - " Extra random (initial seed is truly random)"), + " Extra random (LL default; initial seed is truly random)"), ), + mk('dt', "Options"), + mk('dd', mk('label', + mk('input', {name: 'hide_logic', type: 'checkbox'}), + " Hide wires and logic gates (warning: CC2 also hides pink/black buttons!)")), + mk('dd', mk('label', + mk('input', {name: 'use_cc1_boots', type: 'checkbox'}), + " Use CC1-style inventory (can only pick up the four classic boots; can't drop or cycle)")), ); this.root.elements['viewport'].value = stored_level.viewport_size; - // FIXME this isn't actually saved lol but also it's 24 bytes into the damn options. also - // it should default to 2, the good one this.root.elements['blob_behavior'].value = stored_level.blob_behavior; + this.root.elements['hide_logic'].checked = stored_level.hide_logic; + this.root.elements['use_cc1_boots'].checked = stored_level.use_cc1_boots; // TODO: // - chips? // - password??? @@ -183,6 +190,8 @@ class EditorLevelMetaOverlay extends DialogOverlay { } stored_level.blob_behavior = parseInt(els.blob_behavior.value, 10); + stored_level.hide_logic = els.hide_logic.checked; + stored_level.use_cc1_boots = els.use_cc1_boots.checked; stored_level.viewport_size = parseInt(els.viewport.value, 10); this.conductor.player.update_viewport_size(); @@ -3212,6 +3221,7 @@ export class Editor extends PrimaryView { stored_level.size_x = size_x; stored_level.size_y = size_y; stored_level.viewport_size = 10; + stored_level.blob_behavior = 2; // extra random for (let i = 0; i < size_x * size_y; i++) { stored_level.linear_cells.push(this.make_blank_cell(...stored_level.scalar_to_coords(i))); } diff --git a/js/main.js b/js/main.js index b49fc4c..c6b7245 100644 --- a/js/main.js +++ b/js/main.js @@ -1334,6 +1334,8 @@ class Player extends PrimaryView { // (This happens here because we could technically still do 20tps if we wanted, and the // renderer doesn't actually have any way to know that) this.renderer.update_rate = this.level.update_rate; + // Likewise, we don't want this automatically read from the level, but we do respect it here + this.renderer.hide_logic = this.level.stored_level.hide_logic; this.update_ui(); // Force a redraw, which won't happen on its own since the game isn't running diff --git a/js/renderer-canvas.js b/js/renderer-canvas.js index 221ec37..f6969b6 100644 --- a/js/renderer-canvas.js +++ b/js/renderer-canvas.js @@ -5,7 +5,7 @@ import TILE_TYPES from './tiletypes.js'; class CanvasRendererDrawPacket extends DrawPacket { constructor(renderer, ctx, perception, clock, update_progress, update_rate) { - super(perception, clock, update_progress, update_rate); + super(perception, renderer.hide_logic, clock, update_progress, update_rate); this.renderer = renderer; this.ctx = ctx; // Canvas position of the cell being drawn @@ -62,6 +62,7 @@ export class CanvasRenderer { this.show_actor_order = false; this.use_rewind_effect = false; this.perception = 'normal'; // normal, xray, editor, palette + this.hide_logic = false; this.update_rate = 3; this.use_cc2_anim_speed = false; this.active_player = null; diff --git a/js/tileset.js b/js/tileset.js index 1e1972b..f5a08cd 100644 --- a/js/tileset.js +++ b/js/tileset.js @@ -1994,8 +1994,9 @@ export const TILESET_LAYOUTS = { // Bundle of arguments for drawing a tile, containing some standard state about the game export class DrawPacket { - constructor(perception = 'normal', clock = 0, update_progress = 0, update_rate = 3) { + constructor(perception = 'normal', hide_logic = false, clock = 0, update_progress = 0, update_rate = 3) { this.perception = perception; + this.hide_logic = hide_logic && perception === 'normal'; this.use_cc2_anim_speed = false; this.clock = clock; this.update_progress = update_progress; @@ -2177,7 +2178,7 @@ export class Tileset { let wire_radius = this.layout['#wire-width'] / 2; // TODO circuit block with a lightning bolt is always powered // TODO circuit block in motion doesn't inherit cell's power - if (tile && tile.wire_directions) { + if (tile && tile.wire_directions && ! packet.hide_logic) { // Draw the base tile packet.blit(drawspec.base[0], drawspec.base[1]); @@ -2210,9 +2211,8 @@ export class Tileset { } } - // Wired tiles may also have tunnels, drawn on top of everything else - if (tile && tile.wire_tunnel_directions) { + if (tile && tile.wire_tunnel_directions && ! packet.hide_logic) { let tunnel_coords = this.layout['#wire-tunnel']; let tunnel_width = 6/32; let tunnel_length = 12/32; @@ -2602,7 +2602,12 @@ export class Tileset { } } else if (drawspec.__special__ === 'logic-gate') { - this._draw_logic_gate(drawspec, name, tile, packet); + if (packet.hide_logic) { + this.draw_type('floor', tile, packet); + } + else { + this._draw_logic_gate(drawspec, name, tile, packet); + } } else if (drawspec.__special__ === 'railroad') { this._draw_railroad(drawspec, name, tile, packet);