Bläddra i källkod

Detect when combat has ended; count dead creatures as prey

master
Fen Dweller 5 år sedan
förälder
incheckning
943f4c7bc8
5 ändrade filer med 134 tillägg och 40 borttagningar
  1. +6
    -5
      src/App.vue
  2. +111
    -28
      src/components/Combat.vue
  3. +10
    -0
      src/game/combat.ts
  4. +6
    -6
      src/game/creatures/wolf.ts
  5. +1
    -1
      src/game/vore.ts

+ 6
- 5
src/App.vue Visa fil

@@ -2,7 +2,7 @@
<div id="app"> <div id="app">
<Header /> <Header />
<Explore v-if="mode === 'explore'" :world="world" /> <Explore v-if="mode === 'explore'" :world="world" />
<Combat v-if="mode === 'combat'" :encounter="encounter" />
<Combat @leaveCombat="mode = 'explore'" v-if="mode === 'combat'" :encounter="encounter" />
</div> </div>
</template> </template>


@@ -46,8 +46,13 @@ export default class App extends Vue {
} }


created () { created () {
const player = new Creatures.Wolf()
player.perspective = POV.Second
player.side = Side.Heroes

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


this.$data.encounters.push(new Encounter({ name: 'Wolf' }, [player, new Creatures.Wolf()]))
this.$data.encounters.push(new Encounter({ name: 'Boss Fight' }, this.makeParty().concat([new Creatures.Withers(), new Creatures.Kenzie()]))) this.$data.encounters.push(new Encounter({ name: 'Boss Fight' }, this.makeParty().concat([new Creatures.Withers(), new Creatures.Kenzie()])))
this.$data.encounters.push(new Encounter({ name: 'Cafat' }, this.makeParty().concat([new Creatures.Cafat()]))) this.$data.encounters.push(new Encounter({ name: 'Cafat' }, this.makeParty().concat([new Creatures.Cafat()])))
this.$data.encounters.push(new Encounter({ name: 'Dragon' }, this.makeParty().concat([new Creatures.Dragon()]))) this.$data.encounters.push(new Encounter({ name: 'Dragon' }, this.makeParty().concat([new Creatures.Dragon()])))
@@ -75,10 +80,6 @@ export default class App extends Vue {


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

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


+ 111
- 28
src/components/Combat.vue Visa fil

@@ -40,8 +40,11 @@
<ActionButton @described="described" @executed="executedRight" v-for="(action, index) in right.validActions(right)" :key="'right-' + action.name + '-' + index" :action="action" :user="right" :target="right" :combatants="combatants" /> <ActionButton @described="described" @executed="executedRight" v-for="(action, index) in right.validActions(right)" :key="'right-' + action.name + '-' + index" :action="action" :user="right" :target="right" :combatants="combatants" />
</div> </div>
</div> </div>
<div class="action-description">
<div v-if="encounter.winner === null" class="action-description">
</div> </div>
<button @click="$emit('leaveCombat')" v-if="encounter.winner !== null" class="exit-combat">
Exit Combat
</button>
</div> </div>
</template> </template>


@@ -49,7 +52,7 @@
import { Component, Prop, Vue, Watch, Emit } from 'vue-property-decorator' import { Component, Prop, Vue, Watch, Emit } from 'vue-property-decorator'
import { Creature } from '@/game/creature' import { Creature } from '@/game/creature'
import { POV } from '@/game/language' import { POV } from '@/game/language'
import { LogEntry } from '@/game/interface'
import { LogEntry, LogLine } from '@/game/interface'
import Statblock from './Statblock.vue' import Statblock from './Statblock.vue'
import ActionButton from './ActionButton.vue' import ActionButton from './ActionButton.vue'
import { Side, Encounter } from '@/game/combat' import { Side, Encounter } from '@/game/combat'
@@ -93,7 +96,7 @@ export default class Combat extends Vue {
executedLeft (entry: LogEntry) { executedLeft (entry: LogEntry) {
this.writeLog(entry, "left-move") this.writeLog(entry, "left-move")


this.writeLog(this.encounter.nextMove(), "left-move")
this.writeLog(this.encounter.nextMove(), "center-move")
this.pickNext() this.pickNext()
} }


@@ -103,11 +106,11 @@ export default class Combat extends Vue {
executedRight (entry: LogEntry) { executedRight (entry: LogEntry) {
this.writeLog(entry, "right-move") this.writeLog(entry, "right-move")


this.writeLog(this.encounter.nextMove(), "right-move")
this.writeLog(this.encounter.nextMove(), "center-move")
this.pickNext() this.pickNext()
} }


writeLog (entry: LogEntry, cls: string) {
writeLog (entry: LogEntry, cls = "") {
const log = this.$el.querySelector(".log") const log = this.$el.querySelector(".log")
if (log !== null) { if (log !== null) {
const before = log.querySelector("div.log-entry") const before = log.querySelector("div.log-entry")
@@ -118,7 +121,10 @@ export default class Combat extends Vue {
holder.appendChild(element) holder.appendChild(element)
}) })


holder.classList.add(cls)
if (cls !== "") {
holder.classList.add(cls)
}

const hline = document.createElement("div") const hline = document.createElement("div")
hline.classList.add("log-separator") hline.classList.add("log-separator")
log.insertBefore(hline, before) log.insertBefore(hline, before)
@@ -129,30 +135,41 @@ export default class Combat extends Vue {
} }


pickNext () { pickNext () {
if (this.encounter.currentMove.side === Side.Heroes) {
this.$data.left = this.encounter.currentMove

if (this.encounter.currentMove.containedIn !== null) {
this.$data.right = this.encounter.currentMove.containedIn.owner
}
} else if (this.encounter.currentMove.side === Side.Monsters) {
this.$data.right = this.encounter.currentMove

if (this.encounter.currentMove.containedIn !== null) {
this.$data.left = this.encounter.currentMove.containedIn.owner
// Did one side win?

if (this.encounter.winner !== null) {
this.writeLog(
new LogLine(
`game o-vore lmaoooooooo`
),
"center-move"
)
} else {
if (this.encounter.currentMove.side === Side.Heroes) {
this.$data.left = this.encounter.currentMove

if (this.encounter.currentMove.containedIn !== null) {
this.$data.right = this.encounter.currentMove.containedIn.owner
}
} else if (this.encounter.currentMove.side === Side.Monsters) {
this.$data.right = this.encounter.currentMove

if (this.encounter.currentMove.containedIn !== null) {
this.$data.left = this.encounter.currentMove.containedIn.owner
}
} }
// scroll to the newly selected creature
this.$nextTick(() => {
const creature: HTMLElement|null = this.$el.querySelector("[data-current-turn]")
if (creature !== null) {
this.scrollParentTo(creature)
}
const target: HTMLElement|null = this.$el.querySelector("[data-active]")
if (target !== null) {
this.scrollParentTo(target)
}
})
} }
// scroll to the newly selected creature
this.$nextTick(() => {
const creature: HTMLElement|null = this.$el.querySelector("[data-current-turn]")
if (creature !== null) {
this.scrollParentTo(creature)
}
const target: HTMLElement|null = this.$el.querySelector("[data-active]")
if (target !== null) {
this.scrollParentTo(target)
}
})
} }


selectable (creature: Creature): boolean { selectable (creature: Creature): boolean {
@@ -243,6 +260,19 @@ export default class Combat extends Vue {
min-height: 100%; min-height: 100%;
} }


.exit-combat {
grid-area: 2 / main-col-start / main-row-start / main-col-end;
width: 100%;
padding: 4pt;
flex: 0 1;
background: #333;
border-color: #666;
border-style: outset;
user-select: none;
color: #eee;
font-size: 36px;
}

.combat-layout { .combat-layout {
position: relative; position: relative;
display: grid; display: grid;
@@ -258,6 +288,7 @@ export default class Combat extends Vue {
.log { .log {
grid-area: main-row-start / main-col-start / main-row-end / main-col-end; grid-area: main-row-start / main-col-start / main-row-end / main-col-end;
overflow-y: scroll; overflow-y: scroll;
overflow-x: hidden;
font-size: 12pt; font-size: 12pt;
width: 100%; width: 100%;
max-height: 100%; max-height: 100%;
@@ -494,4 +525,56 @@ div.right-move {
margin: 4pt 0pt 4pt; margin: 4pt 0pt 4pt;
background: linear-gradient(90deg, transparent, #444 10%, #444 90%, transparent 100%); background: linear-gradient(90deg, transparent, #444 10%, #444 90%, transparent 100%);
} }

.left-move {
animation: left-fly-in 1s;
}

.right-move {
animation: right-fly-in 1s;
}

.center-move {
animation: center-fly-in 1s;
}

@keyframes left-fly-in {
0% {
opacity: 0;
transform: translate(-50px, 0);
}

50% {
transform: translate(0, 0);
}

100% {
opacity: 1;
}
}

@keyframes right-fly-in {
0% {
opacity: 0;
transform: translate(50px, 0);
}

50% {
transform: translate(0, 0);
}

100% {
opacity: 1;
}
}

@keyframes center-fly-in {
0% {
opacity: 0;
}

100% {
opacity: 1;
}
}
</style> </style>

+ 10
- 0
src/game/combat.ts Visa fil

@@ -564,6 +564,16 @@ export class Encounter {


return nilLog return nilLog
} }

get winner (): null|Side {
const remaining: Set<Side> = new Set(this.combatants.filter(combatant => !combatant.disabled).map(combatant => combatant.side))

if (remaining.size === 1) {
return Array.from(remaining)[0]
} else {
return null
}
}
} }


export abstract class Consequence { export abstract class Consequence {


+ 6
- 6
src/game/creatures/wolf.ts Visa fil

@@ -20,17 +20,17 @@ export class Wolf extends Creature {
this.side = Side.Monsters this.side = Side.Monsters


const stomach = new Stomach(this, 50, new Damage( const stomach = new Stomach(this, 50, new Damage(
{ amount: 20, type: DamageType.Acid, target: Vigor.Health },
{ amount: 10, type: DamageType.Crush, target: Vigor.Stamina },
{ amount: 10, type: DamageType.Dominance, target: Vigor.Resolve }
{ amount: 60, type: DamageType.Acid, target: Vigor.Health },
{ amount: 30, type: DamageType.Crush, target: Vigor.Stamina },
{ amount: 30, type: DamageType.Dominance, target: Vigor.Resolve }
)) ))


this.containers.push(stomach) this.containers.push(stomach)


const bowels = new Bowels(this, 50, new Damage( const bowels = new Bowels(this, 50, new Damage(
{ amount: 10, type: DamageType.Crush, target: Vigor.Health },
{ amount: 25, type: DamageType.Crush, target: Vigor.Stamina },
{ amount: 25, type: DamageType.Dominance, target: Vigor.Resolve }
{ amount: 30, type: DamageType.Crush, target: Vigor.Health },
{ amount: 60, type: DamageType.Crush, target: Vigor.Stamina },
{ amount: 60, type: DamageType.Dominance, target: Vigor.Resolve }
)) ))


this.containers.push(bowels) this.containers.push(bowels)


+ 1
- 1
src/game/vore.ts Visa fil

@@ -49,7 +49,7 @@ export abstract class Vore extends Mortal {
get [VoreStat.PreyCount] () { get [VoreStat.PreyCount] () {
return containers.reduce( return containers.reduce(
(total: number, container: VoreContainer) => { (total: number, container: VoreContainer) => {
return total + container.contents.reduce(
return total + container.contents.concat(container.digested).reduce(
(total: number, prey: Vore) => { (total: number, prey: Vore) => {
return total + 1 + prey.voreStats[VoreStat.PreyCount] return total + 1 + prey.voreStats[VoreStat.PreyCount]
}, },


Laddar…
Avbryt
Spara