Skip to content

Commit b3bdeb4

Browse files
committed
UPDATED - Combat by chat
1 parent 079c2a3 commit b3bdeb4

189 files changed

Lines changed: 18845 additions & 1787 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
const fs = require('fs');
2+
const path = require('path');
3+
4+
const PSYCHIC_PACKS_DIR = path.join(__dirname, '..', 'src', 'packs', 'psychic_powers');
5+
6+
function parseDamage(text) {
7+
const match = (text ?? '').match(/Daño\s*(base)?\s*(\d+)/i);
8+
return match ? parseInt(match[2], 10) : 0;
9+
}
10+
11+
function parseFatigue(text) {
12+
const match = (text ?? '').match(/Fatiga\s*(\d+)/i);
13+
return match ? parseInt(match[1], 10) : 0;
14+
}
15+
16+
function parseShieldPoints(text) {
17+
const effect = (text ?? '').replace('.', '');
18+
19+
const m1 = effect.match(/(\d+)\s+puntos de resistencia/i);
20+
if (m1) return parseInt(m1[1], 10) || 0;
21+
22+
const m2 = effect.match(/(\d+)\s*PV/i);
23+
if (m2) return parseInt(m2[1], 10) || 0;
24+
25+
return 0;
26+
}
27+
28+
function parseAffectsInmaterial(text) {
29+
return /afecta a seres inmateriales/i.test(text ?? '');
30+
}
31+
32+
function ensureEffectStructured(effect) {
33+
effect.value ??= '';
34+
35+
effect.damage ??= { value: 0 };
36+
effect.fatigue ??= { value: 0 };
37+
effect.shieldPoints ??= { value: 0 };
38+
effect.affectsInmaterial ??= { value: false };
39+
}
40+
41+
function migratePsychicPowerFile(filePath) {
42+
const fileName = path.basename(filePath);
43+
44+
try {
45+
const fileContent = fs.readFileSync(filePath, 'utf8');
46+
const powerData = JSON.parse(fileContent);
47+
48+
if (powerData.type !== 'psychicPower') {
49+
console.log(` ⊘ Skipping ${fileName} (not a psychicPower)`);
50+
return;
51+
}
52+
53+
let modified = false;
54+
55+
const effects = powerData.system?.effects ?? {};
56+
for (const [potency, effect] of Object.entries(effects)) {
57+
if (!effect) continue;
58+
59+
// if the template changed, some entries might still be strings
60+
if (typeof effect === 'string') {
61+
effects[potency] = { value: effect };
62+
modified = true;
63+
}
64+
65+
ensureEffectStructured(effects[potency]);
66+
67+
const text = effects[potency].value ?? '';
68+
69+
const damage = parseDamage(text);
70+
const fatigue = parseFatigue(text);
71+
const shieldPoints = parseShieldPoints(text);
72+
const affectsInmaterial = parseAffectsInmaterial(text);
73+
74+
if (damage > 0 && effects[potency].damage.value !== damage) {
75+
effects[potency].damage.value = damage;
76+
modified = true;
77+
}
78+
79+
if (fatigue > 0 && effects[potency].fatigue.value !== fatigue) {
80+
effects[potency].fatigue.value = fatigue;
81+
modified = true;
82+
}
83+
84+
if (shieldPoints > 0 && effects[potency].shieldPoints.value !== shieldPoints) {
85+
effects[potency].shieldPoints.value = shieldPoints;
86+
modified = true;
87+
}
88+
89+
if (affectsInmaterial && effects[potency].affectsInmaterial.value !== true) {
90+
effects[potency].affectsInmaterial.value = true;
91+
modified = true;
92+
}
93+
}
94+
95+
// write back
96+
powerData.system.effects = effects;
97+
98+
if (modified) {
99+
fs.writeFileSync(filePath, JSON.stringify(powerData, null, 2), 'utf8');
100+
console.log(` ✓ Migrated ${fileName}`);
101+
return true;
102+
}
103+
104+
console.log(` ○ ${fileName} already has structured data`);
105+
return false;
106+
} catch (error) {
107+
console.error(` ✗ Error processing ${fileName}:`, error.message);
108+
return false;
109+
}
110+
}
111+
112+
function migrateAllPsychicPowers() {
113+
console.log('Starting psychic power migration to structured data format...\n');
114+
115+
if (!fs.existsSync(PSYCHIC_PACKS_DIR)) {
116+
console.error(`Error: Psychic packs directory not found at ${PSYCHIC_PACKS_DIR}`);
117+
process.exit(1);
118+
}
119+
120+
const files = fs
121+
.readdirSync(PSYCHIC_PACKS_DIR)
122+
.filter(file => file.endsWith('.json') && file.startsWith('psychicPower_'));
123+
124+
console.log(`Found ${files.length} psychic power files\n`);
125+
126+
let migratedCount = 0;
127+
let skippedCount = 0;
128+
let errorCount = 0;
129+
130+
for (const file of files) {
131+
const result = migratePsychicPowerFile(path.join(PSYCHIC_PACKS_DIR, file));
132+
if (result === true) migratedCount++;
133+
else if (result === false) skippedCount++;
134+
else errorCount++;
135+
}
136+
137+
console.log('\n' + '='.repeat(60));
138+
console.log(`Migration complete!`);
139+
console.log(` ✓ Migrated: ${migratedCount}`);
140+
console.log(` ○ Already migrated: ${skippedCount}`);
141+
if (errorCount > 0) console.log(` ✗ Errors: ${errorCount}`);
142+
console.log('='.repeat(60));
143+
}
144+
145+
migrateAllPsychicPowers();

