mirror of
https://github.com/fzumpe/foundry-dnd5e-adaptive-resistances.git
synced 2026-06-06 21:10:02 +02:00
Initial Commit
This commit is contained in:
parent
bb5c7509bd
commit
e1abf88575
74
lang/de.json
Normal file
74
lang/de.json
Normal file
@ -0,0 +1,74 @@
|
||||
{
|
||||
"ADR.Features.ValidDamageTypes": "Reagiert auf",
|
||||
"ADR.Features.Prefix.Resistance": "Adaptive Resistenz",
|
||||
"ADR.Features.Prefix.Immunity": "Adaptive Immunität",
|
||||
"ADR.Features.RulesText.Resistance": "Nach einem Treffer merkt sich das Wesen die Schadensart, wenn der Schaden tatsächlich durchgedrungen ist. Danach erhält es eine begrenzte Resistenz gegen genau diese Schadensart. Trifft es später eine andere passende Schadensart, ersetzt diese die vorherige Anpassung. Wird der Schaden bereits durch Resistenz oder Immunität abgefangen, verändert sich die Anpassung nicht.",
|
||||
"ADR.Features.RulesText.Immunity": "Nach einem Treffer merkt sich das Wesen die Schadensart, wenn der Schaden tatsächlich durchgedrungen ist. Danach erhält es eine begrenzte Immunität gegen genau diese Schadensart. Trifft es später eine andere passende Schadensart, ersetzt diese die vorherige Anpassung. Wird der Schaden bereits durch Resistenz oder Immunität abgefangen, verändert sich die Anpassung nicht.",
|
||||
"ADR.Features.Set.Elemental.Name": "Elementar",
|
||||
"ADR.Features.Set.Elemental.Description": "Das Wesen passt sich an elementare Gewalt an: ätzende Säure, zehrende Kälte, sengendes Feuer, zuckende Blitze und erschütternden Donner.",
|
||||
"ADR.Features.Set.Magical.Name": "Magisch",
|
||||
"ADR.Features.Set.Magical.Description": "Das Wesen passt sich an übernatürliche Schadensarten an, die aus reiner magischer Kraft, finsterer Nekrose, mentalem Druck oder gleißender Macht entstehen.",
|
||||
"ADR.Features.Set.Profane.Name": "Profan",
|
||||
"ADR.Features.Set.Profane.Description": "Das Wesen passt sich an körperliche Gewalt durch Wucht, Stich und Hieb an. Diese Anpassung folgt den dnd5e-Schadenstypen und unterscheidet nicht zuverlässig, ob eine Waffe magisch oder nichtmagisch ist.",
|
||||
"ADR.Features.Set.Single.acid.Name": "Säure",
|
||||
"ADR.Features.Set.Single.acid.Description": "Das Wesen passt sich an Säureschaden an, sobald dieser tatsächlich durch seine Abwehr dringt.",
|
||||
"ADR.Features.Set.Single.bludgeoning.Name": "Wucht",
|
||||
"ADR.Features.Set.Single.bludgeoning.Description": "Das Wesen passt sich an Wuchtschaden an, sobald dieser tatsächlich durch seine Abwehr dringt.",
|
||||
"ADR.Features.Set.Single.cold.Name": "Kälte",
|
||||
"ADR.Features.Set.Single.cold.Description": "Das Wesen passt sich an Kälteschaden an, sobald dieser tatsächlich durch seine Abwehr dringt.",
|
||||
"ADR.Features.Set.Single.fire.Name": "Feuer",
|
||||
"ADR.Features.Set.Single.fire.Description": "Das Wesen passt sich an Feuerschaden an, sobald dieser tatsächlich durch seine Abwehr dringt.",
|
||||
"ADR.Features.Set.Single.force.Name": "Energie",
|
||||
"ADR.Features.Set.Single.force.Description": "Das Wesen passt sich an Energieschaden an, sobald dieser tatsächlich durch seine Abwehr dringt.",
|
||||
"ADR.Features.Set.Single.lightning.Name": "Blitz",
|
||||
"ADR.Features.Set.Single.lightning.Description": "Das Wesen passt sich an Blitzschaden an, sobald dieser tatsächlich durch seine Abwehr dringt.",
|
||||
"ADR.Features.Set.Single.necrotic.Name": "Nekrotisch",
|
||||
"ADR.Features.Set.Single.necrotic.Description": "Das Wesen passt sich an nekrotischen Schaden an, sobald dieser tatsächlich durch seine Abwehr dringt.",
|
||||
"ADR.Features.Set.Single.piercing.Name": "Stich",
|
||||
"ADR.Features.Set.Single.piercing.Description": "Das Wesen passt sich an Stichschaden an, sobald dieser tatsächlich durch seine Abwehr dringt.",
|
||||
"ADR.Features.Set.Single.poison.Name": "Gift",
|
||||
"ADR.Features.Set.Single.poison.Description": "Das Wesen passt sich an Giftschaden an, sobald dieser tatsächlich durch seine Abwehr dringt.",
|
||||
"ADR.Features.Set.Single.psychic.Name": "Psychisch",
|
||||
"ADR.Features.Set.Single.psychic.Description": "Das Wesen passt sich an psychischen Schaden an, sobald dieser tatsächlich durch seine Abwehr dringt.",
|
||||
"ADR.Features.Set.Single.radiant.Name": "Gleißend",
|
||||
"ADR.Features.Set.Single.radiant.Description": "Das Wesen passt sich an gleißenden Schaden an, sobald dieser tatsächlich durch seine Abwehr dringt.",
|
||||
"ADR.Features.Set.Single.slashing.Name": "Hieb",
|
||||
"ADR.Features.Set.Single.slashing.Description": "Das Wesen passt sich an Hiebschaden an, sobald dieser tatsächlich durch seine Abwehr dringt.",
|
||||
"ADR.Features.Set.Single.thunder.Name": "Donner",
|
||||
"ADR.Features.Set.Single.thunder.Description": "Das Wesen passt sich an Donnerschaden an, sobald dieser tatsächlich durch seine Abwehr dringt.",
|
||||
"ADR.Effects.AdaptiveResistance.Name": "Adaptive Resistenz: {type}",
|
||||
"ADR.Effects.AdaptiveImmunity.Name": "Adaptive Immunität: {type}",
|
||||
"ADR.Notifications.SeedFailed": "Adaptive Damage Resistance: Das Feature-Kompendium konnte nicht befüllt werden. Details stehen in der Konsole.",
|
||||
"ADR.Features.Elemental.Name": "Adaptive Resistenz: Elementar",
|
||||
"ADR.Features.Elemental.Description": "Das Wesen passt sich an elementare Gewalt an: ätzende Säure, zehrende Kälte, sengendes Feuer, zuckende Blitze und erschütternden Donner.",
|
||||
"ADR.Features.Magical.Name": "Adaptive Resistenz: Magisch",
|
||||
"ADR.Features.Magical.Description": "Das Wesen passt sich an übernatürliche Schadensarten an, die aus reiner magischer Kraft, finsterer Nekrose, mentalem Druck oder gleißender Macht entstehen.",
|
||||
"ADR.Features.Profane.Name": "Adaptive Resistenz: Profan",
|
||||
"ADR.Features.Profane.Description": "Das Wesen passt sich an körperliche Gewalt durch Wucht, Stich und Hieb an. Diese Anpassung folgt den dnd5e-Schadenstypen und unterscheidet nicht zuverlässig, ob eine Waffe magisch oder nichtmagisch ist.",
|
||||
"ADR.Features.Single.acid.Name": "Adaptive Resistenz: Säure",
|
||||
"ADR.Features.Single.acid.Description": "Das Wesen passt sich an Säureschaden an, sobald dieser tatsächlich durch seine Abwehr dringt.",
|
||||
"ADR.Features.Single.bludgeoning.Name": "Adaptive Resistenz: Wucht",
|
||||
"ADR.Features.Single.bludgeoning.Description": "Das Wesen passt sich an Wuchtschaden an, sobald dieser tatsächlich durch seine Abwehr dringt.",
|
||||
"ADR.Features.Single.cold.Name": "Adaptive Resistenz: Kälte",
|
||||
"ADR.Features.Single.cold.Description": "Das Wesen passt sich an Kälteschaden an, sobald dieser tatsächlich durch seine Abwehr dringt.",
|
||||
"ADR.Features.Single.fire.Name": "Adaptive Resistenz: Feuer",
|
||||
"ADR.Features.Single.fire.Description": "Das Wesen passt sich an Feuerschaden an, sobald dieser tatsächlich durch seine Abwehr dringt.",
|
||||
"ADR.Features.Single.force.Name": "Adaptive Resistenz: Energie",
|
||||
"ADR.Features.Single.force.Description": "Das Wesen passt sich an Energieschaden an, sobald dieser tatsächlich durch seine Abwehr dringt.",
|
||||
"ADR.Features.Single.lightning.Name": "Adaptive Resistenz: Blitz",
|
||||
"ADR.Features.Single.lightning.Description": "Das Wesen passt sich an Blitzschaden an, sobald dieser tatsächlich durch seine Abwehr dringt.",
|
||||
"ADR.Features.Single.necrotic.Name": "Adaptive Resistenz: Nekrotisch",
|
||||
"ADR.Features.Single.necrotic.Description": "Das Wesen passt sich an nekrotischen Schaden an, sobald dieser tatsächlich durch seine Abwehr dringt.",
|
||||
"ADR.Features.Single.piercing.Name": "Adaptive Resistenz: Stich",
|
||||
"ADR.Features.Single.piercing.Description": "Das Wesen passt sich an Stichschaden an, sobald dieser tatsächlich durch seine Abwehr dringt.",
|
||||
"ADR.Features.Single.poison.Name": "Adaptive Resistenz: Gift",
|
||||
"ADR.Features.Single.poison.Description": "Das Wesen passt sich an Giftschaden an, sobald dieser tatsächlich durch seine Abwehr dringt.",
|
||||
"ADR.Features.Single.psychic.Name": "Adaptive Resistenz: Psychisch",
|
||||
"ADR.Features.Single.psychic.Description": "Das Wesen passt sich an psychischen Schaden an, sobald dieser tatsächlich durch seine Abwehr dringt.",
|
||||
"ADR.Features.Single.radiant.Name": "Adaptive Resistenz: Gleißend",
|
||||
"ADR.Features.Single.radiant.Description": "Das Wesen passt sich an gleißenden Schaden an, sobald dieser tatsächlich durch seine Abwehr dringt.",
|
||||
"ADR.Features.Single.slashing.Name": "Adaptive Resistenz: Hieb",
|
||||
"ADR.Features.Single.slashing.Description": "Das Wesen passt sich an Hiebschaden an, sobald dieser tatsächlich durch seine Abwehr dringt.",
|
||||
"ADR.Features.Single.thunder.Name": "Adaptive Resistenz: Donner",
|
||||
"ADR.Features.Single.thunder.Description": "Das Wesen passt sich an Donnerschaden an, sobald dieser tatsächlich durch seine Abwehr dringt."
|
||||
}
|
||||
74
lang/en.json
Normal file
74
lang/en.json
Normal file
@ -0,0 +1,74 @@
|
||||
{
|
||||
"ADR.Features.ValidDamageTypes": "Reacts to",
|
||||
"ADR.Features.Prefix.Resistance": "Adaptive Resistance",
|
||||
"ADR.Features.Prefix.Immunity": "Adaptive Immunity",
|
||||
"ADR.Features.RulesText.Resistance": "After a hit, the creature remembers the damage type if the damage truly pierced its defenses. It then gains limited resistance to that exact damage type. If another matching damage type harms it later, the new adaptation replaces the old one. If resistance or immunity already softened or stopped the damage, the adaptation does not change.",
|
||||
"ADR.Features.RulesText.Immunity": "After a hit, the creature remembers the damage type if the damage truly pierced its defenses. It then gains limited immunity to that exact damage type. If another matching damage type harms it later, the new adaptation replaces the old one. If resistance or immunity already softened or stopped the damage, the adaptation does not change.",
|
||||
"ADR.Features.Set.Elemental.Name": "Elemental",
|
||||
"ADR.Features.Set.Elemental.Description": "The creature adapts to elemental force: caustic acid, biting cold, searing fire, crackling lightning, and concussive thunder.",
|
||||
"ADR.Features.Set.Magical.Name": "Magical",
|
||||
"ADR.Features.Set.Magical.Description": "The creature adapts to supernatural harm born of raw force, necrotic decay, psychic pressure, or radiant power.",
|
||||
"ADR.Features.Set.Profane.Name": "Profane",
|
||||
"ADR.Features.Set.Profane.Description": "The creature adapts to bodily violence from bludgeoning, piercing, and slashing harm. This follows the dnd5e damage types and does not reliably distinguish magical from nonmagical weapons.",
|
||||
"ADR.Features.Set.Single.acid.Name": "Acid",
|
||||
"ADR.Features.Set.Single.acid.Description": "The creature adapts to acid damage once it truly pierces its defenses.",
|
||||
"ADR.Features.Set.Single.bludgeoning.Name": "Bludgeoning",
|
||||
"ADR.Features.Set.Single.bludgeoning.Description": "The creature adapts to bludgeoning damage once it truly pierces its defenses.",
|
||||
"ADR.Features.Set.Single.cold.Name": "Cold",
|
||||
"ADR.Features.Set.Single.cold.Description": "The creature adapts to cold damage once it truly pierces its defenses.",
|
||||
"ADR.Features.Set.Single.fire.Name": "Fire",
|
||||
"ADR.Features.Set.Single.fire.Description": "The creature adapts to fire damage once it truly pierces its defenses.",
|
||||
"ADR.Features.Set.Single.force.Name": "Force",
|
||||
"ADR.Features.Set.Single.force.Description": "The creature adapts to force damage once it truly pierces its defenses.",
|
||||
"ADR.Features.Set.Single.lightning.Name": "Lightning",
|
||||
"ADR.Features.Set.Single.lightning.Description": "The creature adapts to lightning damage once it truly pierces its defenses.",
|
||||
"ADR.Features.Set.Single.necrotic.Name": "Necrotic",
|
||||
"ADR.Features.Set.Single.necrotic.Description": "The creature adapts to necrotic damage once it truly pierces its defenses.",
|
||||
"ADR.Features.Set.Single.piercing.Name": "Piercing",
|
||||
"ADR.Features.Set.Single.piercing.Description": "The creature adapts to piercing damage once it truly pierces its defenses.",
|
||||
"ADR.Features.Set.Single.poison.Name": "Poison",
|
||||
"ADR.Features.Set.Single.poison.Description": "The creature adapts to poison damage once it truly pierces its defenses.",
|
||||
"ADR.Features.Set.Single.psychic.Name": "Psychic",
|
||||
"ADR.Features.Set.Single.psychic.Description": "The creature adapts to psychic damage once it truly pierces its defenses.",
|
||||
"ADR.Features.Set.Single.radiant.Name": "Radiant",
|
||||
"ADR.Features.Set.Single.radiant.Description": "The creature adapts to radiant damage once it truly pierces its defenses.",
|
||||
"ADR.Features.Set.Single.slashing.Name": "Slashing",
|
||||
"ADR.Features.Set.Single.slashing.Description": "The creature adapts to slashing damage once it truly pierces its defenses.",
|
||||
"ADR.Features.Set.Single.thunder.Name": "Thunder",
|
||||
"ADR.Features.Set.Single.thunder.Description": "The creature adapts to thunder damage once it truly pierces its defenses.",
|
||||
"ADR.Effects.AdaptiveResistance.Name": "Adaptive Resistance: {type}",
|
||||
"ADR.Effects.AdaptiveImmunity.Name": "Adaptive Immunity: {type}",
|
||||
"ADR.Notifications.SeedFailed": "Adaptive Damage Resistance: Could not seed the feature compendium. See the console for details.",
|
||||
"ADR.Features.Elemental.Name": "Adaptive Resistance: Elemental",
|
||||
"ADR.Features.Elemental.Description": "The creature adapts to elemental force: caustic acid, biting cold, searing fire, crackling lightning, and concussive thunder.",
|
||||
"ADR.Features.Magical.Name": "Adaptive Resistance: Magical",
|
||||
"ADR.Features.Magical.Description": "The creature adapts to supernatural harm born of raw force, necrotic decay, psychic pressure, or radiant power.",
|
||||
"ADR.Features.Profane.Name": "Adaptive Resistance: Profane",
|
||||
"ADR.Features.Profane.Description": "The creature adapts to bodily violence from bludgeoning, piercing, and slashing harm. This follows the dnd5e damage types and does not reliably distinguish magical from nonmagical weapons.",
|
||||
"ADR.Features.Single.acid.Name": "Adaptive Resistance: Acid",
|
||||
"ADR.Features.Single.acid.Description": "The creature adapts to acid damage once it truly pierces its defenses.",
|
||||
"ADR.Features.Single.bludgeoning.Name": "Adaptive Resistance: Bludgeoning",
|
||||
"ADR.Features.Single.bludgeoning.Description": "The creature adapts to bludgeoning damage once it truly pierces its defenses.",
|
||||
"ADR.Features.Single.cold.Name": "Adaptive Resistance: Cold",
|
||||
"ADR.Features.Single.cold.Description": "The creature adapts to cold damage once it truly pierces its defenses.",
|
||||
"ADR.Features.Single.fire.Name": "Adaptive Resistance: Fire",
|
||||
"ADR.Features.Single.fire.Description": "The creature adapts to fire damage once it truly pierces its defenses.",
|
||||
"ADR.Features.Single.force.Name": "Adaptive Resistance: Force",
|
||||
"ADR.Features.Single.force.Description": "The creature adapts to force damage once it truly pierces its defenses.",
|
||||
"ADR.Features.Single.lightning.Name": "Adaptive Resistance: Lightning",
|
||||
"ADR.Features.Single.lightning.Description": "The creature adapts to lightning damage once it truly pierces its defenses.",
|
||||
"ADR.Features.Single.necrotic.Name": "Adaptive Resistance: Necrotic",
|
||||
"ADR.Features.Single.necrotic.Description": "The creature adapts to necrotic damage once it truly pierces its defenses.",
|
||||
"ADR.Features.Single.piercing.Name": "Adaptive Resistance: Piercing",
|
||||
"ADR.Features.Single.piercing.Description": "The creature adapts to piercing damage once it truly pierces its defenses.",
|
||||
"ADR.Features.Single.poison.Name": "Adaptive Resistance: Poison",
|
||||
"ADR.Features.Single.poison.Description": "The creature adapts to poison damage once it truly pierces its defenses.",
|
||||
"ADR.Features.Single.psychic.Name": "Adaptive Resistance: Psychic",
|
||||
"ADR.Features.Single.psychic.Description": "The creature adapts to psychic damage once it truly pierces its defenses.",
|
||||
"ADR.Features.Single.radiant.Name": "Adaptive Resistance: Radiant",
|
||||
"ADR.Features.Single.radiant.Description": "The creature adapts to radiant damage once it truly pierces its defenses.",
|
||||
"ADR.Features.Single.slashing.Name": "Adaptive Resistance: Slashing",
|
||||
"ADR.Features.Single.slashing.Description": "The creature adapts to slashing damage once it truly pierces its defenses.",
|
||||
"ADR.Features.Single.thunder.Name": "Adaptive Resistance: Thunder",
|
||||
"ADR.Features.Single.thunder.Description": "The creature adapts to thunder damage once it truly pierces its defenses."
|
||||
}
|
||||
59
module.json
Normal file
59
module.json
Normal file
@ -0,0 +1,59 @@
|
||||
{
|
||||
"id": "adaptive-damage-resistance",
|
||||
"title": "Adaptive Damage Resistance",
|
||||
"description": "Adaptive resistance and immunity features for dnd5e actors. Adds a compendium with draggable feature items and updates actor defenses based on the last valid damage type.",
|
||||
"version": "1.0.0",
|
||||
"compatibility": {
|
||||
"minimum": "13",
|
||||
"verified": "14"
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
"name": "Florian Zumpe",
|
||||
"email": "f.zumpe@gmx.de"
|
||||
}
|
||||
],
|
||||
"relationships": {
|
||||
"systems": [
|
||||
{
|
||||
"id": "dnd5e",
|
||||
"type": "system",
|
||||
"compatibility": {
|
||||
"minimum": "5.0.0",
|
||||
"verified": "5.3.3"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"esmodules": [
|
||||
"scripts/main.js"
|
||||
],
|
||||
"languages": [
|
||||
{
|
||||
"lang": "de",
|
||||
"name": "Deutsch",
|
||||
"path": "lang/de.json"
|
||||
},
|
||||
{
|
||||
"lang": "en",
|
||||
"name": "English",
|
||||
"path": "lang/en.json"
|
||||
}
|
||||
],
|
||||
"packs": [
|
||||
{
|
||||
"name": "adaptive-features",
|
||||
"label": "Adaptive Damage Resistance Features",
|
||||
"path": "packs/adaptive-features",
|
||||
"type": "Item",
|
||||
"system": "dnd5e",
|
||||
"ownership": {
|
||||
"PLAYER": "OBSERVER",
|
||||
"ASSISTANT": "OWNER"
|
||||
}
|
||||
}
|
||||
],
|
||||
"url": "https://github.com/fzumpe/foundry-dnd5e-adaptive-resistances",
|
||||
"manifest": "https://github.com/fzumpe/foundry-dnd5e-adaptive-resistances/releases/latest/download/module.json",
|
||||
"download": "https://github.com/fzumpe/foundry-dnd5e-adaptive-resistances/releases/download/V1.0.0/adaptive-damage-resistance-v1.0.0.zip"
|
||||
}
|
||||
3
packs/adaptive-features/README.txt
Normal file
3
packs/adaptive-features/README.txt
Normal file
@ -0,0 +1,3 @@
|
||||
This directory is used by Foundry VTT for the adaptive-features Item compendium.
|
||||
The module seeds missing feature items automatically when a GM starts the world.
|
||||
Existing compendium items are intentionally not overwritten.
|
||||
149
scripts/constants.js
Normal file
149
scripts/constants.js
Normal file
@ -0,0 +1,149 @@
|
||||
export const MODULE_ID = "adaptive-damage-resistance";
|
||||
export const PACK_NAME = "adaptive-features";
|
||||
export const PACK_ID = `${MODULE_ID}.${PACK_NAME}`;
|
||||
export const FEATURE_FLAG = "adaptiveResistanceFeature";
|
||||
export const EFFECT_FLAG = "adaptiveResistanceEffect";
|
||||
|
||||
export const ADAPTATION_TYPES = Object.freeze({
|
||||
RESISTANCE: "resistance",
|
||||
IMMUNITY: "immunity"
|
||||
});
|
||||
|
||||
export const ADAPTATION_CONFIG = Object.freeze({
|
||||
[ADAPTATION_TYPES.RESISTANCE]: {
|
||||
id: ADAPTATION_TYPES.RESISTANCE,
|
||||
priority: 10,
|
||||
traitKey: "system.traits.dr.value",
|
||||
effectNameKey: "ADR.Effects.AdaptiveResistance.Name",
|
||||
rulesTextKey: "ADR.Features.RulesText.Resistance",
|
||||
itemNamePrefixKey: "ADR.Features.Prefix.Resistance",
|
||||
icon: "icons/magic/defensive/shield-barrier-flaming-diamond-orange.webp"
|
||||
},
|
||||
[ADAPTATION_TYPES.IMMUNITY]: {
|
||||
id: ADAPTATION_TYPES.IMMUNITY,
|
||||
priority: 20,
|
||||
traitKey: "system.traits.di.value",
|
||||
effectNameKey: "ADR.Effects.AdaptiveImmunity.Name",
|
||||
rulesTextKey: "ADR.Features.RulesText.Immunity",
|
||||
itemNamePrefixKey: "ADR.Features.Prefix.Immunity",
|
||||
icon: "icons/magic/defensive/shield-barrier-flaming-pentagon-blue.webp"
|
||||
}
|
||||
});
|
||||
|
||||
export const DAMAGE_TYPES = Object.freeze({
|
||||
ACID: "acid",
|
||||
BLUDGEONING: "bludgeoning",
|
||||
COLD: "cold",
|
||||
FIRE: "fire",
|
||||
FORCE: "force",
|
||||
LIGHTNING: "lightning",
|
||||
NECROTIC: "necrotic",
|
||||
PIERCING: "piercing",
|
||||
POISON: "poison",
|
||||
PSYCHIC: "psychic",
|
||||
RADIANT: "radiant",
|
||||
SLASHING: "slashing",
|
||||
THUNDER: "thunder"
|
||||
});
|
||||
|
||||
export const DAMAGE_SETS = Object.freeze({
|
||||
elemental: {
|
||||
id: "elemental",
|
||||
nameKey: "ADR.Features.Set.Elemental.Name",
|
||||
descriptionKey: "ADR.Features.Set.Elemental.Description",
|
||||
damageTypes: ["acid", "cold", "fire", "lightning", "thunder"]
|
||||
},
|
||||
magical: {
|
||||
id: "magical",
|
||||
nameKey: "ADR.Features.Set.Magical.Name",
|
||||
descriptionKey: "ADR.Features.Set.Magical.Description",
|
||||
damageTypes: ["force", "necrotic", "psychic", "radiant"]
|
||||
},
|
||||
profane: {
|
||||
id: "profane",
|
||||
nameKey: "ADR.Features.Set.Profane.Name",
|
||||
descriptionKey: "ADR.Features.Set.Profane.Description",
|
||||
damageTypes: ["bludgeoning", "piercing", "slashing"]
|
||||
},
|
||||
acid: {
|
||||
id: "acid",
|
||||
nameKey: "ADR.Features.Set.Single.acid.Name",
|
||||
descriptionKey: "ADR.Features.Set.Single.acid.Description",
|
||||
damageTypes: ["acid"]
|
||||
},
|
||||
bludgeoning: {
|
||||
id: "bludgeoning",
|
||||
nameKey: "ADR.Features.Set.Single.bludgeoning.Name",
|
||||
descriptionKey: "ADR.Features.Set.Single.bludgeoning.Description",
|
||||
damageTypes: ["bludgeoning"]
|
||||
},
|
||||
cold: {
|
||||
id: "cold",
|
||||
nameKey: "ADR.Features.Set.Single.cold.Name",
|
||||
descriptionKey: "ADR.Features.Set.Single.cold.Description",
|
||||
damageTypes: ["cold"]
|
||||
},
|
||||
fire: {
|
||||
id: "fire",
|
||||
nameKey: "ADR.Features.Set.Single.fire.Name",
|
||||
descriptionKey: "ADR.Features.Set.Single.fire.Description",
|
||||
damageTypes: ["fire"]
|
||||
},
|
||||
force: {
|
||||
id: "force",
|
||||
nameKey: "ADR.Features.Set.Single.force.Name",
|
||||
descriptionKey: "ADR.Features.Set.Single.force.Description",
|
||||
damageTypes: ["force"]
|
||||
},
|
||||
lightning: {
|
||||
id: "lightning",
|
||||
nameKey: "ADR.Features.Set.Single.lightning.Name",
|
||||
descriptionKey: "ADR.Features.Set.Single.lightning.Description",
|
||||
damageTypes: ["lightning"]
|
||||
},
|
||||
necrotic: {
|
||||
id: "necrotic",
|
||||
nameKey: "ADR.Features.Set.Single.necrotic.Name",
|
||||
descriptionKey: "ADR.Features.Set.Single.necrotic.Description",
|
||||
damageTypes: ["necrotic"]
|
||||
},
|
||||
piercing: {
|
||||
id: "piercing",
|
||||
nameKey: "ADR.Features.Set.Single.piercing.Name",
|
||||
descriptionKey: "ADR.Features.Set.Single.piercing.Description",
|
||||
damageTypes: ["piercing"]
|
||||
},
|
||||
poison: {
|
||||
id: "poison",
|
||||
nameKey: "ADR.Features.Set.Single.poison.Name",
|
||||
descriptionKey: "ADR.Features.Set.Single.poison.Description",
|
||||
damageTypes: ["poison"]
|
||||
},
|
||||
psychic: {
|
||||
id: "psychic",
|
||||
nameKey: "ADR.Features.Set.Single.psychic.Name",
|
||||
descriptionKey: "ADR.Features.Set.Single.psychic.Description",
|
||||
damageTypes: ["psychic"]
|
||||
},
|
||||
radiant: {
|
||||
id: "radiant",
|
||||
nameKey: "ADR.Features.Set.Single.radiant.Name",
|
||||
descriptionKey: "ADR.Features.Set.Single.radiant.Description",
|
||||
damageTypes: ["radiant"]
|
||||
},
|
||||
slashing: {
|
||||
id: "slashing",
|
||||
nameKey: "ADR.Features.Set.Single.slashing.Name",
|
||||
descriptionKey: "ADR.Features.Set.Single.slashing.Description",
|
||||
damageTypes: ["slashing"]
|
||||
},
|
||||
thunder: {
|
||||
id: "thunder",
|
||||
nameKey: "ADR.Features.Set.Single.thunder.Name",
|
||||
descriptionKey: "ADR.Features.Set.Single.thunder.Description",
|
||||
damageTypes: ["thunder"]
|
||||
}
|
||||
});
|
||||
|
||||
// Backwards compatible export for older module-internal imports or local overrides.
|
||||
export const RESISTANCE_SETS = DAMAGE_SETS;
|
||||
43
scripts/effects.js
vendored
Normal file
43
scripts/effects.js
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
import { MODULE_ID, EFFECT_FLAG, ADAPTATION_CONFIG, ADAPTATION_TYPES } from "./constants.js";
|
||||
import { getDamageTypeLabel } from "./utils.js";
|
||||
|
||||
export async function removeOldAdaptiveEffects(actor) {
|
||||
const oldEffects = actor.effects.filter(effect => effect.getFlag(MODULE_ID, EFFECT_FLAG));
|
||||
if (!oldEffects.length) return;
|
||||
|
||||
await actor.deleteEmbeddedDocuments("ActiveEffect", oldEffects.map(effect => effect.id));
|
||||
}
|
||||
|
||||
export async function createAdaptiveEffect(actor, damageType, adaptationType = ADAPTATION_TYPES.RESISTANCE) {
|
||||
const config = ADAPTATION_CONFIG[adaptationType] ?? ADAPTATION_CONFIG[ADAPTATION_TYPES.RESISTANCE];
|
||||
const label = getDamageTypeLabel(damageType);
|
||||
|
||||
await actor.createEmbeddedDocuments("ActiveEffect", [
|
||||
{
|
||||
name: game.i18n.format(config.effectNameKey, { type: label }),
|
||||
icon: config.icon,
|
||||
disabled: false,
|
||||
transfer: false,
|
||||
flags: {
|
||||
[MODULE_ID]: {
|
||||
[EFFECT_FLAG]: {
|
||||
adaptationType: config.id,
|
||||
damageType
|
||||
}
|
||||
}
|
||||
},
|
||||
changes: [
|
||||
{
|
||||
key: config.traitKey,
|
||||
mode: CONST.ACTIVE_EFFECT_MODES.ADD,
|
||||
value: damageType,
|
||||
priority: 20
|
||||
}
|
||||
]
|
||||
}
|
||||
]);
|
||||
}
|
||||
|
||||
export async function createAdaptiveResistanceEffect(actor, damageType) {
|
||||
return createAdaptiveEffect(actor, damageType, ADAPTATION_TYPES.RESISTANCE);
|
||||
}
|
||||
258
scripts/features.js
Normal file
258
scripts/features.js
Normal file
@ -0,0 +1,258 @@
|
||||
import {
|
||||
MODULE_ID,
|
||||
PACK_ID,
|
||||
FEATURE_FLAG,
|
||||
DAMAGE_SETS,
|
||||
ADAPTATION_CONFIG,
|
||||
ADAPTATION_TYPES
|
||||
} from "./constants.js";
|
||||
|
||||
|
||||
const ENGLISH_DAMAGE_TYPE_LABELS = Object.freeze({
|
||||
acid: "Acid",
|
||||
bludgeoning: "Bludgeoning",
|
||||
cold: "Cold",
|
||||
fire: "Fire",
|
||||
force: "Force",
|
||||
lightning: "Lightning",
|
||||
necrotic: "Necrotic",
|
||||
piercing: "Piercing",
|
||||
poison: "Poison",
|
||||
psychic: "Psychic",
|
||||
radiant: "Radiant",
|
||||
slashing: "Slashing",
|
||||
thunder: "Thunder"
|
||||
});
|
||||
|
||||
const ENGLISH_SET_TEXT = Object.freeze({
|
||||
elemental: {
|
||||
name: "Elemental",
|
||||
description: "The creature adapts to elemental force: caustic acid, biting cold, searing fire, crackling lightning, and concussive thunder."
|
||||
},
|
||||
magical: {
|
||||
name: "Magical",
|
||||
description: "The creature adapts to supernatural harm born of raw force, necrotic decay, psychic pressure, or radiant power."
|
||||
},
|
||||
profane: {
|
||||
name: "Profane",
|
||||
description: "The creature adapts to bodily violence from bludgeoning, piercing, and slashing harm. This follows the dnd5e damage types and does not reliably distinguish magical from nonmagical weapons."
|
||||
},
|
||||
acid: {
|
||||
name: "Acid",
|
||||
description: "The creature adapts to acid damage once it truly pierces its defenses."
|
||||
},
|
||||
bludgeoning: {
|
||||
name: "Bludgeoning",
|
||||
description: "The creature adapts to bludgeoning damage once it truly pierces its defenses."
|
||||
},
|
||||
cold: {
|
||||
name: "Cold",
|
||||
description: "The creature adapts to cold damage once it truly pierces its defenses."
|
||||
},
|
||||
fire: {
|
||||
name: "Fire",
|
||||
description: "The creature adapts to fire damage once it truly pierces its defenses."
|
||||
},
|
||||
force: {
|
||||
name: "Force",
|
||||
description: "The creature adapts to force damage once it truly pierces its defenses."
|
||||
},
|
||||
lightning: {
|
||||
name: "Lightning",
|
||||
description: "The creature adapts to lightning damage once it truly pierces its defenses."
|
||||
},
|
||||
necrotic: {
|
||||
name: "Necrotic",
|
||||
description: "The creature adapts to necrotic damage once it truly pierces its defenses."
|
||||
},
|
||||
piercing: {
|
||||
name: "Piercing",
|
||||
description: "The creature adapts to piercing damage once it truly pierces its defenses."
|
||||
},
|
||||
poison: {
|
||||
name: "Poison",
|
||||
description: "The creature adapts to poison damage once it truly pierces its defenses."
|
||||
},
|
||||
psychic: {
|
||||
name: "Psychic",
|
||||
description: "The creature adapts to psychic damage once it truly pierces its defenses."
|
||||
},
|
||||
radiant: {
|
||||
name: "Radiant",
|
||||
description: "The creature adapts to radiant damage once it truly pierces its defenses."
|
||||
},
|
||||
slashing: {
|
||||
name: "Slashing",
|
||||
description: "The creature adapts to slashing damage once it truly pierces its defenses."
|
||||
},
|
||||
thunder: {
|
||||
name: "Thunder",
|
||||
description: "The creature adapts to thunder damage once it truly pierces its defenses."
|
||||
}
|
||||
});
|
||||
|
||||
const ENGLISH_ADAPTATION_TEXT = Object.freeze({
|
||||
[ADAPTATION_TYPES.RESISTANCE]: {
|
||||
prefix: "Adaptive Resistance",
|
||||
rules: "After a hit, the creature remembers the damage type if the damage truly pierced its defenses. It then gains limited resistance to that exact damage type. If another matching damage type harms it later, the new adaptation replaces the old one. If resistance or immunity already softened or stopped the damage, the adaptation does not change."
|
||||
},
|
||||
[ADAPTATION_TYPES.IMMUNITY]: {
|
||||
prefix: "Adaptive Immunity",
|
||||
rules: "After a hit, the creature remembers the damage type if the damage truly pierced its defenses. It then gains limited immunity to that exact damage type. If another matching damage type harms it later, the new adaptation replaces the old one. If resistance or immunity already softened or stopped the damage, the adaptation does not change."
|
||||
}
|
||||
});
|
||||
|
||||
function getEnglishDamageTypeLabel(type) {
|
||||
return ENGLISH_DAMAGE_TYPE_LABELS[type] ?? type;
|
||||
}
|
||||
|
||||
function featureName(set, adaptationType) {
|
||||
const text = ENGLISH_ADAPTATION_TEXT[adaptationType] ?? ENGLISH_ADAPTATION_TEXT[ADAPTATION_TYPES.RESISTANCE];
|
||||
const setText = ENGLISH_SET_TEXT[set.id];
|
||||
return `${text.prefix}: ${setText?.name ?? set.id}`;
|
||||
}
|
||||
|
||||
function featureDescription(set, adaptationType) {
|
||||
const text = ENGLISH_ADAPTATION_TEXT[adaptationType] ?? ENGLISH_ADAPTATION_TEXT[ADAPTATION_TYPES.RESISTANCE];
|
||||
const setText = ENGLISH_SET_TEXT[set.id];
|
||||
const damageTypes = set.damageTypes.map(getEnglishDamageTypeLabel).join(", ");
|
||||
|
||||
return `
|
||||
<p>${setText?.description ?? "The creature adapts to the selected damage type once it truly pierces its defenses."}</p>
|
||||
<p><strong>Reacts to:</strong> ${damageTypes}</p>
|
||||
<p>${text.rules}</p>
|
||||
`;
|
||||
}
|
||||
|
||||
function featureSourceId(setId, adaptationType) {
|
||||
return `${MODULE_ID}.${adaptationType}.${setId}`;
|
||||
}
|
||||
|
||||
export function buildFeatureItemData(set, adaptationType = ADAPTATION_TYPES.RESISTANCE) {
|
||||
const config = ADAPTATION_CONFIG[adaptationType] ?? ADAPTATION_CONFIG[ADAPTATION_TYPES.RESISTANCE];
|
||||
|
||||
return {
|
||||
name: featureName(set, config.id),
|
||||
type: "feat",
|
||||
img: config.icon,
|
||||
system: {
|
||||
description: {
|
||||
value: featureDescription(set, config.id),
|
||||
chat: ""
|
||||
},
|
||||
source: {
|
||||
book: "Adaptive Damage Resistance",
|
||||
page: "",
|
||||
custom: ""
|
||||
},
|
||||
activation: {
|
||||
type: "special",
|
||||
cost: null,
|
||||
condition: ""
|
||||
},
|
||||
uses: {
|
||||
spent: 0,
|
||||
max: "",
|
||||
recovery: []
|
||||
},
|
||||
type: {
|
||||
value: "monster",
|
||||
subtype: ""
|
||||
}
|
||||
},
|
||||
flags: {
|
||||
[MODULE_ID]: {
|
||||
[FEATURE_FLAG]: {
|
||||
enabled: true,
|
||||
adaptationType: config.id,
|
||||
setId: set.id,
|
||||
damageTypes: set.damageTypes
|
||||
}
|
||||
},
|
||||
core: {
|
||||
sourceId: `Item.${featureSourceId(set.id, config.id)}`
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async function getOrCreatePack() {
|
||||
const pack = game.packs.get(PACK_ID);
|
||||
if (!pack) {
|
||||
console.error(`${MODULE_ID} | Compendium ${PACK_ID} wurde nicht gefunden.`);
|
||||
return null;
|
||||
}
|
||||
return pack;
|
||||
}
|
||||
|
||||
async function unlockPack(pack) {
|
||||
if (!pack.locked) return false;
|
||||
await pack.configure({ locked: false });
|
||||
return true;
|
||||
}
|
||||
|
||||
async function restorePackLock(pack, wasLocked) {
|
||||
if (!wasLocked) return;
|
||||
await pack.configure({ locked: true });
|
||||
}
|
||||
|
||||
function getFeatureKey(entry) {
|
||||
const flag = foundry.utils.getProperty(entry, `flags.${MODULE_ID}.${FEATURE_FLAG}`);
|
||||
if (!flag?.setId) return null;
|
||||
return `${flag.adaptationType ?? ADAPTATION_TYPES.RESISTANCE}.${flag.setId}`;
|
||||
}
|
||||
|
||||
async function deleteDuplicatePackItems(pack, featureKey, keepId) {
|
||||
const index = await pack.getIndex({
|
||||
fields: [
|
||||
`flags.${MODULE_ID}.${FEATURE_FLAG}.setId`,
|
||||
`flags.${MODULE_ID}.${FEATURE_FLAG}.adaptationType`
|
||||
]
|
||||
});
|
||||
|
||||
const duplicates = index
|
||||
.filter(entry => entry._id !== keepId)
|
||||
.filter(entry => getFeatureKey(entry) === featureKey)
|
||||
.map(entry => entry._id);
|
||||
|
||||
if (duplicates.length) await Item.deleteDocuments(duplicates, { pack: PACK_ID });
|
||||
}
|
||||
|
||||
export async function seedFeatureCompendium() {
|
||||
if (!game.user?.isGM) return;
|
||||
|
||||
const pack = await getOrCreatePack();
|
||||
if (!pack) return;
|
||||
|
||||
const wasLocked = await unlockPack(pack);
|
||||
|
||||
try {
|
||||
for (const adaptationType of Object.values(ADAPTATION_TYPES)) {
|
||||
for (const set of Object.values(DAMAGE_SETS)) {
|
||||
const itemData = buildFeatureItemData(set, adaptationType);
|
||||
const featureKey = `${adaptationType}.${set.id}`;
|
||||
const index = await pack.getIndex({
|
||||
fields: [
|
||||
`flags.${MODULE_ID}.${FEATURE_FLAG}.setId`,
|
||||
`flags.${MODULE_ID}.${FEATURE_FLAG}.adaptationType`
|
||||
]
|
||||
});
|
||||
const existing = index.find(entry => getFeatureKey(entry) === featureKey);
|
||||
|
||||
if (existing) {
|
||||
// Existing feature items are intentionally left untouched.
|
||||
// This preserves manual edits and prevents GM client language changes
|
||||
// from rewriting already seeded compendium entries.
|
||||
continue;
|
||||
}
|
||||
|
||||
await Item.create(itemData, { pack: PACK_ID });
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`${MODULE_ID} | Fehler beim Befüllen des Feature-Kompendiums.`, error);
|
||||
ui.notifications?.error(game.i18n.localize("ADR.Notifications.SeedFailed"));
|
||||
} finally {
|
||||
await restorePackLock(pack, wasLocked);
|
||||
}
|
||||
}
|
||||
60
scripts/hooks.js
Normal file
60
scripts/hooks.js
Normal file
@ -0,0 +1,60 @@
|
||||
import { MODULE_ID } from "./constants.js";
|
||||
import {
|
||||
actorAlreadyProtected,
|
||||
getAdaptiveFeatureItems,
|
||||
getCandidatesForActor,
|
||||
getDominantDamageCandidate,
|
||||
isActiveGM
|
||||
} from "./utils.js";
|
||||
import { createAdaptiveEffect, removeOldAdaptiveEffects } from "./effects.js";
|
||||
|
||||
function hasAdaptiveFeature(actor) {
|
||||
return getAdaptiveFeatureItems(actor).length > 0;
|
||||
}
|
||||
|
||||
function storeDamageSelection(options, data) {
|
||||
options[MODULE_ID] = data;
|
||||
}
|
||||
|
||||
Hooks.on("dnd5e.preCalculateDamage", (actor, damages, options = {}) => {
|
||||
if (!isActiveGM()) return;
|
||||
if (!hasAdaptiveFeature(actor)) return;
|
||||
|
||||
const candidates = getCandidatesForActor(actor, damages);
|
||||
if (!candidates.length) return;
|
||||
|
||||
const alreadyProtected = candidates.some(candidate => actorAlreadyProtected(actor, candidate.type));
|
||||
if (alreadyProtected) {
|
||||
storeDamageSelection(options, {
|
||||
skip: true,
|
||||
reason: "damage-already-reduced-or-prevented"
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const candidate = getDominantDamageCandidate(candidates);
|
||||
if (!candidate?.type || !candidate?.adaptationType) return;
|
||||
|
||||
storeDamageSelection(options, {
|
||||
skip: false,
|
||||
damageType: candidate.type,
|
||||
adaptationType: candidate.adaptationType
|
||||
});
|
||||
});
|
||||
|
||||
Hooks.on("dnd5e.applyDamage", async (actor, amount, options = {}) => {
|
||||
if (!isActiveGM()) return;
|
||||
if (!hasAdaptiveFeature(actor)) return;
|
||||
|
||||
const data = options[MODULE_ID];
|
||||
if (!data || data.skip) return;
|
||||
if (!data.damageType || !data.adaptationType) return;
|
||||
|
||||
// Der Effekt soll nur entstehen, wenn nach Berechnung wirklich Schaden am Actor ankommt.
|
||||
if (typeof amount !== "number" || amount <= 0) return;
|
||||
|
||||
await removeOldAdaptiveEffects(actor);
|
||||
await createAdaptiveEffect(actor, data.damageType, data.adaptationType);
|
||||
|
||||
console.debug(`${MODULE_ID} | ${actor.name} gains adaptive ${data.adaptationType} against ${data.damageType}.`);
|
||||
});
|
||||
11
scripts/main.js
Normal file
11
scripts/main.js
Normal file
@ -0,0 +1,11 @@
|
||||
import { MODULE_ID } from "./constants.js";
|
||||
import { seedFeatureCompendium } from "./features.js";
|
||||
import "./hooks.js";
|
||||
|
||||
Hooks.once("init", () => {
|
||||
console.info(`${MODULE_ID} | Initializing.`);
|
||||
});
|
||||
|
||||
Hooks.once("ready", async () => {
|
||||
await seedFeatureCompendium();
|
||||
});
|
||||
150
scripts/utils.js
Normal file
150
scripts/utils.js
Normal file
@ -0,0 +1,150 @@
|
||||
import {
|
||||
MODULE_ID,
|
||||
FEATURE_FLAG,
|
||||
DAMAGE_SETS,
|
||||
ADAPTATION_TYPES,
|
||||
ADAPTATION_CONFIG
|
||||
} from "./constants.js";
|
||||
|
||||
export function isActiveGM() {
|
||||
return game.user?.isGM === true;
|
||||
}
|
||||
|
||||
export function localize(key) {
|
||||
return game.i18n.localize(key);
|
||||
}
|
||||
|
||||
export function getDamageTypeLabel(type) {
|
||||
const configured = CONFIG.DND5E?.damageTypes?.[type];
|
||||
if (!configured) return type;
|
||||
if (typeof configured === "string") return game.i18n.localize(configured);
|
||||
return game.i18n.localize(configured.label ?? type);
|
||||
}
|
||||
|
||||
export function getDamageValue(damage) {
|
||||
if (!damage) return 0;
|
||||
|
||||
const candidates = [
|
||||
damage.value,
|
||||
damage.amount,
|
||||
damage.total,
|
||||
damage.damage,
|
||||
damage.active?.value,
|
||||
damage.active?.amount,
|
||||
damage.active?.total
|
||||
];
|
||||
|
||||
for (const value of candidates) {
|
||||
if (typeof value === "number" && Number.isFinite(value)) return value;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
export function getDamageType(damage) {
|
||||
return damage?.type ?? damage?.damageType ?? damage?.application?.type ?? null;
|
||||
}
|
||||
|
||||
export function toArrayValue(value) {
|
||||
if (!value) return [];
|
||||
if (Array.isArray(value)) return value;
|
||||
if (value instanceof Set) return Array.from(value);
|
||||
if (typeof value === "object") return Object.keys(value).filter(key => value[key]);
|
||||
if (typeof value === "string") return [value];
|
||||
return [];
|
||||
}
|
||||
|
||||
export function actorResistanceValues(actor) {
|
||||
return toArrayValue(actor?.system?.traits?.dr?.value);
|
||||
}
|
||||
|
||||
export function actorImmunityValues(actor) {
|
||||
return toArrayValue(actor?.system?.traits?.di?.value);
|
||||
}
|
||||
|
||||
export function actorAlreadyResists(actor, damageType) {
|
||||
return actorResistanceValues(actor).includes(damageType);
|
||||
}
|
||||
|
||||
export function actorAlreadyImmune(actor, damageType) {
|
||||
return actorImmunityValues(actor).includes(damageType);
|
||||
}
|
||||
|
||||
export function actorAlreadyProtected(actor, damageType) {
|
||||
return actorAlreadyResists(actor, damageType) || actorAlreadyImmune(actor, damageType);
|
||||
}
|
||||
|
||||
export function getAdaptiveFeatureItems(actor) {
|
||||
if (!actor?.items) return [];
|
||||
|
||||
return actor.items.filter(item => {
|
||||
const flag = item.getFlag(MODULE_ID, FEATURE_FLAG);
|
||||
const adaptationType = flag?.adaptationType ?? ADAPTATION_TYPES.RESISTANCE;
|
||||
return flag?.enabled === true && DAMAGE_SETS[flag?.setId] && ADAPTATION_CONFIG[adaptationType];
|
||||
});
|
||||
}
|
||||
|
||||
export function getAllowedAdaptationsForActor(actor) {
|
||||
const result = [];
|
||||
|
||||
for (const item of getAdaptiveFeatureItems(actor)) {
|
||||
const flag = item.getFlag(MODULE_ID, FEATURE_FLAG);
|
||||
const set = DAMAGE_SETS[flag.setId];
|
||||
const adaptationType = flag.adaptationType ?? ADAPTATION_TYPES.RESISTANCE;
|
||||
|
||||
for (const damageType of set.damageTypes) {
|
||||
result.push({
|
||||
damageType,
|
||||
adaptationType,
|
||||
priority: ADAPTATION_CONFIG[adaptationType].priority
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export function getCandidatesForActor(actor, damages) {
|
||||
const allowed = getAllowedAdaptationsForActor(actor);
|
||||
if (!allowed.length || !Array.isArray(damages)) return [];
|
||||
|
||||
return damages
|
||||
.map(damage => ({
|
||||
type: getDamageType(damage),
|
||||
value: getDamageValue(damage)
|
||||
}))
|
||||
.filter(damage => {
|
||||
if (!damage.type) return false;
|
||||
if (damage.value <= 0) return false;
|
||||
return true;
|
||||
})
|
||||
.flatMap(damage => {
|
||||
return allowed
|
||||
.filter(entry => entry.damageType === damage.type)
|
||||
.map(entry => ({
|
||||
type: damage.type,
|
||||
value: damage.value,
|
||||
adaptationType: entry.adaptationType,
|
||||
priority: entry.priority
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
export function getDominantDamageCandidate(candidates) {
|
||||
if (!candidates?.length) return null;
|
||||
|
||||
return [...candidates].sort((a, b) => {
|
||||
const valueDifference = b.value - a.value;
|
||||
if (valueDifference !== 0) return valueDifference;
|
||||
return b.priority - a.priority;
|
||||
})[0];
|
||||
}
|
||||
|
||||
export function getDominantDamageType(candidates) {
|
||||
return getDominantDamageCandidate(candidates)?.type ?? null;
|
||||
}
|
||||
|
||||
// Backwards-compatible alias used by older local patches of this module.
|
||||
export function getElementalCandidatesForActor(actor, damages) {
|
||||
return getCandidatesForActor(actor, damages);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user