Enhance progression rolls, damage rolls and other fixes
Some checks failed
Release Creation / build (release) Failing after 56s
Some checks failed
Release Creation / build (release) Failing after 56s
This commit is contained in:
@ -10,6 +10,10 @@ export default class CthulhuEternalSkillSheet extends CthulhuEternalItemSheet {
|
||||
window: {
|
||||
contentClasses: ["skill-content"],
|
||||
},
|
||||
actions: {
|
||||
rollProgress: CthulhuEternalSkillSheet.#onRollProgress,
|
||||
},
|
||||
|
||||
}
|
||||
|
||||
/** @override */
|
||||
@ -22,7 +26,28 @@ export default class CthulhuEternalSkillSheet extends CthulhuEternalItemSheet {
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
context.isGM = game.user.isGM
|
||||
context.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.document.system.description, { async: true })
|
||||
return context
|
||||
}
|
||||
|
||||
static async #onRollProgress(event, target) {
|
||||
console.log("Rolling progress for skill", this, event, target)
|
||||
if (this.actor) {
|
||||
const roll = await new Roll("1d4").evaluate()
|
||||
if (roll) {
|
||||
// Create a chat message with the roll result
|
||||
const chatData = {
|
||||
user: game.user.id,
|
||||
speaker: ChatMessage.getSpeaker({ actor: this.actor }),
|
||||
content: `<div class="progress-roll">${game.i18n.localize("CTHULHUETERNAL.Label.skillProgress")} - ${this.document.name} +${roll.total}</div>`,
|
||||
type: CONST.CHAT_MESSAGE_TYPES.ROLL,
|
||||
roll: roll,
|
||||
};
|
||||
await ChatMessage.create(chatData);
|
||||
this.document.update( {"system.bonus" : this.document.system.bonus + roll.total, "system.rollFailed": false} )
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -55,6 +55,9 @@ export default class CthulhuEternalActor extends Actor {
|
||||
}
|
||||
}
|
||||
if (i.type === "bond") {
|
||||
if (!i.system?.bondType) {
|
||||
return super.createEmbeddedDocuments(embeddedName, data, operation)
|
||||
}
|
||||
if (i.system.bondType === "individual") {
|
||||
i.system.value = this.system.characteristics.cha.value
|
||||
} else {
|
||||
|
@ -84,7 +84,7 @@ export default class CthulhuEternalRoll extends Roll {
|
||||
return this.options.isNudgedRoll
|
||||
}
|
||||
|
||||
get wpCost() {
|
||||
get wpCost() {
|
||||
return this.options.wpCost
|
||||
}
|
||||
|
||||
@ -146,43 +146,48 @@ export default class CthulhuEternalRoll extends Roll {
|
||||
options.rollItem.enableStorage = true
|
||||
options.isNudge = false
|
||||
break
|
||||
case "damage":
|
||||
case "damage": {
|
||||
let isLethal = false
|
||||
options.isNudge = false
|
||||
if (options.rollItem.system.lethality > 0) {
|
||||
let lethalityRoll = new Roll("1d100")
|
||||
await lethalityRoll.evaluate()
|
||||
isLethal = (lethalityRoll.total <= options.rollItem.system.lethality)
|
||||
let flavor = `${options.rollItem.name} - <strong>Lethality Roll</strong> : ${lethalityRoll.total} <= ${options.rollItem.system.lethality} => ${isLethal}`
|
||||
if ( isLethal) {
|
||||
flavor += `<br>The target is lethally wounded => HP = 0`
|
||||
let lethalScore = (options?.previousResultType === "successCritical") ? options.rollItem.system.lethality * 2 : options.rollItem.system.lethality
|
||||
isLethal = (lethalityRoll.total <= lethalScore)
|
||||
let flavor = `${options.rollItem.name} - <strong> ${game.i18n.localize("CTHULHUETERNAL.Label.lethalityRoll")} </strong> : ${lethalityRoll.total} <= ${lethalScore} => ${isLethal}`
|
||||
if (isLethal) {
|
||||
flavor += `<br> ${game.i18n.localize("CTHULHUETERNAL.Label.lethalityWounded")} => HP = 0`
|
||||
} else {
|
||||
let wounds = Math.floor(lethalityRoll.total/10) + (lethalityRoll.total % 10)
|
||||
flavor += `<br>The target is not lethally wounded => HP loss = ${wounds}`
|
||||
let wounds = Math.floor(lethalityRoll.total / 10) + (lethalityRoll.total % 10)
|
||||
flavor += `<br> ${game.i18n.localize("CTHULHUETERNAL.Label.lethalityNotWounded")} => HP loss = ${wounds}`
|
||||
}
|
||||
await lethalityRoll.toMessage({
|
||||
flavor:flavor
|
||||
flavor: flavor
|
||||
});
|
||||
return
|
||||
}
|
||||
let formula = options.rollItem.system.damage
|
||||
if ( options.rollItem.system.weaponType === "melee" || options.rollItem.system.weaponType === "unarmed") {
|
||||
if (options.rollItem.system.weaponType === "melee" || options.rollItem.system.weaponType === "unarmed") {
|
||||
formula += ` + ${options.rollItem.damageBonus}`
|
||||
}
|
||||
if (options?.previousResultType === "successCritical") {
|
||||
formula = `( ${formula} ) * 2`
|
||||
}
|
||||
let damageRoll = new Roll(formula)
|
||||
await damageRoll.evaluate()
|
||||
await damageRoll.toMessage({
|
||||
flavor: `${options.rollItem.name} - Damage Roll`
|
||||
flavor: `${options.rollItem.name} - ${game.i18n.localize("CTHULHUETERNAL.Label.damageRoll")}`
|
||||
});
|
||||
}
|
||||
return
|
||||
case "weapon":
|
||||
case "weapon": {
|
||||
let era = game.settings.get("fvtt-cthulhu-eternal", "settings-era")
|
||||
if (era !== options.rollItem.system.settings) {
|
||||
ui.notifications.error(game.i18n.localize("CTHULHUETERNAL.Notifications.WrongEra"))
|
||||
console.log("WP Wrong Era", era, options.rollItem.system.weaponType)
|
||||
return
|
||||
}
|
||||
if (!SYSTEM.WEAPON_SKILL_MAPPING[era] || !SYSTEM.WEAPON_SKILL_MAPPING[era][options.rollItem.system.weaponType]) {
|
||||
if (!SYSTEM.WEAPON_SKILL_MAPPING[era]?.[options.rollItem.system.weaponType]) {
|
||||
ui.notifications.error(game.i18n.localize("CTHULHUETERNAL.Notifications.NoWeaponType"))
|
||||
console.log("WP Not found", era, options.rollItem.system.weaponType)
|
||||
return
|
||||
@ -190,7 +195,7 @@ export default class CthulhuEternalRoll extends Roll {
|
||||
options.weapon = options.rollItem
|
||||
if (options.rollItem.system.hasDirectSkill) {
|
||||
let skillName = options.rollItem.name
|
||||
options.rollItem = {type: "skill", name: skillName, system: {base: 0, bonus: options.weapon.system.directSkillValue} }
|
||||
options.rollItem = { type: "skill", name: skillName, system: { base: 0, bonus: options.weapon.system.directSkillValue } }
|
||||
options.initialScore = options.weapon.system.directSkillValue
|
||||
} else {
|
||||
let skillName = game.i18n.localize(SYSTEM.WEAPON_SKILL_MAPPING[era][options.rollItem.system.weaponType])
|
||||
@ -203,6 +208,7 @@ export default class CthulhuEternalRoll extends Roll {
|
||||
options.initialScore = options.rollItem.system.computeScore()
|
||||
console.log("WEAPON", skillName, era, options.rollItem)
|
||||
}
|
||||
}
|
||||
break
|
||||
default:
|
||||
options.initialScore = 50
|
||||
@ -343,6 +349,20 @@ export default class CthulhuEternalRoll extends Roll {
|
||||
resultType = "failureCritical"
|
||||
}
|
||||
}
|
||||
// As per the rules, a roll of 100 is always a failure, even if the target is above 100
|
||||
if (this.total === 100) {
|
||||
resultType = "failureCritical"
|
||||
}
|
||||
// A roll of 1 is always a critical success, even if the target is 1
|
||||
if (this.total === 1) {
|
||||
resultType = "successCritical"
|
||||
}
|
||||
if (rollData.targetScore <= 0) {
|
||||
resultType = "failure"
|
||||
if (this.total === 1) {
|
||||
resultType = "success"
|
||||
}
|
||||
}
|
||||
|
||||
this.options.resultType = resultType
|
||||
if (this.options.isNudgedRoll) {
|
||||
@ -354,6 +374,7 @@ export default class CthulhuEternalRoll extends Roll {
|
||||
this.options.isFailure = resultType === "failure" || resultType === "failureCritical"
|
||||
this.options.isCritical = resultType === "successCritical" || resultType === "failureCritical"
|
||||
}
|
||||
rollData.resultType = resultType
|
||||
this.options.isLowWP = rollData.isLowWP
|
||||
this.options.isZeroWP = rollData.isZeroWP
|
||||
this.options.isExhausted = rollData.isExhausted
|
||||
@ -377,6 +398,8 @@ export default class CthulhuEternalRoll extends Roll {
|
||||
return `${game.i18n.localize("CTHULHUETERNAL.Label.titleCharacteristic")}`
|
||||
case "san":
|
||||
return `${game.i18n.localize("CTHULHUETERNAL.Label.titleSAN")}`
|
||||
case "resource":
|
||||
return `${game.i18n.localize("CTHULHUETERNAL.Label.titleResource")}`
|
||||
default:
|
||||
return game.i18n.localize("CTHULHUETERNAL.Label.titleStandard")
|
||||
}
|
||||
@ -462,6 +485,33 @@ export default class CthulhuEternalRoll extends Roll {
|
||||
},
|
||||
{ rollMode: rollMode },
|
||||
)
|
||||
|
||||
console.log("Roll to message", this.options, this.options.rollData, this.options.rollItem)
|
||||
let rollData = this.options.rollData || this.options
|
||||
let rollItem = this.options.rollItem
|
||||
if (rollData.resultType.includes("failure") && rollItem.type === "skill") {
|
||||
// Is the skill able to progress
|
||||
if (rollItem.system.diceEvolved && !rollItem.system.rollFailed) {
|
||||
// If the skill is not adversary, we can evolve it
|
||||
if (!rollItem.system.isAdversary) {
|
||||
rollItem.system.rollFailed = true
|
||||
// Get the actor and update the skill
|
||||
const actor = game.actors.get(rollData.actorId)
|
||||
await actor.updateEmbeddedDocuments("Item", [{
|
||||
_id: rollItem._id,
|
||||
"system.rollFailed": true
|
||||
}])
|
||||
// Create a chat message to inform the user
|
||||
const flavor = `${rollItem.name} - ${game.i18n.localize("CTHULHUETERNAL.Label.skillFailed")}`
|
||||
await ChatMessage.create({
|
||||
user: game.user.id,
|
||||
content: `<div class="cthulhu-eternal-roll"><p>${flavor}</p></div>`,
|
||||
speaker: ChatMessage.getSpeaker({ actor: rollData.actor }),
|
||||
}, { rollMode: rollData.rollMode, create: true })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -42,10 +42,10 @@ export default class CthulhuEternalProtagonist extends foundry.abstract.TypeData
|
||||
value: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
|
||||
max: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
|
||||
recovery: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
|
||||
violence: new fields.ArrayField(new fields.BooleanField(), { required: true, initial: [false, false, false], min:3, max:3}),
|
||||
helplessness: new fields.ArrayField(new fields.BooleanField(), { required: true, initial: [false, false, false], min:3, max:3 }),
|
||||
violence: new fields.ArrayField(new fields.BooleanField(), { required: true, initial: [false, false, false], min: 3, max: 3 }),
|
||||
helplessness: new fields.ArrayField(new fields.BooleanField(), { required: true, initial: [false, false, false], min: 3, max: 3 }),
|
||||
breakingPoint: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
|
||||
insanity: new fields.StringField({ required: true, nullable: false, initial: "none", choices:SYSTEM.INSANITY }),
|
||||
insanity: new fields.StringField({ required: true, nullable: false, initial: "none", choices: SYSTEM.INSANITY }),
|
||||
})
|
||||
|
||||
schema.damageBonus = new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 })
|
||||
@ -59,7 +59,7 @@ export default class CthulhuEternalProtagonist extends foundry.abstract.TypeData
|
||||
currentStowed: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
|
||||
storage: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
|
||||
currentStorage: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
|
||||
checks: new fields.ArrayField(new fields.BooleanField(), { required: true, initial: [false, false, false], min:3, max:3 }),
|
||||
checks: new fields.ArrayField(new fields.BooleanField(), { required: true, initial: [false, false, false], min: 3, max: 3 }),
|
||||
nbValidChecks: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 })
|
||||
})
|
||||
|
||||
@ -72,7 +72,7 @@ export default class CthulhuEternalProtagonist extends foundry.abstract.TypeData
|
||||
birthplace: new fields.StringField({ required: true, nullable: false, initial: "" }),
|
||||
eyes: new fields.StringField({ required: true, nullable: false, initial: "" }),
|
||||
hair: new fields.StringField({ required: true, nullable: false, initial: "" }),
|
||||
harshness: new fields.StringField({ required: true, nullable: false, initial: "normal", choices:SYSTEM.HARSHNESS }),
|
||||
harshness: new fields.StringField({ required: true, nullable: false, initial: "normal", choices: SYSTEM.HARSHNESS }),
|
||||
adaptedToViolence: new fields.BooleanField({ required: true, initial: false }),
|
||||
adaptedToHelplessness: new fields.BooleanField({ required: true, initial: false })
|
||||
})
|
||||
@ -87,14 +87,14 @@ export default class CthulhuEternalProtagonist extends foundry.abstract.TypeData
|
||||
super.prepareDerivedData();
|
||||
|
||||
let updates = {}
|
||||
if ( this.wp.max !== this.characteristics.pow.value) {
|
||||
if (this.wp.max !== this.characteristics.pow.value) {
|
||||
updates[`system.wp.max`] = this.characteristics.pow.value
|
||||
}
|
||||
let hpMax = Math.round((this.characteristics.con.value + this.characteristics.str.value) / 2)
|
||||
if ( this.hp.max !== hpMax) {
|
||||
if (this.hp.max !== hpMax) {
|
||||
updates[`system.hp.max`] = hpMax
|
||||
}
|
||||
|
||||
|
||||
// Get Unnatural skill for MAX SAN
|
||||
let unnatural = this.parent.items.find(i => i.type === "skill" && i.name.toLowerCase() === game.i18n.localize("CTHULHUETERNAL.Skill.Unnatural").toLowerCase())
|
||||
let minus = 0
|
||||
@ -102,7 +102,7 @@ export default class CthulhuEternalProtagonist extends foundry.abstract.TypeData
|
||||
minus = unnatural.system.skillTotal
|
||||
}
|
||||
let maxSan = Math.max(99 - minus, 0)
|
||||
if ( this.san.max !== maxSan) {
|
||||
if (this.san.max !== maxSan) {
|
||||
updates[`system.san.max`] = maxSan
|
||||
}
|
||||
|
||||
@ -110,8 +110,8 @@ export default class CthulhuEternalProtagonist extends foundry.abstract.TypeData
|
||||
if (recoverySan > this.san.max) {
|
||||
recoverySan = this.san.max
|
||||
}
|
||||
if ( this.san.recovery !== recoverySan) {
|
||||
updates[`system.san.recovery`] = recoverySan
|
||||
if (this.san.recovery !== recoverySan) {
|
||||
updates[`system.san.recovery`] = recoverySan
|
||||
}
|
||||
|
||||
let dmgBonus = 0
|
||||
@ -126,7 +126,7 @@ export default class CthulhuEternalProtagonist extends foundry.abstract.TypeData
|
||||
} else if (this.characteristics.str.value <= 20) {
|
||||
dmgBonus = 2
|
||||
}
|
||||
if ( this.damageBonus !== dmgBonus) {
|
||||
if (this.damageBonus !== dmgBonus) {
|
||||
updates[`system.damageBonus`] = dmgBonus
|
||||
}
|
||||
|
||||
@ -144,9 +144,9 @@ export default class CthulhuEternalProtagonist extends foundry.abstract.TypeData
|
||||
if (this.resources.permanentRating < 0) {
|
||||
updates[`system.resources.permanentRating`] = 0
|
||||
}
|
||||
|
||||
|
||||
let resourceIndex = Math.max(Math.min(this.resources.permanentRating, 20), 0)
|
||||
let breakdown = SYSTEM.RESOURCE_BREAKDOWN[resourceIndex]
|
||||
let breakdown = SYSTEM.RESOURCE_BREAKDOWN[resourceIndex]
|
||||
if (this.resources.hand !== breakdown.hand) {
|
||||
updates[`system.resources.hand`] = breakdown.hand
|
||||
}
|
||||
@ -159,7 +159,7 @@ export default class CthulhuEternalProtagonist extends foundry.abstract.TypeData
|
||||
if (this.resources.nbValidChecks !== breakdown.checks) {
|
||||
updates[`system.resources.nbValidChecks`] = breakdown.checks
|
||||
}
|
||||
|
||||
|
||||
if (Object.keys(updates).length > 0) {
|
||||
this.parent.update(updates)
|
||||
}
|
||||
@ -173,14 +173,14 @@ export default class CthulhuEternalProtagonist extends foundry.abstract.TypeData
|
||||
return this.wp.value === 0
|
||||
}
|
||||
|
||||
isExhausted() {
|
||||
isExhausted() {
|
||||
return this.wp.exhausted
|
||||
}
|
||||
|
||||
modifyWP(value) {
|
||||
let updates = {}
|
||||
let wp = Math.max(Math.min(this.wp.value + value, this.wp.max), 0)
|
||||
if ( this.wp.value !== wp) {
|
||||
if (this.wp.value !== wp) {
|
||||
updates[`system.wp.value`] = wp
|
||||
}
|
||||
if (Object.keys(updates).length > 0) {
|
||||
@ -191,14 +191,14 @@ export default class CthulhuEternalProtagonist extends foundry.abstract.TypeData
|
||||
setBP() {
|
||||
let updates = {}
|
||||
let bp = Math.max(this.san.value - this.characteristics.pow.value, 0)
|
||||
if ( this.san.breakingPoint !== bp) {
|
||||
if (this.san.breakingPoint !== bp) {
|
||||
updates[`system.san.breakingPoint`] = bp
|
||||
}
|
||||
if (Object.keys(updates).length > 0) {
|
||||
this.parent.update(updates)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** */
|
||||
/**
|
||||
* Rolls a dice for a character.
|
||||
@ -220,10 +220,12 @@ export default class CthulhuEternalProtagonist extends foundry.abstract.TypeData
|
||||
actorName: this.parent.name,
|
||||
actorImage: this.parent.img,
|
||||
hasTarget,
|
||||
previousResultType: rollItem.resultType,
|
||||
target: opponentTarget
|
||||
})
|
||||
if (!roll) return null
|
||||
|
||||
await roll.toMessage({}, { rollMode: roll.options.rollMode })
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -178,7 +178,17 @@ export default class CthulhuEternalUtils {
|
||||
const html = options.fn(this);
|
||||
return html.replace(rgx, "$& selected");
|
||||
});
|
||||
}
|
||||
|
||||
static async damageRoll(rollMessage) {
|
||||
let rollData = rollMessage.rolls[0]?.options?.rollData
|
||||
let actor = game.actors.get(rollData.actorId)
|
||||
if (!actor) {
|
||||
ui.notifications.error(game.i18n.localize("CTHULHUETERNAL.Label.noActorFound"))
|
||||
return
|
||||
}
|
||||
rollData.weapon.resultType = rollData.resultType // Keep the result type from the roll message
|
||||
actor.system.roll("damage", rollData.weapon)
|
||||
}
|
||||
|
||||
static async nudgeRoll(rollMessage) {
|
||||
|
Reference in New Issue
Block a user