Add sound effects!
This commit is contained in:
parent
6aee8ed622
commit
40aa845e92
31
js/game.js
31
js/game.js
@ -361,6 +361,8 @@ export class Level {
|
|||||||
// TODO but maybe they should be undone anyway so rewind looks better
|
// TODO but maybe they should be undone anyway so rewind looks better
|
||||||
this.player.is_blocked = false;
|
this.player.is_blocked = false;
|
||||||
|
|
||||||
|
this.sfx.set_player_position(this.player.cell);
|
||||||
|
|
||||||
// First pass: tick cooldowns and animations; have actors arrive in their cells. We do the
|
// First pass: tick cooldowns and animations; have actors arrive in their cells. We do the
|
||||||
// arrival as its own mini pass, for one reason: if the player dies (which will end the game
|
// arrival as its own mini pass, for one reason: if the player dies (which will end the game
|
||||||
// immediately), we still want every time's animation to finish, or it'll look like some
|
// immediately), we still want every time's animation to finish, or it'll look like some
|
||||||
@ -591,6 +593,7 @@ export class Level {
|
|||||||
|
|
||||||
// Track whether the player is blocked, for visual effect
|
// Track whether the player is blocked, for visual effect
|
||||||
if (actor === this.player && p1_primary_direction && ! success) {
|
if (actor === this.player && p1_primary_direction && ! success) {
|
||||||
|
this.sfx.play_once('blocked');
|
||||||
actor.is_blocked = true;
|
actor.is_blocked = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -648,6 +651,9 @@ export class Level {
|
|||||||
if (this.time_remaining <= 0) {
|
if (this.time_remaining <= 0) {
|
||||||
this.fail('time');
|
this.fail('time');
|
||||||
}
|
}
|
||||||
|
else if (this.time_remaining % 20 === 0 && this.time_remaining < 30 * 20) {
|
||||||
|
this.sfx.play_once('tick');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.pending_undo.push(() => {
|
this.pending_undo.push(() => {
|
||||||
@ -831,6 +837,10 @@ export class Level {
|
|||||||
this.fail(actor.type.name);
|
this.fail(actor.type.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (actor === this.player && goal_cell[0].type.name === 'floor') {
|
||||||
|
this.sfx.play_once('step-floor');
|
||||||
|
}
|
||||||
|
|
||||||
if (this.compat.tiles_react_instantly) {
|
if (this.compat.tiles_react_instantly) {
|
||||||
this.step_on_cell(actor, actor.cell);
|
this.step_on_cell(actor, actor.cell);
|
||||||
}
|
}
|
||||||
@ -846,6 +856,12 @@ export class Level {
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (tile.type.is_item && this.give_actor(actor, tile.type.name)) {
|
if (tile.type.is_item && this.give_actor(actor, tile.type.name)) {
|
||||||
|
if (tile.type.is_key) {
|
||||||
|
this.sfx.play_once('get-key', cell);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.sfx.play_once('get-tool', cell);
|
||||||
|
}
|
||||||
this.remove_tile(tile);
|
this.remove_tile(tile);
|
||||||
}
|
}
|
||||||
else if (tile.type.is_teleporter) {
|
else if (tile.type.is_teleporter) {
|
||||||
@ -873,9 +889,13 @@ export class Level {
|
|||||||
// XXX not especially undo-efficient
|
// XXX not especially undo-efficient
|
||||||
this.remove_tile(actor);
|
this.remove_tile(actor);
|
||||||
this.add_tile(actor, goal.cell);
|
this.add_tile(actor, goal.cell);
|
||||||
if (this.attempt_step(actor, actor.direction))
|
if (this.attempt_step(actor, actor.direction)) {
|
||||||
// Success, teleportation complete
|
// Success, teleportation complete
|
||||||
|
// Sound plays from the origin cell simply because that's where the sfx player
|
||||||
|
// thinks the player is currently
|
||||||
|
this.sfx.play_once('teleport', cell);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
if (goal === teleporter)
|
if (goal === teleporter)
|
||||||
// We've tried every teleporter, including the one they
|
// We've tried every teleporter, including the one they
|
||||||
// stepped on, so leave them on it
|
// stepped on, so leave them on it
|
||||||
@ -936,6 +956,7 @@ export class Level {
|
|||||||
collect_chip() {
|
collect_chip() {
|
||||||
let current = this.chips_remaining;
|
let current = this.chips_remaining;
|
||||||
if (current > 0) {
|
if (current > 0) {
|
||||||
|
this.sfx.play_once('get-chip');
|
||||||
this.pending_undo.push(() => this.chips_remaining = current);
|
this.pending_undo.push(() => this.chips_remaining = current);
|
||||||
this.chips_remaining--;
|
this.chips_remaining--;
|
||||||
}
|
}
|
||||||
@ -972,6 +993,13 @@ export class Level {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fail(reason) {
|
fail(reason) {
|
||||||
|
if (reason === 'time') {
|
||||||
|
this.sfx.play_once('timeup');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.sfx.play_once('lose');
|
||||||
|
}
|
||||||
|
|
||||||
this.pending_undo.push(() => {
|
this.pending_undo.push(() => {
|
||||||
this.state = 'playing';
|
this.state = 'playing';
|
||||||
this.fail_reason = null;
|
this.fail_reason = null;
|
||||||
@ -984,6 +1012,7 @@ export class Level {
|
|||||||
}
|
}
|
||||||
|
|
||||||
win() {
|
win() {
|
||||||
|
this.sfx.play_once('win');
|
||||||
this.pending_undo.push(() => this.state = 'playing');
|
this.pending_undo.push(() => this.state = 'playing');
|
||||||
this.state = 'success';
|
this.state = 'success';
|
||||||
throw new GameEnded;
|
throw new GameEnded;
|
||||||
|
|||||||
129
js/main.js
129
js/main.js
@ -219,6 +219,126 @@ const OBITUARIES = {
|
|||||||
"goo another way next time",
|
"goo another way next time",
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
// Helper class used to let the game play sounds without knowing too much about the Player
|
||||||
|
class SFXPlayer {
|
||||||
|
constructor() {
|
||||||
|
this.ctx = new window.AudioContext;
|
||||||
|
this.player_x = null;
|
||||||
|
this.player_y = null;
|
||||||
|
this.sounds = {};
|
||||||
|
this.sound_sources = {
|
||||||
|
// handcrafted
|
||||||
|
blocked: 'sfx/mmf.ogg',
|
||||||
|
// https://jummbus.bitbucket.io/#j2N04bombn110s0k0l00e00t3Mm4a3g00j07i0r1O_U00o30T0v0pL0OD0Ou00q1d1f8y0z2C0w2c0h2T2v0kL0OD0Ou02q1d1f6y1z2C1w1b4gp1b0aCTFucgds0
|
||||||
|
bomb: 'sfx/bomb.ogg',
|
||||||
|
// https://jummbus.bitbucket.io/#j2N0cbutton-pressn100s0k0l00e00t3Mm1a3g00j07i0r1O_U0o3T0v0pL0OD0Ou00q1d1f3y1z1C2w0c0h0b4p1bJdn51eMUsS0
|
||||||
|
'button-press': 'sfx/button-press.ogg',
|
||||||
|
// https://jummbus.bitbucket.io/#j2N0ebutton-releasen100s0k0l00e00t3Mm1a3g00j07i0r1O_U0o3T0v0pL0OD0Ou00q1d1f3y1z1C2w0c0h0b4p1aArdkga4sG0
|
||||||
|
'button-release': 'sfx/button-release.ogg',
|
||||||
|
// https://jummbus.bitbucket.io/#j2N04doorn110s0k0l00e00t3Mmfa3g00j07i0r1O_U00o30T0v0zL0OD0Ou00q0d1f8y0z2C0w2c0h0T2v0pL0OD0Ou02q0d1f8y3ziC0w1b4gp1f0aqEQ0lCNzrYUY0
|
||||||
|
door: 'sfx/door.ogg',
|
||||||
|
// https://jummbus.bitbucket.io/#j2N08get-chipn100s0k0l00e00t3Mmca3g00j07i0r1O_U0o4T0v0zL0OD0Ou00q1d1f6y1z2C0wac0h0b4p1dFyW7czgUK7aw0
|
||||||
|
'get-chip': 'sfx/get-chip.ogg',
|
||||||
|
// https://jummbus.bitbucket.io/#j2N07get-keyn100s0k0l00e00t3Mmfa3g00j07i0r1O_U0o5T0v0pL0OD0Ou00q1d5f8y0z2C0w1c0h0b4p1dFyW85CbwwzBg0
|
||||||
|
'get-key': 'sfx/get-key.ogg',
|
||||||
|
// https://jummbus.bitbucket.io/#j2N08get-tooln100s0k0l00e00t3Mm6a3g00j07i0r1O_U0o2T0v0pL0OD0Ou00q1d1f4y2z9C0w2c0h0b4p1bGqKNW4isVk0
|
||||||
|
'get-tool': 'sfx/get-tool.ogg',
|
||||||
|
// https://jummbus.bitbucket.io/#j2N06socketn110s0k0l00e00t3Mm4a3g00j07i0r1O_U00o30T5v0pL0OD0Ou05q1d1f8y1z7C1c0h0HU7000U0006000ET2v0pL0OD0Ou02q1d6f5y3z2C0w0b4gp1xGoKHGhFBcn2FyPkxk0rE2AGcNCQyHwUY0
|
||||||
|
socket: 'sfx/socket.ogg',
|
||||||
|
// https://jummbus.bitbucket.io/#j2N06splashn110s0k0l00e00t3Mm5a3g00j07i0r1O_U00o20T0v0pL0OD0Ou00q0d0fay0z0C0w9c0h8T2v05L0OD0Ou02q2d6fay0z1C0w0b4gp1lGqKQy02gUY1qh7D1wb2Y0
|
||||||
|
// https://jummbus.bitbucket.io/#j2N06splashn110s0k0l00e00t3Mm5a3g00j07i0r1O_U00o20T0v0pL0OD0Ou00q0d0fay0z0C0w9c0h8T2v05L0OD0Ou02q2d6fay0z1C0w0b4gp1lGqKQxw_zzM5F4us60IbM0
|
||||||
|
splash: 'sfx/splash.ogg',
|
||||||
|
// https://jummbus.bitbucket.io/#j2N0astep-floorn100s0k0l00e00t3Mm6a3g00j07i0r1O_U0o1T0v05L0OD0Ou00q0d2f1y1zjC2w0c0h0b4p1aGaKaxqer00
|
||||||
|
'step-floor': 'sfx/step-floor.ogg',
|
||||||
|
// https://jummbus.bitbucket.io/#j2N08teleportn110s1k0l00e00t3Mm7a3g00j07i0r1O_U00o50T0v0pL0OD0Ou00q1d1f8y4z6C2w5c4h0T2v0kL0OD0Ou02q1d7f8y4z3C1w4b4gp1wF2Uzh5wdC18yHH4hhBhHwaATXu0Asds0
|
||||||
|
teleport: 'sfx/teleport.ogg',
|
||||||
|
// https://jummbus.bitbucket.io/#j2N05thiefn100s1k0l00e00t3Mm3a3g00j07i0r1O_U0o1T0v0pL0OD0Ou00q1d1f5y1z8C2w2c0h0b4p1fFyUBBr9mGkKKds0
|
||||||
|
thief: 'sfx/thief.ogg',
|
||||||
|
|
||||||
|
// handcrafted
|
||||||
|
lose: 'sfx/bummer.ogg',
|
||||||
|
// https://jummbus.bitbucket.io/#j2N04tickn100s0k0l00e00t3Mmca3g00j07i0r1O_U0o2T0v0pL0OD0Ou00q1d1f7y1ziC0w4c0h4b4p1bKqE6Rtxex00
|
||||||
|
tick: 'sfx/tick.ogg',
|
||||||
|
// https://jummbus.bitbucket.io/#j2N06timeupn100s0k0l00e00t3Mm4a3g00j07i0r1O_U0o3T1v0pL0OD0Ou01q1d5f4y1z8C1c0A0F0B0V1Q38e0Pa610E0861b4p1dIyfgKPcLucqU0
|
||||||
|
timeup: 'sfx/timeup.ogg',
|
||||||
|
// https://jummbus.bitbucket.io/#j2N03winn200s0k0l00e00t2wm9a3g00j07i0r1O_U00o32T0v0EL0OD0Ou00q1d1f5y1z1C2w1c2h0T0v0pL0OD0Ou00q0d1f2y1z2C0w2c3h0b4gp1xFyW4xo31pe0MaCHCbwLbM5cFDgapBOyY0
|
||||||
|
win: 'sfx/win.ogg',
|
||||||
|
};
|
||||||
|
|
||||||
|
for (let [name, path] of Object.entries(this.sound_sources)) {
|
||||||
|
this.init_sound(name, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.mmf_cooldown = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
async init_sound(name, path) {
|
||||||
|
let buf = await fetch(path);
|
||||||
|
let audiobuf = await this.ctx.decodeAudioData(buf);
|
||||||
|
this.sounds[name] = {
|
||||||
|
buf: buf,
|
||||||
|
audiobuf: audiobuf,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
set_player_position(cell) {
|
||||||
|
this.player_x = cell.x;
|
||||||
|
this.player_y = cell.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
play_once(name, cell = null) {
|
||||||
|
let data = this.sounds[name];
|
||||||
|
if (! data) {
|
||||||
|
// Hasn't loaded yet, not much we can do
|
||||||
|
if (! this.sound_sources[name]) {
|
||||||
|
console.warn("Tried to play non-existent sound", name);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// "Mmf" can technically play every tic since bumping into something doesn't give a movement
|
||||||
|
// cooldown, so give it our own sound cooldown
|
||||||
|
if (name === 'blocked' && this.player_x !== null) {
|
||||||
|
if (this.mmf_cooldown > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.mmf_cooldown = 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let node = this.ctx.createBufferSource();
|
||||||
|
node.buffer = data.audiobuf;
|
||||||
|
|
||||||
|
if (cell && this.player_x !== null) {
|
||||||
|
// Reduce the volume for further-away sounds
|
||||||
|
let dx = cell.x - this.player_x;
|
||||||
|
let dy = cell.y - this.player_y;
|
||||||
|
let dist = Math.sqrt(dx*dx + dy*dy);
|
||||||
|
let gain = this.ctx.createGain();
|
||||||
|
// x/(x + a) is a common and delightful way to get an easy asymptote and output between
|
||||||
|
// 0 and 1. Here, the result is above 80% for almost everything on screen; drops down
|
||||||
|
// to 50% for things 20 tiles away (which is, roughly, the periphery when standing in
|
||||||
|
// the center of a CC1 map), and bottoms out at 12.5% for standing in one corner of a
|
||||||
|
// CC2 map of max size and hearing something on the far opposite corner.
|
||||||
|
gain.gain.value = 1 - dist / (dist + 20);
|
||||||
|
node.connect(gain);
|
||||||
|
gain.connect(this.ctx.destination);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Play at full volume
|
||||||
|
node.connect(this.ctx.destination);
|
||||||
|
}
|
||||||
|
node.start(this.ctx.currentTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reduce cooldowns
|
||||||
|
advance_tic() {
|
||||||
|
if (this.mmf_cooldown > 0) {
|
||||||
|
this.mmf_cooldown -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
class Player extends PrimaryView {
|
class Player extends PrimaryView {
|
||||||
constructor(conductor) {
|
constructor(conductor) {
|
||||||
super(conductor, document.body.querySelector('main#player'));
|
super(conductor, document.body.querySelector('main#player'));
|
||||||
@ -473,6 +593,13 @@ class Player extends PrimaryView {
|
|||||||
window.addEventListener('resize', ev => {
|
window.addEventListener('resize', ev => {
|
||||||
this.adjust_scale();
|
this.adjust_scale();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// TODO yet another thing that should be in setup, but can't be because load_level is called
|
||||||
|
// first
|
||||||
|
this.sfx_player = new SFXPlayer;
|
||||||
|
}
|
||||||
|
|
||||||
|
setup() {
|
||||||
}
|
}
|
||||||
|
|
||||||
activate() {
|
activate() {
|
||||||
@ -495,6 +622,7 @@ class Player extends PrimaryView {
|
|||||||
|
|
||||||
load_level(stored_level) {
|
load_level(stored_level) {
|
||||||
this.level = new Level(stored_level, this.compat);
|
this.level = new Level(stored_level, this.compat);
|
||||||
|
this.level.sfx = this.sfx_player;
|
||||||
this.renderer.set_level(this.level);
|
this.renderer.set_level(this.level);
|
||||||
this.root.classList.toggle('--has-demo', !!this.level.stored_level.demo);
|
this.root.classList.toggle('--has-demo', !!this.level.stored_level.demo);
|
||||||
// TODO base this on a hash of the UA + some identifier for the pack + the level index. StoredLevel doesn't know its own index atm...
|
// TODO base this on a hash of the UA + some identifier for the pack + the level index. StoredLevel doesn't know its own index atm...
|
||||||
@ -620,6 +748,7 @@ class Player extends PrimaryView {
|
|||||||
|
|
||||||
this.previous_input = input;
|
this.previous_input = input;
|
||||||
|
|
||||||
|
this.sfx_player.advance_tic();
|
||||||
this.level.advance_tic(
|
this.level.advance_tic(
|
||||||
this.primary_action ? ACTION_DIRECTIONS[this.primary_action] : null,
|
this.primary_action ? ACTION_DIRECTIONS[this.primary_action] : null,
|
||||||
this.secondary_action ? ACTION_DIRECTIONS[this.secondary_action] : null,
|
this.secondary_action ? ACTION_DIRECTIONS[this.secondary_action] : null,
|
||||||
|
|||||||
@ -240,7 +240,7 @@ const TILE_TYPES = {
|
|||||||
is_swivel: true,
|
is_swivel: true,
|
||||||
on_depart(me, level, other) {
|
on_depart(me, level, other) {
|
||||||
if (other.direction === 'north') {
|
if (other.direction === 'north') {
|
||||||
level.transmute_tile(me, 'swivel_ne');
|
level.transmute_tile(me, 'swivel_sw');
|
||||||
}
|
}
|
||||||
else if (other.direction === 'west') {
|
else if (other.direction === 'west') {
|
||||||
level.transmute_tile(me, 'swivel_ne');
|
level.transmute_tile(me, 'swivel_ne');
|
||||||
@ -263,6 +263,7 @@ const TILE_TYPES = {
|
|||||||
},
|
},
|
||||||
on_arrive(me, level, other) {
|
on_arrive(me, level, other) {
|
||||||
if (level.take_key_from_actor(other, 'key_red')) {
|
if (level.take_key_from_actor(other, 'key_red')) {
|
||||||
|
level.sfx.play_once('door', me.cell);
|
||||||
level.transmute_tile(me, 'floor');
|
level.transmute_tile(me, 'floor');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -274,6 +275,7 @@ const TILE_TYPES = {
|
|||||||
},
|
},
|
||||||
on_arrive(me, level, other) {
|
on_arrive(me, level, other) {
|
||||||
if (level.take_key_from_actor(other, 'key_blue')) {
|
if (level.take_key_from_actor(other, 'key_blue')) {
|
||||||
|
level.sfx.play_once('door', me.cell);
|
||||||
level.transmute_tile(me, 'floor');
|
level.transmute_tile(me, 'floor');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -285,6 +287,7 @@ const TILE_TYPES = {
|
|||||||
},
|
},
|
||||||
on_arrive(me, level, other) {
|
on_arrive(me, level, other) {
|
||||||
if (level.take_key_from_actor(other, 'key_yellow')) {
|
if (level.take_key_from_actor(other, 'key_yellow')) {
|
||||||
|
level.sfx.play_once('door', me.cell);
|
||||||
level.transmute_tile(me, 'floor');
|
level.transmute_tile(me, 'floor');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -296,6 +299,7 @@ const TILE_TYPES = {
|
|||||||
},
|
},
|
||||||
on_arrive(me, level, other) {
|
on_arrive(me, level, other) {
|
||||||
if (level.take_key_from_actor(other, 'key_green')) {
|
if (level.take_key_from_actor(other, 'key_green')) {
|
||||||
|
level.sfx.play_once('door', me.cell);
|
||||||
level.transmute_tile(me, 'floor');
|
level.transmute_tile(me, 'floor');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -344,6 +348,7 @@ const TILE_TYPES = {
|
|||||||
draw_layer: LAYER_TERRAIN,
|
draw_layer: LAYER_TERRAIN,
|
||||||
on_arrive(me, level, other) {
|
on_arrive(me, level, other) {
|
||||||
// TODO cc1 allows items under water, i think; water was on the upper layer
|
// TODO cc1 allows items under water, i think; water was on the upper layer
|
||||||
|
level.sfx.play_once('splash', me.cell);
|
||||||
if (other.type.name === 'dirt_block') {
|
if (other.type.name === 'dirt_block') {
|
||||||
level.transmute_tile(other, 'splash');
|
level.transmute_tile(other, 'splash');
|
||||||
level.transmute_tile(me, 'dirt');
|
level.transmute_tile(me, 'dirt');
|
||||||
@ -478,6 +483,7 @@ const TILE_TYPES = {
|
|||||||
level.fail('exploded');
|
level.fail('exploded');
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
level.sfx.play_once('bomb', me.cell);
|
||||||
level.transmute_tile(other, 'explosion');
|
level.transmute_tile(other, 'explosion');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -487,6 +493,7 @@ const TILE_TYPES = {
|
|||||||
blocks_monsters: true,
|
blocks_monsters: true,
|
||||||
blocks_blocks: true,
|
blocks_blocks: true,
|
||||||
on_arrive(me, level, other) {
|
on_arrive(me, level, other) {
|
||||||
|
level.sfx.play_once('thief', me.cell);
|
||||||
level.take_all_tools_from_actor(other);
|
level.take_all_tools_from_actor(other);
|
||||||
if (other.type.is_player) {
|
if (other.type.is_player) {
|
||||||
level.adjust_bonus(0, 0.5);
|
level.adjust_bonus(0, 0.5);
|
||||||
@ -498,6 +505,7 @@ const TILE_TYPES = {
|
|||||||
blocks_monsters: true,
|
blocks_monsters: true,
|
||||||
blocks_blocks: true,
|
blocks_blocks: true,
|
||||||
on_arrive(me, level, other) {
|
on_arrive(me, level, other) {
|
||||||
|
level.sfx.play_once('thief', me.cell);
|
||||||
level.take_all_keys_from_actor(other);
|
level.take_all_keys_from_actor(other);
|
||||||
if (other.type.is_player) {
|
if (other.type.is_player) {
|
||||||
level.adjust_bonus(0, 0.5);
|
level.adjust_bonus(0, 0.5);
|
||||||
@ -576,6 +584,7 @@ const TILE_TYPES = {
|
|||||||
level.fail('exploded');
|
level.fail('exploded');
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
level.sfx.play_once('bomb', me.cell);
|
||||||
level.transmute_tile(other, 'explosion');
|
level.transmute_tile(other, 'explosion');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -715,6 +724,8 @@ const TILE_TYPES = {
|
|||||||
button_blue: {
|
button_blue: {
|
||||||
draw_layer: LAYER_TERRAIN,
|
draw_layer: LAYER_TERRAIN,
|
||||||
on_arrive(me, level, other) {
|
on_arrive(me, level, other) {
|
||||||
|
level.sfx.play_once('button-press', me.cell);
|
||||||
|
|
||||||
// Flip direction of all blue tanks
|
// Flip direction of all blue tanks
|
||||||
for (let actor of level.actors) {
|
for (let actor of level.actors) {
|
||||||
// TODO generify somehow??
|
// TODO generify somehow??
|
||||||
@ -723,10 +734,15 @@ const TILE_TYPES = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
on_depart(me, level, other) {
|
||||||
|
level.sfx.play_once('button-release', me.cell);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
button_yellow: {
|
button_yellow: {
|
||||||
draw_layer: LAYER_TERRAIN,
|
draw_layer: LAYER_TERRAIN,
|
||||||
on_arrive(me, level, other) {
|
on_arrive(me, level, other) {
|
||||||
|
level.sfx.play_once('button-press', me.cell);
|
||||||
|
|
||||||
// Move all yellow tanks one tile in the direction of the pressing actor
|
// Move all yellow tanks one tile in the direction of the pressing actor
|
||||||
for (let actor of level.actors) {
|
for (let actor of level.actors) {
|
||||||
// TODO generify somehow??
|
// TODO generify somehow??
|
||||||
@ -735,10 +751,15 @@ const TILE_TYPES = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
on_depart(me, level, other) {
|
||||||
|
level.sfx.play_once('button-release', me.cell);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
button_green: {
|
button_green: {
|
||||||
draw_layer: LAYER_TERRAIN,
|
draw_layer: LAYER_TERRAIN,
|
||||||
on_arrive(me, level, other) {
|
on_arrive(me, level, other) {
|
||||||
|
level.sfx.play_once('button-press', me.cell);
|
||||||
|
|
||||||
// Swap green floors and walls
|
// Swap green floors and walls
|
||||||
// TODO could probably make this more compact for undo purposes
|
// TODO could probably make this more compact for undo purposes
|
||||||
for (let row of level.cells) {
|
for (let row of level.cells) {
|
||||||
@ -760,12 +781,17 @@ const TILE_TYPES = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
on_depart(me, level, other) {
|
||||||
|
level.sfx.play_once('button-release', me.cell);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
button_brown: {
|
button_brown: {
|
||||||
draw_layer: LAYER_TERRAIN,
|
draw_layer: LAYER_TERRAIN,
|
||||||
connects_to: 'trap',
|
connects_to: 'trap',
|
||||||
connect_order: 'forward',
|
connect_order: 'forward',
|
||||||
on_arrive(me, level, other) {
|
on_arrive(me, level, other) {
|
||||||
|
level.sfx.play_once('button-press', me.cell);
|
||||||
|
|
||||||
if (me.connection && me.connection.cell) {
|
if (me.connection && me.connection.cell) {
|
||||||
let trap = me.connection;
|
let trap = me.connection;
|
||||||
level._set_prop(trap, 'open', true);
|
level._set_prop(trap, 'open', true);
|
||||||
@ -782,6 +808,9 @@ const TILE_TYPES = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
on_depart(me, level, other) {
|
on_depart(me, level, other) {
|
||||||
|
// TODO this doesn't play if you walk straight across
|
||||||
|
level.sfx.play_once('button-release', me.cell);
|
||||||
|
|
||||||
if (me.connection && me.connection.cell) {
|
if (me.connection && me.connection.cell) {
|
||||||
let trap = me.connection;
|
let trap = me.connection;
|
||||||
level._set_prop(trap, 'open', false);
|
level._set_prop(trap, 'open', false);
|
||||||
@ -798,10 +827,15 @@ const TILE_TYPES = {
|
|||||||
connects_to: 'cloner',
|
connects_to: 'cloner',
|
||||||
connect_order: 'forward',
|
connect_order: 'forward',
|
||||||
on_arrive(me, level, other) {
|
on_arrive(me, level, other) {
|
||||||
|
level.sfx.play_once('button-press', me.cell);
|
||||||
|
|
||||||
if (me.connection && me.connection.cell) {
|
if (me.connection && me.connection.cell) {
|
||||||
me.connection.type.activate(me.connection, level);
|
me.connection.type.activate(me.connection, level);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
on_depart(me, level, other) {
|
||||||
|
level.sfx.play_once('button-release', me.cell);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
button_orange: {
|
button_orange: {
|
||||||
draw_layer: LAYER_TERRAIN,
|
draw_layer: LAYER_TERRAIN,
|
||||||
@ -1233,6 +1267,7 @@ const TILE_TYPES = {
|
|||||||
},
|
},
|
||||||
on_arrive(me, level, other) {
|
on_arrive(me, level, other) {
|
||||||
if (other.type.is_player && level.chips_remaining === 0) {
|
if (other.type.is_player && level.chips_remaining === 0) {
|
||||||
|
level.sfx.play_once('socket');
|
||||||
level.transmute_tile(me, 'floor');
|
level.transmute_tile(me, 'floor');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
BIN
sfx/bomb.ogg
Normal file
BIN
sfx/bomb.ogg
Normal file
Binary file not shown.
BIN
sfx/bummer.ogg
Normal file
BIN
sfx/bummer.ogg
Normal file
Binary file not shown.
BIN
sfx/bummer.wav
Normal file
BIN
sfx/bummer.wav
Normal file
Binary file not shown.
BIN
sfx/button-press.ogg
Normal file
BIN
sfx/button-press.ogg
Normal file
Binary file not shown.
BIN
sfx/button-release.ogg
Normal file
BIN
sfx/button-release.ogg
Normal file
Binary file not shown.
BIN
sfx/door.ogg
Normal file
BIN
sfx/door.ogg
Normal file
Binary file not shown.
BIN
sfx/get-chip.ogg
Normal file
BIN
sfx/get-chip.ogg
Normal file
Binary file not shown.
BIN
sfx/get-key.ogg
Normal file
BIN
sfx/get-key.ogg
Normal file
Binary file not shown.
BIN
sfx/get-tool.ogg
Normal file
BIN
sfx/get-tool.ogg
Normal file
Binary file not shown.
BIN
sfx/mmf-high.ogg
Normal file
BIN
sfx/mmf-high.ogg
Normal file
Binary file not shown.
BIN
sfx/mmf-orig.wav
Normal file
BIN
sfx/mmf-orig.wav
Normal file
Binary file not shown.
BIN
sfx/mmf.ogg
Normal file
BIN
sfx/mmf.ogg
Normal file
Binary file not shown.
BIN
sfx/socket.ogg
Normal file
BIN
sfx/socket.ogg
Normal file
Binary file not shown.
BIN
sfx/splash.ogg
Normal file
BIN
sfx/splash.ogg
Normal file
Binary file not shown.
BIN
sfx/step-floor.ogg
Normal file
BIN
sfx/step-floor.ogg
Normal file
Binary file not shown.
BIN
sfx/teleport.ogg
Normal file
BIN
sfx/teleport.ogg
Normal file
Binary file not shown.
BIN
sfx/thief.ogg
Normal file
BIN
sfx/thief.ogg
Normal file
Binary file not shown.
BIN
sfx/tick.ogg
Normal file
BIN
sfx/tick.ogg
Normal file
Binary file not shown.
BIN
sfx/timeup.ogg
Normal file
BIN
sfx/timeup.ogg
Normal file
Binary file not shown.
BIN
sfx/win.ogg
Normal file
BIN
sfx/win.ogg
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user