From 5b78eabea4370a643186192644862caaf5558010 Mon Sep 17 00:00:00 2001 From: Paul Maskelyne Date: Tue, 10 Oct 2023 13:02:25 +0100 Subject: [PATCH] fixes #516 --- RELEASE_NOTES.md | 1 + macros/drawHazard.js | 14 +- macros/importShadowdarkling.js | 428 ------------------- macros/importToTable.js | 67 --- system/src/apps/ShadowdarklingImporterSD.mjs | 12 - system/src/config.mjs | 10 - system/src/sheets/ItemSheetSD.mjs | 14 +- 7 files changed, 9 insertions(+), 537 deletions(-) delete mode 100644 macros/importShadowdarkling.js delete mode 100644 macros/importToTable.js diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 4ff11136..39bcf6e0 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -2,6 +2,7 @@ ### Bugfixes * [#515] Backstab option not available on attack rolls +* [#516] Wand and Scroll item sheets not showing spell caster classes correctly ## v.1.4.4 diff --git a/macros/drawHazard.js b/macros/drawHazard.js index f9a1f65f..e457d6b3 100644 --- a/macros/drawHazard.js +++ b/macros/drawHazard.js @@ -17,15 +17,15 @@ const weakenTable = await pack.getDocument(weakenTableID); const weakenResult = await weakenTable.draw({displayChat: false}); const weaken = weakenResult.results.pop().getChatText(); -const message = `

