347 lines
11 KiB
Vue
347 lines
11 KiB
Vue
<template>
|
|
<div>
|
|
<div class="md-layout" v-if="error" @click="error = null">
|
|
<div class="md-layout-item">
|
|
<md-app>
|
|
<md-app-content>
|
|
Error: <br>
|
|
{{ error }}
|
|
</md-app-content>
|
|
</md-app>
|
|
</div>
|
|
</div>
|
|
<br>
|
|
<div class="md-layout">
|
|
<div class="md-layout-item">
|
|
<md-app>
|
|
<md-app-content>
|
|
<md-field>
|
|
<label>Name</label>
|
|
<md-input v-model="name" :readonly="gameJoined"></md-input>
|
|
</md-field>
|
|
<md-field v-if="!gameStarted">
|
|
<label>Game code</label>
|
|
<md-input v-model="code" :readonly="gameJoined"></md-input>
|
|
</md-field>
|
|
<template v-if="!gameJoined">
|
|
<md-button @click="createGame" class="md-raised">Create</md-button>
|
|
<md-button @click="joinGame" class="md-raised">Join</md-button>
|
|
</template>
|
|
|
|
<template v-if="gameJoined && !gameStarted && owner">
|
|
<md-button @click="startGame" class="md-raised md-primary">Start</md-button>
|
|
</template>
|
|
|
|
<template v-if="myTurn && !gameEnded">
|
|
It is your turn, make a guess: <br>
|
|
<md-field>
|
|
<label>Dice count</label>
|
|
<md-input type="number" v-model="diceCount"></md-input>
|
|
</md-field>
|
|
Die value: <br>
|
|
<span v-for="n in 6" :key="'v'+n" @click="dieValue = n">
|
|
<die :number="n" :selected="dieValue === n"></die>
|
|
</span> <br><br>
|
|
<md-button @click="makeGuess" class="md-raised md-primary">Guess</md-button>
|
|
<md-button @click="callBluff" class="md-raised md-accent">Call</md-button>
|
|
</template>
|
|
</md-app-content>
|
|
</md-app>
|
|
</div>
|
|
|
|
<div class="md-layout-item">
|
|
<md-app>
|
|
<md-app-content>
|
|
<template v-if="gameJoined && !gameStarted">
|
|
<span v-if="owner">Game created!</span>
|
|
<span v-else>Game joined, now waiting or game to start</span>
|
|
<br>
|
|
PlayerId: {{ playerId }} <br>
|
|
<template v-if="gameStateObject">
|
|
Players: <br>
|
|
<template v-for="player in gameStateObject.players">
|
|
- {{ player.name }}<br>
|
|
</template>
|
|
<br/>
|
|
<game-rules-editor v-model="rules" :readonly="!owner"/>
|
|
</template>
|
|
</template>
|
|
|
|
<template v-if="gameRunning">
|
|
The game has started, lets go! <br>
|
|
</template>
|
|
|
|
<template v-if="gameStateObject && gameRunning">
|
|
<span
|
|
v-if="previousRound && previousRound.loser.hash === playerHash">You lost the previous round!<br></span>
|
|
Round: {{ currentRound.number + 1 }} <br>
|
|
Turn: {{ lastTurn ? lastTurn.number + 2 : 1 }} <br>
|
|
|
|
Your throw: <br>
|
|
<template v-for="(count, number) in currentRound.myRolls">
|
|
<die v-for="n in count" :number="number" :key="'t'+n+number"></die>
|
|
</template>
|
|
<br><br>
|
|
<template v-if="lastTurn">
|
|
Last guesses: <br>
|
|
<round-turns :round="currentRound"/>
|
|
</template>
|
|
<br>
|
|
<template v-if="!myTurn">Someone else is playing, waiting for your turn<br></template>
|
|
Players: <br>
|
|
<template v-for="player in gameStateObject.players">
|
|
-{{ player.hash === gameStateObject.currentPlayer.hash ? '>' : '-' }}{{ player.name }}<br>
|
|
</template>
|
|
<br>
|
|
</template>
|
|
|
|
<template v-if="gameEnded">
|
|
The game is over, the winner is: {{ gameStateObject.currentPlayer.name }}<br>
|
|
</template>
|
|
</md-app-content>
|
|
</md-app>
|
|
</div>
|
|
</div>
|
|
<br>
|
|
<template v-if="gameStateObject && gameStarted">
|
|
History: <br>
|
|
<template v-for="round in gameStateObject.rounds.slice().reverse()">
|
|
<round :round="round" :players="playersKeyedById"/>
|
|
<br>
|
|
</template>
|
|
</template>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import { Component, Vue } from 'vue-property-decorator'
|
|
import PerudoApi from "@/services/PerudoApi";
|
|
import Die from "@/components/Die.vue";
|
|
import {
|
|
ApiObject,
|
|
GameState,
|
|
GameStateObject,
|
|
IsStartedObject,
|
|
JoinCreateGameObject,
|
|
MyTurnObject,
|
|
RoundObject,
|
|
TurnObject,
|
|
GameStateState,
|
|
PlayerObject,
|
|
GameRules
|
|
} from "@/objects/objects";
|
|
import Round from "@/components/Round.vue";
|
|
import RoundTurns from "@/components/RoundTurns.vue";
|
|
import GameRulesEditor from "@/components/GameRulesEditor.vue";
|
|
|
|
@Component({
|
|
components: {GameRulesEditor, RoundTurns, Round, Die}
|
|
})
|
|
export default class Home extends Vue {
|
|
private gameState: GameState = GameState.Setup;
|
|
private gameStateObject: GameStateObject | null = null;
|
|
private error: string | null = null;
|
|
|
|
private name: string = process.env.VUE_APP_NAME;
|
|
private code: string = '';
|
|
private owner: boolean = false;
|
|
|
|
private playerId: string | null = null;
|
|
private playerHash: string | null = null;
|
|
private gameTimer: number | null = null;
|
|
|
|
private diceCount: string = '1';
|
|
private dieValue: number = 2;
|
|
|
|
private get gameJoined (): boolean {
|
|
return this.gameState >= GameState.Joined;
|
|
}
|
|
|
|
private get gameStarted (): boolean {
|
|
return this.gameState >= GameState.Started;
|
|
}
|
|
|
|
private get gameRunning (): boolean {
|
|
return this.gameStarted && !this.gameEnded;
|
|
}
|
|
|
|
private get gameEnded (): boolean {
|
|
return this.gameState === GameState.Ended;
|
|
}
|
|
|
|
private get myTurn (): boolean {
|
|
return this.gameState === GameState.MyTurn;
|
|
}
|
|
|
|
private get playersKeyedById (): Record<string, PlayerObject> | undefined {
|
|
let newPlayers: Record<string, PlayerObject> = {};
|
|
if (this.gameStateObject) {
|
|
let players = this.gameStateObject.players;
|
|
for (let key in players) {
|
|
newPlayers[players[key].hash] = players[key];
|
|
}
|
|
}
|
|
return newPlayers;
|
|
}
|
|
|
|
private get previousRound (): RoundObject | undefined {
|
|
let rounds = this.gameStateObject?.rounds;
|
|
return rounds ? (rounds[rounds.length - 2] ?? undefined) : undefined;
|
|
}
|
|
|
|
private get currentRound (): RoundObject | undefined {
|
|
let rounds = this.gameStateObject?.rounds;
|
|
return rounds ? rounds[rounds.length - 1] : undefined;
|
|
}
|
|
|
|
private get lastTurn (): TurnObject | undefined {
|
|
let turns = this.currentRound?.turns;
|
|
return turns ? turns[turns.length - 1] : undefined;
|
|
}
|
|
|
|
private get rules (): GameRules | undefined {
|
|
return this.gameStateObject?.rules;
|
|
}
|
|
|
|
private set rules (gameRules: GameRules | undefined) {
|
|
console.log(gameRules);
|
|
if (this.playerId && gameRules) {
|
|
PerudoApi.instance.setGameRules(this.playerId, gameRules);
|
|
}
|
|
}
|
|
|
|
private createGame (): void {
|
|
if (this.name === '') {
|
|
this.error = "Name cannot be empty";
|
|
return;
|
|
}
|
|
PerudoApi.instance.createGame(this.name).then((response: JoinCreateGameObject) => {
|
|
this.playerId = response.player.id;
|
|
this.playerHash = response.player.hash;
|
|
this.code = response.code;
|
|
this.owner = true;
|
|
|
|
this.gameState = GameState.Joined;
|
|
this.gameTimer = setInterval(() => {
|
|
this.checkStarted();
|
|
}, 1000);
|
|
}).catch((reason => {
|
|
this.error = reason;
|
|
}));
|
|
}
|
|
|
|
private joinGame (): void {
|
|
if (this.code === '') {
|
|
this.error = "Game code cannot be empty when joining a game";
|
|
return;
|
|
}
|
|
if (this.name === '') {
|
|
this.error = "Name cannot be empty";
|
|
return;
|
|
}
|
|
PerudoApi.instance.joinGame(this.name, this.code).then((response: JoinCreateGameObject) => {
|
|
this.playerId = response.player.id;
|
|
this.playerHash = response.player.hash;
|
|
this.gameTimer = setInterval(() => {
|
|
this.checkStarted();
|
|
}, 1000);
|
|
|
|
this.gameState = GameState.Joined;
|
|
}).catch((reason => {
|
|
this.error = reason;
|
|
}));
|
|
}
|
|
|
|
private startGame (): void {
|
|
if (this.gameJoined && this.playerId) {
|
|
PerudoApi.instance.startGame(this.playerId).then((response: ApiObject) => {
|
|
this.gameState = GameState.Started;
|
|
this.gameStateObject = null; // Bug fix because checkStarted gameStateObject misses some properties
|
|
this.checkTurn();
|
|
}).catch((reason => {
|
|
this.error = reason;
|
|
}));
|
|
}
|
|
}
|
|
|
|
private makeGuess (): void {
|
|
if (this.myTurn && this.playerId) {
|
|
PerudoApi.instance.makeGuess(this.playerId, {
|
|
diceCount: parseInt(this.diceCount),
|
|
dieValue: this.dieValue,
|
|
}).then((response: MyTurnObject) => {
|
|
this.gameState = GameState.Started;
|
|
this.gameTimer = setInterval(() => {
|
|
this.checkTurn();
|
|
}, 1000);
|
|
this.checkTurn();
|
|
}).catch((reason => {
|
|
this.error = reason;
|
|
}));
|
|
}
|
|
}
|
|
|
|
private callBluff (): void {
|
|
if (this.myTurn && this.playerId) {
|
|
PerudoApi.instance.callBluff(this.playerId).then((response: MyTurnObject) => {
|
|
this.gameState = GameState.Started;
|
|
this.gameTimer = setInterval(() => {
|
|
this.checkTurn();
|
|
}, 1000);
|
|
this.checkTurn();
|
|
}).catch((reason => {
|
|
this.error = reason;
|
|
}));
|
|
}
|
|
}
|
|
|
|
private checkStarted (): void {
|
|
console.log("Check started");
|
|
if (this.gameJoined && this.playerId) {
|
|
PerudoApi.instance.gameStarted(this.playerId).then((response: IsStartedObject) => {
|
|
this.gameStateObject = response.gameState;
|
|
console.log(this.gameStateObject.rules);
|
|
if (response.started) {
|
|
this.gameState = GameState.Started;
|
|
|
|
this.clearGameTimer();
|
|
this.gameTimer = setInterval(() => {
|
|
this.checkTurn();
|
|
}, 1000);
|
|
}
|
|
}).catch((reason => {
|
|
this.error = reason;
|
|
}));
|
|
}
|
|
}
|
|
|
|
private checkTurn (): void {
|
|
console.log("Check turn");
|
|
if (this.gameStarted && this.playerId) {
|
|
PerudoApi.instance.myTurn(this.playerId).then((response: MyTurnObject) => {
|
|
this.gameStateObject = response.gameState;
|
|
if (this.gameStateObject.state === GameStateState.Ended) {
|
|
this.gameState = GameState.Ended;
|
|
this.clearGameTimer();
|
|
}
|
|
if (response.turn) {
|
|
this.gameState = GameState.MyTurn;
|
|
this.diceCount = this.lastTurn?.diceCount.toString() ?? this.diceCount;
|
|
this.dieValue = this.lastTurn?.dieValue ?? this.dieValue;
|
|
this.clearGameTimer();
|
|
|
|
console.log(this.gameStateObject);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
private clearGameTimer (): void {
|
|
if (this.gameTimer) {
|
|
clearInterval(this.gameTimer);
|
|
this.gameTimer = null;
|
|
}
|
|
}
|
|
}
|
|
</script>
|