nix global cycler, terraformer and dormant lava

This commit is contained in:
Timothy Stiles 2021-02-19 08:48:21 +11:00
parent 3ea7a045da
commit c7af08b694
7 changed files with 3 additions and 398 deletions

View File

@ -875,35 +875,11 @@ const TILE_ENCODING = {
name: 'sand', name: 'sand',
is_extension: true, is_extension: true,
}, },
0xe8: {
name: 'terraformer_n',
is_extension: true,
},
0xe9: {
name: 'terraformer_e',
is_extension: true,
},
0xea: {
name: 'terraformer_s',
is_extension: true,
},
0xeb: {
name: 'terraformer_w',
is_extension: true,
},
0xec: {
name: 'global_cycler',
is_extension: true,
},
0xed: { 0xed: {
name: 'halo', name: 'halo',
has_next: true, has_next: true,
is_extension: true, is_extension: true,
}, },
0xee: {
name: 'fire_sticks',
is_extension: true,
},
0xef: { 0xef: {
name: 'turntable_cw', name: 'turntable_cw',
modifier: modifier_wire, modifier: modifier_wire,

View File

@ -1947,7 +1947,7 @@ export class Level extends LevelInterface {
// already in this cell's actor layer. But we also know for sure that there's no // already in this cell's actor layer. But we also know for sure that there's no
// item in this cell, so we'll cheat a little: remove the dropping actor, set the // item in this cell, so we'll cheat a little: remove the dropping actor, set the
// item moving, then put the dropping actor back before anyone notices. // item moving, then put the dropping actor back before anyone notices.
this.remove_tile(dropping_actor, true); this.remove_tile(dropping_actor);
this.add_tile(tile, cell); this.add_tile(tile, cell);
if (! this.attempt_out_of_turn_step(tile, dropping_actor.direction)) { if (! this.attempt_out_of_turn_step(tile, dropping_actor.direction)) {
// It was unable to move, so there's nothing we can do but destroy it // It was unable to move, so there's nothing we can do but destroy it
@ -2393,7 +2393,7 @@ export class Level extends LevelInterface {
player = this.player; player = this.player;
} }
if (player != null && reason !== 'nonexistence' && this.take_tool_from_actor(player, 'halo')) { if (player != null && this.take_tool_from_actor(player, 'halo')) {
this.sfx.play_once('revive'); this.sfx.play_once('revive');
if (reason === 'time') if (reason === 'time')
{ {
@ -2460,12 +2460,7 @@ export class Level extends LevelInterface {
// have things stacked in a weird order though // have things stacked in a weird order though
// TODO would be nice to make these not be closures but order matters much more here // TODO would be nice to make these not be closures but order matters much more here
remove_tile(tile, temporary = false) { remove_tile(tile) {
if (!temporary && tile == this.player)
{
this.fail('nonexistence');
return;
}
let cell = tile.cell; let cell = tile.cell;
cell._remove(tile); cell._remove(tile);
this._push_pending_undo(() => cell._add(tile)); this._push_pending_undo(() => cell._add(tile));

View File

@ -1613,8 +1613,6 @@ const EDITOR_PALETTE = [{
'score_5x', 'score_5x',
'boulder', 'boulder',
'logic_gate/diode', 'logic_gate/diode',
'terraformer_n',
'global_cycler',
], ],
}]; }];
@ -2193,22 +2191,10 @@ const EDITOR_TILE_DESCRIPTIONS = {
name: "Sand", name: "Sand",
desc: "Anything walking on it moves at half speed. Stops all blocks.", desc: "Anything walking on it moves at half speed. Stops all blocks.",
}, },
terraformer_n: {
name: "Terraformer",
desc: "When activated, if there's an item on its tile, copies the item to the tile in front of it. Otherwise, copies the item AND terrain BEHIND it to the tile in front of it.",
},
global_cycler: {
name: "Global cycler",
desc: "When activated, every terrain/item/actor on the surrounding four tiles in the entire level becomes the terrain/item/actor one clockwise. Adjacent tiles with a 'no sign' on them are ignored. Two of the same tile in a row mean that tile will not be transformed and will stay as-is. Actors facing different directions will cause a relative direction change. Tiles next to Global Cyclers are not transformed.",
},
halo: { halo: {
name: "Halo", name: "Halo",
desc: "Protects the player from death once, destroying the would-be killer in the process.", desc: "Protects the player from death once, destroying the would-be killer in the process.",
}, },
fire_sticks: {
name: "Dormant lava",
desc: "Acts like dirt. However, fireballs will enter it and turn it into Fire in the process.",
},
turntable_cw: { turntable_cw: {
name: "Turntable (clockwise)", name: "Turntable (clockwise)",
desc: "Rotates anything entering this tile clockwise. Frame blocks are rotated too. If connected to wire, only functions while receiving power.", desc: "Rotates anything entering this tile clockwise. Frame blocks are rotated too. If connected to wire, only functions while receiving power.",

View File

@ -112,12 +112,6 @@ const OBITUARIES = {
"you're feeling quite alarmed", "you're feeling quite alarmed",
//" //"
], ],
nonexistence: [
"I guess you don't exist",
"critical existence failure",
"no place to be",
"on a trip to nowhere",
],
electrocuted: [ electrocuted: [
"a shocking revelation", "a shocking revelation",
"danger: high voltage", "danger: high voltage",

View File

@ -1039,13 +1039,7 @@ export const LL_TILESET_LAYOUT = Object.assign({}, CC2_TILESET_LAYOUT, {
skeleton_key: [4, 40], skeleton_key: [4, 40],
sand: [10, 41], sand: [10, 41],
terraformer_n: [0, 43],
terraformer_e: [1, 43],
terraformer_s: [2, 43],
terraformer_w: [3, 43],
global_cycler: [4, 43],
halo: [5, 43], halo: [5, 43],
fire_sticks: [6, 43],
turntable_cw: { turntable_cw: {
__special__: 'wires', __special__: 'wires',
base: [0, 2], base: [0, 2],

View File

@ -113,91 +113,6 @@ function update_wireable(me, level) {
} }
} }
function activate_terraformer(me, level, dx, dy) {
//decide if we're copying from our own tile (if we have an item) or the tile behind us (otherwise)
let did_something = false;
let item_only = false;
let old_cell = level.cell(me.cell.x, me.cell.y);
if (old_cell.get_item() != null)
{
item_only = true;
}
else
{
old_cell = level.cell(
(me.cell.x - dx + level.width) % level.width,
(me.cell.y - dy + level.height) % level.height);
}
let new_cell = level.cell(
(me.cell.x + dx + level.width) % level.width,
(me.cell.y + dy + level.height) % level.height);
//copy terrain from the tile behind us, if we're looking at that tile
if (!item_only)
{
let old_terrain = old_cell.get_terrain();
let new_terrain = new_cell.get_terrain();
if (old_terrain.type.name != new_terrain.type.name
|| (old_terrain.type.name == 'railroad' && old_terrain.tracks !== new_terrain.track)
|| (old_terrain.type.name == 'logic_gate' && (old_terrain.gate_type !== new_terrain.gate_type || old_terrain.direction !== new_terrain.direction))
|| old_terrain.wire_directions !== new_terrain.wire_directions
)
{
let changed_wiring_properties = false;
//hardcode-change some extended terrain properties before we transmute and call on_begin
//TODO: would be nice to have a per-type 'on_clone' and 'equality_check'
if (old_terrain.type.name == 'railroad') {
level._set_tile_prop(new_terrain, 'tracks', old_terrain.tracks);
level._set_tile_prop(new_terrain, 'track_switch', old_terrain.track_switch);
}
if (old_terrain.type.name == 'logic_gate') {
level._set_tile_prop(new_terrain, 'gate_type', old_terrain.gate_type);
level._set_tile_prop(new_terrain, 'direction', old_terrain.direction);
changed_wiring_properties = true;
}
if (old_terrain.wire_directions !== new_terrain.wire_directions) {
level._set_tile_prop(new_terrain, 'wire_directions', old_terrain.wire_directions);
changed_wiring_properties = true;
}
level.transmute_tile(new_terrain, old_terrain.type.name);
if (changed_wiring_properties) {
level.recalculate_circuitry_next_wire_phase = true;
}
did_something = true;
}
}
//copy item from (the tile we chose) but only if the space in front of us is free
let old_item = old_cell.get_item();
if (old_item != null)
{
let new_item = new_cell.get_item();
if (new_item == null)
{
let type = TILE_TYPES[old_item.type.name];
let tile = new old_item.constructor(type);
level.add_tile(tile, new_cell);
did_something = true;
}
}
let old_item_mod = old_cell.get_item_mod();
if (old_item_mod != null)
{
let new_item_mod = new_cell.get_item_mod();
if (new_item_mod == null)
{
let type = TILE_TYPES[old_item_mod.type.name];
let tile = new old_item_mod.constructor(type);
level.add_tile(tile, new_cell);
did_something = true;
}
}
//animation
if (did_something)
{
level.spawn_animation(new_cell, 'transmogrify_flash');
}
}
function player_visual_state(me) { function player_visual_state(me) {
if (! me) { if (! me) {
return 'normal'; return 'normal';
@ -745,30 +660,6 @@ const TILE_TYPES = {
return !(!other.type.is_player || other.has_item('hiking_boots')); return !(!other.type.is_player || other.has_item('hiking_boots'));
}, },
}, },
fire_sticks: {
layer: LAYERS.terrain,
blocks_collision: COLLISION.block_cc1 | (COLLISION.monster_solid & ~COLLISION.rover & ~COLLISION.fireball),
blocks(me, level, other) {
return ((other.type.name === 'player2' || other.type.name === 'doppelganger2') &&
! other.has_item('hiking_boots'));
},
on_arrive(me, level, other) {
// Bizarre interaction
if (other.type.name === 'ghost' && ! other.has_item('hiking_boots'))
return;
if (other.type.name === 'fireball')
{
level.transmute_tile(me, 'fire');
}
else
{
level.transmute_tile(me, 'floor');
}
if (other === level.player) {
level.sfx.play_once('step-gravel', me.cell);
}
},
},
turntable_cw: { turntable_cw: {
layer: LAYERS.terrain, layer: LAYERS.terrain,
wire_propagation_mode: 'all', wire_propagation_mode: 'all',
@ -1874,237 +1765,6 @@ const TILE_TYPES = {
} }
}, },
}, },
terraformer_n: {
layer: LAYERS.terrain,
blocks_collision: COLLISION.real_player | COLLISION.block_cc1 | COLLISION.monster_solid,
activate(me, level) {
activate_terraformer(me, level, 0, -1);
},
// Also terraforms on rising pulse or gray button
on_power(me, level) {
me.type.activate(me, level);
},
on_gray_button(me, level) {
me.type.activate(me, level);
},
},
terraformer_e: {
layer: LAYERS.terrain,
blocks_collision: COLLISION.real_player | COLLISION.block_cc1 | COLLISION.monster_solid,
activate(me, level) {
activate_terraformer(me, level, 1, 0);
},
// Also terraforms on rising pulse or gray button
on_power(me, level) {
me.type.activate(me, level);
},
on_gray_button(me, level) {
me.type.activate(me, level);
},
},
terraformer_s: {
layer: LAYERS.terrain,
blocks_collision: COLLISION.real_player | COLLISION.block_cc1 | COLLISION.monster_solid,
activate(me, level) {
activate_terraformer(me, level, 0, 1);
},
// Also terraforms on rising pulse or gray button
on_power(me, level) {
me.type.activate(me, level);
},
on_gray_button(me, level) {
me.type.activate(me, level);
},
},
terraformer_w: {
layer: LAYERS.terrain,
blocks_collision: COLLISION.real_player | COLLISION.block_cc1 | COLLISION.monster_solid,
activate(me, level) {
activate_terraformer(me, level, -1, 0);
},
// Also terraforms on rising pulse or gray button
on_power(me, level) {
me.type.activate(me, level);
},
on_gray_button(me, level) {
me.type.activate(me, level);
},
},
global_cycler: {
layer: LAYERS.terrain,
blocks_collision: COLLISION.real_player | COLLISION.block_cc1 | COLLISION.monster_solid,
activate(me, level) {
//learn about surrounding tiles
//some logic: we ignore tiles with a 'no sign' on them. for items, we ignore itemless tiles. if the same terrain/item is twice in a row, it stays the same. tiles next to global cycles aren't touched.
let cells = [level.cell(
me.cell.x + 0,
me.cell.y - 1),
level.cell(
me.cell.x + 1,
me.cell.y + 0),
level.cell(
me.cell.x + 0 ,
me.cell.y + 1),
level.cell(
me.cell.x - 1,
me.cell.y + 0)].filter(x => x != null && x.get_item_mod()?.type.name != 'no_sign');
let terrains = cells.map(x => x.get_terrain().type.name).filter(x => x != 'global_cycler');
let items = cells.map(x => x.get_item()?.type.name ?? null).filter(x => x != null);
let actors = cells.map(x => x.get_actor()).filter(x => x != null);
//globally cycle terrain
if (new Set(terrains).size > 1)
{
for (var i = 0; i < level.width; ++i)
{
for (var j = 0; j < level.height; ++j)
{
let target_safe = [level.cell(
i + 0,
j + 0),
level.cell(
i + 0,
j - 1),
level.cell(
i + 1,
j + 0),
level.cell(
i + 0,
j + 1),
level.cell(
i - 1,
j + 0)].filter(x => x != null && x.get_terrain().type.name == 'global_cycler');
if (target_safe.length > 0)
{
continue;
}
let thing = level.cell(i, j).get_terrain();
let things = terrains;
for (var k = 0; k < things.length; ++k)
{
if (thing.type.name == things[k] && thing.type.name != things[(k - 1 + things.length) % things.length])
{
level.transmute_tile(thing, things[(k + 1) % things.length]);
break;
}
}
}
}
}
//globally cycle items
//some logic: we skip over itemless spots and if two items in the row are a same, then that item stays the same
if (new Set(items).size > 1)
{
for (var i = 0; i < level.width; ++i)
{
for (var j = 0; j < level.height; ++j)
{
let target_safe = [level.cell(
i + 0,
j + 0),
level.cell(
i + 0,
j - 1),
level.cell(
i + 1,
j + 0),
level.cell(
i + 0,
j + 1),
level.cell(
i - 1,
j + 0)].filter(x => x != null && x.get_terrain().type.name == 'global_cycler');
if (target_safe.length > 0)
{
continue;
}
let thing = level.cell(i, j).get_item();
let things = items;
if (thing == null)
{
continue;
}
for (var k = 0; k < things.length; ++k)
{
if (thing.type.name == things[k] && thing.type.name != things[(k - 1 + things.length) % things.length])
{
level.transmute_tile(thing, things[(k + 1) % things.length]);
break;
}
}
}
}
}
//globally cycle... actors???
//intended logic: if the same monster exists twice in a row we rotate it it by the relative direction (left, right, flip or do nothing). if it's two different monsters, we do that AND transmute.
//this code is slightly different from the previous two blocks!
if (actors.length > 1)
{
for (let a = level.actors.length - 1; a >= 0; a--)
{
let thing = level.actors[a];
let i = thing.cell.x;
let j = thing.cell.y;
let target_safe = [level.cell(
i + 0,
j + 0),
level.cell(
i + 0,
j - 1),
level.cell(
i + 1,
j + 0),
level.cell(
i + 0,
j + 1),
level.cell(
i - 1,
j + 0)].filter(x => x != null && x.get_terrain().type.name == 'global_cycler');
if (target_safe.length > 0)
{
continue;
}
let things = actors;
for (var k = 0; k < things.length; ++k)
{
if (thing.type.name == things[k].type.name)
{
let turn = ['right', 'left', 'opposite'].filter(t => {
return DIRECTIONS[things[k].direction][t] === things[(k + 1) % things.length].direction;
})[0]
if (turn !== undefined)
{
thing.direction = DIRECTIONS[thing.direction][turn];
}
if (thing.type.name != things[(k - 1 + things.length) % things.length].type.name)
{
let old_thing = things[(k + 1) % things.length];
level.transmute_tile(thing, old_thing.type.name);
if (old_thing.type.on_clone) {
old_thing.type.on_clone(thing, old_thing);
}
}
break;
}
}
}
}
},
// Also activates on rising pulse or gray button
on_power(me, level) {
me.type.activate(me, level);
},
on_gray_button(me, level) {
me.type.activate(me, level);
},
},
electrified_floor: { electrified_floor: {
layer: LAYERS.terrain, layer: LAYERS.terrain,
wire_propagation_mode: 'all', wire_propagation_mode: 'all',

Binary file not shown.

Before

Width:  |  Height:  |  Size: 176 KiB

After

Width:  |  Height:  |  Size: 174 KiB