Skip to content

Commit

Permalink
Merge pull request #144 from juanferrer/master
Browse files Browse the repository at this point in the history
More stuff
  • Loading branch information
ClipplerBlood authored Nov 9, 2023
2 parents 839f4f8 + a5378b0 commit 89b4b8e
Show file tree
Hide file tree
Showing 15 changed files with 170 additions and 80 deletions.
1 change: 1 addition & 0 deletions src/lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,7 @@
"DL.LanguagesReadShort": "R",
"DL.LanguagesWriteShort": "W",
"DL.LanguagesSpeakShort": "S",
"DL.DialogInput": "Dialog Input",
"DL.DialogChallengeRoll": "Challenge Roll: ",
"DL.DialogAttackRoll": "Attack Roll: ",
"DL.DialogTalentRoll": "Talent Roll: ",
Expand Down
78 changes: 40 additions & 38 deletions src/module/actor/actor.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ export class DemonlordActor extends Actor {
attribute.min = 0
attribute.value = Math.min(attribute.max, Math.max(attribute.min, attribute.value))
attribute.label = game.i18n.localize(`DL.Attribute${capitalize(key)}`)
attribute.key = key
}
system.attributes.perception.label = game.i18n.localize(`DL.AttributePerception`)

Expand Down Expand Up @@ -185,7 +186,7 @@ export class DemonlordActor extends Actor {
// Final armor computation
system.characteristics.defense += system.bonuses.armor.defense
system.characteristics.defense = system.bonuses.armor.override || system.characteristics.defense
for (let change of effectChanges.filter(e => e.key.includes("defense"))) {
for (let change of effectChanges.filter(e => e.key.includes("defense") && !e.key.startsWith("system.characteristics"))) {
const result = change.effect.apply(this, change)
if (result !== null) this.overrides[change.key] = result
}
Expand Down Expand Up @@ -309,8 +310,11 @@ export class DemonlordActor extends Actor {
/* Rolls and Actions */

/* -------------------------------------------- */
rollFormula(mod, boba, bobaRerolls) {
let rollFormula = '1d20' + plusify(mod)
rollFormula(mods, boba, bobaRerolls) {
let rollFormula = '1d20'
for (const mod of mods) {
rollFormula += plusify(mod)
}
if (boba > 0 && parseInt(bobaRerolls) > 0) rollFormula += `+${boba}d6r1kh`
else if (boba) rollFormula += plusify(boba) + 'd6kh'
console.log(rollFormula)
Expand All @@ -323,7 +327,7 @@ export class DemonlordActor extends Actor {
* @param inputBoons Number of boons/banes from the user dialog
* @param inputModifier Attack modifier from the user dialog
*/
rollAttack(item, inputBoons = 0, inputModifier = 0) {
async rollAttack(item, inputBoons = 0, inputModifier = 0) {
const attacker = this
const defendersTokens = tokenManager.targets
const defender = defendersTokens[0]?.actor
Expand All @@ -341,8 +345,7 @@ export class DemonlordActor extends Actor {
// if !target -> ui.notifications.warn(Please select target) ??

// Attack modifier and Boons/Banes
const modifier =
(attacker.system?.attributes[attackAttribute]?.modifier || 0) + (parseInt(inputModifier) || 0)
const modifiers = [attacker.system?.attributes[attackAttribute]?.modifier || 0, parseInt(inputModifier) || 0]
let boons =
(parseInt(item.system.action.boonsbanes) || 0) +
(parseInt(inputBoons) || 0) +
Expand All @@ -363,10 +366,10 @@ export class DemonlordActor extends Actor {
const boonsReroll = parseInt(this.system.bonuses.rerollBoon1Dice)

// Roll the attack
const attackRoll = new Roll(this.rollFormula(modifier, boons, boonsReroll), {})
attackRoll.evaluate({async: false})
const attackRoll = new Roll(this.rollFormula(modifiers, boons, boonsReroll), {})
await attackRoll.evaluate()

postAttackToChat(attacker, defender, item, attackRoll, attackAttribute, defenseAttribute)
postAttackToChat(attacker, defender, item, attackRoll, attackAttribute, defenseAttribute, parseInt(inputBoons) || 0)

const hitTargets = defendersTokens.filter(d => {
const targetNumber =
Expand All @@ -389,7 +392,7 @@ export class DemonlordActor extends Actor {
* @param itemID The id of the item
* @param _options Additional options
*/
rollWeaponAttack(itemID, _options = {event: null}) {
async rollWeaponAttack(itemID, _options = {event: null}) {
const item = this.getEmbeddedDocument('Item', itemID)

// If no attribute to roll, roll without modifiers and boons
Expand All @@ -401,30 +404,29 @@ export class DemonlordActor extends Actor {

// Check if actor is blocked by an affliction
if (!DLAfflictions.isActorBlocked(this, 'action', attribute))
launchRollDialog(game.i18n.localize('DL.DialogAttackRoll') + game.i18n.localize(item.name), html =>
this.rollAttack(item, html.find('[id="boonsbanes"]').val(), html.find('[id="modifier"]').val()),
launchRollDialog(game.i18n.localize('DL.DialogAttackRoll') + game.i18n.localize(item.name), async html =>
await this.rollAttack(item, html.find('[id="boonsbanes"]').val(), html.find('[id="modifier"]').val()),
)
}

/* -------------------------------------------- */

rollAttribute(attribute, inputBoons, inputModifier) {
attribute = attribute.label.toLowerCase()
const modifier = parseInt(inputModifier) + (this.getAttribute(attribute)?.modifier || 0)
const boons = parseInt(inputBoons) + (this.system.bonuses.challenge.boons[attribute] || 0) + (this.system.bonuses.challenge.boons.all || 0)
async rollAttribute(attribute, inputBoons, inputModifier) {
const modifiers = [parseInt(inputModifier), this.getAttribute(attribute.key)?.modifier || 0]
const boons = (parseInt(inputBoons) || 0) + (this.system.bonuses.challenge.boons[attribute.key] || 0) + (this.system.bonuses.challenge.boons.all || 0)
const boonsReroll = parseInt(this.system.bonuses.rerollBoon1Dice)

const challengeRoll = new Roll(this.rollFormula(modifier, boons, boonsReroll), {})
challengeRoll.evaluate({async: false})
postAttributeToChat(this, attribute, challengeRoll)
const challengeRoll = new Roll(this.rollFormula(modifiers, boons, boonsReroll), {})
await challengeRoll.evaluate()
postAttributeToChat(this, attribute.key, challengeRoll, parseInt(inputBoons) || 0)
}

rollChallenge(attribute) {
if (typeof attribute === 'string' || attribute instanceof String) attribute = this.getAttribute(attribute)

if (!DLAfflictions.isActorBlocked(this, 'challenge', attribute.label))
launchRollDialog(this.name + ': ' + game.i18n.localize('DL.DialogChallengeRoll').slice(0, -2), html =>
this.rollAttribute(attribute, html.find('[id="boonsbanes"]').val(), html.find('[id="modifier"]').val()),
if (!DLAfflictions.isActorBlocked(this, 'challenge', attribute.key))
launchRollDialog(this.name + ': ' + game.i18n.localize('DL.DialogChallengeRoll').slice(0, -2), async html =>
await this.rollAttribute(attribute, html.find('[id="boonsbanes"]').val(), html.find('[id="modifier"]').val()),
)
}

Expand Down Expand Up @@ -466,7 +468,7 @@ export class DemonlordActor extends Actor {
const attackAttribute = talentData.action.attack.toLowerCase()
const defenseAttribute = talentData.action?.attack?.toLowerCase()

let modifier = parseInt(inputModifier) + (this.getAttribute(attackAttribute)?.modifier || 0)
let modifiers = [parseInt(inputModifier), this.getAttribute(attackAttribute)?.modifier || 0]

let boons =
(parseInt(inputBoons) || 0) +
Expand All @@ -476,8 +478,8 @@ export class DemonlordActor extends Actor {
if (targets.length === 1) boons -= ((target?.actor?.system.bonuses.defense.boons[defenseAttribute] || 0) + (target?.actor?.system.bonuses.defense.boons.all || 0))
const boonsReroll = parseInt(this.system.bonuses.rerollBoon1Dice)

attackRoll = new Roll(this.rollFormula(modifier, boons, boonsReroll), {})
attackRoll.evaluate({async: false})
attackRoll = new Roll(this.rollFormula(modifiers, boons, boonsReroll), {})
await attackRoll.evaluate()
}

Hooks.call('DL.UseTalent', {
Expand All @@ -486,7 +488,7 @@ export class DemonlordActor extends Actor {
itemId: talent.id,
})

postTalentToChat(this, talent, attackRoll, target?.actor)
postTalentToChat(this, talent, attackRoll, target?.actor, parseInt(inputBoons) || 0)
}

/* -------------------------------------------- */
Expand Down Expand Up @@ -543,11 +545,11 @@ export class DemonlordActor extends Actor {
(target?.actor?.system.bonuses.defense.boons.all || 0) +
(target?.actor?.system.bonuses.defense.boons.spell || 0)

const modifier = (parseInt(inputModifier) || 0) + this.getAttribute(attackAttribute).modifier || 0
const modifiers = [parseInt(inputModifier) || 0, this.getAttribute(attackAttribute).modifier || 0]
const boonsReroll = parseInt(this.system.bonuses.rerollBoon1Dice)

attackRoll = new Roll(this.rollFormula(modifier, boons, boonsReroll), {})
attackRoll.evaluate({async: false})
attackRoll = new Roll(this.rollFormula(modifiers, boons, boonsReroll), {})
await attackRoll.evaluate()
}

Hooks.call('DL.UseSpell', {
Expand All @@ -556,7 +558,7 @@ export class DemonlordActor extends Actor {
itemId: spell.id,
})

postSpellToChat(this, spell, attackRoll, target?.actor)
postSpellToChat(this, spell, attackRoll, target?.actor, parseInt(inputBoons) || 0)
}

/* -------------------------------------------- */
Expand Down Expand Up @@ -590,34 +592,34 @@ export class DemonlordActor extends Actor {
let attackRoll = null

if (!itemData?.action?.attack) {
postItemToChat(this, item, null, null)
postItemToChat(this, item, null, null, null)
return
} else {
const attackAttribute = itemData.action.attack.toLowerCase()
const defenseAttribute = itemData.action?.attack?.toLowerCase()

let modifier = parseInt(inputModifier) + (this.getAttribute(attackAttribute)?.modifier || 0)
let modifiers = [parseInt(inputModifier), (this.getAttribute(attackAttribute)?.modifier || 0)]

let boons =
parseInt(inputBoons) +
(parseInt(inputBoons) || 0) +
(this.system.bonuses.attack[attackAttribute] || 0) +
(this.system.bonuses.attack.boons.all || 0) +
parseInt(itemData.action?.boonsbanes || 0)
if (targets.length === 1) boons -= ((target?.actor?.system.bonuses.defense.boons[defenseAttribute] || 0) + (target?.actor?.system.bonuses.defense.boons.all || 0))
const boonsReroll = parseInt(this.system.bonuses.rerollBoon1Dice)

attackRoll = new Roll(this.rollFormula(modifier, boons, boonsReroll), {})
attackRoll.evaluate({async: false})
attackRoll = new Roll(this.rollFormula(modifiers, boons, boonsReroll), {})
await attackRoll.evaluate()
}

postItemToChat(this, item, attackRoll, target?.actor)
postItemToChat(this, item, attackRoll, target?.actor, parseInt(inputBoons) || 0)
}

/* -------------------------------------------- */

rollCorruption() {
async rollCorruption() {
const corruptionRoll = new Roll('1d20')
corruptionRoll.evaluate({async: false})
await corruptionRoll.evaluate()
postCorruptionToChat(this, corruptionRoll)
}

Expand Down
6 changes: 3 additions & 3 deletions src/module/actor/sheets/base-actor-sheet.js
Original file line number Diff line number Diff line change
Expand Up @@ -333,9 +333,9 @@ export default class DLBaseActorSheet extends ActorSheet {
})

// Rollable Attack
html.find('.attack-roll').click(ev => {
html.find('.attack-roll').click(async ev => {
const id = $(ev.currentTarget).closest('[data-item-id]').data('itemId')
this.actor.rollWeaponAttack(id, {event: ev})
await this.actor.rollWeaponAttack(id, {event: ev})
})

// Rollable Talent
Expand Down Expand Up @@ -368,7 +368,7 @@ export default class DLBaseActorSheet extends ActorSheet {
if (dataset.roll) {
const roll = new Roll(dataset.roll, this.actor.system)
const label = dataset.label ? `Rolling ${dataset.label}` : ''
roll.roll({async: false}).toMessage({
await roll.roll().toMessage({
speaker: ChatMessage.getSpeaker({actor: this.actor}),
flavor: label,
})
Expand Down
2 changes: 1 addition & 1 deletion src/module/actor/sheets/character-sheet.js
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ export default class DLCharacterSheet extends DLBaseActorSheet {
if (!this.options.editable) return

// Corruption Roll
html.find('.corruption-roll').click(_ => this.actor.rollCorruption())
html.find('.corruption-roll').click(async _ => await this.actor.rollCorruption())

// Edit HealthBar, Insanity and Corruption
html.find('.bar-edit').click(async () => {
Expand Down
66 changes: 66 additions & 0 deletions src/module/actor/token.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/* globals Color */

import {MapRange} from '../utils/utils.js'

// Shamelessly stolen from Shadow of the Weird Wizard
export class DemonlordToken extends Token {

static getDamageColor(current, max) {
const minDegrees = 30
const maxDegrees = 120

// Get the degrees on the HSV wheel, going from 30º (green) to 120º (red)
const degrees = MapRange(current, 0, max, minDegrees, maxDegrees)
// Invert the degrees and map them from 0 to a third
const hue = MapRange(maxDegrees - degrees, 0, maxDegrees, 0, 1 / 3)

return Color.fromHSV([hue, 1, 0.9])
}

_drawBar(number, bar, data) {
if (data?.attribute === 'characteristics.health') {
return this._drawDamageBar(number, bar, data)
}

return super._drawBar(number, bar, data)
}

_drawDamageBar(number, bar, data) {
const { value, max } = data
const colorPct = Math.clamped(value, 0, max) / max
const damageColor = DemonlordToken.getDamageColor(value, max)

// Determine the container size (logic borrowed from core)
const w = this.w
let h = Math.max(canvas.dimensions.size / 12, 8)
if (this.document.height >= 2)
h *= 1.6
const stroke = Math.clamped(h / 8, 1, 2)

// Set up bar container
this._resetVitalsBar(bar, w, h, stroke)

// Fill bar as damage increases, gradually going from green to red as it fills
bar
.beginFill(damageColor, 1.0)
.lineStyle(stroke, this.blk, 1.0)
.drawRoundedRect(0, 0, colorPct * w, h, 2)

// Position the bar according to its number
this._setVitalsBarPosition(bar, number, h)
}

_resetVitalsBar(bar, width, height, stroke) {
bar
.clear()
.beginFill(this.blk, 0.5)
.lineStyle(stroke, this.blk, 1.0)
.drawRoundedRect(0, 0, width, height, 3)
}

_setVitalsBarPosition(bar, order, height) {
// Set position
const posY = order === 0 ? this.h - height : 0
bar.position.set(0, posY)
}
}
4 changes: 2 additions & 2 deletions src/module/chat/chat-listeners.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ async function _onChatRollDamage(event) {
const itemId = item.dataset.itemId || li.closest('.demonlord').dataset.itemId

const damageRoll = new Roll(damageformula, {})
damageRoll.evaluate({async: false})
await damageRoll.evaluate()

let totalDamage = ''
let totalDamageGM = ''
Expand Down Expand Up @@ -254,7 +254,7 @@ async function _onChatMakeChallengeRoll(event) {
const start = li.closest('.demonlord')
const boonsbanesEntered = start.children[1].children[0].children[0].children[1]?.value

actor.rollAttribute(attribute, parseInt(boonsbanes) + parseInt(boonsbanesEntered), 0)
await actor.rollAttribute(attribute, parseInt(boonsbanes) + parseInt(boonsbanesEntered), 0)
}

/* -------------------------------------------- */
Expand Down
13 changes: 9 additions & 4 deletions src/module/chat/effect-messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ const changeListToMsg = (m, keys, title, f=plusify) => {
if (m.has(key)) changes.push(m.get(key))
})

return changes.flat(Infinity).reduce((acc, change) => acc + _toMsg(change.name, f(change.value)), title)
if (changes.length > 0) return changes.flat(Infinity).reduce((acc, change) => acc + _toMsg(change.name, f(change.value)), title)
return ''
}

/* -------------------------------------------- */
Expand All @@ -61,13 +62,14 @@ const changeListToMsg = (m, keys, title, f=plusify) => {
* @param defenseAttribute
* @returns {*}
*/
export function buildAttackEffectsMessage(attacker, defender, item, attackAttribute, defenseAttribute) {
export function buildAttackEffectsMessage(attacker, defender, item, attackAttribute, defenseAttribute, inputBoons) {
const attackerEffects = attacker.getEmbeddedCollection('ActiveEffect').filter(effect => !effect.disabled)
let m = _remapEffects(attackerEffects)

let defenderBoons = (defender?.system.bonuses.defense.boons[defenseAttribute] || 0) + (defender?.system.bonuses.defense.boons.all || 0)
const defenderString = defender?.name + ' [' + game.i18n.localize('DL.SpellTarget') + ']'
let otherBoons = ''
let inputBoonsMsg = inputBoons ? _toMsg(game.i18n.localize('DL.DialogInput'), plusify(inputBoons)) : ''
let itemBoons
switch (item.type) {
case 'spell':
Expand Down Expand Up @@ -98,6 +100,7 @@ export function buildAttackEffectsMessage(attacker, defender, item, attackAttrib

return (
boonsMsg +
inputBoonsMsg +
changeToMsg(m, 'system.bonuses.attack.damage', 'DL.TalentExtraDamage') +
changeToMsg(m, 'system.bonuses.attack.plus20Damage', 'DL.TalentExtraDamage20plus')
)
Expand All @@ -112,11 +115,13 @@ export function buildAttackEffectsMessage(attacker, defender, item, attackAttrib
* @param attribute
* @returns {string}
*/
export function buildAttributeEffectsMessage(actor, attribute) {
export function buildAttributeEffectsMessage(actor, attribute, inputBoons) {
const actorEffects = actor?.getEmbeddedCollection('ActiveEffect').filter(effect => !effect.disabled)
let m = _remapEffects(actorEffects)
let inputBoonsMsg = inputBoons ? _toMsg(game.i18n.localize('DL.DialogInput'), plusify(inputBoons)) : ''
let result = ''
result += changeListToMsg(m, [`system.bonuses.challenge.boons.${attribute}`, 'system.bonuses.challenge.boons.all' ], 'DL.TalentChallengeBoonsBanes')
result += changeListToMsg(m, [`system.bonuses.challenge.boons.${attribute}`, 'system.bonuses.challenge.boons.all' ], 'DL.TalentChallengeBoonsBanes') +
inputBoonsMsg
return result
}

Expand Down
Loading

0 comments on commit 89b4b8e

Please sign in to comment.