Browse Source

Add an action button component; fix struggle text

master
Fen Dweller 5 years ago
parent
commit
8da6b66bd6
6 changed files with 86 additions and 38 deletions
  1. +39
    -0
      src/components/ActionButton.vue
  2. +22
    -13
      src/components/Combat.vue
  3. +5
    -4
      src/components/Statblock.vue
  4. +3
    -3
      src/game/combat.ts
  5. +12
    -0
      src/game/entity.ts
  6. +5
    -18
      src/game/interface.ts

+ 39
- 0
src/components/ActionButton.vue View File

@@ -0,0 +1,39 @@
<template>
<button class="action-button" @click="execute">
{{ action.name }}
</button>
</template>

<script lang="ts">

import { Component, Prop, Vue, Watch, Emit } from 'vue-property-decorator'
import { Action } from '@/game/combat'
import { Creature } from '@/game/entity'

@Component({})
export default class ActionButton extends Vue {
@Prop()
action!: Action

@Prop()
user!: Creature

@Prop()
target!: Creature

@Emit("execute")
execute () {
this.$emit('executed', this.action.execute(this.user, this.target))
}
}

</script>

<style scoped>

.action-button {
width: 100px;
height: 100px;
}

</style>

+ 22
- 13
src/components/Combat.vue View File

@@ -5,21 +5,28 @@
<Statblock :subject="player" /> <Statblock :subject="player" />
<Statblock :subject="enemy" /> <Statblock :subject="enemy" />
</div> </div>
<div id="log"></div>
<div id="log">
<div v-for="(entry, index) in combatLog" :key="'log' + index">
<div v-for="(line, lineIndex) in entry.render()" :key="index + ' ' + lineIndex">
{{ line }}
</div>
<br>
</div>
</div>
<div class="horiz-display"> <div class="horiz-display">
<div> <div>
<h2>Your moves</h2> <h2>Your moves</h2>
<div class="vert-display"> <div class="vert-display">
<button class="combat-button" @mouseleave="actionDescription= ''" @mouseover="actionDescription = action.desc" v-for="action in player.validActions(enemy)" :key="'player-' + action.name" v-on:click="log(action.execute(player, enemy))">{{action.name}}</button>
<button class="combat-button" @mouseleave="actionDescription= ''" @mouseover="actionDescription = action.desc" v-for="action in player.validActions(player)" :key="'player-' + action.name" v-on:click="log(action.execute(player, player))">{{action.name}}</button>
<ActionButton @executed="executed" v-for="action in player.validActions(enemy)" :key="'player' + action.name" :action="action" :user="player" :target="enemy" />
<ActionButton @executed="executed" v-for="action in player.validActions(player)" :key="'player' + action.name" :action="action" :user="player" :target="enemy" />
</div> </div>
<div>{{actionDescription}}</div> <div>{{actionDescription}}</div>
</div> </div>
<div> <div>
<h2>Enemy moves</h2> <h2>Enemy moves</h2>
<div class="vert-display"> <div class="vert-display">
<button class="combat-button" v-for="action in enemy.validActions(player)" :key="'enemy-' + action.name" v-on:click="log(action.execute(enemy, player))">{{action.name}}</button>
<button class="combat-button" v-for="action in enemy.validActions(enemy)" :key="'enemy-' + action.name" v-on:click="log(action.execute(enemy, enemy))">{{action.name}}</button>
<ActionButton @executed="executed" v-for="action in enemy.validActions(player)" :key="'player' + action.name" :action="action" :user="enemy" :target="player" />
<ActionButton @executed="executed" v-for="action in enemy.validActions(enemy)" :key="'player' + action.name" :action="action" :user="enemy" :target="player" />
</div> </div>
</div> </div>
</div> </div>
@@ -29,12 +36,13 @@
<script lang="ts"> <script lang="ts">
import { Component, Prop, Vue, Watch, Emit } from 'vue-property-decorator' import { Component, Prop, Vue, Watch, Emit } from 'vue-property-decorator'
import { Creature, POV } from '@/game/entity' import { Creature, POV } from '@/game/entity'
import { log, LogEntry } from '@/game/interface'
import { LogEntry } from '@/game/interface'
import Statblock from './Statblock.vue' import Statblock from './Statblock.vue'
import ActionButton from './ActionButton.vue'


