Implement game rules
This commit is contained in:
parent
5a39307fa6
commit
ffded017c7
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<img width="50px" :src="'Dice-' + number + '-b.svg'" alt="dice">
|
<img width="50px" :src="'Dice-' + number + '-b.svg'" alt="dice" :class="{ inverted: selected }">
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
@ -8,5 +8,14 @@ import {Component, Prop, Vue} from 'vue-property-decorator'
|
|||||||
@Component
|
@Component
|
||||||
export default class Die extends Vue {
|
export default class Die extends Vue {
|
||||||
@Prop() private number!: number;
|
@Prop() private number!: number;
|
||||||
|
@Prop() private selected!: boolean;
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.inverted {
|
||||||
|
// https://codepen.io/sosuke/pen/Pjoqqp
|
||||||
|
filter: invert(58%) sepia(99%) saturate(4021%) hue-rotate(203deg) brightness(103%) contrast(100%);
|
||||||
|
//filter: invert(43%) sepia(31%) saturate(2346%) hue-rotate(324deg) brightness(109%) contrast(113%);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
127
src/components/GameRulesEditor.vue
Normal file
127
src/components/GameRulesEditor.vue
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
<template>
|
||||||
|
<form>
|
||||||
|
Rules:<br/>
|
||||||
|
<md-field>
|
||||||
|
<label>Start dice count per player</label>
|
||||||
|
<md-input type="number" v-model="startDicePerPlayer" :readonly="readonly"></md-input>
|
||||||
|
</md-field>
|
||||||
|
<md-checkbox v-model="higherCountLowerValueEnabled" :disabled="readonly">
|
||||||
|
Higher count lower value
|
||||||
|
</md-checkbox>
|
||||||
|
<br/>
|
||||||
|
<md-checkbox v-model="jokerEnabled" :disabled="readonly">Joker enabled</md-checkbox>
|
||||||
|
<br/>
|
||||||
|
<md-checkbox v-model="jokerCountsDouble" :disabled="readonly">Joker counts double</md-checkbox>
|
||||||
|
<br/>
|
||||||
|
Joker die value: <br>
|
||||||
|
<span v-for="n in 6" @click="!readonly && (jokerDieValue = n)">
|
||||||
|
<die :number="n" :selected="jokerDieValue === n"></die>
|
||||||
|
</span> <br>
|
||||||
|
<md-checkbox v-model="palificoEnabled" :disabled="readonly">Palifico enabled</md-checkbox>
|
||||||
|
<br/>
|
||||||
|
<md-checkbox v-model="calzaEnabled" :disabled="readonly">Calza enabled</md-checkbox>
|
||||||
|
<br/>
|
||||||
|
<md-checkbox v-model="randomPlayerOrder" :disabled="readonly">Random player order</md-checkbox>
|
||||||
|
<br/>
|
||||||
|
<md-checkbox v-model="anonymizePlayers" :disabled="readonly">Anonymize players</md-checkbox>
|
||||||
|
</form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { Component, Prop, Vue } from 'vue-property-decorator'
|
||||||
|
import { GameRules } from "@/objects/objects";
|
||||||
|
import Die from "@/components/Die.vue";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
components: {Die}
|
||||||
|
})
|
||||||
|
export default class GameRulesEditor extends Vue {
|
||||||
|
@Prop() private value!: GameRules;
|
||||||
|
@Prop() private readonly!: boolean;
|
||||||
|
|
||||||
|
private get startDicePerPlayer (): number {
|
||||||
|
return this.value.startDicePerPlayer;
|
||||||
|
}
|
||||||
|
|
||||||
|
private set startDicePerPlayer (b: number) {
|
||||||
|
this.value.startDicePerPlayer = b;
|
||||||
|
this.emitRules();
|
||||||
|
}
|
||||||
|
|
||||||
|
private get jokerDieValue (): number {
|
||||||
|
return this.value.jokerDieValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private set jokerDieValue (b: number) {
|
||||||
|
this.value.jokerDieValue = b;
|
||||||
|
this.emitRules();
|
||||||
|
}
|
||||||
|
|
||||||
|
private get higherCountLowerValueEnabled (): boolean {
|
||||||
|
return this.value.higherCountLowerValueEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
private set higherCountLowerValueEnabled (b: boolean) {
|
||||||
|
this.value.higherCountLowerValueEnabled = b;
|
||||||
|
this.emitRules();
|
||||||
|
}
|
||||||
|
|
||||||
|
private get jokerEnabled (): boolean {
|
||||||
|
return this.value.jokerEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
private set jokerEnabled (b: boolean) {
|
||||||
|
this.value.jokerEnabled = b;
|
||||||
|
this.emitRules();
|
||||||
|
}
|
||||||
|
|
||||||
|
private get jokerCountsDouble (): boolean {
|
||||||
|
return this.value.jokerCountsDouble;
|
||||||
|
}
|
||||||
|
|
||||||
|
private set jokerCountsDouble (b: boolean) {
|
||||||
|
this.value.jokerCountsDouble = b;
|
||||||
|
this.emitRules();
|
||||||
|
}
|
||||||
|
|
||||||
|
private get palificoEnabled (): boolean {
|
||||||
|
return this.value.palificoEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
private set palificoEnabled (b: boolean) {
|
||||||
|
this.value.palificoEnabled = b;
|
||||||
|
this.emitRules();
|
||||||
|
}
|
||||||
|
|
||||||
|
private get calzaEnabled (): boolean {
|
||||||
|
return this.value.calzaEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
private set calzaEnabled (b: boolean) {
|
||||||
|
this.value.calzaEnabled = b;
|
||||||
|
this.emitRules();
|
||||||
|
}
|
||||||
|
|
||||||
|
private get randomPlayerOrder (): boolean {
|
||||||
|
return this.value.randomPlayerOrder;
|
||||||
|
}
|
||||||
|
|
||||||
|
private set randomPlayerOrder (b: boolean) {
|
||||||
|
this.value.randomPlayerOrder = b;
|
||||||
|
this.emitRules();
|
||||||
|
}
|
||||||
|
|
||||||
|
private get anonymizePlayers (): boolean {
|
||||||
|
return this.value.anonymizePlayers;
|
||||||
|
}
|
||||||
|
|
||||||
|
private set anonymizePlayers (b: boolean) {
|
||||||
|
this.value.anonymizePlayers = b;
|
||||||
|
this.emitRules();
|
||||||
|
}
|
||||||
|
|
||||||
|
private emitRules (): void {
|
||||||
|
this.$emit('input', this.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@ -1,65 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="hello center">
|
|
||||||
<img alt="Vue logo" src="../assets/logo.png">
|
|
||||||
<h1>{{ msg }}</h1>
|
|
||||||
<p>
|
|
||||||
For a guide and recipes on how to configure / customize this project,<br>
|
|
||||||
check out the
|
|
||||||
<a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>.
|
|
||||||
</p>
|
|
||||||
<h3>Installed CLI Plugins</h3>
|
|
||||||
<ul>
|
|
||||||
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank" rel="noopener">babel</a></li>
|
|
||||||
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-router" target="_blank" rel="noopener">router</a></li>
|
|
||||||
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-vuex" target="_blank" rel="noopener">vuex</a></li>
|
|
||||||
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint" target="_blank" rel="noopener">eslint</a></li>
|
|
||||||
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-typescript" target="_blank" rel="noopener">typescript</a></li>
|
|
||||||
</ul>
|
|
||||||
<h3>Essential Links</h3>
|
|
||||||
<ul>
|
|
||||||
<li><a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a></li>
|
|
||||||
<li><a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a></li>
|
|
||||||
<li><a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a></li>
|
|
||||||
<li><a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a></li>
|
|
||||||
<li><a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a></li>
|
|
||||||
</ul>
|
|
||||||
<h3>Ecosystem</h3>
|
|
||||||
<ul>
|
|
||||||
<li><a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a></li>
|
|
||||||
<li><a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a></li>
|
|
||||||
<li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li>
|
|
||||||
<li><a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li>
|
|
||||||
<li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { Component, Prop, Vue } from 'vue-property-decorator'
|
|
||||||
|
|
||||||
@Component
|
|
||||||
export default class HelloWorld extends Vue {
|
|
||||||
@Prop() private msg!: string;
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
|
||||||
<style scoped lang="scss">
|
|
||||||
h3 {
|
|
||||||
margin: 40px 0 0;
|
|
||||||
}
|
|
||||||
ul {
|
|
||||||
list-style-type: none;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
li {
|
|
||||||
display: inline-block;
|
|
||||||
margin: 0 10px;
|
|
||||||
}
|
|
||||||
a {
|
|
||||||
color: #42b983;
|
|
||||||
}
|
|
||||||
.center {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -11,7 +11,7 @@
|
|||||||
<td>
|
<td>
|
||||||
<die v-for="n in turn.diceCount" :number="turn.dieValue" :key="'g'+n+turn.dieValue"></die>
|
<die v-for="n in turn.diceCount" :number="turn.dieValue" :key="'g'+n+turn.dieValue"></die>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>x
|
||||||
</table>
|
</table>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -38,6 +38,19 @@ export interface GameStateObject {
|
|||||||
players: PlayerObject[],
|
players: PlayerObject[],
|
||||||
currentPlayer: PlayerObject,
|
currentPlayer: PlayerObject,
|
||||||
owningPlayer: PlayerObject,
|
owningPlayer: PlayerObject,
|
||||||
|
rules: GameRules
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GameRules {
|
||||||
|
startDicePerPlayer: number,
|
||||||
|
higherCountLowerValueEnabled: boolean,
|
||||||
|
jokerCountsDouble: boolean,
|
||||||
|
jokerEnabled: boolean,
|
||||||
|
palificoEnabled: boolean,
|
||||||
|
calzaEnabled: boolean,
|
||||||
|
jokerDieValue: number,
|
||||||
|
randomPlayerOrder: boolean,
|
||||||
|
anonymizePlayers: boolean,
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RoundObject {
|
export interface RoundObject {
|
||||||
|
@ -5,6 +5,7 @@ import 'vue-material/dist/vue-material.min.css'
|
|||||||
import 'vue-material/dist/theme/default-dark.css'
|
import 'vue-material/dist/theme/default-dark.css'
|
||||||
|
|
||||||
import MdButton from 'vue-material/dist/components/MdButton';
|
import MdButton from 'vue-material/dist/components/MdButton';
|
||||||
|
import MdCheckbox from 'vue-material/dist/components/MdCheckbox';
|
||||||
import MdField from 'vue-material/dist/components/MdField';
|
import MdField from 'vue-material/dist/components/MdField';
|
||||||
import MdApp from 'vue-material/dist/components/MdApp';
|
import MdApp from 'vue-material/dist/components/MdApp';
|
||||||
import MdAppContent from 'vue-material/dist/components/MdContent';
|
import MdAppContent from 'vue-material/dist/components/MdContent';
|
||||||
@ -12,6 +13,7 @@ Vue.use(MdButton);
|
|||||||
Vue.use(MdField);
|
Vue.use(MdField);
|
||||||
Vue.use(MdApp);
|
Vue.use(MdApp);
|
||||||
Vue.use(MdAppContent);
|
Vue.use(MdAppContent);
|
||||||
|
Vue.use(MdCheckbox)
|
||||||
|
|
||||||
Vue.use(VueRouter)
|
Vue.use(VueRouter)
|
||||||
|
|
||||||
|
@ -1,5 +1,13 @@
|
|||||||
import axios, {AxiosPromise, AxiosResponse} from 'axios'
|
import axios, {AxiosPromise, AxiosResponse} from 'axios'
|
||||||
import {JoinCreateGameObject, IsStartedObject, ApiObject, GameStateObject, MyTurnObject, GuessAction} from "@/objects/objects";
|
import {
|
||||||
|
JoinCreateGameObject,
|
||||||
|
IsStartedObject,
|
||||||
|
ApiObject,
|
||||||
|
GameStateObject,
|
||||||
|
MyTurnObject,
|
||||||
|
GuessAction,
|
||||||
|
GameRules
|
||||||
|
} from "@/objects/objects";
|
||||||
|
|
||||||
export default class PerudoApi {
|
export default class PerudoApi {
|
||||||
private static baseUrl = process.env.VUE_APP_BASE_URL;
|
private static baseUrl = process.env.VUE_APP_BASE_URL;
|
||||||
@ -27,6 +35,13 @@ export default class PerudoApi {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public setGameRules(playerId: string, rules: GameRules): Promise<ApiObject> {
|
||||||
|
return this.post<ApiObject>('game/rules/' + playerId, rules)
|
||||||
|
.then((response: AxiosResponse<ApiObject>) => {
|
||||||
|
return response.data;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public gameStarted(playerId: string): Promise<IsStartedObject> {
|
public gameStarted(playerId: string): Promise<IsStartedObject> {
|
||||||
return this.get<IsStartedObject>('game/started/' + playerId)
|
return this.get<IsStartedObject>('game/started/' + playerId)
|
||||||
.then((response: AxiosResponse<IsStartedObject>) => {
|
.then((response: AxiosResponse<IsStartedObject>) => {
|
||||||
|
1
src/typings/vue-material.d.ts
vendored
1
src/typings/vue-material.d.ts
vendored
@ -1,5 +1,6 @@
|
|||||||
declare module 'vue-material';
|
declare module 'vue-material';
|
||||||
declare module 'vue-material/dist/components/MdButton';
|
declare module 'vue-material/dist/components/MdButton';
|
||||||
|
declare module 'vue-material/dist/components/MdCheckbox';
|
||||||
declare module 'vue-material/dist/components/MdField';
|
declare module 'vue-material/dist/components/MdField';
|
||||||
declare module 'vue-material/dist/components/MdApp';
|
declare module 'vue-material/dist/components/MdApp';
|
||||||
declare module 'vue-material/dist/components/MdContent';
|
declare module 'vue-material/dist/components/MdContent';
|
||||||
|
@ -39,8 +39,8 @@
|
|||||||
<md-input type="number" v-model="diceCount"></md-input>
|
<md-input type="number" v-model="diceCount"></md-input>
|
||||||
</md-field>
|
</md-field>
|
||||||
Die value: <br>
|
Die value: <br>
|
||||||
<span v-for="n in 6" :key="'v'+n" @click="dieValue = n" :class="(dieValue === n) ? 'inverted' : ''">
|
<span v-for="n in 6" :key="'v'+n" @click="dieValue = n">
|
||||||
<die :number="n"></die>
|
<die :number="n" :selected="dieValue === n"></die>
|
||||||
</span> <br><br>
|
</span> <br><br>
|
||||||
<md-button @click="makeGuess" class="md-raised md-primary">Guess</md-button>
|
<md-button @click="makeGuess" class="md-raised md-primary">Guess</md-button>
|
||||||
<md-button @click="callBluff" class="md-raised md-accent">Call</md-button>
|
<md-button @click="callBluff" class="md-raised md-accent">Call</md-button>
|
||||||
@ -62,6 +62,8 @@
|
|||||||
<template v-for="player in gameStateObject.players">
|
<template v-for="player in gameStateObject.players">
|
||||||
- {{ player.name }}<br>
|
- {{ player.name }}<br>
|
||||||
</template>
|
</template>
|
||||||
|
<br/>
|
||||||
|
<game-rules-editor v-model="rules" :readonly="!owner"/>
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -70,7 +72,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-if="gameStateObject && gameRunning">
|
<template v-if="gameStateObject && gameRunning">
|
||||||
<span v-if="previousRound && previousRound.loser.hash === playerHash">You lost the previous round!<br></span>
|
<span
|
||||||
|
v-if="previousRound && previousRound.loser.hash === playerHash">You lost the previous round!<br></span>
|
||||||
Round: {{ currentRound.number + 1 }} <br>
|
Round: {{ currentRound.number + 1 }} <br>
|
||||||
Turn: {{ lastTurn ? lastTurn.number + 2 : 1 }} <br>
|
Turn: {{ lastTurn ? lastTurn.number + 2 : 1 }} <br>
|
||||||
|
|
||||||
@ -124,13 +127,15 @@ import {
|
|||||||
RoundObject,
|
RoundObject,
|
||||||
TurnObject,
|
TurnObject,
|
||||||
GameStateState,
|
GameStateState,
|
||||||
PlayerObject
|
PlayerObject,
|
||||||
|
GameRules
|
||||||
} from "@/objects/objects";
|
} from "@/objects/objects";
|
||||||
import Round from "@/components/Round.vue";
|
import Round from "@/components/Round.vue";
|
||||||
import RoundTurns from "@/components/RoundTurns.vue";
|
import RoundTurns from "@/components/RoundTurns.vue";
|
||||||
|
import GameRulesEditor from "@/components/GameRulesEditor.vue";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
components: {RoundTurns, Round, Die}
|
components: {GameRulesEditor, RoundTurns, Round, Die}
|
||||||
})
|
})
|
||||||
export default class Home extends Vue {
|
export default class Home extends Vue {
|
||||||
private gameState: GameState = GameState.Setup;
|
private gameState: GameState = GameState.Setup;
|
||||||
@ -194,6 +199,17 @@ export default class Home extends Vue {
|
|||||||
return turns ? turns[turns.length - 1] : undefined;
|
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 {
|
private createGame (): void {
|
||||||
if (this.name === '') {
|
if (this.name === '') {
|
||||||
this.error = "Name cannot be empty";
|
this.error = "Name cannot be empty";
|
||||||
@ -206,7 +222,7 @@ export default class Home extends Vue {
|
|||||||
this.owner = true;
|
this.owner = true;
|
||||||
|
|
||||||
this.gameState = GameState.Joined;
|
this.gameState = GameState.Joined;
|
||||||
this.gameTimer = setInterval(() => {
|
setTimeout(() => {
|
||||||
this.checkStarted();
|
this.checkStarted();
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}).catch((reason => {
|
}).catch((reason => {
|
||||||
@ -241,6 +257,7 @@ export default class Home extends Vue {
|
|||||||
PerudoApi.instance.startGame(this.playerId).then((response: ApiObject) => {
|
PerudoApi.instance.startGame(this.playerId).then((response: ApiObject) => {
|
||||||
this.gameState = GameState.Started;
|
this.gameState = GameState.Started;
|
||||||
this.gameStateObject = null; // Bug fix because checkStarted gameStateObject misses some properties
|
this.gameStateObject = null; // Bug fix because checkStarted gameStateObject misses some properties
|
||||||
|
this.checkTurn();
|
||||||
}).catch((reason => {
|
}).catch((reason => {
|
||||||
this.error = reason;
|
this.error = reason;
|
||||||
}));
|
}));
|
||||||
@ -283,6 +300,7 @@ export default class Home extends Vue {
|
|||||||
if (this.gameJoined && this.playerId) {
|
if (this.gameJoined && this.playerId) {
|
||||||
PerudoApi.instance.gameStarted(this.playerId).then((response: IsStartedObject) => {
|
PerudoApi.instance.gameStarted(this.playerId).then((response: IsStartedObject) => {
|
||||||
this.gameStateObject = response.gameState;
|
this.gameStateObject = response.gameState;
|
||||||
|
console.log(this.gameStateObject.rules);
|
||||||
if (response.started) {
|
if (response.started) {
|
||||||
this.gameState = GameState.Started;
|
this.gameState = GameState.Started;
|
||||||
|
|
||||||
@ -326,9 +344,3 @@ export default class Home extends Vue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
.inverted {
|
|
||||||
filter: invert(1);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
Loading…
Reference in New Issue
Block a user