Ver código fonte

Add choices to places and better nav buttons

master
Fen Dweller 5 anos atrás
pai
commit
37b369deed
6 arquivos alterados com 185 adições e 29 exclusões
  1. +31
    -14
      src/App.vue
  2. +75
    -0
      src/components/ChoiceButton.vue
  3. +57
    -11
      src/components/Explore.vue
  4. +0
    -3
      src/components/Header.vue
  5. +1
    -1
      src/components/NavButton.vue
  6. +21
    -0
      src/game/world.ts

+ 31
- 14
src/App.vue Ver arquivo

@@ -1,8 +1,8 @@
<template>
<div id="app">
<Header version="pre-alpha" @selectEncounter="selectEncounter" :encounters="encounters" />
<Explore :world="world" />
<!-- <Combat v-show="$data.encounter === encounter" v-for="(encounter, index) in encounters" :key="'encounter-' + index" :encounter="encounter" /> -->
<Header />
<Explore v-if="mode === 'explore'" :world="world" />
<Combat v-if="mode === 'combat'" :encounter="encounter" />
</div>
</template>

@@ -15,8 +15,10 @@ import * as Creatures from '@/game/creatures'
import * as Items from '@/game/items'
import { Creature } from '@/game/creature'
import { ProperNoun, TheyPronouns, FemalePronouns, MalePronouns, ImproperNoun, POV } from '@/game/language'
import { Place, Direction, World } from '@/game/world'
import { Encounter } from './game/combat'
import { Place, Direction, World, Choice } from '@/game/world'
import { Encounter, Side } from './game/combat'
import { LogLine, nilLog } from './game/interface'
import { InstantKillEffect } from './game/combat/effects'

@Component({
components: {
@@ -26,7 +28,8 @@ import { Encounter } from './game/combat'
return {
encounter: null,
encounters: null,
world: null
world: null,
mode: 'explore'
}
}
})
@@ -35,9 +38,10 @@ export default class App extends Vue {
super()
}

@Emit('selectEncounter')
selectEncounter (encounter: Encounter) {
@Emit('startFight')
startFight (encounter: Encounter) {
this.$data.encounter = encounter
this.$data.mode = 'combat'
}

created () {
@@ -51,16 +55,29 @@ export default class App extends Vue {

this.$data.encounter = this.$data.encounters[0]

const foo = new Place('Foo', 'A very foo-y place')
const other = new Place('Bar', 'The bar')
foo.biconnect(Direction.North, other)
const home = new Place('Home', 'This is not not home')

const something = new Place('Baz', 'Despacito 3')
foo.biconnect(Direction.East, something)
const street = new Place('Street', 'The street')
home.biconnect(Direction.North, street)

this.$data.encounters.forEach((encounter: Encounter) => home.choices.push(new Choice(
encounter.desc.name,
'Fight time!',
(world, executor) => {
this.startFight(
encounter
)
return nilLog
}
)))

const bar = new Place('Bar', 'This is the bar')
street.biconnect(Direction.East, bar)

const player = new Creatures.Wolf()
player.perspective = POV.Second
player.location = foo
player.side = Side.Heroes
player.location = home
this.$data.world = new World(player)
}



+ 75
- 0
src/components/ChoiceButton.vue Ver arquivo

@@ -0,0 +1,75 @@
<template>
<button :class="{ 'choice-button': true, 'enabled': choice.accessible(world) }">
{{ choice.name }}
<div class="tooltip-template">
<div class="tooltip-title">{{ choice.name }}</div>
<div class="tooltip-body">{{ choice.desc }}</div>
</div>
</button>
</template>

<script lang="ts">

import { Component, Prop, Vue, Watch, Emit } from 'vue-property-decorator'
import { Action, GroupAction } from '@/game/combat'
import { Creature } from '@/game/creature'
import { Place, Direction, Choice, World } from '@/game/world'
import tippy from 'tippy.js'

@Component({})
export default class ChoiceButton extends Vue {
@Prop()
choice!: Choice

@Prop()
world!: World

mounted () {
const elem = this.$el
const tooltip = this.$el.querySelector(".tooltip-template") as HTMLElement
tippy(
elem,
{
content: tooltip
}
)
}
}
</script>

<style scoped>

.choice-button,
.choice-button:hover,
.choice-button:active {
width: 90%;
margin: 5%;
background: repeating-linear-gradient(45deg, #333, #333 20px, #222 20px, #222 40px);
color: #ccc;
font-size: 200%;
border-color: #ccc;
border-width: 3px;
border-radius: 8px;
border-style: outset;
outline: none;
padding: 0;
}

.choice-button:focus {
background: repeating-linear-gradient(45deg, #444, #444 20px, #333 20px, #333 40px);
}

.choice-button.enabled {
background: #555;
}

.choice-button.enabled:hover {
background: #777;
}

.choice-button.enabled:active {
background: #888;
border-style: inset;
}

</style>

+ 57
- 11
src/components/Explore.vue Ver arquivo

@@ -4,18 +4,20 @@

</div>
<div class="explore-worldinfo">
<p class="worldinfo-date">{{ world.time.format("MMMM Do YYYY") }}</p>
<p class="worldinfo-time">{{ world.time.format("h:mm:ss A")}}</p>
<p class="worldinfo-date">{{ world.time.format("MMMM Do yyy") }}</p>
<p class="worldinfo-time">{{ world.time.format("h:mm A")}}</p>
</div>
<Statblock :subject="world.player" :initiative="0" />
<div class="explore-info">
<h2 class="location-name">{{ location.name }}</h2>
<p class="location-desc">{{ location.desc }}</p>
</div>
<div class="explore-nav">
<NavButton @click.native="location=location.connections[direction]" v-for="direction in Object.keys(location.connections)" :key="direction" :style="navBtnCss(direction)" :location="location" :direction="direction" />
<NavButton @click.native="location.connections[direction].travel(world.player, world)" v-for="direction in Object.keys(location.connections)" :key="direction" :style="navBtnCss(direction)" :location="location" :direction="direction" />
<div class="nav-filler" :Style="navBtnCss(direction)" v-for="direction in Object.keys(directions)" :key="direction"></div>
</div>
<div class="explore-actions">
<div class="explore-choices">
<ChoiceButton @click.native="writeLog(choice.execute(world, world.player))" v-for="(choice, index) in location.choices.filter(choice => choice.visible(world))" :key="'choice' + index" :choice="choice" :world="world" />
</div>
</div>
</template>
@@ -25,10 +27,18 @@
import { Component, Prop, Vue } from 'vue-property-decorator'
import { Direction, World, Place } from '@/game/world'
import NavButton from './NavButton.vue'
import ChoiceButton from './ChoiceButton.vue'
import Statblock from './Statblock.vue'
import { LogEntry } from '@/game/interface'

@Component({
components: {
NavButton
NavButton, ChoiceButton, Statblock
},
data () {
return {
directions: Direction
}
}
})

@@ -49,6 +59,27 @@ export default class Explore extends Vue {
'--nav-direction': dir
}
}

writeLog (entry: LogEntry) {
const log = this.$el.querySelector(".explore-log")
if (log !== null) {
const before = log.querySelector("div.log-entry")
const holder = document.createElement("div")
holder.classList.add("log-entry")

entry.render().forEach(element => {
holder.appendChild(element)
})

holder.classList.add("left-move")
const hline = document.createElement("div")
hline.classList.add("log-separator")
log.insertBefore(hline, before)
log.insertBefore(holder, hline)

log.scrollTo({ top: 0, left: 0 })
}
}
}

</script>
@@ -56,21 +87,25 @@ export default class Explore extends Vue {
<style scoped>

.explore-layout {
flex: 10;
position: relative;
display: grid;
grid-template-areas: "log worldinfo"
"log statblock"
"log info "
"log actions "
"nav actions ";
grid-template-rows: 0.5fr 2fr 1fr 1fr;
"log choices "
"nav choices ";
grid-template-rows: 0.5fr fit-content(250pt) 2fr 1fr 1fr;
grid-template-columns: 2fr 1fr;
width: 100%;
height: 100%;
overflow: hidden;
}

.explore-log {
grid-area: log;
background: #222;
overflow-y: scroll;
}

.explore-worldinfo {
@@ -82,6 +117,7 @@ export default class Explore extends Vue {
.worldinfo-time {
font-size: 125%;
}

.explore-info {
grid-area: info;
background: #333;
@@ -99,6 +135,7 @@ export default class Explore extends Vue {
.location-desc {
font-size: 150%;
}

.explore-nav {
grid-area: nav;
background: #444;
@@ -112,8 +149,17 @@ export default class Explore extends Vue {
grid-template-columns: 1fr 1fr 1fr;
}

.explore-actions {
grid-area: actions;
.nav-filler {
grid-area: var(--nav-direction);
background: #222;
margin: 10px;
}

.explore-choices {
grid-area: choices;
background: #555;
display: flex;
flex-direction: column;
overflow-y: scroll;
}
</style>

+ 0
- 3
src/components/Header.vue Ver arquivo

@@ -7,9 +7,6 @@
<div>
<a href="https://discord.gg/2DmtgEM"><i class="fab fa-discord" /></a>
</div>
<div>
<button @click="select(encounter)" v-for="(encounter, index) in encounters" :key="'encounter-'+index">{{encounter.desc.name.toString()}}</button>
</div>
</div>
</template>



+ 1
- 1
src/components/NavButton.vue Ver arquivo

@@ -1,6 +1,6 @@
<template>
<button class="nav-button">
{{location.connections[direction].dst.name}}
{{ location.connections[direction].dst.name }}
<div class="tooltip-template">
<div class="tooltip-title">{{ location.connections[direction].name }}</div>
<div class="tooltip-body">{{ location.connections[direction].desc }}</div>


+ 21
- 0
src/game/world.ts Ver arquivo

@@ -2,6 +2,7 @@ import { TextLike } from './language'
import { Entity } from './entity'
import { Creature } from './creature'
import moment, { Moment, Duration } from 'moment'
import { LogEntry, LogLine } from './interface'

export enum Direction {
Northwest = "Northwest",
@@ -27,14 +28,34 @@ export function reverse (dir: Direction): Direction {
}
}

export class Choice {
constructor (public name: TextLike, public desc: TextLike, public execute: (world: World, executor: Creature) => LogEntry) {

}

visible (world: World): boolean {
return true
}

accessible (world: World): boolean {
return true
}
}

export class Connection {
constructor (public src: Place, public dst: Place, public name: TextLike = "Travel", public desc: TextLike = "Go there lol") {

}

travel (traveler: Creature, world: World) {
world.advance(moment.duration(5, "minutes"))
traveler.location = this.dst
}
}

export class Place {
connections: {[key in Direction]?: Connection} = {}
choices: Choice[] = []

constructor (public name: TextLike, public desc: TextLike) {



Carregando…
Cancelar
Salvar