Skip to content
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
2 changes: 2 additions & 0 deletions src/assets/ui/consumables/incantation.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@
"DL.ConsumableType": "Consumable Type",
"DL.ConsumableTypeD": "Drink",
"DL.ConsumableTypeF": "Food",
"DL.ConsumableTypeI": "Incantation",
"DL.ConsumableTypeP": "Potion",
"DL.ConsumableTypeT": "Trinket",
"DL.ConsumableTypeV": "Poison",
Expand Down
106 changes: 58 additions & 48 deletions src/module/actor/actor.js
Original file line number Diff line number Diff line change
Expand Up @@ -449,27 +449,27 @@ export class DemonlordActor extends Actor {

// Attack modifier and Boons/Banes
const modifiers = [
item.system.action?.rollbonus || 0,
attacker.system?.attributes[attackAttribute]?.modifier || 0,
attacker.system?.bonuses.attack.modifier?.[attackAttribute] || 0,
attacker.system?.bonuses.attack.modifier?.all || 0,
attacker.system?.bonuses.attack.modifier?.weapon || 0,
parseInt(item.system.action?.rollbonus) || 0,
parseInt(attacker.system?.attributes[attackAttribute]?.modifier) || 0,
parseInt(attacker.system?.bonuses.attack.modifier?.[attackAttribute]) || 0,
parseInt(attacker.system?.bonuses.attack.modifier?.all) || 0,
parseInt(attacker.system?.bonuses.attack.modifier?.weapon) || 0,
parseInt(inputModifier) || 0,
]

let boons =
(parseInt(item.system.action.boonsbanes) || 0) +
(parseInt(inputBoons) || 0) +
(attacker.system.bonuses.attack.boons[attackAttribute] || 0) +
(attacker.system.bonuses.attack.boons.all || 0) +
(attacker.system.bonuses.attack.boons.weapon || 0)
(parseInt(attacker.system.bonuses.attack.boons[attackAttribute]) || 0) +
(parseInt(attacker.system.bonuses.attack.boons.all) || 0) +
(parseInt(attacker.system.bonuses.attack.boons.weapon) || 0)

const horrifyingBane = game.settings.get('demonlord', 'horrifyingBane')
const ignoreLevelDependentBane = (game.settings.get('demonlord', 'optionalRuleLevelDependentBane') && ((attacker.system?.level >=3 && attacker.system?.level <=6 && defender?.system?.difficulty <= 25) || (attacker.system?.level >=7 && defender?.system?.difficulty <= 50))) ? false : true
boons -=
(defender?.system.bonuses.defense.boons[defenseAttribute] || 0) +
(defender?.system.bonuses.defense.boons.all || 0) +
(defender?.system.bonuses.defense.boons.weapon || 0) +
(parseInt(defender?.system.bonuses.defense.boons[defenseAttribute]) || 0) +
(parseInt(defender?.system.bonuses.defense.boons.all) || 0) +
(parseInt(defender?.system.bonuses.defense.boons.weapon) || 0) +
(horrifyingBane && ignoreLevelDependentBane && !attacker.system.horrifying && !attacker.system.frightening && defender?.system.horrifying && 1 || 0)

// Check if requirements met
Expand Down Expand Up @@ -560,7 +560,7 @@ export class DemonlordActor extends Actor {

async rollAttributeChallenge(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 boons = (parseInt(inputBoons) || 0) + (parseInt(this.system.bonuses.challenge.boons[attribute.key]) || 0) + (parseInt(this.system.bonuses.challenge.boons.all) || 0)
const boonsReroll = parseInt(this.system.bonuses.rerollBoon1Dice)

const challengeRoll = new Roll(this.rollFormula(modifiers, boons, boonsReroll), this.system)
Expand Down Expand Up @@ -596,15 +596,15 @@ export class DemonlordActor extends Actor {

const modifiers = [
parseInt(inputModifier),
attacker.system?.attributes[attribute.key]?.modifier || 0,
attacker.system?.bonuses?.attack?.modifier?.[attribute.key] || 0,
attacker.system?.bonuses?.attack?.modifier?.all || 0,
parseInt(attacker.system?.attributes[attribute.key]?.modifier) || 0,
parseInt(attacker.system?.bonuses?.attack?.modifier?.[attribute.key]) || 0,
parseInt(attacker.system?.bonuses?.attack?.modifier?.all) || 0,
]

let boons =
(parseInt(inputBoons) || 0) +
(attacker.system.bonuses.attack.boons?.[attribute.key] || 0) +
(attacker.system.bonuses.attack.boons?.all || 0)
(parseInt(attacker.system.bonuses.attack.boons?.[attribute.key]) || 0) +
(parseInt(attacker.system.bonuses.attack.boons?.all) || 0)

if (defendersTokens.length === 1) boons -= (defender?.system.bonuses.defense.boons[defense] || 0) + (defender?.system.bonuses.defense.boons.all || 0) +
(horrifyingBane && ignoreLevelDependentBane && !attacker.system.horrifying && !attacker.system.frightening && defender?.system.horrifying && 1 || 0)
Expand Down Expand Up @@ -684,17 +684,17 @@ export class DemonlordActor extends Actor {
const attacker = this

const modifiers = [
talentData.action?.rollbonus || 0,
attacker.system?.attributes[attackAttribute]?.modifier || 0,
attacker.system?.bonuses.attack.modifier?.[attackAttribute] || 0,
attacker.system?.bonuses.attack.modifier?.all || 0,
parseInt(talentData.action?.rollbonus) || 0,
parseInt(attacker.system?.attributes[attackAttribute]?.modifier) || 0,
parseInt(attacker.system?.bonuses.attack.modifier?.[attackAttribute]) || 0,
parseInt(attacker.system?.bonuses.attack.modifier?.all) || 0,
parseInt(inputModifier) || 0,
]

let boons =
(parseInt(inputBoons) || 0) +
(this.system.bonuses.attack.boons[attackAttribute] || 0) +
(this.system.bonuses.attack.boons.all || 0) +
(parseInt(this.system.bonuses.attack.boons[attackAttribute]) || 0) +
(parseInt(this.system.bonuses.attack.boons.all) || 0) +
parseInt(talentData.action?.boonsbanes || 0)

const horrifyingBane = game.settings.get('demonlord', 'horrifyingBane')
Expand Down Expand Up @@ -773,29 +773,29 @@ export class DemonlordActor extends Actor {
const attacker = this

const modifiers = [
spellData.action?.rollbonus || 0,
attacker.system?.attributes[attackAttribute]?.modifier || 0,
attacker.system?.bonuses.attack.modifier?.[attackAttribute] || 0,
attacker.system?.bonuses.attack.modifier?.all || 0,
attacker.system?.bonuses.attack.modifier?.spell || 0,
parseInt(spellData.action?.rollbonus) || 0,
parseInt(attacker.system?.attributes[attackAttribute]?.modifier) || 0,
parseInt(attacker.system?.bonuses.attack.modifier?.[attackAttribute]) || 0,
parseInt(attacker.system?.bonuses.attack.modifier?.all) || 0,
parseInt(attacker.system?.bonuses.attack.modifier?.spell) || 0,
parseInt(inputModifier) || 0,
]

let boons =
(parseInt(inputBoons) || 0) +
(parseInt(spellData.action?.boonsbanes) || 0) +
(this.system.bonuses.attack.boons[attackAttribute] || 0) +
(this.system.bonuses.attack.boons.all || 0) +
(this.system.bonuses.attack.boons.spell || 0)
(parseInt(this.system.bonuses.attack.boons[attackAttribute]) || 0) +
(parseInt(this.system.bonuses.attack.boons.all) || 0) +
(parseInt(this.system.bonuses.attack.boons.spell) || 0)

const horrifyingBane = game.settings.get('demonlord', 'horrifyingBane')
const ignoreLevelDependentBane = (game.settings.get('demonlord', 'optionalRuleLevelDependentBane') && ((this.system?.level >=3 && this.system?.level <=6 && target?.actor?.system?.difficulty <= 25) || (this.system?.level >=7 && target?.actor?.system?.difficulty <= 50))) ? false : true

if (target)
boons -=
(target?.actor?.system.bonuses.defense.boons[defenseAttribute] || 0) +
(target?.actor?.system.bonuses.defense.boons.all || 0) +
(target?.actor?.system.bonuses.defense.boons.spell || 0) +
(parseInt(target?.actor?.system.bonuses.defense.boons[defenseAttribute]) || 0) +
(parseInt(target?.actor?.system.bonuses.defense.boons.all) || 0) +
(parseInt(target?.actor?.system.bonuses.defense.boons.spell) || 0) +
(horrifyingBane && ignoreLevelDependentBane && !this.system.horrifying && !this.system.frightening && target?.actor?.system.horrifying && 1 || 0)

const boonsReroll = parseInt(this.system.bonuses.rerollBoon1Dice)
Expand Down Expand Up @@ -864,14 +864,24 @@ export class DemonlordActor extends Actor {
await item.update({'system.quantity': --item.system.quantity}, {parent: this})
}

if (item.system?.action?.attack) {
launchRollDialog(game.i18n.localize('DL.ItemVSRoll') + game.i18n.localize(item.name), async (event, html) =>
await this.useItem(item, html.form.elements.boonsbanes.value, html.form.elements.modifier.value),
)
// Incantations
if (item.system.consumabletype === 'I' && item.system.contents.length === 1) {
item.system.contents[0].name = `${game.i18n.localize('DL.ConsumableTypeI')}: ${item.system.contents[0].name}`
let spell = new Item(item.system.contents[0])
let tempSpell = await this.createEmbeddedDocuments('Item', [spell])
// Before deleting the spell we store the uuid of the spell in the chat card for later use
const updateData = {[`flags.${game.system.id}.incantationSpellUuid`]: item.system.contents[0]._stats.compendiumSource};
await tempSpell[0].update(updateData);
await this.rollSpell(tempSpell[0].id)
await this.deleteEmbeddedDocuments('Item', [tempSpell[0].id])
} else {
await this.useItem(item, 0, 0)
if (item.system?.action?.attack) {
launchRollDialog(game.i18n.localize('DL.ItemVSRoll') + game.i18n.localize(item.name), async (event, html) =>
await this.useItem(item, html.form.elements.boonsbanes.value, html.form.elements.modifier.value), )
} else {
await this.useItem(item, 0, 0)
}
}

if (deleteItem) await item.delete()

}
Expand All @@ -891,26 +901,26 @@ export class DemonlordActor extends Actor {
const attacker = this

const modifiers = [
item.system.action.rollbonus || 0,
attacker.system?.attributes[attackAttribute]?.modifier || 0,
attacker.system?.bonuses.attack.modifier?.[attackAttribute] || 0,
attacker.system?.bonuses.attack.modifier?.all || 0,
parseInt(item.system.action.rollbonus) || 0,
parseInt(attacker.system?.attributes[attackAttribute]?.modifier) || 0,
parseInt(attacker.system?.bonuses.attack.modifier?.[attackAttribute]) || 0,
parseInt(attacker.system?.bonuses.attack.modifier?.all) || 0,
parseInt(inputModifier) || 0,
]

let boons =
(parseInt(inputBoons) || 0) +
(this.system.bonuses.attack.boons[attackAttribute] || 0) +
(this.system.bonuses.attack.boons.all || 0) +
(parseInt(this.system.bonuses.attack.boons[attackAttribute]) || 0) +
(parseInt(this.system.bonuses.attack.boons.all) || 0) +
parseInt(itemData.action?.boonsbanes || 0)

const horrifyingBane = game.settings.get('demonlord', 'horrifyingBane')
const ignoreLevelDependentBane = (game.settings.get('demonlord', 'optionalRuleLevelDependentBane') && ((this.system?.level >=3 && this.system?.level <=6 && target?.actor?.system?.difficulty <= 25) || (this.system?.level >=7 && target?.actor?.system?.difficulty <= 50))) ? false : true

if (targets.length === 1)
boons -= (
(target?.actor?.system.bonuses.defense.boons[defenseAttribute] || 0) +
(target?.actor?.system.bonuses.defense.boons.all || 0) +
(parseInt(target?.actor?.system.bonuses.defense.boons[defenseAttribute]) || 0) +
(parseInt(target?.actor?.system.bonuses.defense.boons.all || 0)) +
(horrifyingBane && ignoreLevelDependentBane && !this.system.horrifying && !this.system.frightening && target?.actor?.system.horrifying && 1 || 0))
const boonsReroll = parseInt(this.system.bonuses.rerollBoon1Dice)

Expand Down
78 changes: 76 additions & 2 deletions src/module/actor/sheets/base-actor-sheet.js
Original file line number Diff line number Diff line change
Expand Up @@ -714,16 +714,18 @@ export default class DLBaseActorSheet extends HandlebarsApplicationMixin(ActorSh
/** @override */
async _onDropItem(ev, _item) {
try {
const item = _item
const incantation = this.tabGroups.primary === 'inventory' && _item.type === 'spell' ? true : false
const item = incantation ? await this.createIncantation(_item) : _item

// TODO: If item (by ID) exists in this object, ignore
if (this.actor.items.has(_item.id)) return

const isAllowed = await this.checkDroppedItem(_item)
if (isAllowed) {
const data = foundry.utils.duplicate(item);
this.actor.createEmbeddedDocuments('Item', [data])
let dropItem = await this.actor.createEmbeddedDocuments('Item', [data])
await this.postDropItemCreate(data)
if (incantation) await this.embedSpell(dropItem[0], foundry.utils.duplicate(_item))
} else {
console.warn('Wrong item type dragged', this.document, item)
}
Expand All @@ -739,4 +741,76 @@ export default class DLBaseActorSheet extends HandlebarsApplicationMixin(ActorSh
async postDropItemCreate(_itemData) {
return true
}

async embedSpell(incantation, spell) {
const containerData = foundry.utils.duplicate(incantation)
containerData.system.contents.push(spell)
await incantation.update(containerData, {diff: false})
}

async createIncantation(_itemData) {
let availability
let value
switch (_itemData.system.rank) {
case 0:
availability = 'U'
value = '1 ss'
break
case 1:
availability = 'U'
value = '5 ss'
break
case 2:
availability = 'R'
value = '1 gc'
break
case 3:
availability = 'R'
value = '5 gc'
break
case 4:
availability = 'E'
value = '10 gc'
break
case 5:
availability = 'E'
value = '50 gc'
break
case 6:
availability = 'E'
value = '100 gc'
break
case 7:
availability = 'E'
value = '250 gc'
break
case 8:
availability = 'E'
value = '500 gc'
break
case 9:
availability = 'E'
value = '1000 gc'
break
case 10:
availability = 'E'
value = '5000 gc'
break
}

let incantation = new Item({
name: `${game.i18n.localize('DL.ConsumableTypeI')}: ${_itemData.name}`,
type: 'item',
system: {
consumabletype: 'I',
description : _itemData.system.description,
enrichedDescription : _itemData.system.enrichedDescription,
enrichedDescriptionUnrolled : _itemData.system.enrichedDescriptionUnrolled,
availability : availability,
value : value,
},
img: _itemData.img,
})
return incantation
}
}
8 changes: 8 additions & 0 deletions src/module/chat/roll-messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,12 @@ export async function postSpellToChat(actor, spell, attackRoll, target, inputBoo
data['damageType'] = spellData.action?.damagetype
data['damageTypes'] = spellData.action?.damagetypes
data['damageExtra20PlusFormula'] = spellData.action?.plus20damage + extraDamage20Plus
// Incantation (effects) - We replace the uuid of the Scene.Actor.SpellItem.effect with the uuid of the SpellItem.effect as we already deleted the spell from the actor.
if (spell.getFlag('demonlord','incantationSpellUuid')) {
[...spell.effects].forEach((effect) => {
effect.incantationspelluuid = `${spell.getFlag('demonlord','incantationSpellUuid')}.ActiveEffect.${effect._id}`
})
}
data['itemEffects'] = spell.effects
}
data['description'] = spellData.description
Expand Down Expand Up @@ -435,6 +441,8 @@ export async function postSpellToChat(actor, spell, attackRoll, target, inputBoo
data['ifBlindedRoll'] = rollMode === 'blindroll'
data['hasAreaTarget'] = spellData?.activatedEffect?.target?.type in CONFIG.DL.actionAreaShape
data['actorInfo'] = buildActorInfo(actor)
// Incantation (measured templates) - We replace the uuid of the Scene.Actor.SpellItem with the uuid of the SpellItem as we already deleted the spell from the actor.
data['incantationspelluuid'] = spell.getFlag('demonlord','incantationSpellUuid')

const chatData = getChatBaseData(actor, rollMode)
if (attackRoll) {
Expand Down
6 changes: 3 additions & 3 deletions src/module/combat/combat.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export class DLCombat extends Combat {
await this.rollInitiativeStandard(ids, options)
return this
case "i":
await this.rollInitiativeInduvidual(ids, options)
await this.rollInitiativeIndividual(ids, options)
return this
case "h":
await this.rollInitiativeGroup(ids, options)
Expand All @@ -30,8 +30,8 @@ export class DLCombat extends Combat {
}

// eslint-disable-next-line no-unused-vars
async rollInitiativeInduvidual(ids, {formula = null, updateTurn = true, messageOptions = {}} = {}) {
console.log("Calling rollInitiativeInduvidual with", ids, formula, updateTurn, messageOptions)
async rollInitiativeIndividual(ids, {formula = null, updateTurn = true, messageOptions = {}} = {}) {
console.log("Calling rollInitiativeIndividual with", ids, formula, updateTurn, messageOptions)
// Structure input data
ids = typeof ids === 'string' ? [ids] : ids
const combatantUpdates = []
Expand Down
Loading