Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More stuff #144

Merged
merged 13 commits into from
Nov 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading