working summon

This commit is contained in:
Mike Bloy 2023-09-09 20:47:57 -05:00
parent d7c30e3990
commit 19c1e697db
3 changed files with 191 additions and 7 deletions

View File

@ -1,9 +1,10 @@
import { helpers } from './helpers.js' import { helpers } from './helpers.js'
import { shim, log } from './shim.js'
import { powerEffects } from './powerEffects.js' import { powerEffects } from './powerEffects.js'
export class api { export class api {
static registerFunctions () { static registerFunctions () {
console.log('SWADE MB Helpers initialized') log('SWADE MB Helpers initialized')
api.globals() api.globals()
} }
@ -11,11 +12,11 @@ export class api {
globalThis.swadeMBHelpers = { globalThis.swadeMBHelpers = {
DEBUG: true, DEBUG: true,
powerEffects, powerEffects,
createEffectDocument: helpers.createEffectDocument, createEffectDocument: shim.createEffectDocument,
createMutationWithEffect: helpers.createMutationWithEffect, createMutationWithEffect: helpers.createMutationWithEffect,
defaultMutationOptions: helpers.defaultMutationOptions, defaultMutationOptions: helpers.defaultMutationOptions,
getActorFolderByPath: helpers.getActorFolderByPath, getActorFolderByPath: shim.getActorFolderByPath,
getActorsInFolder: helpers.getActorsInFolder, getActorsInFolder: shim.getActorsInFolder,
runOnTargetOrSelectedTokens: helpers.runOnTargetOrSelectedTokens runOnTargetOrSelectedTokens: helpers.runOnTargetOrSelectedTokens
} }
} }

View File

@ -1,4 +1,4 @@
import { CONST, shim } from './shim.js' import { CONST, log, shim } from './shim.js'
class PowerEffect { class PowerEffect {
constructor (token, targets) { constructor (token, targets) {
@ -40,7 +40,12 @@ class PowerEffect {
} }
async powerEffect () { async powerEffect () {
this.prepMenu() try {
await this.prepMenu()
} catch (e) {
log('Error preparing menu for power effect: ' + e.toString())
return
}
const { buttons, inputs } = await shim.warpgateMenu( const { buttons, inputs } = await shim.warpgateMenu(
this.menuData, this.menuOptions) this.menuData, this.menuOptions)
this.buttons = buttons this.buttons = buttons
@ -518,6 +523,132 @@ class SmiteEffect extends TargetedPowerEffect {
} }
} }
class SummonEffect extends PowerEffect {
ICON = 'icons/magic/symbols/runes-triangle-blue.webp'
get actorFolder () {
return 'Summonables'
}
get name () {
return 'Summon Creature'
}
get durationRounds () {
return 5
}
async prepFolders () {
const folders = []
const folderNames = [
this.actorFolder,
`${this.actorFolder} - Default`,
`${this.actorFolder}/Default`,
`${this.actorFolder} - ${this.token.name}`,
`${this.actorFolder} - ${this.token.actor.name}`,
`${this.actorFolder}/${this.token.name}`,
`${this.actorFolder}/${this.token.actor.name}`
]
for (const folderName of folderNames) {
const folder = shim.getActorFolderByPath(folderName)
if (folder) {
log(`Found actor folder ${folderName}`)
folders.push(folder)
}
}
if (folders.length > 1) {
folders.shift()
}
return folders
}
async prepActors () {
const folders = await this.prepFolders()
const actors = {}
for (const folder of folders) {
const folderActors = shim.getActorsInFolder(folder)
for (const key in folderActors) {
actors[key] = folderActors[key]
}
}
return actors
}
async prepMenu () {
this.menuData.inputs[1].label = `${this.token.name} is summoning...`
const actors = await this.prepActors()
if (Object.keys(actors).length < 1) {
shim.notifications.error('No summonables found')
throw new Error('No summonables found')
}
function actorData (key) {
return {
value: actors[key].id,
html: key
}
}
this.menuData.inputs.push({
type: 'select',
label: 'Creature to summon',
options: Object.keys(actors).filter(
k => !k.includes('_template')).sort().map(actorData)
})
this.menuData.inputs.push({
type: 'number',
label: 'Number to spawn (+half base cost per)',
options: 1
})
}
async prepResult () {
this.raise = (this.buttons === 'raise')
this.actorId = (this.inputs[this.inputIndex])
this.number = (this.inputs[this.inputIndex + 1])
this.actor = shim.actors.get(this.actorId)
this.icon = this.actor.prototypeToken.texture.src
this.protoDoc = await this.actor.getTokenDocument()
this.spawnOptions = {
controllingActor: this.token.actor,
duplicates: this.number,
crosshairs: {
icon: this.icon,
label: `Summon ${this.actor.name}`,
drawOutline: true,
rememberControlled: true
}
}
this.spawnMutation = {
actor: {
name: `${this.token.name}'s ${this.actor.name}`
},
token: {
actorLink: false,
name: `${this.token.name}'s ${this.protoDoc.name}`
},
embedded: { ActiveEffect: {} }
}
for (const effectDocument of this.effectDocs) {
this.spawnMutation.embedded.ActiveEffect[effectDocument.name] = effectDocument
}
}
async applyResult () {
await shim.warpgateSpawn(this.protoDoc, this.spawnMutation, {}, this.spawnOptions)
}
}
class SummonAllyEffect extends SummonEffect {
get name () {
return 'Summon Ally'
}
get actorFolder () {
return `${super.actorFolder}/Summon Ally`
}
}
const PowerClasses = { const PowerClasses = {
blind: BlindEffect, blind: BlindEffect,
'boost/lower trait': BoostLowerTraitEffect, 'boost/lower trait': BoostLowerTraitEffect,
@ -529,7 +660,8 @@ const PowerClasses = {
invisibility: InvisibilityEffect, invisibility: InvisibilityEffect,
'lower trait': BoostLowerTraitEffect, 'lower trait': BoostLowerTraitEffect,
protection: ProtectionEffect, protection: ProtectionEffect,
smite: SmiteEffect smite: SmiteEffect,
'summon ally': SummonAllyEffect
} }
export async function powerEffects (options = {}) { export async function powerEffects (options = {}) {

View File

@ -24,6 +24,10 @@ export class shim {
return game.user return game.user
} }
static get actors () {
return game.actors
}
static getStatus (label, name, favorite = true) { static getStatus (label, name, favorite = true) {
const effect = JSON.parse(JSON.stringify( const effect = JSON.parse(JSON.stringify(
CONFIG.statusEffects.find(se => se.label === label))) CONFIG.statusEffects.find(se => se.label === label)))
@ -76,6 +80,53 @@ export class shim {
static warpgateMenu (menuData, menuOptions) { static warpgateMenu (menuData, menuOptions) {
return warpgate.menu(menuData, menuOptions) return warpgate.menu(menuData, menuOptions)
} }
static warpgateSpawn (...args) {
return warpgate.spawn(...args)
}
static getActorFolderByPath (path) {
const names = path.split('/')
if (names[0] === '') {
names.shift()
}
let name = names.shift()
let folder = shim.folders.filter(
f => f.type === 'Actor' && !f.folder
).find(f => f.name === name)
if (!folder) { return undefined }
while (names.length > 0) {
name = names.shift()
folder = folder.children.find(c => c.folder.name === name)
if (!folder) { return undefined }
folder = folder.folder
}
return folder
}
static getActorsInFolder (inFolder) {
const prefixStack = ['']
const actors = {}
const folderStack = [inFolder]
while (folderStack.length > 0) {
const prefix = prefixStack.shift()
const folder = folderStack.shift()
for (const actor of folder.contents) {
if (shim.user.isGM ||
actor.testUserPermission(
shim.user, CONST.FOUNDRY.DOCUMENT_OWNERSHIP_LEVELS.OBSERVER)
) {
actors[`${prefix}${actor.name}`] = actor
}
}
for (const child of folder.children) {
const newPrefix = `${prefix}${child.folder.name} | `
prefixStack.push(newPrefix)
folderStack.push(child.folder)
}
}
return actors
}
} }
export function log (...args) { export function log (...args) {