@Component( @Component(
{ {
components: { Statblock }
components: { Statblock, ActionButton }
} }
) )
export default class Combat extends Vue { export default class Combat extends Vue {
@@ -46,11 +54,16 @@ export default class Combat extends Vue {


actionDescription = '' actionDescription = ''


private log: (entry: LogEntry) => void;
private combatLog: Array<LogEntry>


constructor () { constructor () {
super() super()
this.log = log
this.combatLog = []
}

@Emit("executed")
executed (entry: LogEntry) {
this.combatLog.push(entry)
} }
} }
</script> </script>
@@ -79,10 +92,6 @@ a {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
.combat-button {
width: 100px;
height: 100px;
}
</style> </style>


<style> <style>


+ 5
- 4
src/components/Statblock.vue View File

@@ -1,10 +1,10 @@
<template> <template>
<div class="statblock"> <div class="statblock">
<h2 v-if="subject.perspective === firstperson">Player</h2>
<h2 v-if="subject.perspective === firstperson">You</h2>
<h2 v-if="subject.perspective !== firstperson">{{subject.name.all.capital}}</h2> <h2 v-if="subject.perspective !== firstperson">{{subject.name.all.capital}}</h2>
<div>Health: {{subject.health.toFixed(0)}} / {{subject.maxHealth.toFixed(0)}}</div> <div>Health: {{subject.health.toFixed(0)}} / {{subject.maxHealth.toFixed(0)}}</div>
<div v-for="stat in Object.keys(subject.stats)" v-bind:key="stat">{{stat}}: {{subject.stats[stat]}}</div> <div v-for="stat in Object.keys(subject.stats)" v-bind:key="stat">{{stat}}: {{subject.stats[stat]}}</div>
<div>Status: {{subject.state}}</div>
<div>Status: {{subject.status}}</div>
<ContainerView v-for="container in subject.containers" :key="container.name" :container="container" /> <ContainerView v-for="container in subject.containers" :key="container.name" :container="container" />
</div> </div>
</template> </template>
@@ -33,8 +33,9 @@ export default class Statblock extends Vue {


<!-- Add "scoped" attribute to limit CSS to this component only --> <!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped> <style scoped>
h3 {
margin: 40px 0 0;
h2 {
margin-bottom: 16pt;
font-size: 200%;
} }
ul { ul {
list-style-type: none; list-style-type: none;


+ 3
- 3
src/game/combat.ts View File

@@ -225,9 +225,9 @@ export class StruggleAction extends PairAction {
private test: StatTest private test: StatTest


protected failLines: POVPair<Entity, Entity> = new POVPair([ protected failLines: POVPair<Entity, Entity> = new POVPair([
[[POV.First, POV.Third], (user, target) => new LogLines(`You fail to make a meal out of ${target.name}`)],
[[POV.Third, POV.First], (user, target) => new LogLines(`${user.name.capital} tries to devour you, but fails`)],
[[POV.Third, POV.Third], (user, target) => new LogLines(`${target.name} unsuccessfully tries to swallow ${target.name}`)]
[[POV.First, POV.Third], (user, target) => new LogLines(`You fail to escape from ${target.name}`)],
[[POV.Third, POV.First], (user, target) => new LogLines(`${user.name.capital} tries to escape from you, but fails`)],
[[POV.Third, POV.Third], (user, target) => new LogLines(`${target.name} unsuccessfully struggles within ${target.name}`)]
]) ])


allowed (user: Creature, target: Creature) { allowed (user: Creature, target: Creature) {


+ 12
- 0
src/game/entity.ts View File

@@ -17,6 +17,7 @@ export interface Mortal extends Entity {
resistances: Map<DamageType, number>; resistances: Map<DamageType, number>;
takeDamage: (damage: Damage) => void; takeDamage: (damage: Damage) => void;
stats: Stats; stats: Stats;
status: string;
} }


export class Creature implements Mortal, Pred, Prey, Combatant { export class Creature implements Mortal, Pred, Prey, Combatant {
@@ -53,6 +54,17 @@ export class Creature implements Mortal, Pred, Prey, Combatant {
}) })
} }


get status (): string {
if (this.health < 0) {
return "Unconscious"
}
if (this.containedIn !== null) {
return "Devoured"
}

return "Normal"
}

validActions (target: Creature): Array<Action> { validActions (target: Creature): Array<Action> {
let choices = this.actions.concat(this.containers.flatMap(container => container.actions)) let choices = this.actions.concat(this.containers.flatMap(container => container.actions))




+ 5
- 18
src/game/interface.ts View File

@@ -1,5 +1,5 @@
export interface LogEntry { export interface LogEntry {
render: () => HTMLElement[];
render: () => string[];
} }


export class LogLines implements LogEntry { export class LogLines implements LogEntry {
@@ -9,15 +9,8 @@ export class LogLines implements LogEntry {
this.lines = lines this.lines = lines
} }


render (): HTMLElement[] {
const p = document.createElement('p')
this.lines.forEach(line => {
const div = document.createElement('div')
div.innerText = line
p.appendChild(div)
})

return [p]
render (): string[] {
return this.lines
} }
} }


@@ -28,13 +21,7 @@ export class CompositeLog implements LogEntry {
this.entries = entries this.entries = entries
} }


render (): HTMLElement[] {
return this.entries.map(entry => entry.render()).reduce((results: HTMLElement[], next: HTMLElement[]) => results.concat(next), [])
render (): string[] {
return this.entries.flatMap(e => e.render())
} }
} }

export function log (entry: LogEntry): void {
entry.render().forEach(elem => {
document.querySelector('#log')!.appendChild(elem)
})
}

Loading…
Cancel
Save