Created
August 24, 2018 23:41
-
-
Save robertz/af1c19f3123f1af51c3909a51271d4ae to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { mapState } from 'vuex' | |
import mobData from '../5e-SRD-Monsters.json' | |
import gameData from '../gameData.json' | |
export default { | |
name: 'combat', | |
data () { | |
return { | |
mobs: mobData.filter((mob) => { return ('name' in mob) }), | |
alive: true, | |
mobsAlive: false, | |
rounds: 0, | |
hasInitiative: false, | |
opponents: [], | |
combatLog: [] | |
} | |
}, | |
methods: { | |
pcAttack: function () { | |
let pcAtk = this.roll('1d20') | |
switch (pcAtk) { | |
case 1: | |
this.combatLog.push('You rolled a 1 for attack roll. You missed!') | |
break | |
case 20: | |
this.combatLog.push('You rolled a 20 for attack roll. Critical Hit!') | |
let baseDmg = this.roll('1d6', true) + this.modifier(this.character.stats.str) | |
this.combatLog.push(`You hit the ${this.opponents[0].name} for ${baseDmg} points of damage.`) | |
this.opponents[0]._hit_points -= baseDmg | |
break | |
default: | |
let doesHit = pcAtk + this.modifier(this.character.stats.str) + this.byLevel.proficiency > this.opponents[0].armor_class | |
if (doesHit) { | |
let baseDmg = this.roll('1d6') + this.modifier(this.character.stats.str) | |
this.combatLog.push(`You hit the ${this.opponents[0].name} for ${baseDmg} points of damage.`) | |
this.opponents[0]._hit_points -= baseDmg | |
} else { | |
this.combatLog.push(`You attack the ${this.opponents[0].name}, but miss!`) | |
} | |
break | |
} | |
}, | |
npcAttack: function () { | |
// calculate attack for each opponent | |
for (let m = 0; m < this.opponents.length; m++) { | |
if (this.character.current.hp > 0) { // if alive and opponents alive | |
let npcAtk = this.roll('1d20') | |
let validActions = this.opponents[m].actions.filter((action) => { return ('damage_dice' in action) }) || [] | |
let selectedAction = validActions[ Math.floor(Math.random() * validActions.length) ] | |
let attackBonus = ('attack_bonus' in selectedAction) ? selectedAction.attack_bonus : 0 | |
let damageBonus = ('damage_bonus' in selectedAction) ? selectedAction.damage_bonus : 0 | |
let baseDmg = 0 | |
switch (npcAtk) { | |
case 1: | |
this.combatLog.push(this.opponents[m].name + ' rolled a 1 for attack roll. It missed!') | |
break | |
case 20: | |
this.combatLog.push(this.opponents[m].name + ' rolled a 20 for attack roll. Critical Hit!') | |
baseDmg = this.roll(selectedAction.damage_dice, true) + this.modifier(this.opponents[m].strength) + damageBonus | |
this.combatLog.push(`${this.opponents[m].name}: ${selectedAction.name} for ${baseDmg} points of damage.`) | |
this.character.current.hp -= baseDmg | |
break | |
default: | |
baseDmg = this.roll(selectedAction.damage_dice) + damageBonus | |
let doesHit = npcAtk + this.modifier(this.opponents[m].strength) + attackBonus > this.character.attr.ac | |
if (doesHit) { | |
this.combatLog.push(`${this.opponents[m].name}: ${selectedAction.name} for ${baseDmg} points of damage.`) | |
this.character.current.hp -= baseDmg | |
} else { | |
this.combatLog.push(`${this.opponents[m].name}: ${selectedAction.name}, but misses!`) | |
} | |
} | |
} | |
} | |
}, | |
eventLoop: function () { | |
if (this.rounds === 0) { | |
this.hasInitiative = this.character.stats.dex + this.modifier(this.character.stats.dex) > this.opponents[0].dexterity + this.modifier(this.opponents[0].dexterity) | |
this.opponents[0]._hit_points = this.opponents[0].hit_points | |
} | |
this.rounds++ | |
this.mobsAlive = this.opponents.filter((op) => { return op._hit_points > 0 }).length > 0 | |
// if hasInit player goes first, otherwise opponents go first | |
if (this.hasInitiative) { | |
this.pcAttack() | |
this.mobsAlive = this.opponents.filter((op) => { return op._hit_points > 0 }).length > 0 | |
if (this.mobsAlive) { | |
this.npcAttack() | |
} | |
} else { | |
// calculate attack for each opponent | |
this.npcAttack() | |
if (this.character.current.hp > 0) { | |
this.pcAttack() | |
} | |
} | |
this.alive = this.character.current.hp > 0 | |
this.mobsAlive = this.opponents.filter((op) => { return op._hit_points > 0 }).length > 0 | |
// All opponents are dead and pc is alive | |
if (!this.mobsAlive && this.alive) { | |
this.combatLog.push('You have won!!!!') | |
for (let i = 0; i < this.opponents.length; i++) { | |
this.character.attr.xp += gameData.experience.filter((cr) => { return cr.challenge_rating === this.opponents[i].challenge_rating })[0].xp | |
} | |
this.$store.commit('SET_CHARACTER', this.character) | |
this.saveCharacter(this.character) | |
} | |
// DED | |
if (this.mobsAlive && !this.alive) { | |
this.combatLog.push('You have died!!!!') | |
} | |
}, | |
modifier: function (value) { | |
return Math.floor((parseInt(value) - 10) / 2) | |
}, | |
restart: function () { | |
this.$store.dispatch('refreshCharacter') | |
this.character.current.hp = this.character.attr.hp | |
this.rounds = 0 | |
this.opponents = [] | |
this.combatLog = [] | |
let isValid = false | |
let op | |
// Not all monsters have damage rolls... this weeds out any bad data (i.e., Sprite) | |
while (!isValid) { | |
op = this.mobs[ Math.floor(Math.random() * this.mobs.length) ] | |
isValid = op.actions.filter((action) => { return ('damage_dice' in action) }).length > 0 | |
} | |
this.opponents.push(op) | |
// this.opponents.push(this.mobs.filter((mob) => { return mob.name === 'Sprite' })[0]) | |
for (let i = 0; i < this.opponents.length; i++) { | |
this.opponents[i]._hit_points = this.opponents[i].hit_points | |
} | |
this.alive = true | |
this.mobsAlive = true | |
}, | |
roll: function (dice, critical = false) { | |
let rolls = dice.split('+') | |
let result = 0 | |
for (let r = 0; r < rolls.length; r++) { | |
// critical roles should roll double ie 1d6 becomes 2d6 | |
let count = critical ? rolls[r].split('d')[0] * 2 : rolls[r].split('d')[0] | |
let die = rolls[r].split('d')[1] | |
for (let i = 0; i < count; i++) { | |
result += Math.floor(Math.random() * die) + 1 | |
} | |
} | |
return parseInt(result) | |
}, | |
saveCharacter: function () { | |
localStorage.setItem('character', JSON.stringify(this.character)) | |
this.$store.dispatch('refreshCharacter') | |
} | |
}, | |
filters: { | |
plussed: function (value) { | |
return parseInt(value) >= 0 ? '+' + value : value | |
}, | |
modifier: function (value) { | |
return Math.floor((parseInt(value) - 10) / 2) | |
} | |
}, | |
computed: { | |
byLevel: function () { | |
return gameData.advancement.filter((data) => { return data.level === this.character.attr.lvl })[0] | |
}, | |
...mapState(['character']) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I came across this gist from the medium post, a nice read. For the love of syntax highlighting, please change your file extension to
.js
.