Przeglądaj źródła

Add an action button component; fix struggle text

vintage
Fen Dweller 5 lat temu
rodzic
commit
8da6b66bd6
6 zmienionych plików z 86 dodań i 38 usunięć
  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 Wyświetl plik

@@ -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 Wyświetl plik

@@ -5,21 +5,28 @@
<Statblock :subject="player" />
<Statblock :subject="enemy" />
</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>
<h2>Your moves</h2>
<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>{{actionDescription}}</div>
</div>
<div>
<h2>Enemy moves</h2>
<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>
@@ -29,12 +36,13 @@
<script lang="ts">
import { Component, Prop, Vue, Watch, Emit } from 'vue-property-decorator'
import { Creature, POV } from '@/game/entity'
import { log, LogEntry } from '@/game/interface'
import { LogEntry } from '@/game/interface'
import Statblock from './Statblock.vue'
import ActionButton from './ActionButton.vue'

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

actionDescription = ''

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

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

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

<style>


+ 5
- 4
src/components/Statblock.vue Wyświetl plik

@@ -1,10 +1,10 @@
<template>
<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>
<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>Status: {{subject.state}}</div>
<div>Status: {{subject.status}}</div>
<ContainerView v-for="container in subject.containers" :key="container.name" :container="container" />
</div>
</template>
@@ -33,8 +33,9 @@ export default class Statblock extends Vue {

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


+ 3
- 3
src/game/combat.ts Wyświetl plik

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

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) {


+ 12
- 0
src/game/entity.ts Wyświetl plik

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

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> {
let choices = this.actions.concat(this.containers.flatMap(container => container.actions))



+ 5
- 18
src/game/interface.ts Wyświetl plik

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

export class LogLines implements LogEntry {
@@ -9,15 +9,8 @@ export class LogLines implements LogEntry {
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
}

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)
})
}

Ładowanie…
Anuluj
Zapisz