scripts/migrateSpellsToStructuredData.cjs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,17 @@ function parseResistanceEffect(description) {
3636
return { value: 0, type: null };
3737
}
3838

39+
function parseShieldPoints(description) {
40+
const effect = (description || '').replace('.', '');
41+
const m1 = effect.match(/(\d+)\s+puntos de resistencia/i);
42+
if (m1) return parseInt(m1[1], 10) || 0;
43+
44+
const m2 = effect.match(/(\d+)\s*PV/i);
45+
if (m2) return parseInt(m2[1], 10) || 0;
46+
47+
return 0;
48+
}
49+
3950
function migrateSpellFile(filePath) {
4051
const fileName = path.basename(filePath);
4152

@@ -59,6 +70,7 @@ function migrateSpellFile(filePath) {
5970
const damage = parseDamage(description);
6071
const area = parseArea(description);
6172
const resistanceEffect = parseResistanceEffect(description);
73+
const shieldPoints = parseShieldPoints(description);
6274

6375
if (damage > 0 && !grade.damage) {
6476
grade.damage = { value: damage };
@@ -80,11 +92,22 @@ function migrateSpellFile(filePath) {
8092
} else if (
8193
grade.resistanceEffect &&
8294
(grade.resistanceEffect.value !== resistanceEffect.value ||
83-
grade.resistanceEffect.type !== resistanceEffect.type) &&
95+
grade.resistanceEffect.type !== resistanceEffect.type) &&
8496
resistanceEffect.value > 0
8597
) {
8698
console.log(` ⚠ ${fileName} [${gradeName}]: resistance mismatch`);
8799
}
100+
101+
if (shieldPoints > 0 && !grade.shieldPoints) {
102+
grade.shieldPoints = { value: shieldPoints };
103+
modified = true;
104+
} else if (
105+
grade.shieldPoints &&
106+
grade.shieldPoints.value !== shieldPoints &&
107+
shieldPoints > 0
108+
) {
109+
console.log(` ⚠ ${fileName} [${gradeName}]: shieldPoints mismatch`);
110+
}
88111
}
89112

90113
if (modified) {
@@ -109,7 +132,8 @@ function migrateAllSpells() {
109132
process.exit(1);
110133
}
111134

112-
const files = fs.readdirSync(MAGIC_PACKS_DIR)
135+
const files = fs
136+
.readdirSync(MAGIC_PACKS_DIR)
113137
.filter(file => file.endsWith('.json') && file.startsWith('spell_'));
114138

115139
console.log(`Found ${files.length} spell files\n`);

src/lang/en.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,12 @@
143143
"anima.ui.combat.weapons.defaultAttackButton.title": "Default Attack",
144144
"anima.ui.combat.supernaturalShields.origin.title": "Origin",
145145
"anima.ui.combat.supernaturalShields.shieldPoints.title": "Life points",
146+
"anima.ui.combat.supernaturalShields.ability.title": "Ability",
146147
"anima.ui.combat.supernaturalShields.name.title": "Shield",
147148
"anima.ui.combat.supernaturalShields.title": "Supernatural shields",
149+
"anima.ui.combat.supernaturalShields.bonus.title": "Modifier",
150+
"anima.ui.combat.attack.modifier.title": "Modifier",
151+
"anima.ui.psychic.psychicPowers.castButton.title": "Cast Power",
148152
"anima.ui.contactSection.contactRow.description": "Description",
149153
"anima.ui.contactSection.contactRow.name": "Name",
150154
"anima.ui.contactSection.title": "Contacts",
@@ -833,6 +837,7 @@
833837

834838
"chat.defense.autoRollFlavor.block": "Auto defense — Block",
835839
"chat.defense.autoRollFlavor.dodge": "Auto defense — Dodge",
840+
"chat.defense.autoRollFlavor.supernaturalShield": "Auto defense — Shield",
836841

837842
"chat.common.msgNotFound": "Message not found.",
838843
"chat.defend.noAttackData": "Attack data missing.",

src/lang/es.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,12 @@
143143
"anima.ui.combat.weapons.defaultAttackButton.title": "Mandar Ataque sin configurar",
144144
"anima.ui.combat.supernaturalShields.origin.title": "Origen",
145145
"anima.ui.combat.supernaturalShields.shieldPoints.title": "Puntos de vida",
146+
"anima.ui.combat.supernaturalShields.ability.title": "Habilidad",
146147
"anima.ui.combat.supernaturalShields.name.title": "Escudo",
147148
"anima.ui.combat.supernaturalShields.title": "Escudos Sobrenaturales",
149+
"anima.ui.combat.supernaturalShields.bonus.title": "Modificador",
150+
"anima.ui.combat.attack.modifier.title": "Modificador",
151+
"anima.ui.psychic.psychicPowers.castButton.title": "Lanzar Poder",
148152
"anima.ui.contactSection.contactRow.description": "Descripción",
149153
"anima.ui.contactSection.contactRow.name": "Nombre",
150154
"anima.ui.contactSection.title": "Contactos",
@@ -841,6 +845,7 @@
841845

842846
"chat.defense.autoRollFlavor.block": "Defensa automática — Bloqueo",
843847
"chat.defense.autoRollFlavor.dodge": "Defensa automática — Esquiva",
848+
"chat.defense.autoRollFlavor.supernaturalShield": "Auto defense — Escudo",
844849

845850
"chat.result.confirmTitle": "¿Aplicar el daño de nuevo?",
846851
"chat.result.confirmBody": "Este resultado ya aplicó daño antes. ¿Seguro?",

src/lang/fr.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,12 @@
113113
"anima.ui.combat.weapons.damage.base.title": "Base de dégâts",
114114
"anima.ui.combat.weapons.damage.final.title": "Dégats",
115115
"anima.ui.combat.weapons.defaultAttackButton.title": "Attaque par défaut",
116+
"anima.ui.combat.supernaturalShields.origin.title": "Origin",
117+
"anima.ui.combat.supernaturalShields.shieldPoints.title": "Life points",
118+
"anima.ui.combat.supernaturalShields.ability.title": "Ability",
119+
"anima.ui.combat.supernaturalShields.bonus.title": "Modifier",
120+
"anima.ui.combat.attack.modifier.title": "Modifier",
121+
"anima.ui.psychic.psychicPowers.castButton.title": "Lancer le pouvoir",
116122
"anima.ui.combat.weapons.equipped.title": "Equipé?",
117123
"anima.ui.combat.weapons.hasOwnStr.title": "Assez de FOR?",
118124
"anima.ui.combat.weapons.damage.formula.title": "Damage Formula",
@@ -717,6 +723,7 @@
717723

718724
"chat.defense.autoRollFlavor.block": "Défense automatique — Parade",
719725
"chat.defense.autoRollFlavor.dodge": "Défense automatique — Esquive",
726+
"chat.defense.autoRollFlavor.supernaturalShield": "Défense automatique — Shield",
720727

721728
"chat.common.msgNotFound": "Message introuvable.",
722729
"chat.defend.noAttackData": "Données d’attaque manquantes.",

src/module/actor/ABFActor.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ export class ABFActor extends Actor {
139139
? shieldData.toItemCreateData()
140140
: shieldData;
141141

142-
const item = await this.createItem(itemCreateData);
142+
const [item] = await this.createEmbeddedDocuments('Item', [itemCreateData]);
143143

144144
const args = { thisActor: this, newShield: true, shieldId: item._id };
145145
executeMacro(itemCreateData.name, args);
@@ -190,7 +190,7 @@ export class ABFActor extends Actor {
190190
// If shield breaks, apply damage to actor
191191
if (newShieldPoints < 0 && newCombatResult) {
192192
const needToRound = game.settings.get(
193-
game.abf.id,
193+
game.animabf.id,
194194
ABFSettingsKeys.ROUND_DAMAGE_IN_MULTIPLES_OF_5
195195
);
196196
const result = calculateDamage(
@@ -541,13 +541,15 @@ export class ABFActor extends Actor {
541541
* @param {import('../items/ABFItems').ABFItemsEnum} data.type
542542
* @param {string} data.name
543543
* @param {ABFItem["system"]} data.system
544+
* @param {Record<string, unknown>} [data.flags]
544545
*/
545-
async createItem({ type, name, system = {} }) {
546+
async createItem({ type, name, system = {}, flags = {} }) {
546547
const items = await this.createEmbeddedDocuments('Item', [
547548
{
548549
type,
549550
name,
550-
system
551+
system,
552+
flags
551553
}
552554
]);
553555
return items[0];

0 commit comments

Comments
 (0)