From 20dad5c76aa65995b98d403992659fb93541f957 Mon Sep 17 00:00:00 2001 From: Timothy Stiles Date: Sun, 14 Feb 2021 18:38:56 +1100 Subject: [PATCH] Implement Boulder Similar to a dirt block, but rolls when pushed. Boulders transfer momentum to each other. Has ice block/frame block collision. Turns into gravel in water. Spreads slime. --- js/format-c2g.js | 5 +++++ js/game.js | 4 ++++ js/main-editor.js | 7 +++++- js/tileset.js | 1 + js/tiletypes.js | 54 +++++++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 68 insertions(+), 3 deletions(-) diff --git a/js/format-c2g.js b/js/format-c2g.js index 63b15e3..5789189 100644 --- a/js/format-c2g.js +++ b/js/format-c2g.js @@ -812,6 +812,11 @@ const TILE_ENCODING = { name: 'spikes', is_extension: true, }, + 0xd6: { + name: 'boulder', + has_next: true, + extra_args: [arg_direction], + }, 0xe0: { name: 'gift_bow', has_next: true, diff --git a/js/game.js b/js/game.js index 9a40c5f..ebd989d 100644 --- a/js/game.js +++ b/js/game.js @@ -1577,6 +1577,10 @@ export class Level extends LevelInterface { move_to(actor, goal_cell, speed) { if (actor.cell === goal_cell) return; + + if (actor.type.on_starting_move) { + actor.type.on_starting_move(actor, this); + } let original_cell = actor.cell; // Physically remove the actor first, so that it won't get in the way of e.g. a splash diff --git a/js/main-editor.js b/js/main-editor.js index e5f2a6d..8a9bcc9 100644 --- a/js/main-editor.js +++ b/js/main-editor.js @@ -1609,7 +1609,8 @@ const EDITOR_PALETTE = [{ 'cracked_floor', 'cracked_ice', 'score_5x', - 'spikes' + 'spikes', + 'boulder', ], }]; @@ -2232,6 +2233,10 @@ const EDITOR_TILE_DESCRIPTIONS = { name: "Spikes", desc: "Stops players (and doppelgangers) unless they have hiking boots. Everything else can pass.", }, + boulder: { + name: "Boulder", + desc: "Similar to a dirt block, but rolls when pushed. Boulders transfer momentum to each other. Has ice block/frame block collision. Turns into gravel in water. Spreads slime.", + }, }; const SPECIAL_PALETTE_ENTRIES = { diff --git a/js/tileset.js b/js/tileset.js index 0168201..b5331ec 100644 --- a/js/tileset.js +++ b/js/tileset.js @@ -1064,6 +1064,7 @@ export const LL_TILESET_LAYOUT = Object.assign({}, CC2_TILESET_LAYOUT, { cracked_ice: [7, 40], score_5x: [10, 40], spikes: [5, 40], + boulder: [8, 40], }); export const TILESET_LAYOUTS = { diff --git a/js/tiletypes.js b/js/tiletypes.js index b6b3890..dd54d8a 100644 --- a/js/tiletypes.js +++ b/js/tiletypes.js @@ -259,7 +259,7 @@ const TILE_TYPES = { floor: { layer: LAYERS.terrain, on_approach(me, level, other) { - if (other.type.name === 'blob') { + if (other.type.name === 'blob' || other.type.name === 'boulder') { // Blobs spread slime onto floor if (other.previous_cell && other.previous_cell.has('slime')) { level.transmute_tile(me, 'slime'); @@ -830,6 +830,10 @@ const TILE_TYPES = { level.transmute_tile(other, 'splash'); level.transmute_tile(me, 'ice'); } + else if (other.type.name === 'boulder') { + level.transmute_tile(other, 'splash'); + level.transmute_tile(me, 'gravel'); + } else if (other.type.is_real_player) { level.fail('drowned', me, other); } @@ -1021,7 +1025,7 @@ const TILE_TYPES = { slime: { layer: LAYERS.terrain, on_arrive(me, level, other) { - if (other.type.name === 'ghost' || other.type.name === 'blob') { + if (other.type.name === 'ghost' || other.type.name === 'blob' || other.type.name === 'boulder') { // No effect return; } @@ -1185,6 +1189,7 @@ const TILE_TYPES = { pushes: { ice_block: true, frame_block: true, + boulder: true, }, on_bumped(me, level, other) { // Fireballs melt ice blocks on regular floor FIXME and water! @@ -1215,6 +1220,7 @@ const TILE_TYPES = { dirt_block: true, ice_block: true, frame_block: true, + boulder: true, }, on_clone(me, original) { me.arrows = new Set(original.arrows); @@ -1228,6 +1234,43 @@ const TILE_TYPES = { level._set_tile_prop(me, 'arrows', new_arrows); }, }, + boulder: { + layer: LAYERS.actor, + collision_mask: COLLISION.block_cc2, + blocks_collision: COLLISION.all, + is_actor: true, + is_block: true, + can_reveal_walls: true, + pushes: { + ice_block: true, + frame_block: true, + //boulders don't push each other; instead on_bumped will chain through them + }, + ignores: new Set(['fire', 'flame_jet_on', 'electrified_floor']), + can_reverse_on_railroad: true, + movement_speed: 4, + decide_movement(me, level) { + if (me.rolling) { + level._set_tile_prop(me, 'rolling', false); + return [me.direction, null]; + } + else { + return null; + } + }, + on_bumped(me, level, other) { + if (other.type.name === 'boulder') { + level._set_tile_prop(me, 'rolling', true); + level._set_tile_prop(me, 'direction', other.direction); + level._set_tile_prop(other, 'rolling', false); + } + }, + on_starting_move(me, level) { + if (!me.rolling) { + level._set_tile_prop(me, 'rolling', true); + } + }, + }, glass_block: { layer: LAYERS.actor, collision_mask: COLLISION.block_cc2, @@ -1244,6 +1287,7 @@ const TILE_TYPES = { dirt_block: true, ice_block: true, frame_block: true, + boulder: true, }, on_clone(me, original) { me.arrows = new Set(original.arrows); @@ -2490,6 +2534,7 @@ const TILE_TYPES = { ice_block: true, frame_block: true, circuit_block: true, + boulder: true, }, movement_speed: 4, decide_movement(me, level) { @@ -2641,6 +2686,7 @@ const TILE_TYPES = { ice_block: true, frame_block: true, circuit_block: true, + boulder: true, }, on_ready(me, level) { me.current_emulatee = 0; @@ -3004,6 +3050,7 @@ const TILE_TYPES = { ice_block: true, frame_block: true, circuit_block: true, + boulder: true, }, infinite_items: { key_green: true, @@ -3026,6 +3073,7 @@ const TILE_TYPES = { ice_block: true, frame_block: true, circuit_block: true, + boulder: true, }, infinite_items: { key_yellow: true, @@ -3047,6 +3095,7 @@ const TILE_TYPES = { ice_block: true, frame_block: true, circuit_block: true, + boulder: true, }, infinite_items: { key_green: true, @@ -3072,6 +3121,7 @@ const TILE_TYPES = { ice_block: true, frame_block: true, circuit_block: true, + boulder: true, }, infinite_items: { key_yellow: true,