add audio options, improve sfx handling code

This commit is contained in:
Omsi 2020-06-14 22:01:26 -07:00
parent 78f6351dea
commit c7c04e664e
17 changed files with 115 additions and 46 deletions

BIN
audio/Fix Infinity.wav Normal file

Binary file not shown.

BIN
audio/Tab changed deep.wav Normal file

Binary file not shown.

View File

@ -369,6 +369,7 @@
<script type="text/javascript" src="javascripts/components/modals/modal-start-eternity-challenge.js"></script>
<script type="text/javascript" src="javascripts/components/modals/options/modal-options.js"></script>
<script type="text/javascript" src="javascripts/components/modals/options/modal-news-options.js"></script>
<script type="text/javascript" src="javascripts/components/modals/options/modal-audio-options.js"></script>
<script type="text/javascript" src="javascripts/components/modals/options/modal-animation-options.js"></script>
<script type="text/javascript" src="javascripts/components/modals/options/modal-confirmation-options.js"></script>
<script type="text/javascript" src="javascripts/components/modals/options/modal-info-display-options.js"></script>

View File

@ -0,0 +1,59 @@
"use strict";
Vue.component("modal-audio-options", {
data() {
return {
dimensionBoost: 0,
antimatterGalaxy: 0,
glyphMoved: 0,
tabChanged: 0,
achievementUnlocked: 0,
breakInfinity: 0,
fixInfinity: 0
};
},
computed: {
sounds() {
return GameDatabase.sounds;
}
},
methods: {
update() {
const sounds = Object.keys(this.$data);
const options = player.options.audio;
for (const sound of sounds) {
this[sound] = options[sound];
}
},
updateOption(sound) {
const name = `${sound.name.camelize()}`;
player.options.audio[name] = (player.options.audio[name] + 1) % this.getLabels(sound.options).length;
},
getText(name) {
return `${name}: `;
},
getLabels(options) {
if (options) {
const labels = options.distinct();
labels.unshift("Off");
return labels;
}
return ["Off", "On"];
},
getButtonText(sound) {
const labelIndex = this[`${sound.name.camelize()}`];
return `${sound.name}: ${this.getLabels(sound.options)[labelIndex]}`;
}
},
template: `
<modal-options @close="emitClose">
<primary-button
v-for="(sound, index) in sounds"
:key="index"
@click="updateOption(sound)"
class="o-primary-btn--option"
>
{{ getButtonText(sound) }}
</primary-button>
</modal-options>`
});

View File

