Merge branch 'selectable-cooldown-duration' into 'master'
feat: only allow specific selectable values for the cooldown duration of spells See merge request dungeonslayers/ds4!175
This commit is contained in:
commit
f40e1436f8
20 changed files with 558 additions and 876 deletions
36
lang/de.json
36
lang/de.json
|
@ -114,10 +114,12 @@
|
|||
"DS4.ArmorMaterialTypeNaturalAbbr": "Natürlich",
|
||||
"DS4.SpellType": "Zauberspruchtyp",
|
||||
"DS4.SpellTypeAbbr": "T",
|
||||
"DS4.SpellTypeDescription": "Der Typ des Zauberspruchs.",
|
||||
"DS4.SortBySpellType": "Nach Zauberspruchtyp sortieren",
|
||||
"DS4.SpellTypeSpellcasting": "Zaubern",
|
||||
"DS4.SpellTypeTargetedSpellcasting": "Zielzaubern",
|
||||
"DS4.SpellCategory": "Kategorie",
|
||||
"DS4.SpellCategoryDescription": "Eine Kategorie, der der Zauberspruch zugehörig ist.",
|
||||
"DS4.SpellCategoryHealing": "Heilung",
|
||||
"DS4.SpellCategoryFire": "Feuer",
|
||||
"DS4.SpellCategoryIce": "Eis",
|
||||
|
@ -127,18 +129,33 @@
|
|||
"DS4.SpellCategoryElectricity": "Elektrizität",
|
||||
"DS4.SpellCategoryNone": "Keine",
|
||||
"DS4.SpellCategoryUnset": "Nicht gesetzt",
|
||||
"DS4.SpellBonus": "Zauberbonus",
|
||||
"DS4.SpellBonusAbbr": "ZB",
|
||||
"DS4.SortBySpellBonus": "Nach Zauberbonus sortieren",
|
||||
"DS4.SpellMaxDistance": "Reichweite",
|
||||
"DS4.SpellEffectRadius": "Effektradius",
|
||||
"DS4.SpellDuration": "Wirkdauer",
|
||||
"DS4.SpellCooldownDuration": "Abklingzeit",
|
||||
"DS4.SpellModifier": "Zauberbonus",
|
||||
"DS4.SpellModifierAbbr": "ZB",
|
||||
"DS4.SpellModifierDescription": "Der Zauberbonus auf die Probe.",
|
||||
"DS4.SortBySpellModifier": "Nach Zauberbonus sortieren",
|
||||
"DS4.SpellDistance": "Distanz",
|
||||
"DS4.SpellDistanceDescription": "Die maximale Entfernung zum Ziel. „Selbst“ bedeutet, dass nur der Zauberwirker selbst das Ziel des Zaubers sein kann.",
|
||||
"DS4.SpellEffectRadius": "Wirkungsradius",
|
||||
"DS4.SpellEffectRadiusDescription": "Der Wirkungsradius des Zaubers.",
|
||||
"DS4.SpellDuration": "Dauer",
|
||||
"DS4.SpellDurationDescription": "Die Wirkungszeit des Zaubers.",
|
||||
"DS4.CooldownDuration": "Abklingzeit",
|
||||
"DS4.CooldownDurationDescription": "Die Dauer, die der Zauber nach erfolgreichem Wirken nicht einsetzbar ist.",
|
||||
"DS4.CooldownDuration0R": "0 Kampfrunden",
|
||||
"DS4.CooldownDuration1R": "1 Kampfrunde",
|
||||
"DS4.CooldownDuration2R": "2 Kampfrunden",
|
||||
"DS4.CooldownDuration5R": "5 Kampfrunden",
|
||||
"DS4.CooldownDuration10R": "10 Kampfrunden",
|
||||
"DS4.CooldownDuration100R": "100 Kampfrunden",
|
||||
"DS4.CooldownDuration1D": "1 Tag",
|
||||
"DS4.CooldownDurationD20D": "W20 Tage",
|
||||
"DS4.SpellMinimumLevel": "Zugangsstufe",
|
||||
"DS4.SpellMinimumLevelDescription": "Die minimale Stufe, ab der ein Zauberwirker den Zauberspruch erlernen kann.",
|
||||
"DS4.SpellCasterClassHealer": "Heiler",
|
||||
"DS4.SpellCasterClassSorcerer": "Schwarzmagier",
|
||||
"DS4.SpellCasterClassWizard": "Zauberer",
|
||||
"DS4.SpellPrice": "Preis (Gold)",
|
||||
"DS4.SpellPriceDescription": "Der Kaufpreis des Zauberspruchs.",
|
||||
"DS4.EffectEnabled": "Aktiv",
|
||||
"DS4.EffectEnabledAbbr": "A",
|
||||
"DS4.EffectEffectivelyEnabled": "Effektiv Aktiv (unter Betrachtung, ob ein eventuelles Quellen-Item ausgerüstet ist usw.)",
|
||||
|
@ -240,6 +257,7 @@
|
|||
"DS4.ErrorSlayingDiceRecursionLimitExceeded": "Die maximale Rekursionstiefe für slayende Würfelwürfe wurde überschritten.",
|
||||
"DS4.ErrorInvalidNumberOfDice": "Ungültige Anzahl an Würfeln.",
|
||||
"DS4.ErrorDuringMigration": "Fehler während der Aktualisierung des DS4 Systems von Migrationsversion {currentVersion} auf {targetVersion}. Der Fehler trat während der Ausführung des Migrationsskripts mit der Version {migrationVersion} auf. Spätere Migrationsskripte wurden nicht ausgeführt. Mehr Details finden Sie in der Entwicklerkonsole (F12).",
|
||||
"DS4.ErrorDuringCompendiumMigration": "Fehler während der Aktualisierung Kompendiums '{pack}' für DS4 von Migrationsversion {currentVersion} auf {targetVersion}. Der Fehler trat während der Ausführung des Migrationsskripts mit der Version {migrationVersion} auf. Spätere Migrationsskripte wurden nicht ausgeführt. Mehr Details finden Sie in der Entwicklerkonsole (F12).",
|
||||
"DS4.ErrorCannotRollUnownedItem": "Für das Item '{name}' ({id}) kann nicht gewürfelt werden, da es keinem Aktor gehört.",
|
||||
"DS4.ErrorRollingForItemTypeNotPossible": "Würfeln ist für Items vom Typ '{type}' nicht möglich.",
|
||||
"DS4.ErrorWrongItemType": "Ein Item vom Type '{expectedType}' wurde erwartet aber das Item '{name}' ({id}) ist vom Typ '{actualType}'.",
|
||||
|
@ -255,9 +273,11 @@
|
|||
"DS4.WarningItemIsNotRollable": "Für das Item '{name}' ({id}) vom Typ '{type}' kann nicht gewürfelt werden.",
|
||||
"DS4.WarningMacrosCanOnlyBeCreatedForOwnedItems": "Makros können nur für besessene Items angelegt werden.",
|
||||
"DS4.WarningInvalidCheckDropped": "Eine ungültige Probe wurde auf die Hotbar gezogen.",
|
||||
"DS4.InfoManuallyEnterSpellBonus": "Der korrekte Wert für den Zauberbonus '{spellBonus}' des Zaubers '{name}' muss manuell angegeben werden.",
|
||||
"DS4.InfoManuallyEnterSpellModifier": "Der korrekte Wert für den Zauberbonus '{spellModifier}' des Zaubers '{name}' muss manuell angegeben werden.",
|
||||
"DS4.InfoSystemUpdateStart": "Aktualisiere DS4 System von Migrationsversion {currentVersion} auf {targetVersion}. Bitte haben Sie etwas Geduld, schließen Sie nicht das Spiel und fahren Sie nicht den Server herunter.",
|
||||
"DS4.InfoSystemUpdateCompleted": "Aktualisierung des DS4 Systems von Migrationsversion {currentVersion} auf {targetVersion} erfolgreich!",
|
||||
"DS4.InfoCompendiumMigrationStart": "Aktualisiere Kompendium '{pack}' für DS4 von Migrationsversion {currentVersion} auf {targetVersion}. Bitte haben Sie etwas Geduld, schließen Sie nicht das Spiel und fahren Sie nicht den Server herunter.",
|
||||
"DS4.InfoCompendiumMigrationCompleted": "Aktualisierung des Kompendiums '{pack}' für DS4 von Migrationsversion {currentVersion} auf {targetVersion} erfolgreich!",
|
||||
"DS4.UnitRounds": "Runden",
|
||||
"DS4.UnitRoundsAbbr": "Rnd",
|
||||
"DS4.UnitMinutes": "Minuten",
|
||||
|
|
34
lang/en.json
34
lang/en.json
|
@ -114,10 +114,12 @@
|
|||
"DS4.ArmorMaterialTypeNaturalAbbr": "Natural",
|
||||
"DS4.SpellType": "Spell Type",
|
||||
"DS4.SpellTypeAbbr": "T",
|
||||
"DS4.SpellTypeDescription": "The type of the spell.",
|
||||
"DS4.SortBySpellType": "Sort by Spell Type",
|
||||
"DS4.SpellTypeSpellcasting": "Spellcasting",
|
||||
"DS4.SpellTypeTargetedSpellcasting": "Targeted Spellcasting",
|
||||
"DS4.SpellCategory": "Category",
|
||||
"DS4.SpellCategoryDescription": "A category which the spell belongs to.",
|
||||
"DS4.SpellCategoryHealing": "Healing",
|
||||
"DS4.SpellCategoryFire": "Fire",
|
||||
"DS4.SpellCategoryIce": "Ice",
|
||||
|
@ -127,18 +129,33 @@
|
|||
"DS4.SpellCategoryElectricity": "Electricity",
|
||||
"DS4.SpellCategoryNone": "None",
|
||||
"DS4.SpellCategoryUnset": "Unset",
|
||||
"DS4.SpellBonus": "Spell Bonus",
|
||||
"DS4.SpellBonusAbbr": "SB",
|
||||
"DS4.SortBySpellBonus": "Sort by Spell Bonus",
|
||||
"DS4.SpellMaxDistance": "Range",
|
||||
"DS4.SpellEffectRadius": "Radius",
|
||||
"DS4.SpellModifier": "Spell Modifier",
|
||||
"DS4.SpellModifierAbbr": "SM",
|
||||
"DS4.SpellModifierDescription": "The spell modifier for the corresponding check.",
|
||||
"DS4.SortBySpellModifier": "Sort by Spell Modifier",
|
||||
"DS4.SpellDistance": "Distance",
|
||||
"DS4.SpellDistanceDescription": "The maximum distance to the target, “Self” meaning that only the caster can be the target of this spell.",
|
||||
"DS4.SpellEffectRadius": "Area of Effect Radius",
|
||||
"DS4.SpellEffectRadiusDescription": "The radius of the area of effect of the spell.",
|
||||
"DS4.SpellDuration": "Duration",
|
||||
"DS4.SpellCooldownDuration": "Cooldown",
|
||||
"DS4.SpellDurationDescription": "The spell’s duration.",
|
||||
"DS4.CooldownDuration": "Cooldown Period",
|
||||
"DS4.CooldownDurationDescription": "The length of time to wait after a successful casting before the spell can be cast again.",
|
||||
"DS4.CooldownDuration0R": "0 Rounds",
|
||||
"DS4.CooldownDuration1R": "1 Round",
|
||||
"DS4.CooldownDuration2R": "2 Rounds",
|
||||
"DS4.CooldownDuration5R": "5 Rounds",
|
||||
"DS4.CooldownDuration10R": "10 Rounds",
|
||||
"DS4.CooldownDuration100R": "100 Rounds",
|
||||
"DS4.CooldownDuration1D": "1 Day",
|
||||
"DS4.CooldownDurationD20D": "D20 Days",
|
||||
"DS4.SpellMinimumLevel": "Minimum Level",
|
||||
"DS4.SpellMinimumLevelDescription": "The minimum level at which a spell caster may learn the spell.",
|
||||
"DS4.SpellCasterClassHealer": "Healer",
|
||||
"DS4.SpellCasterClassSorcerer": "Sorcerer",
|
||||
"DS4.SpellCasterClassWizard": "Wizard",
|
||||
"DS4.SpellPrice": "Price (Gold)",
|
||||
"DS4.SpellPriceDescription": "The price to purchase the spell.",
|
||||
"DS4.EffectEnabled": "Enabled",
|
||||
"DS4.EffectEnabledAbbr": "E",
|
||||
"DS4.EffectEffectivelyEnabled": "Effectively Enabled (taking into account whether a potential source item is equipped etc.)",
|
||||
|
@ -240,6 +257,7 @@
|
|||
"DS4.ErrorSlayingDiceRecursionLimitExceeded": "Maximum recursion depth for slaying dice roll exceeded.",
|
||||
"DS4.ErrorInvalidNumberOfDice": "Invalid number of dice.",
|
||||
"DS4.ErrorDuringMigration": "Error while migrating DS4 system from migration version {currentVersion} to {targetVersion}. The error occurred during execution of migration script with version {migrationVersion}. Later migrations have not been executed. For more details, please look at the development console (F12).",
|
||||
"DS4.ErrorDuringCompendiumMigration": "Error while migrating compendium '{pack}' for DS4 from migration version {currentVersion} to {targetVersion}. The error occurred during execution of migration script with version {migrationVersion}. Later migrations have not been executed. For more details, please look at the development console (F12).",
|
||||
"DS4.ErrorCannotRollUnownedItem": "Rolling for item '{name}' ({id})is not possible because it is not owned.",
|
||||
"DS4.ErrorRollingForItemTypeNotPossible": "Rolling is not possible for items of type '{type}'.",
|
||||
"DS4.ErrorWrongItemType": "Expected an item of type '{expectedType}' but item '{name}' ({id}) is of type '{actualType}'.",
|
||||
|
@ -255,9 +273,11 @@
|
|||
"DS4.WarningItemIsNotRollable": "Item '{name}' ({id}) of type '{type}' is not rollable.",
|
||||
"DS4.WarningMacrosCanOnlyBeCreatedForOwnedItems": "Macros can only be created for owned items.",
|
||||
"DS4.WarningInvalidCheckDropped": "An invalid check was dropped on the Hotbar.",
|
||||
"DS4.InfoManuallyEnterSpellBonus": "The correct value of the spell bonus '{spellBonus}' of the spell '{name}' needs to be entered by manually.",
|
||||
"DS4.InfoManuallyEnterSpellModifier": "The correct value of the spell modifier '{spellModifier}' of the spell '{name}' needs to be entered by manually.",
|
||||
"DS4.InfoSystemUpdateStart": "Migrating DS4 system from migration version {currentVersion} to {targetVersion}. Please be patient and do not close your game or shut down your server.",
|
||||
"DS4.InfoSystemUpdateCompleted": "Migration of DS4 system from migration version {currentVersion} to {targetVersion} successful!",
|
||||
"DS4.InfoCompendiumMigrationStart": "Migrating compendium '{pack}' for DS4 from migration version {currentVersion} to {targetVersion}. Please be patient and do not close your game or shut down your server.",
|
||||
"DS4.InfoCompendiumMigrationCompleted": "Migration of compendium '{pack}' for DS4 from migration version {currentVersion} to {targetVersion} successful!",
|
||||
"DS4.UnitRounds": "Rounds",
|
||||
"DS4.UnitRoundsAbbr": "rnd",
|
||||
"DS4.UnitMinutes": "Minutes",
|
||||
|
|
|
@ -1881,10 +1881,7 @@
|
|||
"value": "",
|
||||
"unit": "custom"
|
||||
},
|
||||
"cooldownDuration": {
|
||||
"value": "10",
|
||||
"unit": "rounds"
|
||||
},
|
||||
"cooldownDuration": "10r",
|
||||
"minimumLevels": {
|
||||
"healer": null,
|
||||
"wizard": null,
|
||||
|
@ -3584,10 +3581,7 @@
|
|||
"value": "Sofort",
|
||||
"unit": "custom"
|
||||
},
|
||||
"cooldownDuration": {
|
||||
"value": "10",
|
||||
"unit": "rounds"
|
||||
},
|
||||
"cooldownDuration": "10r",
|
||||
"minimumLevels": {
|
||||
"healer": 2,
|
||||
"wizard": 5,
|
||||
|
@ -3629,10 +3623,7 @@
|
|||
"value": "VE / 2",
|
||||
"unit": "rounds"
|
||||
},
|
||||
"cooldownDuration": {
|
||||
"value": "24",
|
||||
"unit": "hours"
|
||||
},
|
||||
"cooldownDuration": "1d",
|
||||
"minimumLevels": {
|
||||
"healer": null,
|
||||
"wizard": 12,
|
||||
|
@ -3674,10 +3665,7 @@
|
|||
"value": "Sofort",
|
||||
"unit": "custom"
|
||||
},
|
||||
"cooldownDuration": {
|
||||
"value": "5",
|
||||
"unit": "rounds"
|
||||
},
|
||||
"cooldownDuration": "5r",
|
||||
"minimumLevels": {
|
||||
"healer": 16,
|
||||
"wizard": 10,
|
||||
|
@ -3719,10 +3707,7 @@
|
|||
"value": "Sofort",
|
||||
"unit": "custom"
|
||||
},
|
||||
"cooldownDuration": {
|
||||
"value": "10",
|
||||
"unit": "rounds"
|
||||
},
|
||||
"cooldownDuration": "10r",
|
||||
"minimumLevels": {
|
||||
"healer": 16,
|
||||
"wizard": 12,
|
||||
|
@ -3764,10 +3749,7 @@
|
|||
"value": "Prb.",
|
||||
"unit": "rounds"
|
||||
},
|
||||
"cooldownDuration": {
|
||||
"value": "100",
|
||||
"unit": "rounds"
|
||||
},
|
||||
"cooldownDuration": "100r",
|
||||
"minimumLevels": {
|
||||
"healer": 4,
|
||||
"wizard": 8,
|
||||
|
@ -3809,10 +3791,7 @@
|
|||
"value": "Prb.",
|
||||
"unit": "rounds"
|
||||
},
|
||||
"cooldownDuration": {
|
||||
"value": "100",
|
||||
"unit": "rounds"
|
||||
},
|
||||
"cooldownDuration": "100r",
|
||||
"minimumLevels": {
|
||||
"healer": 4,
|
||||
"wizard": 8,
|
||||
|
@ -3854,10 +3833,7 @@
|
|||
"value": "Konzentration",
|
||||
"unit": "custom"
|
||||
},
|
||||
"cooldownDuration": {
|
||||
"value": "0",
|
||||
"unit": "rounds"
|
||||
},
|
||||
"cooldownDuration": "0r",
|
||||
"minimumLevels": {
|
||||
"healer": null,
|
||||
"wizard": 6,
|
||||
|
@ -3899,10 +3875,7 @@
|
|||
"value": "Prb.",
|
||||
"unit": "minutes"
|
||||
},
|
||||
"cooldownDuration": {
|
||||
"value": "24",
|
||||
"unit": "hours"
|
||||
},
|
||||
"cooldownDuration": "1d",
|
||||
"minimumLevels": {
|
||||
"healer": 20,
|
||||
"wizard": 12,
|
||||
|
@ -3944,10 +3917,7 @@
|
|||
"value": "Prb.",
|
||||
"unit": "rounds"
|
||||
},
|
||||
"cooldownDuration": {
|
||||
"value": "10",
|
||||
"unit": "rounds"
|
||||
},
|
||||
"cooldownDuration": "10r",
|
||||
"minimumLevels": {
|
||||
"healer": 8,
|
||||
"wizard": 5,
|
||||
|
@ -3990,10 +3960,7 @@
|
|||
"value": "Prb.",
|
||||
"unit": "rounds"
|
||||
},
|
||||
"cooldownDuration": {
|
||||
"value": "5",
|
||||
"unit": "rounds"
|
||||
},
|
||||
"cooldownDuration": "5r",
|
||||
"minimumLevels": {
|
||||
"healer": 1,
|
||||
"wizard": 5,
|
||||
|
@ -16049,10 +16016,7 @@
|
|||
"value": "Prb.",
|
||||
"unit": "rounds"
|
||||
},
|
||||
"cooldownDuration": {
|
||||
"value": "100",
|
||||
"unit": "rounds"
|
||||
},
|
||||
"cooldownDuration": "100r",
|
||||
"minimumLevels": {
|
||||
"healer": 7,
|
||||
"wizard": 7,
|
||||
|
@ -20114,10 +20078,7 @@
|
|||
"value": "VE",
|
||||
"unit": "minutes"
|
||||
},
|
||||
"cooldownDuration": {
|
||||
"value": "24",
|
||||
"unit": "hours"
|
||||
},
|
||||
"cooldownDuration": "1d",
|
||||
"minimumLevels": {
|
||||
"healer": 5,
|
||||
"wizard": 9,
|
||||
|
@ -21132,7 +21093,7 @@
|
|||
"name": "Gedankenzehrerstrahl",
|
||||
"type": "spell",
|
||||
"data": {
|
||||
"description": "<p>Gedankenzehrerstrahl (nicht sichtbar; verursacht mental Schaden und führt zu <strong>Werteverlust</strong>)</p>",
|
||||
"description": "<p>Nicht sichtbar; verursacht mental Schaden und führt zu <strong>Werteverlust</strong></p>",
|
||||
"equipped": true,
|
||||
"spellType": "targetedSpellcasting",
|
||||
"bonus": "",
|
||||
|
@ -21149,10 +21110,7 @@
|
|||
"value": "",
|
||||
"unit": "custom"
|
||||
},
|
||||
"cooldownDuration": {
|
||||
"value": "",
|
||||
"unit": "rounds"
|
||||
},
|
||||
"cooldownDuration": "0r",
|
||||
"minimumLevels": {
|
||||
"healer": null,
|
||||
"wizard": null,
|
||||
|
@ -25446,10 +25404,7 @@
|
|||
"value": "VE x 2",
|
||||
"unit": "rounds"
|
||||
},
|
||||
"cooldownDuration": {
|
||||
"value": "24",
|
||||
"unit": "hours"
|
||||
},
|
||||
"cooldownDuration": "1d",
|
||||
"minimumLevels": {
|
||||
"healer": null,
|
||||
"wizard": 10,
|
||||
|
@ -25491,10 +25446,7 @@
|
|||
"value": "VE",
|
||||
"unit": "minutes"
|
||||
},
|
||||
"cooldownDuration": {
|
||||
"value": "W20",
|
||||
"unit": "days"
|
||||
},
|
||||
"cooldownDuration": "d20d",
|
||||
"minimumLevels": {
|
||||
"healer": null,
|
||||
"wizard": 18,
|
||||
|
@ -25536,10 +25488,7 @@
|
|||
"value": "Sofort",
|
||||
"unit": "custom"
|
||||
},
|
||||
"cooldownDuration": {
|
||||
"value": "10",
|
||||
"unit": "rounds"
|
||||
},
|
||||
"cooldownDuration": "10r",
|
||||
"minimumLevels": {
|
||||
"healer": 2,
|
||||
"wizard": 5,
|
||||
|
@ -25581,10 +25530,7 @@
|
|||
"value": "VE",
|
||||
"unit": "rounds"
|
||||
},
|
||||
"cooldownDuration": {
|
||||
"value": "24",
|
||||
"unit": "hours"
|
||||
},
|
||||
"cooldownDuration": "1d",
|
||||
"minimumLevels": {
|
||||
"healer": null,
|
||||
"wizard": 15,
|
||||
|
@ -25626,10 +25572,7 @@
|
|||
"value": "Sofort",
|
||||
"unit": "custom"
|
||||
},
|
||||
"cooldownDuration": {
|
||||
"value": "10",
|
||||
"unit": "rounds"
|
||||
},
|
||||
"cooldownDuration": "10r",
|
||||
"minimumLevels": {
|
||||
"healer": null,
|
||||
"wizard": 12,
|
||||
|
@ -25671,10 +25614,7 @@
|
|||
"value": "Prb. x 5",
|
||||
"unit": "rounds"
|
||||
},
|
||||
"cooldownDuration": {
|
||||
"value": "24",
|
||||
"unit": "hours"
|
||||
},
|
||||
"cooldownDuration": "1d",
|
||||
"minimumLevels": {
|
||||
"healer": null,
|
||||
"wizard": 15,
|
||||
|
@ -25716,10 +25656,7 @@
|
|||
"value": "VE / 2",
|
||||
"unit": "rounds"
|
||||
},
|
||||
"cooldownDuration": {
|
||||
"value": "24",
|
||||
"unit": "hours"
|
||||
},
|
||||
"cooldownDuration": "1d",
|
||||
"minimumLevels": {
|
||||
"healer": null,
|
||||
"wizard": 12,
|
||||
|
@ -25761,10 +25698,7 @@
|
|||
"value": "Bis erlöst",
|
||||
"unit": "custom"
|
||||
},
|
||||
"cooldownDuration": {
|
||||
"value": "10",
|
||||
"unit": "rounds"
|
||||
},
|
||||
"cooldownDuration": "10r",
|
||||
"minimumLevels": {
|
||||
"healer": null,
|
||||
"wizard": 8,
|
||||
|
@ -25806,10 +25740,7 @@
|
|||
"value": "Bis Schloss geöffnet",
|
||||
"unit": "custom"
|
||||
},
|
||||
"cooldownDuration": {
|
||||
"value": "5",
|
||||
"unit": "rounds"
|
||||
},
|
||||
"cooldownDuration": "5r",
|
||||
"minimumLevels": {
|
||||
"healer": 3,
|
||||
"wizard": 1,
|
||||
|
@ -25851,10 +25782,7 @@
|
|||
"value": "Prb. / 2",
|
||||
"unit": "rounds"
|
||||
},
|
||||
"cooldownDuration": {
|
||||
"value": "10",
|
||||
"unit": "rounds"
|
||||
},
|
||||
"cooldownDuration": "10r",
|
||||
"minimumLevels": {
|
||||
"healer": 4,
|
||||
"wizard": 9,
|
||||
|
@ -25896,10 +25824,7 @@
|
|||
"value": "Prb. / 2",
|
||||
"unit": "rounds"
|
||||
},
|
||||
"cooldownDuration": {
|
||||
"value": "5",
|
||||
"unit": "rounds"
|
||||
},
|
||||
"cooldownDuration": "5r",
|
||||
"minimumLevels": {
|
||||
"healer": null,
|
||||
"wizard": 6,
|
||||
|
@ -25941,10 +25866,7 @@
|
|||
"value": "Sofort",
|
||||
"unit": "custom"
|
||||
},
|
||||
"cooldownDuration": {
|
||||
"value": "24",
|
||||
"unit": "hours"
|
||||
},
|
||||
"cooldownDuration": "1d",
|
||||
"minimumLevels": {
|
||||
"healer": null,
|
||||
"wizard": null,
|
||||
|
@ -25986,10 +25908,7 @@
|
|||
"value": "Sofort",
|
||||
"unit": "custom"
|
||||
},
|
||||
"cooldownDuration": {
|
||||
"value": "0",
|
||||
"unit": "rounds"
|
||||
},
|
||||
"cooldownDuration": "0r",
|
||||
"minimumLevels": {
|
||||
"healer": null,
|
||||
"wizard": 15,
|
||||
|
@ -26031,10 +25950,7 @@
|
|||
"value": "Sofort",
|
||||
"unit": "custom"
|
||||
},
|
||||
"cooldownDuration": {
|
||||
"value": "10",
|
||||
"unit": "rounds"
|
||||
},
|
||||
"cooldownDuration": "10r",
|
||||
"minimumLevels": {
|
||||
"healer": 5,
|
||||
"wizard": 2,
|
||||
|
@ -26076,10 +25992,7 @@
|
|||
"value": "Sofort",
|
||||
"unit": "custom"
|
||||
},
|
||||
"cooldownDuration": {
|
||||
"value": "100",
|
||||
"unit": "rounds"
|
||||
},
|
||||
"cooldownDuration": "100r",
|
||||
"minimumLevels": {
|
||||
"healer": null,
|
||||
"wizard": 4,
|
||||
|
@ -26121,10 +26034,7 @@
|
|||
"value": "VE / 2",
|
||||
"unit": "hours"
|
||||
},
|
||||
"cooldownDuration": {
|
||||
"value": "100",
|
||||
"unit": "rounds"
|
||||
},
|
||||
"cooldownDuration": "100r",
|
||||
"minimumLevels": {
|
||||
"healer": null,
|
||||
"wizard": 5,
|
||||
|
@ -26166,10 +26076,7 @@
|
|||
"value": "Prb.",
|
||||
"unit": "minutes"
|
||||
},
|
||||
"cooldownDuration": {
|
||||
"value": "24",
|
||||
"unit": "hours"
|
||||
},
|
||||
"cooldownDuration": "1d",
|
||||
"minimumLevels": {
|
||||
"healer": 20,
|
||||
"wizard": 12,
|
||||
|
@ -26211,10 +26118,7 @@
|
|||
"value": "Prb.",
|
||||
"unit": "rounds"
|
||||
},
|
||||
"cooldownDuration": {
|
||||
"value": "10",
|
||||
"unit": "rounds"
|
||||
},
|
||||
"cooldownDuration": "10r",
|
||||
"minimumLevels": {
|
||||
"healer": 8,
|
||||
"wizard": 5,
|
||||
|
@ -26256,10 +26160,7 @@
|
|||
"value": "Prb. / 2",
|
||||
"unit": "rounds"
|
||||
},
|
||||
"cooldownDuration": {
|
||||
"value": "100",
|
||||
"unit": "rounds"
|
||||
},
|
||||
"cooldownDuration": "100r",
|
||||
"minimumLevels": {
|
||||
"healer": null,
|
||||
"wizard": 6,
|
||||
|
@ -26301,10 +26202,7 @@
|
|||
"value": "Prb. x 2",
|
||||
"unit": "rounds"
|
||||
},
|
||||
"cooldownDuration": {
|
||||
"value": "100",
|
||||
"unit": "rounds"
|
||||
},
|
||||
"cooldownDuration": "100r",
|
||||
"minimumLevels": {
|
||||
"healer": null,
|
||||
"wizard": null,
|
||||
|
@ -26346,10 +26244,7 @@
|
|||
"value": "Prb.",
|
||||
"unit": "rounds"
|
||||
},
|
||||
"cooldownDuration": {
|
||||
"value": "W20",
|
||||
"unit": "days"
|
||||
},
|
||||
"cooldownDuration": "d20d",
|
||||
"minimumLevels": {
|
||||
"healer": null,
|
||||
"wizard": 15,
|
||||
|
@ -28333,10 +28228,7 @@
|
|||
"value": "VE / 2",
|
||||
"unit": "rounds"
|
||||
},
|
||||
"cooldownDuration": {
|
||||
"value": "10",
|
||||
"unit": "rounds"
|
||||
},
|
||||
"cooldownDuration": "10r",
|
||||
"minimumLevels": {
|
||||
"healer": null,
|
||||
"wizard": null,
|
||||
|
@ -28882,10 +28774,7 @@
|
|||
"value": "Sofort",
|
||||
"unit": "custom"
|
||||
},
|
||||
"cooldownDuration": {
|
||||
"value": "1",
|
||||
"unit": "rounds"
|
||||
},
|
||||
"cooldownDuration": "1r",
|
||||
"minimumLevels": {
|
||||
"healer": 10,
|
||||
"wizard": 7,
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -2,7 +2,7 @@
|
|||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
import { DS4SpellDataSourceData, TemporalUnit, UnitData } from "../../../src/item/item-data-source";
|
||||
import { CooldownDuration, DS4SpellDataSourceData } from "../../../src/item/item-data-source";
|
||||
import { calculateSpellPrice } from "../../../src/item/type-specific-helpers/spell";
|
||||
|
||||
const defaultData: DS4SpellDataSourceData = {
|
||||
|
@ -23,10 +23,7 @@ const defaultData: DS4SpellDataSourceData = {
|
|||
value: "",
|
||||
unit: "custom",
|
||||
},
|
||||
cooldownDuration: {
|
||||
value: "",
|
||||
unit: "rounds",
|
||||
},
|
||||
cooldownDuration: "0r",
|
||||
minimumLevels: {
|
||||
healer: null,
|
||||
wizard: null,
|
||||
|
@ -167,65 +164,41 @@ function buildCombinedTestCases(): CombinedTestCase[] {
|
|||
}
|
||||
|
||||
describe("calculateSpellPrice", () => {
|
||||
const cooldownDurations: (UnitData<TemporalUnit> & { factor: number })[] = [
|
||||
{ value: "", unit: "rounds", factor: 1 },
|
||||
{ value: "foo", unit: "rounds", factor: 1 },
|
||||
{ value: "0", unit: "rounds", factor: 1 },
|
||||
{ value: "1", unit: "rounds", factor: 1 },
|
||||
{ value: "17279", unit: "rounds", factor: 1 },
|
||||
{ value: "17280", unit: "rounds", factor: 2 },
|
||||
{ value: "34559", unit: "rounds", factor: 2 },
|
||||
{ value: "34560", unit: "rounds", factor: 3 },
|
||||
|
||||
{ value: "", unit: "minutes", factor: 1 },
|
||||
{ value: "foo", unit: "minutes", factor: 1 },
|
||||
{ value: "0", unit: "minutes", factor: 1 },
|
||||
{ value: "1", unit: "minutes", factor: 1 },
|
||||
{ value: "1439", unit: "minutes", factor: 1 },
|
||||
{ value: "1440", unit: "minutes", factor: 2 },
|
||||
{ value: "2879", unit: "minutes", factor: 2 },
|
||||
{ value: "2880", unit: "minutes", factor: 3 },
|
||||
|
||||
{ value: "", unit: "hours", factor: 1 },
|
||||
{ value: "foo", unit: "hours", factor: 1 },
|
||||
{ value: "0", unit: "hours", factor: 1 },
|
||||
{ value: "1", unit: "hours", factor: 1 },
|
||||
{ value: "23", unit: "hours", factor: 1 },
|
||||
{ value: "24", unit: "hours", factor: 2 },
|
||||
{ value: "47", unit: "hours", factor: 2 },
|
||||
{ value: "48", unit: "hours", factor: 3 },
|
||||
|
||||
{ value: "", unit: "days", factor: 3 },
|
||||
{ value: "foo", unit: "days", factor: 3 },
|
||||
{ value: "0", unit: "days", factor: 1 },
|
||||
{ value: "1", unit: "days", factor: 2 },
|
||||
{ value: "2", unit: "days", factor: 3 },
|
||||
const cooldownDurations: { cooldownDuration: CooldownDuration; factor: number }[] = [
|
||||
{ cooldownDuration: "0r", factor: 1 },
|
||||
{ cooldownDuration: "1r", factor: 1 },
|
||||
{ cooldownDuration: "2r", factor: 1 },
|
||||
{ cooldownDuration: "5r", factor: 1 },
|
||||
{ cooldownDuration: "10r", factor: 1 },
|
||||
{ cooldownDuration: "100r", factor: 1 },
|
||||
{ cooldownDuration: "1d", factor: 2 },
|
||||
{ cooldownDuration: "d20d", factor: 3 },
|
||||
];
|
||||
|
||||
describe.each(cooldownDurations)("with cooldown duration set to $value $unit", ({ value, unit, factor }) => {
|
||||
const dataWithCooldownDuration = {
|
||||
...defaultData,
|
||||
cooldownDuration: {
|
||||
value,
|
||||
unit,
|
||||
},
|
||||
};
|
||||
describe.each(cooldownDurations)(
|
||||
"with cooldown duration set to $cooldownDuration",
|
||||
({ cooldownDuration, factor }) => {
|
||||
const dataWithCooldownDuration = {
|
||||
...defaultData,
|
||||
cooldownDuration,
|
||||
};
|
||||
|
||||
it.each(buildCombinedTestCases())(
|
||||
`returns ${factor} × $expected if the minimum leves are $minimumLevels`,
|
||||
({ minimumLevels, expected }) => {
|
||||
// given
|
||||
const data: DS4SpellDataSourceData = {
|
||||
...dataWithCooldownDuration,
|
||||
minimumLevels,
|
||||
};
|
||||
it.each(buildCombinedTestCases())(
|
||||
`returns ${factor} × $expected if the minimum leves are $minimumLevels`,
|
||||
({ minimumLevels, expected }) => {
|
||||
// given
|
||||
const data: DS4SpellDataSourceData = {
|
||||
...dataWithCooldownDuration,
|
||||
minimumLevels,
|
||||
};
|
||||
|
||||
// when
|
||||
const spellPrice = calculateSpellPrice(data);
|
||||
// when
|
||||
const spellPrice = calculateSpellPrice(data);
|
||||
|
||||
// then
|
||||
expect(spellPrice).toBe(expected !== null ? expected * factor : expected);
|
||||
},
|
||||
);
|
||||
});
|
||||
// then
|
||||
expect(spellPrice).toBe(expected !== null ? expected * factor : expected);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2021 Johannes Loher
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
export const secondsPerRound = 5;
|
||||
export const secondsPerMinute = 60;
|
||||
export const minutesPerHour = 60;
|
||||
export const hoursPerDay = 24;
|
|
@ -106,6 +106,17 @@ const i18nKeys = {
|
|||
unset: "DS4.SpellCategoryUnset",
|
||||
},
|
||||
|
||||
cooldownDurations: {
|
||||
"0r": "DS4.CooldownDuration0R",
|
||||
"1r": "DS4.CooldownDuration1R",
|
||||
"2r": "DS4.CooldownDuration2R",
|
||||
"5r": "DS4.CooldownDuration5R",
|
||||
"10r": "DS4.CooldownDuration10R",
|
||||
"100r": "DS4.CooldownDuration100R",
|
||||
"1d": "DS4.CooldownDuration1D",
|
||||
d20d: "DS4.CooldownDurationD20D",
|
||||
},
|
||||
|
||||
/**
|
||||
* Define the set of actor types
|
||||
*/
|
||||
|
@ -276,16 +287,6 @@ const i18nKeys = {
|
|||
minutes: "DS4.UnitMinutes",
|
||||
hours: "DS4.UnitHours",
|
||||
days: "DS4.UnitDays",
|
||||
},
|
||||
|
||||
/**
|
||||
* Define translations for available duration units including "custom"
|
||||
*/
|
||||
customTemporalUnits: {
|
||||
rounds: "DS4.UnitRounds",
|
||||
minutes: "DS4.UnitMinutes",
|
||||
hours: "DS4.UnitHours",
|
||||
days: "DS4.UnitDays",
|
||||
custom: "DS4.UnitCustom",
|
||||
},
|
||||
|
||||
|
@ -297,16 +298,6 @@ const i18nKeys = {
|
|||
minutes: "DS4.UnitMinutesAbbr",
|
||||
hours: "DS4.UnitHoursAbbr",
|
||||
days: "DS4.UnitDaysAbbr",
|
||||
},
|
||||
|
||||
/**
|
||||
* Define abbreviations for available duration units including "custom"
|
||||
*/
|
||||
customTemporalUnitsAbbr: {
|
||||
rounds: "DS4.UnitRoundsAbbr",
|
||||
minutes: "DS4.UnitMinutesAbbr",
|
||||
hours: "DS4.UnitHoursAbbr",
|
||||
days: "DS4.UnitDaysAbbr",
|
||||
custom: "DS4.UnitCustomAbbr",
|
||||
},
|
||||
|
||||
|
|
|
@ -18,7 +18,14 @@ export default function registerForSetupHooks(): void {
|
|||
* Localizes all objects in {@link DS4.i18n} and sorts them unless they are explicitly excluded.
|
||||
*/
|
||||
function localizeAndSortConfigObjects() {
|
||||
const noSort = ["attributes", "traits", "combatValues", "creatureSizeCategories"];
|
||||
const noSort = [
|
||||
"attributes",
|
||||
"combatValues",
|
||||
"cooldownDurations",
|
||||
"creatureSizeCategories",
|
||||
"spellCategories",
|
||||
"traits",
|
||||
];
|
||||
|
||||
const localizeObject = <T extends { [s: string]: string }>(obj: T, sort = true): T => {
|
||||
const localized = Object.entries(obj).map(([key, value]): [string, string] => {
|
||||
|
|
|
@ -136,14 +136,16 @@ export interface DS4ShieldDataSourceData
|
|||
DS4ItemDataSourceDataEquipable,
|
||||
DS4ItemDataSourceDataProtective {}
|
||||
|
||||
export type CooldownDuration = keyof typeof DS4.i18n.cooldownDurations;
|
||||
|
||||
export interface DS4SpellDataSourceData extends DS4ItemDataSourceDataBase, DS4ItemDataSourceDataEquipable {
|
||||
spellType: keyof typeof DS4.i18n.spellTypes;
|
||||
bonus: string;
|
||||
spellCategory: keyof typeof DS4.i18n.spellCategories;
|
||||
maxDistance: UnitData<DistanceUnit>;
|
||||
effectRadius: UnitData<DistanceUnit>;
|
||||
duration: UnitData<CustomTemporalUnit>;
|
||||
cooldownDuration: UnitData<TemporalUnit>;
|
||||
duration: UnitData<TemporalUnit>;
|
||||
cooldownDuration: CooldownDuration;
|
||||
minimumLevels: {
|
||||
healer: number | null;
|
||||
wizard: number | null;
|
||||
|
@ -158,9 +160,7 @@ export interface UnitData<UnitType> {
|
|||
|
||||
type DistanceUnit = keyof typeof DS4.i18n.distanceUnits;
|
||||
|
||||
type CustomTemporalUnit = keyof typeof DS4.i18n.customTemporalUnits;
|
||||
|
||||
export type TemporalUnit = keyof typeof DS4.i18n.temporalUnits;
|
||||
type TemporalUnit = keyof typeof DS4.i18n.temporalUnits;
|
||||
|
||||
export interface DS4EquipmentDataSourceData
|
||||
extends DS4ItemDataSourceDataBase,
|
||||
|
|
|
@ -148,17 +148,17 @@ export class DS4Item extends Item {
|
|||
}
|
||||
|
||||
const ownerDataData = this.actor.data.data;
|
||||
const spellBonus = Number.isNumeric(this.data.data.bonus) ? parseInt(this.data.data.bonus) : undefined;
|
||||
if (spellBonus === undefined) {
|
||||
const spellModifier = Number.isNumeric(this.data.data.bonus) ? parseInt(this.data.data.bonus) : undefined;
|
||||
if (spellModifier === undefined) {
|
||||
notifications.info(
|
||||
getGame().i18n.format("DS4.InfoManuallyEnterSpellBonus", {
|
||||
getGame().i18n.format("DS4.InfoManuallyEnterSpellModifier", {
|
||||
name: this.name,
|
||||
spellBonus: this.data.data.bonus,
|
||||
spellModifier: this.data.data.bonus,
|
||||
}),
|
||||
);
|
||||
}
|
||||
const spellType = this.data.data.spellType;
|
||||
const checkTargetNumber = ownerDataData.combatValues[spellType].total + (spellBonus ?? 0);
|
||||
const checkTargetNumber = ownerDataData.combatValues[spellType].total + (spellModifier ?? 0);
|
||||
|
||||
const speaker = ChatMessage.getSpeaker({ actor: this.actor, ...options.speaker });
|
||||
await createCheckRoll(checkTargetNumber, {
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
import { hoursPerDay, minutesPerHour, secondsPerMinute, secondsPerRound } from "../../common/time-helpers";
|
||||
import { DS4SpellDataSourceData, TemporalUnit, UnitData } from "../item-data-source";
|
||||
import { CooldownDuration, DS4SpellDataSourceData } from "../item-data-source";
|
||||
|
||||
export function calculateSpellPrice(data: DS4SpellDataSourceData): number | null {
|
||||
const spellPriceFactor = calculateSpellPriceFactor(data.cooldownDuration);
|
||||
|
@ -16,39 +15,18 @@ export function calculateSpellPrice(data: DS4SpellDataSourceData): number | null
|
|||
return baseSpellPrice === Infinity ? null : baseSpellPrice * spellPriceFactor;
|
||||
}
|
||||
|
||||
function calculateSpellPriceFactor(temporalData: UnitData<TemporalUnit>): number {
|
||||
let days: number;
|
||||
if (Number.isNumeric(temporalData.value)) {
|
||||
const value = Number.fromString(temporalData.value);
|
||||
switch (temporalData.unit) {
|
||||
case "days": {
|
||||
days = value;
|
||||
break;
|
||||
}
|
||||
case "hours": {
|
||||
days = value / hoursPerDay;
|
||||
break;
|
||||
}
|
||||
case "minutes": {
|
||||
days = value / (hoursPerDay * minutesPerHour);
|
||||
break;
|
||||
}
|
||||
case "rounds": {
|
||||
days = (value * secondsPerRound) / (hoursPerDay * minutesPerHour * secondsPerMinute);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
switch (temporalData.unit) {
|
||||
case "days": {
|
||||
days = 2;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
days = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
function calculateSpellPriceFactor(cooldownDuration: CooldownDuration): number {
|
||||
switch (cooldownDuration) {
|
||||
case "0r":
|
||||
case "1r":
|
||||
case "2r":
|
||||
case "5r":
|
||||
case "10r":
|
||||
case "100r":
|
||||
return 1;
|
||||
case "1d":
|
||||
return 2;
|
||||
case "d20d":
|
||||
return 3;
|
||||
}
|
||||
return Math.clamped(Math.floor(days), 0, 2) + 1;
|
||||
}
|
||||
|
|
|
@ -4,10 +4,11 @@
|
|||
|
||||
import { getGame } from "./helpers";
|
||||
import logger from "./logger";
|
||||
import { migrate as migrate001 } from "./migrations/001";
|
||||
import { migrate as migrate002 } from "./migrations/002";
|
||||
import { migrate as migrate003 } from "./migrations/003";
|
||||
import { migrate as migrate004 } from "./migrations/004";
|
||||
import { migration as migration001 } from "./migrations/001";
|
||||
import { migration as migration002 } from "./migrations/002";
|
||||
import { migration as migration003 } from "./migrations/003";
|
||||
import { migration as migration004 } from "./migrations/004";
|
||||
import { migration as migration005 } from "./migrations/005";
|
||||
import notifications from "./ui/notifications";
|
||||
|
||||
async function migrate(): Promise<void> {
|
||||
|
@ -43,11 +44,11 @@ async function migrateFromTo(oldMigrationVersion: number, targetMigrationVersion
|
|||
{ permanent: true },
|
||||
);
|
||||
|
||||
for (const [i, migration] of migrationsToExecute.entries()) {
|
||||
for (const [i, { migrate }] of migrationsToExecute.entries()) {
|
||||
const currentMigrationVersion = oldMigrationVersion + i + 1;
|
||||
logger.info("executing migration script ", currentMigrationVersion);
|
||||
try {
|
||||
await migration();
|
||||
await migrate();
|
||||
getGame().settings.set("ds4", "systemMigrationVersion", currentMigrationVersion);
|
||||
} catch (err) {
|
||||
notifications.error(
|
||||
|
@ -73,18 +74,76 @@ async function migrateFromTo(oldMigrationVersion: number, targetMigrationVersion
|
|||
}
|
||||
}
|
||||
|
||||
async function migrateCompendiumFromTo(
|
||||
pack: CompendiumCollection<CompendiumCollection.Metadata>,
|
||||
oldMigrationVersion: number,
|
||||
targetMigrationVersion: number,
|
||||
): Promise<void> {
|
||||
if (!getGame().user?.isGM) {
|
||||
return;
|
||||
}
|
||||
|
||||
const migrationsToExecute = migrations.slice(oldMigrationVersion, targetMigrationVersion);
|
||||
|
||||
if (migrationsToExecute.length > 0) {
|
||||
notifications.info(
|
||||
getGame().i18n.format("DS4.InfoCompendiumMigrationStart", {
|
||||
pack: pack.title,
|
||||
currentVersion: oldMigrationVersion,
|
||||
targetVersion: targetMigrationVersion,
|
||||
}),
|
||||
{ permanent: true },
|
||||
);
|
||||
|
||||
for (const [i, { migrateCompendium }] of migrationsToExecute.entries()) {
|
||||
const currentMigrationVersion = oldMigrationVersion + i + 1;
|
||||
logger.info("executing compendium migration ", currentMigrationVersion);
|
||||
try {
|
||||
await migrateCompendium(pack);
|
||||
} catch (err) {
|
||||
notifications.error(
|
||||
getGame().i18n.format("DS4.ErrorDuringCompendiumMigration", {
|
||||
pack: pack.title,
|
||||
currentVersion: oldMigrationVersion,
|
||||
targetVersion: targetMigrationVersion,
|
||||
migrationVersion: currentMigrationVersion,
|
||||
}),
|
||||
{ permanent: true },
|
||||
);
|
||||
logger.error("Failed ds4 compendium migration:", err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
notifications.info(
|
||||
getGame().i18n.format("DS4.InfoCompendiumMigrationCompleted", {
|
||||
pack: pack.title,
|
||||
currentVersion: oldMigrationVersion,
|
||||
targetVersion: targetMigrationVersion,
|
||||
}),
|
||||
{ permanent: true },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function getTargetMigrationVersion(): number {
|
||||
return migrations.length;
|
||||
}
|
||||
|
||||
const migrations: Array<() => Promise<void>> = [migrate001, migrate002, migrate003, migrate004];
|
||||
interface Migration {
|
||||
migrate: () => Promise<void>;
|
||||
migrateCompendium: (pack: CompendiumCollection<CompendiumCollection.Metadata>) => Promise<void>;
|
||||
}
|
||||
|
||||
const migrations: Migration[] = [migration001, migration002, migration003, migration004, migration005];
|
||||
|
||||
function isFirstWorldStart(migrationVersion: number): boolean {
|
||||
return migrationVersion < 0;
|
||||
}
|
||||
|
||||
export const migration = {
|
||||
migrate: migrate,
|
||||
migrateFromTo: migrateFromTo,
|
||||
getTargetMigrationVersion: getTargetMigrationVersion,
|
||||
migrate,
|
||||
migrateFromTo,
|
||||
getTargetMigrationVersion,
|
||||
migrateCompendiumFromTo,
|
||||
};
|
||||
|
|
|
@ -10,7 +10,7 @@ import {
|
|||
migrateScenes,
|
||||
} from "./migrationHelpers";
|
||||
|
||||
export async function migrate(): Promise<void> {
|
||||
async function migrate(): Promise<void> {
|
||||
await migrateActors(getActorUpdateData);
|
||||
await migrateScenes(getSceneUpdateData);
|
||||
await migrateCompendiums(migrateCompendium);
|
||||
|
@ -39,3 +39,8 @@ function getActorUpdateData(): Record<string, unknown> {
|
|||
|
||||
const getSceneUpdateData = getSceneUpdateDataGetter(getActorUpdateData);
|
||||
const migrateCompendium = getCompendiumMigrator({ getActorUpdateData, getSceneUpdateData });
|
||||
|
||||
export const migration = {
|
||||
migrate,
|
||||
migrateCompendium,
|
||||
};
|
||||
|
|
|
@ -12,7 +12,7 @@ import {
|
|||
migrateScenes,
|
||||
} from "./migrationHelpers";
|
||||
|
||||
export async function migrate(): Promise<void> {
|
||||
async function migrate(): Promise<void> {
|
||||
await migrateItems(getItemUpdateData);
|
||||
await migrateActors(getActorUpdateData);
|
||||
await migrateScenes(getSceneUpdateData);
|
||||
|
@ -32,3 +32,8 @@ const migrateCompendium = getCompendiumMigrator(
|
|||
{ getItemUpdateData, getActorUpdateData, getSceneUpdateData },
|
||||
{ migrateToTemplateEarly: false },
|
||||
);
|
||||
|
||||
export const migration = {
|
||||
migrate,
|
||||
migrateCompendium,
|
||||
};
|
||||
|
|
|
@ -12,7 +12,7 @@ import {
|
|||
migrateScenes,
|
||||
} from "./migrationHelpers";
|
||||
|
||||
export async function migrate(): Promise<void> {
|
||||
async function migrate(): Promise<void> {
|
||||
await migrateItems(getItemUpdateData);
|
||||
await migrateActors(getActorUpdateData);
|
||||
await migrateScenes(getSceneUpdateData);
|
||||
|
@ -34,3 +34,8 @@ const migrateCompendium = getCompendiumMigrator(
|
|||
{ getItemUpdateData, getActorUpdateData },
|
||||
{ migrateToTemplateEarly: false },
|
||||
);
|
||||
|
||||
export const migration = {
|
||||
migrate,
|
||||
migrateCompendium,
|
||||
};
|
||||
|
|
|
@ -12,7 +12,7 @@ import {
|
|||
migrateScenes,
|
||||
} from "./migrationHelpers";
|
||||
|
||||
export async function migrate(): Promise<void> {
|
||||
async function migrate(): Promise<void> {
|
||||
await migrateItems(getItemUpdateData);
|
||||
await migrateActors(getActorUpdateData);
|
||||
await migrateScenes(getSceneUpdateData);
|
||||
|
@ -21,6 +21,7 @@ export async function migrate(): Promise<void> {
|
|||
|
||||
function getItemUpdateData(itemData: Partial<foundry.data.ItemData["_source"]>) {
|
||||
if (itemData.type !== "spell") return;
|
||||
// @ts-expect-error the type of cooldownDuration was UnitData<TemporalUnit> at the point for this migration, but it changed later on
|
||||
const cooldownDurationUnit: string | undefined = itemData.data?.cooldownDuration.unit;
|
||||
|
||||
const updateData: Record<string, unknown> = {
|
||||
|
@ -38,3 +39,8 @@ function getItemUpdateData(itemData: Partial<foundry.data.ItemData["_source"]>)
|
|||
const getActorUpdateData = getActorUpdateDataGetter(getItemUpdateData);
|
||||
const getSceneUpdateData = getSceneUpdateDataGetter(getActorUpdateData);
|
||||
const migrateCompendium = getCompendiumMigrator({ getItemUpdateData, getActorUpdateData, getSceneUpdateData });
|
||||
|
||||
export const migration = {
|
||||
migrate,
|
||||
migrateCompendium,
|
||||
};
|
||||
|
|
119
src/migrations/005.ts
Normal file
119
src/migrations/005.ts
Normal file
|
@ -0,0 +1,119 @@
|
|||
// SPDX-FileCopyrightText: 2021 Johannes Loher
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
import { CooldownDuration } from "../item/item-data-source";
|
||||
import {
|
||||
getActorUpdateDataGetter,
|
||||
getCompendiumMigrator,
|
||||
getSceneUpdateDataGetter,
|
||||
migrateActors,
|
||||
migrateCompendiums,
|
||||
migrateItems,
|
||||
migrateScenes,
|
||||
} from "./migrationHelpers";
|
||||
|
||||
const secondsPerRound = 5;
|
||||
const secondsPerMinute = 60;
|
||||
const roundsPerMinute = secondsPerMinute / secondsPerRound;
|
||||
const minutesPerHour = 60;
|
||||
const roundsPerHour = minutesPerHour / roundsPerMinute;
|
||||
const hoursPerDay = 24;
|
||||
const roundsPerDay = hoursPerDay / roundsPerHour;
|
||||
const secondsPerDay = secondsPerMinute * minutesPerHour * hoursPerDay;
|
||||
|
||||
async function migrate(): Promise<void> {
|
||||
await migrateItems(getItemUpdateData);
|
||||
await migrateActors(getActorUpdateData);
|
||||
await migrateScenes(getSceneUpdateData);
|
||||
await migrateCompendiums(migrateCompendium);
|
||||
}
|
||||
|
||||
function getItemUpdateData(itemData: Partial<foundry.data.ItemData["_source"]>) {
|
||||
if (itemData.type !== "spell") return;
|
||||
// @ts-expect-error the type of cooldownDuration is changed from UnitData<TemporalUnit> to CooldownDuation with this migration
|
||||
const cooldownDurationUnit: string | undefined = itemData.data?.cooldownDuration.unit;
|
||||
// @ts-expect-error the type of cooldownDuration is changed from UnitData<TemporalUnit> to CooldownDuation with this migration
|
||||
const cooldownDurationValue: string | undefined = itemData.data?.cooldownDuration.value;
|
||||
const cooldownDuration = migrateCooldownDuration(cooldownDurationValue, cooldownDurationUnit);
|
||||
|
||||
const updateData: Record<string, unknown> = {
|
||||
data: {
|
||||
cooldownDuration,
|
||||
},
|
||||
};
|
||||
return updateData;
|
||||
}
|
||||
|
||||
function migrateCooldownDuration(cooldownDurationValue?: string, cooldownDurationUnit?: string) {
|
||||
if (Number.isNumeric(cooldownDurationValue)) {
|
||||
const value = Number.fromString(cooldownDurationValue!);
|
||||
const rounds = getRounds(cooldownDurationUnit ?? "", value);
|
||||
|
||||
if (rounds * secondsPerRound > secondsPerDay) {
|
||||
return "d20d";
|
||||
} else if (rounds > 100) {
|
||||
return "1d";
|
||||
} else if (rounds > 10) {
|
||||
return "100r";
|
||||
} else if (rounds > 5) {
|
||||
return "10r";
|
||||
} else if (rounds > 2) {
|
||||
return "5r";
|
||||
} else if (rounds > 1) {
|
||||
return "2r";
|
||||
} else if (rounds > 0) {
|
||||
return "1r";
|
||||
} else {
|
||||
return "0r";
|
||||
}
|
||||
} else {
|
||||
// if the value is not numeric, we can only make a best guess
|
||||
switch (cooldownDurationUnit) {
|
||||
case "rounds": {
|
||||
return "10r";
|
||||
}
|
||||
case "minutes": {
|
||||
return "100r";
|
||||
}
|
||||
case "hours": {
|
||||
return "1d";
|
||||
}
|
||||
case "days": {
|
||||
return "d20d";
|
||||
}
|
||||
default: {
|
||||
return "0r";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getRounds(unit: string, value: number): number {
|
||||
switch (unit) {
|
||||
case "rounds": {
|
||||
return value;
|
||||
}
|
||||
case "minutes": {
|
||||
return value * roundsPerMinute;
|
||||
}
|
||||
case "hours": {
|
||||
return value * roundsPerHour;
|
||||
}
|
||||
case "days": {
|
||||
return value * roundsPerDay;
|
||||
}
|
||||
default: {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const getActorUpdateData = getActorUpdateDataGetter(getItemUpdateData);
|
||||
const getSceneUpdateData = getSceneUpdateDataGetter(getActorUpdateData);
|
||||
const migrateCompendium = getCompendiumMigrator({ getItemUpdateData, getActorUpdateData, getSceneUpdateData });
|
||||
|
||||
export const migration = {
|
||||
migrate,
|
||||
migrateCompendium,
|
||||
};
|
|
@ -187,10 +187,7 @@
|
|||
"value": "",
|
||||
"unit": "custom"
|
||||
},
|
||||
"cooldownDuration": {
|
||||
"value": "",
|
||||
"unit": "rounds"
|
||||
},
|
||||
"cooldownDuration": "0r",
|
||||
"minimumLevels": {
|
||||
"healer": null,
|
||||
"wizard": null,
|
||||
|
|
|
@ -25,7 +25,7 @@ SPDX-License-Identifier: MIT
|
|||
{{/inline}}
|
||||
|
||||
{{!--
|
||||
!-- Three templates based on the "unit" template for displaying values with unit.
|
||||
!-- Two templates based on the "unit" template for displaying values with unit.
|
||||
!-- Both accept a `config` object holding the unitNames and unitAbbr instead of
|
||||
!-- directly handing over the latter two.
|
||||
!-- @param titleKey: The key of the localized title to use.
|
||||
|
@ -35,11 +35,6 @@ SPDX-License-Identifier: MIT
|
|||
titleKey=titleKey}}
|
||||
{{/inline}}
|
||||
|
||||
{{#*inline "customTemporalUnit"}}
|
||||
{{> unit unitNames=config.i18n.customTemporalUnits unitAbbrs=config.i18n.customTemporalUnitsAbbr unitDatum=unitDatum
|
||||
titleKey=titleKey}}
|
||||
{{/inline}}
|
||||
|
||||
{{#*inline "distanceUnit"}}
|
||||
{{> unit unitNames=config.i18n.distanceUnits unitAbbrs=config.i18n.distanceUnitsAbbr unitDatum=unitDatum
|
||||
titleKey=titleKey}}
|
||||
|
@ -60,16 +55,16 @@ titleKey=titleKey}}
|
|||
|
||||
{{!-- spell bonus --}}
|
||||
<div class="ds4-embedded-document-list__clickable sort-items" data-data-path="data.bonus"
|
||||
title="{{localize 'DS4.SortBySpellBonus'}}">{{localize 'DS4.SpellBonusAbbr'}}</div>
|
||||
title="{{localize 'DS4.SortBySpellModifier'}}">{{localize 'DS4.SpellModifierAbbr'}}</div>
|
||||
|
||||
{{!-- max. distance --}}
|
||||
<div title="{{localize 'DS4.SpellMaxDistance'}}"><i class="fas fa-ruler"></i></div>
|
||||
<div title="{{localize 'DS4.SpellDistance'}}"><i class="fas fa-ruler"></i></div>
|
||||
|
||||
{{!-- duration --}}
|
||||
<div title="{{localize 'DS4.SpellDuration'}}"><i class="far fa-clock"></i></div>
|
||||
|
||||
{{!-- cooldown duration --}}
|
||||
<div title="{{localize 'DS4.SpellCooldownDuration'}}"><i class="fas fa-hourglass-half"></i></div>
|
||||
<div title="{{localize 'DS4.CooldownDuration'}}"><i class="fas fa-hourglass-half"></i></div>
|
||||
{{/systems/ds4/templates/sheets/actor/components/item-list-header.hbs}}
|
||||
|
||||
{{#each itemsByType.spell as |itemData id|}}
|
||||
|
@ -77,23 +72,24 @@ titleKey=titleKey}}
|
|||
hideDescription=true}}
|
||||
{{!-- spell type --}}
|
||||
<img class="ds4-embedded-document-list__image"
|
||||
src="{{lookup ../../config.icons.spellTypes itemData.data.spellType}}"
|
||||
title="{{lookup ../../config.i18n.spellTypes itemData.data.spellType}}" />
|
||||
src="{{lookup @root/config.icons.spellTypes itemData.data.spellType}}"
|
||||
title="{{lookup @root/config.i18n.spellTypes itemData.data.spellType}}" />
|
||||
|
||||
{{!-- spell bonus --}}
|
||||
<input class="ds4-embedded-document-list__editable change-item" type="text" data-dtype="String"
|
||||
data-property="data.bonus" value="{{itemData.data.bonus}}" title="{{localize 'DS4.SpellBonus'}}" />
|
||||
data-property="data.bonus" value="{{itemData.data.bonus}}" title="{{localize 'DS4.SpellModifier'}}" />
|
||||
|
||||
{{!-- max. distance --}}
|
||||
{{> distanceUnit titleKey='DS4.SpellMaxDistance' unitDatum=itemData.data.maxDistance
|
||||
config=../../config}}
|
||||
{{> distanceUnit titleKey='DS4.SpellDistance' unitDatum=itemData.data.maxDistance
|
||||
config=@root/config}}
|
||||
|
||||
{{!-- duration --}}
|
||||
{{> customTemporalUnit titleKey='DS4.SpellDuration' unitDatum=itemData.data.duration config=../../config}}
|
||||
{{> temporalUnit titleKey='DS4.SpellDuration' unitDatum=itemData.data.duration config=@root/config}}
|
||||
|
||||
{{!-- cooldown duration --}}
|
||||
{{> temporalUnit titleKey='DS4.SpellCooldownDuration' unitDatum=itemData.data.cooldownDuration
|
||||
config=../../config}}
|
||||
<div title="{{localize 'DS4.CooldownDuration'}}">{{lookup @root/config.i18n.cooldownDurations
|
||||
itemData.data.cooldownDuration}}</div>
|
||||
|
||||
{{/systems/ds4/templates/sheets/actor/components/item-list-entry.hbs}}
|
||||
{{/each}}
|
||||
</ol>
|
||||
|
|
|
@ -7,12 +7,16 @@ SPDX-License-Identifier: MIT
|
|||
<div class="ds4-item-properties ds4-item-properties--spell">
|
||||
<h4 class="ds4-item-properties__title">{{localize 'DS4.ItemPropertiesSpell'}}</h4>
|
||||
<div class="form-group">
|
||||
<label for="data.bonus-{{data._id}}">{{localize "DS4.SpellBonus"}}</label>
|
||||
<input id="data.bonus-{{data._id}}" data-dtype="String" type="text" name="data.bonus" placeholder="0"
|
||||
value="{{data.data.bonus}}" />
|
||||
<label for="data.bonus-{{data._id}}" title="{{localize 'DS4.SpellModifierDescription'}}">{{localize
|
||||
"DS4.SpellModifier"}}</label>
|
||||
<div class="form-fields">
|
||||
<input id="data.bonus-{{data._id}}" data-dtype="String" type="text" name="data.bonus" placeholder="0"
|
||||
value="{{data.data.bonus}}" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="data.spellType-{{data._id}}">{{localize "DS4.SpellType"}}</label>
|
||||
<label for="data.spellType-{{data._id}}" title="{{localize 'DS4.SpellTypeDescription'}}">{{localize
|
||||
"DS4.SpellType"}}</label>
|
||||
<div class="form-fields">
|
||||
<select id="data.spellType-{{data._id}}" name="data.spellType" data-dtype="String">
|
||||
{{#select data.data.spellType}}
|
||||
|
@ -24,7 +28,8 @@ SPDX-License-Identifier: MIT
|
|||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="data.spellCategory-{{data._id}}">{{localize "DS4.SpellCategory"}}</label>
|
||||
<label for="data.spellCategory-{{data._id}}" title="{{localize 'DS4.SpellCategoryDescription'}}">{{localize
|
||||
"DS4.SpellCategory"}}</label>
|
||||
<div class="form-fields">
|
||||
<select id="data.spellCategory-{{data._id}}" name="data.spellCategory" data-dtype="String">
|
||||
{{#select data.data.spellCategory}}
|
||||
|
@ -36,7 +41,7 @@ SPDX-License-Identifier: MIT
|
|||
</div>
|
||||
</div>
|
||||
<div class="form-group slim">
|
||||
<label>{{localize "DS4.SpellMaxDistance"}}</label>
|
||||
<label title="{{localize 'DS4.SpellDistanceDescription'}}">{{localize "DS4.SpellDistance"}}</label>
|
||||
<div class="form-fields">
|
||||
<input data-dtype="String" type="text" name="data.maxDistance.value"
|
||||
value="{{data.data.maxDistance.value}}" />
|
||||
|
@ -50,7 +55,7 @@ SPDX-License-Identifier: MIT
|
|||
</div>
|
||||
</div>
|
||||
<div class="form-group slim">
|
||||
<label>{{localize "DS4.SpellEffectRadius"}}</label>
|
||||
<label title="{{localize 'DS4.SpellEffectRadiusDescription'}}">{{localize "DS4.SpellEffectRadius"}}</label>
|
||||
<div class="form-fields">
|
||||
<input data-dtype="String" type="text" name="data.effectRadius.value"
|
||||
value="{{data.data.effectRadius.value}}" />
|
||||
|
@ -64,25 +69,11 @@ SPDX-License-Identifier: MIT
|
|||
</div>
|
||||
</div>
|
||||
<div class="form-group slim">
|
||||
<label>{{localize "DS4.SpellDuration"}}</label>
|
||||
<label title="{{localize 'DS4.SpellDurationDescription'}}">{{localize "DS4.SpellDuration"}}</label>
|
||||
<div class="form-fields">
|
||||
<input data-dtype="String" type="text" name="data.duration.value" value="{{data.data.duration.value}}" />
|
||||
<select name="data.duration.unit" data-dtype="String">
|
||||
{{#select data.data.duration.unit}}
|
||||
{{#each config.i18n.customTemporalUnits as |value key|}}
|
||||
<option value="{{key}}">{{value}}</option>
|
||||
{{/each}}
|
||||
{{/select}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group slim">
|
||||
<label>{{localize "DS4.SpellCooldownDuration"}}</label>
|
||||
<div class="form-fields">
|
||||
<input data-dtype="String" type="text" name="data.cooldownDuration.value"
|
||||
value="{{data.data.cooldownDuration.value}}" />
|
||||
<select name="data.cooldownDuration.unit" data-dtype="String">
|
||||
{{#select data.data.cooldownDuration.unit}}
|
||||
{{#each config.i18n.temporalUnits as |value key|}}
|
||||
<option value="{{key}}">{{value}}</option>
|
||||
{{/each}}
|
||||
|
@ -90,8 +81,21 @@ SPDX-License-Identifier: MIT
|
|||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="data.cooldownDuration-{{data._id}}"
|
||||
title="{{localize 'DS4.CooldownDurationDescription'}}">{{localize "DS4.CooldownDuration"}}</label>
|
||||
<div class="form-fields">
|
||||
<select id="data.cooldownDuration-{{data._id}}" name="data.cooldownDuration" data-dtype="String">
|
||||
{{#select data.data.cooldownDuration}}
|
||||
{{#each config.i18n.cooldownDurations as |value key|}}
|
||||
<option value="{{key}}">{{value}}</option>
|
||||
{{/each}}
|
||||
{{/select}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group slim">
|
||||
<label>{{localize "DS4.SpellMinimumLevel"}}</label>
|
||||
<label title="{{localize 'DS4.SpellMinimumLevelDescription'}}">{{localize "DS4.SpellMinimumLevel"}}</label>
|
||||
<div class="form-fields">
|
||||
<label for="data.minimumLevels.healer-{{data._id}}">{{localize "DS4.SpellCasterClassHealer"}}</label>
|
||||
<input id="data.minimumLevels.healer-{{data._id}}" data-dtype="Number" type="number" min="0" step="1"
|
||||
|
@ -105,7 +109,10 @@ SPDX-License-Identifier: MIT
|
|||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="data.price-{{data._id}}">{{localize "DS4.SpellPrice"}}</label>
|
||||
<span id="data.price-{{data._id}}">{{data.data.price}}</span>
|
||||
<label for="data.price-{{data._id}}" title="{{localize 'DS4.SpellPriceDescription'}}">{{localize
|
||||
"DS4.SpellPrice"}}</label>
|
||||
<div class="form-fields">
|
||||
<span id="data.price-{{data._id}}">{{data.data.price}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
Loading…
Reference in a new issue