Mostly implement orange buttons and flame jets
This commit is contained in:
parent
0c9a7e3d07
commit
368e4676fd
51
js/game.js
51
js/game.js
@ -291,22 +291,25 @@ export class Level {
|
||||
let cell = connectable.cell;
|
||||
let x = cell.x;
|
||||
let y = cell.y;
|
||||
let goal = connectable.type.connects_to;
|
||||
// FIXME this is a single string for red/brown buttons (to match iter_tiles_in_RO) but a
|
||||
// set for orange buttons (because flame jet states are separate tiles), which sucks ass
|
||||
let goals = connectable.type.connects_to;
|
||||
|
||||
// Check for custom wiring, for MSCC .DAT levels
|
||||
// TODO would be neat if this applied to orange buttons too
|
||||
if (this.stored_level.has_custom_connections) {
|
||||
let n = this.stored_level.coords_to_scalar(x, y);
|
||||
let target_cell_n = null;
|
||||
if (goal === 'trap') {
|
||||
if (connectable.type.name === 'button_brown') {
|
||||
target_cell_n = this.stored_level.custom_trap_wiring[n] ?? null;
|
||||
}
|
||||
else if (goal === 'cloner') {
|
||||
else if (connectable.type.name === 'button_red') {
|
||||
target_cell_n = this.stored_level.custom_cloner_wiring[n] ?? null;
|
||||
}
|
||||
if (target_cell_n && target_cell_n < this.width * this.height) {
|
||||
let [tx, ty] = this.stored_level.scalar_to_coords(target_cell_n);
|
||||
for (let tile of this.cells[ty][tx]) {
|
||||
if (tile.type.name === goal) {
|
||||
if (goals === tile.type.name) {
|
||||
connectable.connection = tile;
|
||||
break;
|
||||
}
|
||||
@ -315,8 +318,26 @@ export class Level {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Orange buttons do a really weird diamond search
|
||||
if (connectable.type.connect_order === 'diamond') {
|
||||
for (let cell of this.iter_cells_in_diamond(connectable.cell)) {
|
||||
let target = null;
|
||||
for (let tile of cell) {
|
||||
if (goals.has(tile.type.name)) {
|
||||
target = tile;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (target !== null) {
|
||||
connectable.connection = target;
|
||||
break;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Otherwise, look in reading order
|
||||
for (let tile of this.iter_tiles_in_reading_order(cell, goal)) {
|
||||
for (let tile of this.iter_tiles_in_reading_order(cell, goals)) {
|
||||
// TODO ideally this should be a weak connection somehow, since dynamite can destroy
|
||||
// empty cloners and probably traps too
|
||||
connectable.connection = tile;
|
||||
@ -1189,6 +1210,26 @@ export class Level {
|
||||
}
|
||||
}
|
||||
|
||||
// Iterates over the grid in a diamond pattern, spreading out from the given start cell (but not
|
||||
// including it). Only used for connecting orange buttons.
|
||||
*iter_cells_in_diamond(start_cell) {
|
||||
let max_search_radius = Math.max(this.size_x, this.size_y);
|
||||
for (let dist = 1; dist <= max_search_radius; dist++) {
|
||||
// Start east and move counterclockwise
|
||||
let sx = start_cell.x + dist;
|
||||
let sy = start_cell.y;
|
||||
for (let direction of [[-1, -1], [-1, 1], [1, 1], [1, -1]]) {
|
||||
for (let i = 0; i < dist; i++) {
|
||||
if (this.is_point_within_bounds(sx, sy)) {
|
||||
yield this.cells[sy][sx];
|
||||
}
|
||||
sx += direction[0];
|
||||
sy += direction[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Undo handling
|
||||
|
||||
|
||||
@ -524,6 +524,7 @@ const EDITOR_PALETTE = [{
|
||||
'button_blue',
|
||||
'button_red', 'cloner',
|
||||
'button_brown', 'trap',
|
||||
'button_orange', 'flame_jet_off', 'flame_jet_on',
|
||||
'teleport_blue',
|
||||
'teleport_red',
|
||||
'teleport_green',
|
||||
|
||||
@ -565,7 +565,7 @@ const TILE_TYPES = {
|
||||
blocks_all: true,
|
||||
is_actor: true,
|
||||
is_block: true,
|
||||
ignores: new Set(['fire']),
|
||||
ignores: new Set(['fire', 'flame_jet_on']),
|
||||
movement_speed: 4,
|
||||
},
|
||||
ice_block: {
|
||||
@ -583,14 +583,13 @@ const TILE_TYPES = {
|
||||
directional_block: {
|
||||
// TODO directional, obviously
|
||||
// TODO floor in water
|
||||
// TODO destroyed in fire, flame jet, slime
|
||||
// TODO destroyed in slime
|
||||
// TODO rotate on train tracks
|
||||
draw_layer: LAYER_ACTOR,
|
||||
blocks_all: true,
|
||||
is_actor: true,
|
||||
is_block: true,
|
||||
can_reveal_walls: true,
|
||||
ignores: new Set(['fire']),
|
||||
movement_speed: 4,
|
||||
pushes: {
|
||||
dirt_block: true,
|
||||
@ -857,6 +856,10 @@ const TILE_TYPES = {
|
||||
return level.iter_tiles_in_reading_order(me.cell, 'teleport_yellow', true);
|
||||
},
|
||||
},
|
||||
// Flame jet rules:
|
||||
// - State toggles /while/ an orange button is held or wire current is received
|
||||
// - Multiple such inputs cancel each other out
|
||||
// - Gray button toggles it permanently
|
||||
flame_jet_off: {
|
||||
draw_layer: LAYER_TERRAIN,
|
||||
activate(me, level) {
|
||||
@ -871,7 +874,6 @@ const TILE_TYPES = {
|
||||
},
|
||||
flame_jet_on: {
|
||||
draw_layer: LAYER_TERRAIN,
|
||||
// FIXME every tic, kills every actor in the cell
|
||||
activate(me, level) {
|
||||
level.transmute_tile(me, 'flame_jet_off');
|
||||
},
|
||||
@ -881,6 +883,21 @@ const TILE_TYPES = {
|
||||
on_power(me, level) {
|
||||
me.type.activate(me, level);
|
||||
},
|
||||
// Kill anything that shows up
|
||||
// FIXME every tic, also kills every actor in the cell (mostly matters if you step on with
|
||||
// fire boots and then drop them)
|
||||
on_arrive(me, level, other) {
|
||||
// Note that blocks, fireballs, and anything with fire boots are immune
|
||||
// TODO would be neat if this understood "ignores anything with fire immunity" but that
|
||||
// might be a bit too high-level for this game
|
||||
if (other.type.is_player) {
|
||||
level.fail('burned');
|
||||
}
|
||||
else {
|
||||
// TODO should this play a sound?
|
||||
level.transmute_tile(other, 'explosion');
|
||||
}
|
||||
},
|
||||
},
|
||||
// Buttons
|
||||
button_blue: {
|
||||
@ -999,7 +1016,26 @@ const TILE_TYPES = {
|
||||
},
|
||||
button_orange: {
|
||||
draw_layer: LAYER_TERRAIN,
|
||||
// FIXME toggles flame jets, connected somehow, ???
|
||||
connects_to: new Set(['flame_jet_off', 'flame_jet_on']),
|
||||
connect_order: 'diamond',
|
||||
// Both stepping on and leaving the button have the same effect: toggle the state of the
|
||||
// connected flame jet
|
||||
_toggle_flame_jet(me, level, other) {
|
||||
let jet = me.connection;
|
||||
if (jet && jet.cell) {
|
||||
jet.type.activate(jet, level);
|
||||
}
|
||||
},
|
||||
on_arrive(me, level, other) {
|
||||
level.sfx.play_once('button-press', me.cell);
|
||||
|
||||
me.type._toggle_flame_jet(me, level, other);
|
||||
},
|
||||
on_depart(me, level, other) {
|
||||
level.sfx.play_once('button-release', me.cell);
|
||||
|
||||
me.type._toggle_flame_jet(me, level, other);
|
||||
},
|
||||
},
|
||||
button_pink: {
|
||||
draw_layer: LAYER_TERRAIN,
|
||||
@ -1164,7 +1200,7 @@ const TILE_TYPES = {
|
||||
blocks_blocks: true,
|
||||
movement_mode: 'turn-right',
|
||||
movement_speed: 4,
|
||||
ignores: new Set(['fire']),
|
||||
ignores: new Set(['fire', 'flame_jet_on']),
|
||||
},
|
||||
glider: {
|
||||
draw_layer: LAYER_ACTOR,
|
||||
@ -1279,7 +1315,7 @@ const TILE_TYPES = {
|
||||
is_tool: true,
|
||||
blocks_monsters: true,
|
||||
blocks_blocks: true,
|
||||
item_ignores: new Set(['fire']),
|
||||
item_ignores: new Set(['fire', 'flame_jet_on']),
|
||||
},
|
||||
flippers: {
|
||||
draw_layer: LAYER_ITEM,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user