@ -119,6 +119,10 @@ Vue.component("options-visual-tab", {
class="o-primary-btn--option"
onclick="Modal.infoDisplayOptions.show()"
>Open Info Display Options</options-button>
<options-button
class="o-primary-btn--option"
onclick="Modal.audioOptions.show();"
>Open Audio Options</options-button>
</div>
<p onclick="Modal.shortcuts.show()" class="c-options-tab__shortcuts-link">
Press <kbd>?</kbd> to open shortcut list.

View File

@ -54,6 +54,7 @@ class ChallengeConfirmationModal extends Modal {
Modal.h2p = new Modal("modal-h2p");
Modal.shortcuts = new Modal("modal-shortcuts");
Modal.newsOptions = new Modal("modal-news-options");
Modal.audioOptions = new Modal("modal-audio-options");
Modal.animationOptions = new Modal("modal-animation-options");
Modal.confirmationOptions = new Modal("modal-confirmation-options");
Modal.infoDisplayOptions = new Modal("modal-info-display-options");

View File

@ -97,7 +97,12 @@ function safeCall(fn) {
}
String.prototype.capitalize = function() {
return this.toLowerCase().replace(/^\w/, c => c.toUpperCase());
return this.toLowerCase().replace(/^\w/u, c => c.toUpperCase());
};
String.prototype.camelize = function() {
// eslint-disable-next-line no-unused-vars
return this.toLowerCase().replace(/[^a-zA-Z0-9]+(.)/gu, (x, char) => char.toUpperCase());
};
String.prototype.splice = function(start, delCount, newSubStr) {

View File

@ -506,6 +506,15 @@ let player = {
AIChance: 0,
speed: 1
},
audio: {
dimensionBoost: 0,
antimatterGalaxy: 0,
glyphMoved: 0,
tabChanged: 0,
achievementUnlocked: 0,
breakInfinity: 0,
fixInfinity: 0
},
notation: "Mixed scientific",
retryChallenge: false,
retryCelestial: false,

View File

@ -541,6 +541,7 @@ const Glyphs = {
this.updateRealityGlyphEffects();
this.updateGlyphCountForV();
EventHub.dispatch(GAME_EVENT.GLYPHS_CHANGED);
EventHub.dispatch(GAME_EVENT.GLYPHS_MOVED);
this.validate();
},
unequipAll() {
@ -554,6 +555,7 @@ const Glyphs = {
this.updateRealityGlyphEffects();
this.updateGlyphCountForV();
EventHub.dispatch(GAME_EVENT.GLYPHS_CHANGED);
EventHub.dispatch(GAME_EVENT.GLYPHS_MOVED);
},
unequip(activeIndex, requestedInventoryIndex) {
if (this.active[activeIndex] === null) return;
@ -565,6 +567,7 @@ const Glyphs = {
this.updateRealityGlyphEffects();
this.updateGlyphCountForV();
EventHub.dispatch(GAME_EVENT.GLYPHS_CHANGED);
EventHub.dispatch(GAME_EVENT.GLYPHS_MOVED);
},
updateRealityGlyphEffects() {
// There should only be one reality glyph; this picks one pseudo-randomly if multiple are cheated/glitched in
@ -591,6 +594,7 @@ const Glyphs = {
this.inventory[targetSlot] = glyph;
glyph.idx = targetSlot;
EventHub.dispatch(GAME_EVENT.GLYPHS_CHANGED);
EventHub.dispatch(GAME_EVENT.GLYPHS_MOVED);
} else {
throw new Error("Attempted glyph move into non-empty slot");
}
@ -606,6 +610,7 @@ const Glyphs = {
glyphB.idx = swapGlyph;
this.validate();
EventHub.dispatch(GAME_EVENT.GLYPHS_CHANGED);
EventHub.dispatch(GAME_EVENT.GLYPHS_MOVED);
},
addToInventory(glyph, requestedInventoryIndex) {
this.validate();

View File

@ -2,39 +2,32 @@
GameDatabase.sounds = [
{
id: 1,
fileName: "dimension_boost",
checkRequirement: () => true,
checkEvent: GameEvent.DIMBOOST_AFTER
name: "Dimension Boost",
checkEvent: GAME_EVENT.DIMBOOST_AFTER
},
{
id: 2,
fileName: "galaxy",
checkRequirement: () => true,
checkEvent: GameEvent.GALAXY_RESET_AFTER
name: "Antimatter Galaxy",
checkEvent: GAME_EVENT.GALAXY_RESET_AFTER
},
{
id: 3,
fileName: "glyphs_changed",
checkRequirement: () => true,
checkEvent: GameEvent.GLYPHS_CHANGED
name: "Glyph moved",
checkEvent: GAME_EVENT.GLYPHS_MOVED
},
{
id: 4,
fileName: "tab_change",
checkRequirement: () => true,
checkEvent: GameEvent.TAB_CHANGED
name: "Tab changed",
options: ["Clicky", "Deep"],
checkEvent: GAME_EVENT.TAB_CHANGED
},
{
id: 5,
fileName: "achievement_unlocked",
checkRequirement: () => true,
checkEvent: GameEvent.ACHIEVEMENT_UNLOCKED
name: "Achievement unlocked",
checkEvent: GAME_EVENT.ACHIEVEMENT_UNLOCKED
},
{
id: 6,
fileName: "break_infinity",
checkRequirement: () => true,
checkEvent: GameEvent.BREAK_INFINITY
name: "Break Infinity",
checkEvent: GAME_EVENT.BREAK_INFINITY
},
{
name: "Fix Infinity",
checkEvent: GAME_EVENT.FIX_INFINITY
},
];

View File

@ -1,40 +1,32 @@
"use strict";
class SoundEffectState {
class SoundEffectState extends GameMechanicState {
constructor(config) {
if (!config) throw new Error("Must specify config for SoundEffectState");
this.config = config;
super(config);
this.registerEvents(config.checkEvent, args => this.tryPlay(args));
}
static createIndex(gameData) {
this.index = mapGameData(gameData, config => new this(config));
}
play() {
const sound = new Audio(`audio/${this.config.fileName}.wav`);
tryPlay() {
const option = player.options.audio[this.config.name.camelize()];
if (option === 0) return;
const path = this.config.options
? `audio/${this.config.name} ${this.config.options[option - 1].toLowerCase()}.wav`
: `audio/${this.config.name}.wav`;
const sound = new Audio(path);
sound.volume = 0.5;
sound.play();
}
}
SoundEffectState.createIndex(GameDatabase.sounds);
/**
* @param {number} id
* @returns {SoundEffectState}
*/
const SoundEffect = id => SoundEffectState.index[id];
const SoundEffect = SoundEffectState.createAccessor(GameDatabase.sounds);
const SoundEffects = {
/**
* @type {SoundEffectState[]}
*/
all: SoundEffectState.index.compact()
};
EventHub.registerStateCollectionEvents(
SoundEffects.all,
sound => sound.config.checkEvent,
// eslint-disable-next-line max-params
sound => sound.play()
);
all: SoundEffect.index.compact()
};