From 16bfe22593fc300ec064c3421e54a75608d256f6 Mon Sep 17 00:00:00 2001 From: "Eevee (Evelyn Woods)" Date: Thu, 10 Sep 2020 17:45:14 -0600 Subject: [PATCH] Implement score flags and the stopwatches --- index.html | 10 +++++++ js/format-c2m.js | 8 ++--- js/game.js | 44 ++++++++++++++++++++++++---- js/main.js | 4 +-- js/tileset.js | 6 ++-- js/tiletypes.js | 76 ++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 133 insertions(+), 15 deletions(-) diff --git a/index.html b/index.html index 579c177..f06ca34 100644 --- a/index.html +++ b/index.html @@ -81,6 +81,16 @@
+
diff --git a/js/format-c2m.js b/js/format-c2m.js index 5311925..da4dd46 100644 --- a/js/format-c2m.js +++ b/js/format-c2m.js @@ -138,8 +138,8 @@ const TILE_ENCODING = { 0x49: ['swivel_nw', 'swivel_floor'], 0x4a: ['swivel_ne', 'swivel_floor'], 0x4b: ['swivel_se', 'swivel_floor'], - // 0x4c: Time bonus : '#next' - // 0x4d: Stopwatch : '#next' + 0x4c: ['stopwatch_bonus', '#next'], + 0x4d: ['stopwatch_toggle', '#next'], // 0x4e: Transmogrifier : // 0x4f: Railroad track (Modifier required, see section below) : // 0x50: Steel wall : @@ -163,7 +163,7 @@ const TILE_ENCODING = { // 0x66: Mirror Melinda : '#direction', '#next' // 0x68: Bowling ball : '#next' // 0x69: Rover : '#direction', '#next' - // 0x6a: Time penalty : '#next' + 0x6a: ['stopwatch_penalty', '#next'], 0x6b: ['#mod8?', ['floor_custom_green', 'floor_custom_pink', 'floor_custom_yellow', 'floor_custom_blue']], 0x6d: ['#thinwall/canopy', '#next'], // 0x6f: Railroad sign : '#next' @@ -240,7 +240,7 @@ export function parse_level(buf) { let level = new util.StoredLevel; let full_view = new DataView(buf); let next_section_start = 0; - let extra_hints; + let extra_hints = []; let hint_tiles = []; while (next_section_start < buf.byteLength) { // Read section header and length diff --git a/js/game.js b/js/game.js index 95be78a..d9b7e34 100644 --- a/js/game.js +++ b/js/game.js @@ -178,13 +178,16 @@ export class Level { this.player = null; this.actors = []; this.chips_remaining = this.stored_level.chips_required; + this.bonus_points = 0; + + // Time if (this.stored_level.time_limit === 0) { this.time_remaining = null; } else { - this.time_remaining = this.stored_level.time_limit; + this.time_remaining = this.stored_level.time_limit * 20; } - this.bonus_points = 0; + this.timer_paused = false; this.tic_counter = 0; // 0 to 7, indicating the first tic that teeth can move on. // 0 is equivalent to even step; 4 is equivalent to odd step. @@ -551,10 +554,9 @@ export class Level { // Advance the clock let tic_counter = this.tic_counter; - let time_remaining = this.time_remaining; - this.tic_counter++; - if (this.time_remaining !== null && this.tic_counter % 20 === 0) { - // 20 tics means one second! Tic that time down + this.tic_counter += 1; + if (this.time_remaining !== null && ! this.timer_paused) { + let time_remaining = this.time_remaining; this.pending_undo.push(() => { this.tic_counter = tic_counter; this.time_remaining = time_remaining; @@ -834,6 +836,36 @@ export class Level { } } + adjust_bonus(add, mult = 1) { + let current = this.bonus_points; + this.pending_undo.push(() => this.bonus_points = current); + this.bonus_points = Math.ceil(this.bonus_points * mult) + add; + } + + pause_timer() { + if (this.time_remaining === null) + return; + + this.pending_undo.push(() => this.timer_paused = ! this.timer_paused); + this.timer_paused = ! this.timer_paused; + } + + adjust_timer(dt) { + let current = this.time_remaining; + this.pending_undo.push(() => this.time_remaining = current); + + // Untimed levels become timed levels with 0 seconds remaining + this.time_remaining = Math.max(0, (this.time_remaining ?? 0) + dt * 20); + if (this.time_remaining <= 0) { + if (this.timer_paused) { + this.time_remaining = 1; + } + else { + this.fail("Time's up!"); + } + } + } + fail(message) { this.pending_undo.push(() => { this.state = 'playing'; diff --git a/js/main.js b/js/main.js index 52580d6..775a657 100644 --- a/js/main.js +++ b/js/main.js @@ -508,7 +508,7 @@ class Player extends PrimaryView { this.time_el.textContent = '---'; } else { - this.time_el.textContent = this.level.time_remaining; + this.time_el.textContent = Math.ceil(this.level.time_remaining / 20); } this.bonus_el.textContent = this.level.bonus_points; this.message_el.textContent = this.level.hint_shown ?? ""; @@ -557,7 +557,7 @@ class Player extends PrimaryView { else { this.bummer_el.textContent = ""; let base = (this.conductor.level_index + 1) * 500; - let time = (this.level.time_remaining || 0) * 10; + let time = Math.ceil((this.level.time_remaining ?? 0) / 20) * 10; this.bummer_el.append( mk('p', "go bit buster!"), mk('dl.score-chart', diff --git a/js/tileset.js b/js/tileset.js index 442512b..968fa71 100644 --- a/js/tileset.js +++ b/js/tileset.js @@ -188,7 +188,7 @@ export const CC2_TILESET_LAYOUT = { swivel_se: [12, 11], swivel_floor: [13, 11], // TODO some kinda four-edges thing again - // TODO stopwatch with a - sign?? + stopwatch_penalty: [15, 11], paramecium: { north: [[0, 12], [1, 12], [2, 12]], east: [[3, 12], [4, 12], [5, 12]], @@ -205,8 +205,8 @@ export const CC2_TILESET_LAYOUT = { walker: [0, 13], // TODO walker animations span multiple tiles, rgh helmet: [0, 14], - // 14: stopwatch - // 15: stopwatch with + + stopwatch_toggle: [14, 14], + stopwatch_bonus: [15, 14], blob: [0, 15], // TODO blob animations also span multiple tiles diff --git a/js/tiletypes.js b/js/tiletypes.js index 1350651..13bc935 100644 --- a/js/tiletypes.js +++ b/js/tiletypes.js @@ -392,6 +392,9 @@ const TILE_TYPES = { } } } + if (other.type.is_player) { + level.adjust_bonus(0, 0.5); + } }, }, thief_keys: { @@ -406,6 +409,9 @@ const TILE_TYPES = { } } } + if (other.type.is_player) { + level.adjust_bonus(0, 0.5); + } }, }, forbidden: { @@ -595,6 +601,39 @@ const TILE_TYPES = { } }, }, + // Time alternation + stopwatch_bonus: { + draw_layer: LAYER_ITEM, + blocks_monsters: true, + blocks_blocks: true, + on_arrive(me, level, other) { + if (other.type.is_player) { + level.remove_tile(me); + level.adjust_timer(+10); + } + }, + }, + stopwatch_penalty: { + draw_layer: LAYER_ITEM, + blocks_monsters: true, + blocks_blocks: true, + on_arrive(me, level, other) { + if (other.type.is_player) { + level.remove_tile(me); + level.adjust_timer(-10); + } + }, + }, + stopwatch_toggle: { + draw_layer: LAYER_ITEM, + blocks_monsters: true, + blocks_blocks: true, + on_arrive(me, level, other) { + if (other.type.is_player) { + level.pause_timer(); + } + }, + }, // Critters bug: { @@ -683,6 +722,7 @@ const TILE_TYPES = { }, // Keys + // Note that red and blue keys do NOT block monsters, but yellow and green DO key_red: { draw_layer: LAYER_ITEM, is_item: true, @@ -697,11 +737,15 @@ const TILE_TYPES = { draw_layer: LAYER_ITEM, is_item: true, is_key: true, + blocks_monsters: true, + blocks_blocks: true, }, key_green: { draw_layer: LAYER_ITEM, is_item: true, is_key: true, + blocks_monsters: true, + blocks_blocks: true, }, // Tools // TODO note: ms allows blocks to pass over tools @@ -794,15 +838,47 @@ const TILE_TYPES = { }, score_10: { draw_layer: LAYER_ITEM, + blocks_monsters: true, + blocks_blocks: true, + on_arrive(me, level, other) { + if (other.type.is_player) { + level.adjust_bonus(10); + } + level.remove_tile(me); + }, }, score_100: { draw_layer: LAYER_ITEM, + blocks_monsters: true, + blocks_blocks: true, + on_arrive(me, level, other) { + if (other.type.is_player) { + level.adjust_bonus(100); + } + level.remove_tile(me); + }, }, score_1000: { draw_layer: LAYER_ITEM, + blocks_monsters: true, + blocks_blocks: true, + on_arrive(me, level, other) { + if (other.type.is_player) { + level.adjust_bonus(1000); + } + level.remove_tile(me); + }, }, score_2x: { draw_layer: LAYER_ITEM, + blocks_monsters: true, + blocks_blocks: true, + on_arrive(me, level, other) { + if (other.type.is_player) { + level.adjust_bonus(0, 2); + } + level.remove_tile(me); + }, }, hint: {