feat: separate skill value/max (transcendence pool vs level)
Release Creation / build (release) Successful in 58s

- skill.value = spendable transcendence pool (editable select)
- skill.max = max level (locked by default, unlock btn)
- computeRollFormula/computeResults/confront use skill.max
- clamp transcendence spend to skill.value
- resetTranscendence button in Bio&Notes
- v14 compat: duplicate→deepClone, mergeObject→spread, socket fixes
- Dialog v1 removed, DragDrop dedup, await fixes
This commit is contained in:
2026-07-24 09:00:26 +02:00
parent 8c79e6f0ba
commit 31e2561797
63 changed files with 385 additions and 340 deletions
+68 -42
View File
@@ -29,9 +29,9 @@ export class EcrymeActor extends Actor {
if (data instanceof Array) {
return super.create(data, options);
}
// If the created actor has items (only applicable to foundry.utils.duplicated actors) bypass the new actor creation logic
// If the created actor has items bypass the new actor creation logic
if (data.items) {
let actor = super.create(data, options);
let actor = await super.create(data, options);
return actor;
}
@@ -49,9 +49,9 @@ export class EcrymeActor extends Actor {
}
/* -------------------------------------------- */
_preUpdate(changed, options, user) {
async _preUpdate(changed, options, user) {
super._preUpdate(changed, options, user);
await super._preUpdate(changed, options, user);
}
/* -------------------------------------------- */
@@ -73,7 +73,7 @@ export class EcrymeActor extends Actor {
return comp;
}
getArchetype() {
let comp = foundry.utils.duplicate(this.items.find(item => item.type == 'archetype') || { name: "Pas d'archetype" })
let comp = foundry.utils.deepClone(this.items.find(item => item.type == 'archetype') || { name: "Pas d'archetype" })
if (comp?.system) {
comp.tarot = EcrymeUtility.getTarot(comp.system.lametutelaire)
}
@@ -92,7 +92,7 @@ export class EcrymeActor extends Actor {
}
/* ----------------------- --------------------- */
addAnnencyActor(actorId) {
let members = foundry.utils.duplicate(this.system.base.characters)
let members = foundry.utils.deepClone(this.system.base.characters)
members.push(actorId)
this.update({ 'system.base.characters': members })
}
@@ -123,7 +123,7 @@ export class EcrymeActor extends Actor {
/* -------------------------------------------- */
getTrait(id) {
//console.log("TRAITS", this.items, this.items.filter(it => it.type == "trait") )
return this.items.find(it => it.type == "trait" && it._id == id)
return this.items.find(it => it.type == "trait" && it.id === id)
}
/* -------------------------------------------- */
getSpecialization(id) {
@@ -136,7 +136,7 @@ export class EcrymeActor extends Actor {
}
/* -------------------------------------------- */
prepareSkills() {
let skills = foundry.utils.duplicate(this.system.skills)
let skills = foundry.utils.deepClone(this.system.skills)
for (let categKey in skills) {
let category = skills[categKey]
for (let skillKey in category.skilllist) {
@@ -148,22 +148,22 @@ export class EcrymeActor extends Actor {
}
/* -------------------------------------------- */
getCephalySkills() {
let skills = foundry.utils.duplicate(this.system.cephaly.skilllist)
let skills = foundry.utils.deepClone(this.system.cephaly.skilllist)
return skills
}
/* -------------------------------------------- */
getImpacts() {
let comp = foundry.utils.duplicate(this.items.filter(item => item.type == 'impact') || [])
let comp = foundry.utils.deepClone(this.items.filter(item => item.type == 'impact') || [])
return comp;
}
/* -------------------------------------------- */
getWeapons() {
let comp = foundry.utils.duplicate(this.items.filter(item => item.type == 'weapon') || [])
let comp = foundry.utils.deepClone(this.items.filter(item => item.type == 'weapon') || [])
EcrymeUtility.sortArrayObjectsByName(comp)
return comp;
}
getManeuvers() {
let comp = foundry.utils.duplicate(this.items.filter(item => item.type == 'maneuver') || [])
let comp = foundry.utils.deepClone(this.items.filter(item => item.type == 'maneuver') || [])
EcrymeUtility.sortArrayObjectsByName(comp)
return comp;
}
@@ -171,7 +171,7 @@ export class EcrymeActor extends Actor {
getItemById(id) {
let item = this.items.find(item => item.id == id);
if (item) {
item = foundry.utils.duplicate(item)
item = foundry.utils.deepClone(item)
}
return item;
}
@@ -206,13 +206,13 @@ export class EcrymeActor extends Actor {
/* ------------------------------------------- */
async buildContainerTree() {
let equipments = foundry.utils.duplicate(this.items.filter(item => item.type == "equipment") || [])
let equipments = foundry.utils.deepClone(this.items.filter(item => item.type == "equipment") || [])
for (let equip1 of equipments) {
if (equip1.system.iscontainer) {
equip1.system.contents = []
equip1.system.contentsEnc = 0
for (let equip2 of equipments) {
if (equip1._id != equip2.id && equip2.system.containerid == equip1.id) {
if (equip1.id !== equip2.id && equip2.system.containerid == equip1.id) {
equip1.system.contents.push(equip2)
let q = equip2.system.quantity ?? 1
equip1.system.contentsEnc += q * equip2.system.weight
@@ -288,7 +288,7 @@ export class EcrymeActor extends Actor {
/* -------------------------------------------- */
clearInitiative() {
this.getFlag("world", "initiative", -1)
this.setFlag("world", "initiative", -1)
}
/* -------------------------------------------- */
getInitiativeScore(combatId, combatantId) {
@@ -301,13 +301,13 @@ export class EcrymeActor extends Actor {
getSubActors() {
let subActors = [];
for (let id of this.system.subactors) {
subActors.push(foundry.utils.duplicate(game.actors.get(id)))
subActors.push(foundry.utils.deepClone(game.actors.get(id)))
}
return subActors;
}
/* -------------------------------------------- */
async addSubActor(subActorId) {
let subActors = foundry.utils.duplicate(this.system.subactors);
let subActors = foundry.utils.deepClone(this.system.subactors);
subActors.push(subActorId);
await this.update({ 'system.subactors': subActors });
}
@@ -378,10 +378,10 @@ export class EcrymeActor extends Actor {
rollData.actorId = this.id
rollData.img = this.img
rollData.isReroll = false
rollData.config = game.system.ecryme.config
rollData.traits = this.getRollTraits().map(t => ({ _id: t.id, name: t.name, img: t.img, system: { level: t.system.level, traitype: t.system.traitype } }))
rollData.spleen = this.getSpleen() ? foundry.utils.duplicate(this.getSpleen()) : null
rollData.ideal = this.getIdeal() ? foundry.utils.duplicate(this.getIdeal()) : null
rollData.config = game.ecryme.config
rollData.traits = this.getRollTraits().map(t => ({ id: t.id, name: t.name, img: t.img, system: { level: t.system.level, traitype: t.system.traitype } }))
rollData.spleen = this.getSpleen() ? foundry.utils.deepClone(this.getSpleen()) : null
rollData.ideal = this.getIdeal() ? foundry.utils.deepClone(this.getIdeal()) : null
rollData.confrontBonus = this.getBonusList()
return rollData
@@ -402,7 +402,7 @@ export class EcrymeActor extends Actor {
}
} else {
skill = this.system.skills[categKey].skilllist[skillKey]
skill = foundry.utils.duplicate(skill)
skill = foundry.utils.deepClone(skill)
skill.spec = this.getSpecializations(skillKey)
}
@@ -434,7 +434,7 @@ export class EcrymeActor extends Actor {
let spec = this.items.find(it => it.type == "specialization" && it.id == specId)
rollData.mode = "skill"
rollData.selectedSpecs = [spec.id]
rollData.forcedSpec = foundry.utils.duplicate(spec)
rollData.forcedSpec = foundry.utils.deepClone(spec)
rollData.title = game.i18n.localize(rollData.skill.name)
this.startRoll(rollData).catch("Error on startRoll")
}
@@ -444,11 +444,11 @@ export class EcrymeActor extends Actor {
let rollData = this.getCommonSkill(categKey, skillKey)
rollData.mode = "skill"
rollData.title = game.i18n.localize("ECRY.ui.confrontation") + " : " + game.i18n.localize(rollData.skill.name)
rollData.executionTotal = rollData.skill.value
rollData.preservationTotal = rollData.skill.value
rollData.executionTotal = rollData.skill.max
rollData.preservationTotal = rollData.skill.max
rollData.applyTranscendence = "execution"
rollData.traitsBonus = foundry.utils.duplicate(rollData.traits)
rollData.traitsMalus = foundry.utils.duplicate(rollData.traits)
rollData.traitsBonus = foundry.utils.deepClone(rollData.traits)
rollData.traitsMalus = foundry.utils.deepClone(rollData.traits)
console.log("ROLLDATA", rollData)
let confrontStartDialog = await EcrymeConfrontStartDialog.create(this, rollData)
confrontStartDialog.render(true)
@@ -457,16 +457,16 @@ export class EcrymeActor extends Actor {
async rollCephalySkillConfront(skillKey) {
let rollData = this.getCommonRollData()
rollData.mode = "cephaly"
rollData.skill = foundry.utils.duplicate(this.system.cephaly.skilllist[skillKey])
rollData.annency = foundry.utils.duplicate(this.getAnnency())
rollData.skill = foundry.utils.deepClone(this.system.cephaly.skilllist[skillKey])
rollData.annency = foundry.utils.deepClone(this.getAnnency())
rollData.img = rollData.skill.img
rollData.skill.categKey = "cephaly"
rollData.skill.skillKey = skillKey
rollData.title = game.i18n.localize("ECRY.ui.cephaly") + " : " + game.i18n.localize(rollData.skill.name)
rollData.executionTotal = rollData.skill.value
rollData.preservationTotal = rollData.skill.value
rollData.traitsBonus = foundry.utils.duplicate(rollData.traits)
rollData.traitsMalus = foundry.utils.duplicate(rollData.traits)
rollData.executionTotal = rollData.skill.max
rollData.preservationTotal = rollData.skill.max
rollData.traitsBonus = foundry.utils.deepClone(rollData.traits)
rollData.traitsMalus = foundry.utils.deepClone(rollData.traits)
rollData.applyTranscendence = "execution"
let confrontStartDialog = await EcrymeConfrontStartDialog.create(this, rollData)
confrontStartDialog.render(true)
@@ -482,27 +482,27 @@ export class EcrymeActor extends Actor {
rollData = this.getCommonSkill("physical", "shooting")
}
rollData.mode = "weapon"
rollData.weapon = foundry.utils.duplicate(weapon)
rollData.weapon = foundry.utils.deepClone(weapon)
rollData.title = game.i18n.localize("ECRY.ui.confrontation") + " : " + game.i18n.localize(rollData.skill.name)
rollData.executionTotal = rollData.skill.value
rollData.preservationTotal = rollData.skill.value
rollData.traitsBonus = foundry.utils.duplicate(rollData.traits)
rollData.traitsMalus = foundry.utils.duplicate(rollData.traits)
rollData.executionTotal = rollData.skill.max
rollData.preservationTotal = rollData.skill.max
rollData.traitsBonus = foundry.utils.deepClone(rollData.traits)
rollData.traitsMalus = foundry.utils.deepClone(rollData.traits)
rollData.applyTranscendence = "execution"
let confrontStartDialog = await EcrymeConfrontStartDialog.create(this, rollData)
confrontStartDialog.render(true)
}
/* -------------------------------------------- */
rollWeapon(weaponId) {
let weapon = this.items.get(weaponId)
if (weapon) {
weapon = foundry.utils.duplicate(weapon)
weapon = foundry.utils.deepClone(weapon)
let rollData = this.getCommonRollData()
if (weapon.system.armetype == "mainsnues" || weapon.system.armetype == "epee") {
rollData.attr = { label: "(Physique+Habilité)/2", value: Math.floor((this.getPhysiqueMalus() + this.system.attributs.physique.value + this.system.attributs.habilite.value) / 2) }
} else {
rollData.attr = foundry.utils.duplicate(this.system.attributs.habilite)
rollData.attr = foundry.utils.deepClone(this.system.attributs.habilite)
}
rollData.mode = "weapon"
rollData.weapon = weapon
@@ -514,6 +514,32 @@ export class EcrymeActor extends Actor {
}
}
/* -------------------------------------------- */
resetSkillPool() {
const updateData = {}
const skills = this.system.skills
for (const categKey of Object.keys(skills)) {
const skilllist = skills[categKey]?.skilllist
if (!skilllist) continue
for (const skillKey of Object.keys(skilllist)) {
const skill = skilllist[skillKey]
if (skill.max !== undefined) {
updateData[`system.skills.${categKey}.skilllist.${skillKey}.value`] = skill.max
}
}
}
const cephaly = this.system.cephaly?.skilllist
if (cephaly) {
for (const skillKey of Object.keys(cephaly)) {
const skill = cephaly[skillKey]
if (skill.max !== undefined) {
updateData[`system.cephaly.skilllist.${skillKey}.value`] = skill.max
}
}
}
return this.update(updateData)
}
/* -------------------------------------------- */
async startRoll(rollData) {
let rollDialog = await EcrymeRollDialog.create(this, rollData)