A location with ${movement} -that will weaken the characters with ${weaken} +const message = `

A location with ${movement} +that will weaken the characters with ${weaken} and causes damage through ${damage}

`; const chatData = { - user: game.user._id, - speaker: ChatMessage.getSpeaker(), - content: message, - whisper: game.users.filter(u => u.isGM).map(u => u._id), + user: game.user._id, + speaker: ChatMessage.getSpeaker(), + content: message, + whisper: game.users.filter(u => u.isGM).map(u => u._id), }; -ChatMessage.create(chatData, {}); \ No newline at end of file +ChatMessage.create(chatData, {}); diff --git a/macros/importShadowdarkling.js b/macros/importShadowdarkling.js deleted file mode 100644 index bef0685d..00000000 --- a/macros/importShadowdarkling.js +++ /dev/null @@ -1,428 +0,0 @@ -const json = { - name: "Treeplin", - stats: { - STR: 14, - DEX: 10, - CON: 10, - INT: 12, - WIS: 8, - CHA: 9, - }, - ancestry: "Human", - class: "Wizard", - level: 1, - title: "Shaman", - alignment: "Neutral", - background: "Ranger", - deity: "The Lost", - maxHitPoints: 2, - armorClass: 10, - gearSlotsTotal: 14, - gearSlotsUsed: 7, - bonuses: [ - { - sourceType: "Class", - sourceName: "Wizard", - sourceCategory: "Ability", - gainedAtLevel: 1, - name: "Spell: Wizard, Tier 1, Spell 2", - bonusTo: "Tier:1, Spell:2", - bonusName: "Alarm", - }, - { - sourceType: "Class", - sourceName: "Wizard", - sourceCategory: "Talent", - gainedAtLevel: 1, - name: "AdvOnCastOneSpell", - bonusTo: "AdvOnCastOneSpell", - bonusName: "Alarm", - }, - { - sourceType: "Class", - sourceName: "Wizard", - sourceCategory: "Ability", - gainedAtLevel: 1, - name: "ExtraLanguage: Wizard 1", - bonusTo: "Languages", - bonusName: "Dwarvish", - }, - { - sourceType: "Class", - sourceName: "Wizard", - sourceCategory: "Ability", - gainedAtLevel: 1, - name: "ExtraLanguage: Wizard 2", - bonusTo: "Languages", - bonusName: "Elvish", - }, - { - sourceType: "Class", - sourceName: "Wizard", - sourceCategory: "Ability", - gainedAtLevel: 1, - name: "ExtraLanguage: Wizard 3", - bonusTo: "Languages", - bonusName: "Celestial", - }, - { - sourceType: "Class", - sourceName: "Wizard", - sourceCategory: "Ability", - gainedAtLevel: 1, - name: "ExtraLanguage: Wizard 4", - bonusTo: "Languages", - bonusName: "Diabolic", - }, - { - sourceType: "Class", - sourceName: "Wizard", - sourceCategory: "Ability", - gainedAtLevel: 1, - name: "Spell: Wizard, Tier 1, Spell 1", - bonusTo: "Tier:1, Spell:1", - bonusName: "Burning Hands", - }, - { - sourceType: "Class", - sourceName: "Wizard", - sourceCategory: "Ability", - gainedAtLevel: 1, - name: "Spell: Wizard, Tier 1, Spell 3", - bonusTo: "Tier:1, Spell:3", - bonusName: "Floating Disk", - }, - { - sourceType: "Ancestry", - sourceName: "Human Ambition", - sourceCategory: "Talent", - gainedAtLevel: 1, - name: "AdvOnCastOneSpell", - bonusTo: "AdvOnCastOneSpell", - bonusName: "Burning Hands", - }, - { - sourceType: "Ancestry", - sourceName: "Human", - sourceCategory: "Ability", - gainedAtLevel: 1, - name: "ExtraLanguage: Human undefined", - bonusTo: "Languages", - bonusName: "Reptilian", - }, - ], - goldRolled: 45, - gold: 38, - silver: 0, - copper: 0, - gear: [ - { - instanceId: "lfwl9ekm", - gearId: "s2", - name: "Backpack", - type: "sundry", - quantity: 1, - totalUnits: 1, - slots: 0, - cost: 2, - currency: "gp", - }, - { - instanceId: "lfwl9ekn", - gearId: "s8", - name: "Flint and steel", - type: "sundry", - quantity: 1, - totalUnits: 1, - slots: 1, - cost: 5, - currency: "sp", - }, - { - instanceId: "lfwl9eko", - gearId: "s17", - name: "Torch", - type: "sundry", - quantity: 2, - totalUnits: 2, - slots: 2, - cost: 10, - currency: "sp", - }, - { - instanceId: "lfwl9ekq", - gearId: "s15", - name: "Rations", - type: "sundry", - quantity: 1, - totalUnits: 3, - slots: 1, - cost: 5, - currency: "sp", - }, - { - instanceId: "lfwl9ekr", - gearId: "s10", - name: "Iron spikes", - type: "sundry", - quantity: 1, - totalUnits: 10, - slots: 1, - cost: 1, - currency: "gp", - }, - { - instanceId: "lfwl9eks", - gearId: "s9", - name: "Grappling hook", - type: "sundry", - quantity: 1, - totalUnits: 1, - slots: 1, - cost: 1, - currency: "gp", - }, - { - instanceId: "lfwl9ekt", - gearId: "s16", - name: "Rope, 60'", - type: "sundry", - quantity: 1, - totalUnits: 1, - slots: 1, - cost: 1, - currency: "gp", - }, - ], - spellsKnown: "Alarm, Burning Hands, Floating Disk", - languages: "Celestial, Common, Diabolic, Dwarvish, Elvish, Reptilian", -}; - -function _getSpellCastingAbility(actorClass) { - if (Object.keys(CONFIG.SHADOWDARK.SPELL_CASTER_CLASSES).includes(actorClass)) { - return CONFIG.SHADOWDARK.SPELLCASTING_ABILITY[actorClass]; - } - return ""; -} - -async function _spellCastingAdvantageTalent(spell) { - const talent = await _findInCompendium("Spellcasting Advantage", "shadowdark.talents"); - const modifiedTalent = talent.toObject(); - modifiedTalent.effects[0].changes[0].value = spell.slugify(); - modifiedTalent.name += ` (${spell})`; - return modifiedTalent; -} - -async function _findInCompendium(contentName, packName) { - const pack = await game.packs.get(packName); - const itemIndex = pack.index.find( - i => i.name.toLowerCase() === contentName.toLowerCase() - ); - if (itemIndex) { - const item = await pack.getDocument(itemIndex._id); - return item; - } - return false; -} - -async function importActor(json) { - const importedActor = { - name: json.name, - type: "Player", - system: { - abilities: { - str: { value: json.stats.STR }, - dex: { value: json.stats.DEX }, - con: { value: json.stats.CON }, - int: { value: json.stats.INT }, - wis: { value: json.stats.WIS }, - cha: { value: json.stats.CHA }, - }, - alignment: json.alignment.toLowerCase(), - ancestry: json.ancestry, - attributes: { - hp: { - value: json.maxHitPoints, - max: json.maxHitPoints, - base: (json.ancestry === "Dwarf") ? json.maxHitPoints - 2 : json.maxHitPoints, - }, - }, - background: json.background, - class: json.class.toLowerCase(), - coins: { - gp: json.gold, - sp: json.silver, - cp: json.copper, - }, - deity: json.deity, - languages: json.languages.toLowerCase().split(", "), - level: { - value: json.level, - xp: 0, - }, - slots: json.gearSlotsTotal, - title: json.title, - spellcastingAbility: _getSpellCastingAbility(json.class.toLowerCase()), - }, - }; - - const spells = []; - const talents = []; - const statBonus = { - "STR:+2": "+2 to Strength", - "DEX:+2": "+2 to Dexterity", - "CON:+2": "+2 to Constitution", - "INT:+2": "+2 to Intelligence", - "WIS:+2": "+2 to Wisdom", - "CHA:+2": "+2 to Charisma", - }; - json.bonuses.forEach(async bonus => { - if (bonus.name.includes("Spell:") || bonus.name === "LearnExtraSpell") { - const spell = await _findInCompendium(bonus.bonusName, "shadowdark.spells"); - spells.push(spell); - } - if (bonus.sourceCategory === "Talent") { - if (bonus.name === "StatBonus") { - talents.push( - await _findInCompendium(statBonus[bonus.bonusTo], "shadowdark.talents") - ); - } - // Fighter - if (bonus.name === "WeaponMastery") { - talents.push( - await _findInCompendium(`Weapon Master (${bonus.bonusTo})`, "shadowdark.talents") - ); - } - if (bonus.name === "Grit") { - talents.push( - await _findInCompendium(`Grit (${bonus.bonusName})`, "shadowdark.talents") - ); - } - if (bonus.name === "ArmorMastery") { - talents.push( - await _findInCompendium("Armor Mastery", "shadowdark.talents") - ); - } - // Thief - if (bonus.name === "BackstabIncrease") { - talents.push( - await _findInCompendium("Backstab +1 Damage Dice", "shadowdark.talents") - ); - } - if (bonus.name === "AdvOnInitiative") { - talents.push( - await _findInCompendium("Initiative Advantage", "shadowdark.talents") - ); - } - // Priest - if (bonus.name === "Plus1ToHit") { - talents.push( - await _findInCompendium(bonus.bonusTo, "shadowdark.talents") - ); - } - // Wizard - if (bonus.bonusName === "Plus1ToCastingSpells") { - talents.push( - await _findInCompendium("+1 on Spellcasting Checks", "shadowdark.talents") - ); // Also Priest - } - if (bonus.name === "LearnExtraSpell") { - talents.push( - await _findInCompendium("Learn Spell", "shadowdark.talents") - ); - } - if (bonus.name === "AdvOnCastOneSpell") { - talents.push( - await _spellCastingAdvantageTalent(bonus.bonusName) - ); - } - } - }); - - // Class talents - if (json.class === "Thief") { - talents.push( - await _findInCompendium("Backstab", "shadowdark.talents") - ); - talents.push( - await _findInCompendium("Thievery", "shadowdark.talents") - ); - } - if (json.class === "Fighter") { - talents.push( - await _findInCompendium("Hauler", "shadowdark.talents") - ); - } - if (json.class === "Wizard") { - talents.push( - await _findInCompendium("Magic Missile Advantage", "shadowdark.talents") - ); - } - if (json.priest === "Priest") { - talents.push( - await _findInCompendium("Turn Undead", "shadowdark.talents") - ); - spells.push( - await _findInCompendium("Turn Undead", "shadowdark.spells") - ); - } - - // Ancestry talents - if (json.ancestry === "Elf") { - const farSight = json.bonuses.find(o => o.name === "FarSight"); - const bonus = (farSight.bonusTo === "RangedWeapon") ? "Farsight (Ranged)" : "Farsight (Spell)"; - talents.push( - await _findInCompendium(bonus, "shadowdark.talents") - ); - } - if (json.ancestry === "Orc") { - talents.push( - await _findInCompendium("Mighty", "shadowdark.talents") - ); - } - if (json.ancestry === "Halfling") { - talents.push( - await _findInCompendium("Stealthy", "shadowdark.talents") - ); - } - if (json.ancestry === "Dwarf") { - talents.push( - await _findInCompendium("Stout", "shadowdark.talents") - ); - } - if (json.ancestry === "Human") { - talents.push( - await _findInCompendium("Ambitious", "shadowdark.talents") - ); - } - if (json.ancestry === "Goblin") { - talents.push( - await _findInCompendium("Keen Senses", "shadowdark.talents") - ); - } - - // Gear - const items = []; - const compendium = [ - "shadowdark.armor", - "shadowdark.weapons", - "shadowdark.basic-gear", - ]; - - await json.gear.forEach(async item => { - compendium.forEach(async comp => { - const newItem = await _findInCompendium(item.name, comp); - if (newItem) items.push(newItem); - }); - }); - - // Create the actor - const newActor = await Actor.create(importedActor); - await newActor.createEmbeddedDocuments("Item", [...spells, ...items, ...talents]); - await newActor.update({ - "system.spellcastingAbility": newActor.getSpellcastingAbility(), - }); - return newActor; -} - -console.log(await importActor(json)); diff --git a/macros/importToTable.js b/macros/importToTable.js deleted file mode 100644 index 6d6d0b0d..00000000 --- a/macros/importToTable.js +++ /dev/null @@ -1,67 +0,0 @@ -const items = [ - "A mutated cave brute explodes through a crumbling wall", - "A silent gelatinous cube sweeps up a corridor", - "A roving brown bear scavenges for dead bodies to eat", - "Rival crawlers confront the PCs; they were \"here first\"", - "[[/r 1d6]] rust monsters swarm a crack bubbling with mercury", - "A legless suit of animated armor pulls itself along the floor", - "A groaning wall collapses at the slightest touch", - "A chalk note on the wall: \"Karov, we'll be at the Loyal Hog\"", - "Mort the goblin is digging in cracks for grubs and beetles", - "The floor collapses into a pit [[/r 1d6*10]] feet deep", - "A raiding team of [[/r 2d4]] hobgoblins moves in tight formation", - "[[/r 2d4]] web-covered skeletons form from scattered bones", - "[[/r 1d4]] giant dung beetles roll huge balls of dried excrement", - "An ochre jelly hides inside a pond or sinkhole", - "A single, perfect rose grows up between the flagstones", - "[[/r 2d4]] bandits shutter lanterns and set up a hasty ambush", - "Three goblins toughen each other's skulls with frying pans", - "[[/r 2d6]] beastmen pummel a giant centipede with rocks", - "A gas leak causes all light sources to explode and go out", - "A gelatinous cube full of handy items is stuck inside a pit", - "A swarm of clattering, gold scarab beetles flies into sight", - "A wounded NPC staggers up to the PCs and begs for help", - "A rusty portcullis slams down, separating the PCs", - "A giant spider hides above an old, rotten backpack", - "A weeping ghost floats by, distracted by its own ranting", - "[[/r 2d4]] kobolds sneak up behind the PCs for a surprise attack", - "Ancient clay pots vibrate with hypnotizing resonance", - "[[/r 1d6]] gricks shred dead giant rats and use the fur for nesting", - "Rival crawlers escort a frail noble tourist on an \"adventure\"", - "[[/r 3d4]] goblin scavengers barter and trade for odd trinkets", - "[[/r 2d4]] dwarven miners (soldiers) shore up a collapsing wall", - "[[/r 2d4]] giant wasps build a huge, papery nest on the ceiling", - "A dense cloud of sulfuric mist rises from a floor crack", - "A swarm of spiders surges out of a gauzy egg sack", - "An ogre named Lud scratches rude words into the wall", - "[[/r 1d6]] goblins brawl with [[/r 2d4]] kobolds over a grick carcass", - "[[/r 2d4]] giant bats roost on the ceiling; light disturbs them", - "An ettercap spins web cocoons around its still-living prey", - "[[/r 1d6]] cultists hunt for humanoid bones for a nefarious ritual", - "A dryad searches for her tree that bugbears chopped up", - "A deep gnome plays haunting music on humming fungi", - "[[/r 2d6]] kobolds work in a makeshift, volatile alchemy lab", - "A stone golem endlessly stacks the same rocks into piles", - "Two darkmantles circle each other in a duel of intimidation", - "[[/r 2d6]] goblins carry their bugbear king on a rickety litter", - "[[/r 2d4]] cave creepers swarm up the hallway", - "A recent campfire still burns with glowing cinders", - "A minotaur guides a mysterious merchant along a path", - "Roll two encounters and combine the results (reroll 98-99)", - "The body of a dead crawler holds a random magic item", -]; - -const table = await RollTable.create({name: "Ruin Encounters"}); -const results = []; - -items.forEach((value, idx) => { - results.push( - { - text: value, - weight: 2, - range: [idx+1, idx+1] - } - ) -}); - -await table.createEmbeddedDocuments("TableResult", results); \ No newline at end of file diff --git a/system/src/apps/ShadowdarklingImporterSD.mjs b/system/src/apps/ShadowdarklingImporterSD.mjs index 818c6615..9b88d9a6 100644 --- a/system/src/apps/ShadowdarklingImporterSD.mjs +++ b/system/src/apps/ShadowdarklingImporterSD.mjs @@ -55,18 +55,6 @@ export default class ShadowdarklingImporterSD extends FormApplication { }).render(true); } - /** - * Parse the spellcasting modifier through the config - * @param {string} actorClass - Class from the exported JSON - * @returns {string} - */ - _getSpellCastingAbility(actorClass) { - if (Object.keys(CONFIG.SHADOWDARK.SPELL_CASTER_CLASSES).includes(actorClass)) { - return CONFIG.SHADOWDARK.SPELLCASTING_ABILITY[actorClass]; - } - return ""; - } - /** * Manipulates the Spell Advantage talent so it may be used on the actor * @param {string} spell - Spell name to be used for advantage diff --git a/system/src/config.mjs b/system/src/config.mjs index 69d4f5a5..87bb8b32 100644 --- a/system/src/config.mjs +++ b/system/src/config.mjs @@ -142,16 +142,6 @@ SHADOWDARK.OFFICIAL_SOURCES = { "core-rules": "Shadowdark RPG: Core Rules", }; -SHADOWDARK.SPELLCASTING_ABILITY = { - priest: "wis", - wizard: "int", -}; - -SHADOWDARK.SPELL_CASTER_CLASSES = { - priest: "SHADOWDARK.spell_caster.priest", - wizard: "SHADOWDARK.spell_caster.wizard", -}; - SHADOWDARK.SPELL_DURATIONS = { focus: "SHADOWDARK.spell_duration.focus", instant: "SHADOWDARK.spell_duration.instant", diff --git a/system/src/sheets/ItemSheetSD.mjs b/system/src/sheets/ItemSheetSD.mjs index d3192182..e9f753db 100644 --- a/system/src/sheets/ItemSheetSD.mjs +++ b/system/src/sheets/ItemSheetSD.mjs @@ -309,7 +309,7 @@ export default class ItemSheetSD extends ItemSheet { await this.getClassSelectorConfigs(context); } - if (["Spell"].includes(item.type)) { + if (["Scroll", "Spell", "Wand"].includes(item.type)) { await this.getSpellSelectorConfigs(context); } @@ -352,18 +352,6 @@ export default class ItemSheetSD extends ItemSheet { context.effects = item.effects; } - if (["Potion", "Scroll", "Spell", "Wand"].includes(item.type)) { - context.casterClasses = []; - - for (const key of this.item.system.class) { - context.casterClasses.push( - CONFIG.SHADOWDARK.SPELL_CASTER_CLASSES[key] - ); - } - - context.casterClassesDisplay = context.casterClasses.join(", "); - } - context.descriptionHTML = await TextEditor.enrichHTML( context.system.description, {