This commit is contained in:
syuilo 2024-01-09 20:49:26 +09:00
parent 9181e3db7d
commit f85b9107e2
3 changed files with 33 additions and 14 deletions

1
locales/index.d.ts vendored
View file

@ -1195,6 +1195,7 @@ export interface Locale {
"bubbleGame": string; "bubbleGame": string;
"sfx": string; "sfx": string;
"soundWillBePlayed": string; "soundWillBePlayed": string;
"showReplay": string;
"replay": string; "replay": string;
"replaying": string; "replaying": string;
"_announcement": { "_announcement": {

View file

@ -1192,6 +1192,7 @@ enableQuickAddMfmFunction: "高度なMFMのピッカーを表示する"
bubbleGame: "バブルゲーム" bubbleGame: "バブルゲーム"
sfx: "効果音" sfx: "効果音"
soundWillBePlayed: "サウンドが再生されます" soundWillBePlayed: "サウンドが再生されます"
showReplay: "リプレイを見る"
replay: "リプレイ" replay: "リプレイ"
replaying: "リプレイ中" replaying: "リプレイ中"

View file

@ -61,7 +61,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div> </div>
</div> </div>
</div> </div>
<div ref="containerEl" :class="[$style.gameContainer, { [$style.gameOver]: gameOver && !replaying }]" @contextmenu.stop.prevent @click.stop.prevent="onClick" @touchmove.stop.prevent="onTouchmove" @touchend="onTouchend" @mousemove="onMousemove"> <div ref="containerEl" :class="[$style.gameContainer, { [$style.gameOver]: isGameOver && !replaying }]" @contextmenu.stop.prevent @click.stop.prevent="onClick" @touchmove.stop.prevent="onTouchmove" @touchend="onTouchend" @mousemove="onMousemove">
<img v-if="defaultStore.state.darkMode" src="/client-assets/drop-and-fusion/frame-dark.svg" :class="$style.mainFrameImg"/> <img v-if="defaultStore.state.darkMode" src="/client-assets/drop-and-fusion/frame-dark.svg" :class="$style.mainFrameImg"/>
<img v-else src="/client-assets/drop-and-fusion/frame-light.svg" :class="$style.mainFrameImg"/> <img v-else src="/client-assets/drop-and-fusion/frame-light.svg" :class="$style.mainFrameImg"/>
<canvas ref="canvasEl" :class="$style.canvas"/> <canvas ref="canvasEl" :class="$style.canvas"/>
@ -74,7 +74,7 @@ SPDX-License-Identifier: AGPL-3.0-only
> >
<div v-show="combo > 1" :class="$style.combo" :style="{ fontSize: `${100 + ((comboPrev - 2) * 15)}%` }">{{ comboPrev }} Chain!</div> <div v-show="combo > 1" :class="$style.combo" :style="{ fontSize: `${100 + ((comboPrev - 2) * 15)}%` }">{{ comboPrev }} Chain!</div>
</Transition> </Transition>
<div v-if="!gameOver && !replaying" :class="$style.dropperContainer" :style="{ left: dropperX + 'px' }"> <div v-if="!isGameOver && !replaying" :class="$style.dropperContainer" :style="{ left: dropperX + 'px' }">
<!--<img v-if="currentPick" src="/client-assets/drop-and-fusion/dropper.png" :class="$style.dropper" :style="{ left: dropperX + 'px' }"/>--> <!--<img v-if="currentPick" src="/client-assets/drop-and-fusion/dropper.png" :class="$style.dropper" :style="{ left: dropperX + 'px' }"/>-->
<Transition <Transition
:enterActiveClass="$style.transition_picked_enterActive" :enterActiveClass="$style.transition_picked_enterActive"
@ -91,16 +91,11 @@ SPDX-License-Identifier: AGPL-3.0-only
<div :class="$style.dropGuide"/> <div :class="$style.dropGuide"/>
</template> </template>
</div> </div>
<div v-if="gameOver && !replaying" :class="$style.gameOverLabel"> <div v-if="isGameOver && !replaying" :class="$style.gameOverLabel">
<div class="_gaps_s"> <div class="_gaps_s">
<img src="/client-assets/drop-and-fusion/gameover.png" style="width: 200px; max-width: 100%; display: block; margin: auto; margin-bottom: -5px;"/> <img src="/client-assets/drop-and-fusion/gameover.png" style="width: 200px; max-width: 100%; display: block; margin: auto; margin-bottom: -5px;"/>
<div>SCORE: <MkNumber :value="score"/></div> <div>SCORE: <MkNumber :value="score"/></div>
<div>MAX CHAIN: <MkNumber :value="maxCombo"/></div> <div>MAX CHAIN: <MkNumber :value="maxCombo"/></div>
<div class="_buttonsCenter">
<MkButton primary rounded @click="restart">{{ i18n.ts.ok }}</MkButton>
<MkButton primary rounded @click="replay">{{ i18n.ts.replay }}</MkButton>
<MkButton primary rounded @click="share">{{ i18n.ts.share }}</MkButton>
</div>
</div> </div>
</div> </div>
<div v-if="replaying" :class="$style.replayIndicator"><span :class="$style.replayIndicatorText"><i class="ti ti-player-play"></i> {{ i18n.ts.replaying }}</span></div> <div v-if="replaying" :class="$style.replayIndicator"><span :class="$style.replayIndicatorText"><i class="ti ti-player-play"></i> {{ i18n.ts.replaying }}</span></div>
@ -112,6 +107,16 @@ SPDX-License-Identifier: AGPL-3.0-only
</div> </div>
</div> </div>
</div> </div>
<div v-if="isGameOver" :class="$style.frame">
<div :class="$style.frameInner">
<div class="_buttonsCenter">
<MkButton primary rounded @click="end">{{ i18n.ts.done }}</MkButton>
<MkButton primary rounded @click="replay">{{ i18n.ts.showReplay }}</MkButton>
<MkButton primary rounded @click="share">{{ i18n.ts.share }}</MkButton>
<MkButton rounded @click="exportLog">Copy replay data</MkButton>
</div>
</div>
</div>
<div style="display: flex;"> <div style="display: flex;">
<div :class="$style.frame" style="flex: 1; margin-right: 10px;"> <div :class="$style.frame" style="flex: 1; margin-right: 10px;">
<div :class="$style.frameInner"> <div :class="$style.frameInner">
@ -177,6 +182,7 @@ import { DropAndFusionGame, Mono } from '@/scripts/drop-and-fusion-engine.js';
import * as sound from '@/scripts/sound.js'; import * as sound from '@/scripts/sound.js';
import MkRange from '@/components/MkRange.vue'; import MkRange from '@/components/MkRange.vue';
import MkSwitch from '@/components/MkSwitch.vue'; import MkSwitch from '@/components/MkSwitch.vue';
import copyToClipboard from '@/scripts/copy-to-clipboard.js';
const NORMAL_BASE_SIZE = 30; const NORMAL_BASE_SIZE = 30;
const NORAML_MONOS: Mono[] = [{ const NORAML_MONOS: Mono[] = [{
@ -425,7 +431,7 @@ const comboPrev = ref(0);
const maxCombo = ref(0); const maxCombo = ref(0);
const dropReady = ref(true); const dropReady = ref(true);
const gameMode = ref<'normal' | 'square'>('normal'); const gameMode = ref<'normal' | 'square'>('normal');
const gameOver = ref(false); const isGameOver = ref(false);
const gameStarted = ref(false); const gameStarted = ref(false);
const highScore = ref<number | null>(null); const highScore = ref<number | null>(null);
const showConfig = ref(false); const showConfig = ref(false);
@ -472,9 +478,9 @@ function surrender() {
game.surrender(); game.surrender();
} }
function restart() { function end() {
game.dispose(); game.dispose();
gameOver.value = false; isGameOver.value = false;
currentPick.value = null; currentPick.value = null;
dropReady.value = true; dropReady.value = true;
stock.value = []; stock.value = [];
@ -513,6 +519,17 @@ function endReplay() {
game.dispose(); game.dispose();
} }
function exportLog() {
if (!logs) return;
const data = JSON.stringify({
seed: seed,
date: new Date().toISOString(),
logs: logs,
});
copyToClipboard(data);
os.success();
}
function attachGameEvents() { function attachGameEvents() {
game.addListener('changeScore', value => { game.addListener('changeScore', value => {
score.value = value; score.value = value;
@ -542,7 +559,7 @@ function attachGameEvents() {
dropReady.value = false; dropReady.value = false;
window.setTimeout(() => { window.setTimeout(() => {
if (!gameOver.value) { if (!isGameOver.value) {
dropReady.value = true; dropReady.value = true;
} }
}, game.DROP_INTERVAL); }, game.DROP_INTERVAL);
@ -581,7 +598,7 @@ function attachGameEvents() {
logs = game.getLogs(); logs = game.getLogs();
currentPick.value = null; currentPick.value = null;
dropReady.value = false; dropReady.value = false;
gameOver.value = true; isGameOver.value = true;
if (score.value > (highScore.value ?? 0)) { if (score.value > (highScore.value ?? 0)) {
highScore.value = score.value; highScore.value = score.value;
@ -749,7 +766,7 @@ useInterval(() => {
}, 1000, { immediate: false, afterMounted: true }); }, 1000, { immediate: false, afterMounted: true });
onDeactivated(() => { onDeactivated(() => {
restart(); end();
}); });
definePageMetadata({ definePageMetadata({