Initial commit

This commit is contained in:
Neill Cox 2024-05-04 19:45:07 +10:00
commit 03761d2e2f
17 changed files with 5662 additions and 0 deletions

131
scripts/action-handler.js Normal file
View file

@ -0,0 +1,131 @@
// System Module Imports
import { ACTION_TYPE, ITEM_TYPE } from './constants.js'
import { Utils } from './utils.js'
export let ActionHandler = null
Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
/**
* Extends Token Action HUD Core's ActionHandler class and builds system-defined actions for the HUD
*/
ActionHandler = class ActionHandler extends coreModule.api.ActionHandler {
/**
* Build system actions
* Called by Token Action HUD Core
* @override
* @param {array} groupIds
*/a
async buildSystemActions (groupIds) {
// Set actor and token variables
this.actors = (!this.actor) ? this._getActors() : [this.actor]
this.actorType = this.actor?.type
// Settings
this.displayUnequipped = Utils.getSetting('displayUnequipped')
// Set items variable
if (this.actor) {
let items = this.actor.items
items = coreModule.api.Utils.sortItemsByName(items)
this.items = items
}
if (this.actorType === 'character') {
debugger;
this.#buildCharacterActions()
} else if (!this.actor) {
this.#buildMultipleTokenActions()
}
}
/**
* Build character actions
* @private
*/
#buildCharacterActions () {
this._get_attributes({id: "attributes", type:"system"})
this.#buildInventory()
}
_get_attributes(parent) {
const macroType = "attributes";
let actions = [];
let attributes = Object.entries(this.actor.system.attributes)
attributes.forEach((a) => {
const key = a[0];
const value = a[1].value
// img
actions.push({
id: key,
name: coreModule.api.Utils.i18n(key),
description: coreModule.api.Utils.i18n('GURPS.Attributes'),
encodedValue: [macroType, key].join(this.delimiter),
})
});
this.addActions(actions, parent)
}
/**
* Build multiple token actions
* @private
* @returns {object}
*/
#buildMultipleTokenActions () {
}
/**
* Build inventory
* @private
*/
async #buildInventory () {
if (this.items.size === 0) return
const actionTypeId = 'item'
const inventoryMap = new Map()
for (const [itemId, itemData] of this.items) {
const type = itemData.type
const equipped = itemData.equipped
if (equipped || this.displayUnequipped) {
const typeMap = inventoryMap.get(type) ?? new Map()
typeMap.set(itemId, itemData)
inventoryMap.set(type, typeMap)
}
}
for (const [type, typeMap] of inventoryMap) {
const groupId = ITEM_TYPE[type]?.groupId
if (!groupId) continue
const groupData = { id: groupId, type: 'system' }
// Get actions
const actions = [...typeMap].map(([itemId, itemData]) => {
const id = itemId
const name = itemData.name
const actionTypeName = coreModule.api.Utils.i18n(ACTION_TYPE[actionTypeId])
const listName = `${actionTypeName ? `${actionTypeName}: ` : ''}${name}`
const encodedValue = [actionTypeId, id].join(this.delimiter)
return {
id,
name,
listName,
encodedValue
}
})
// TAH Core method to add actions to the action list
this.addActions(actions, groupData)
}
}
}
})

55
scripts/constants.js Normal file
View file

@ -0,0 +1,55 @@
/**
* Module-based constants
*/
export const MODULE = {
ID: 'token-action-hud-gurps'
}
/**
* Core module
*/
export const CORE_MODULE = {
ID: 'token-action-hud-core'
}
/**
* Core module version required by the system module
*/
export const REQUIRED_CORE_MODULE_VERSION = '1.5'
/**
* Action types
*/
export const ACTION_TYPE = {
item: 'tokenActionHud.template.item',
utility: 'tokenActionHud.utility'
}
/**
* Groups
*/
export const GROUP = {
attributes: { id: 'attributes', name: 'tokenActionHud.gurps.attributes', type: 'system' },
armor: { id: 'armor', name: 'tokenActionHud.template.armor', type: 'system' },
equipment: { id: 'equipment', name: 'tokenActionHud.template.equipment', type: 'system' },
consumables: { id: 'consumables', name: 'tokenActionHud.template.consumables', type: 'system' },
containers: { id: 'containers', name: 'tokenActionHud.template.containers', type: 'system' },
treasure: { id: 'treasure', name: 'tokenActionHud.template.treasure', type: 'system' },
weapons: { id: 'weapons', name: 'tokenActionHud.template.weapons', type: 'system' },
combat: { id: 'combat', name: 'tokenActionHud.combat', type: 'system' },
token: { id: 'token', name: 'tokenActionHud.token', type: 'system' },
utility: { id: 'utility', name: 'tokenActionHud.utility', type: 'system' }
}
/**
* Item types
*/
export const ITEM_TYPE = {
attributes: { groupId: 'attributes' },
armor: { groupId: 'armor' },
backpack: { groupId: 'containers' },
consumable: { groupId: 'consumables' },
equipment: { groupId: 'equipment' },
treasure: { groupId: 'treasure' },
weapon: { groupId: 'weapons' }
}

53
scripts/defaults.js Normal file
View file

@ -0,0 +1,53 @@
import { GROUP } from './constants.js'
/**
* Default layout and groups
*/
export let DEFAULTS = null
Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
const groups = GROUP
Object.values(groups).forEach(group => {
group.name = coreModule.api.Utils.i18n(group.name)
group.listName = `Group: ${coreModule.api.Utils.i18n(group.listName ?? group.name)}`
})
const groupsArray = Object.values(groups)
debugger;
DEFAULTS = {
layout: [
{
nestId: 'inventory',
id: 'inventory',
name: coreModule.api.Utils.i18n('Template.Inventory'),
groups: [
{ ...groups.weapons, nestId: 'inventory_weapons' },
{ ...groups.armor, nestId: 'inventory_armor' },
{ ...groups.equipment, nestId: 'inventory_equipment' },
{ ...groups.consumables, nestId: 'inventory_consumables' },
{ ...groups.containers, nestId: 'inventory_containers' },
{ ...groups.treasure, nestId: 'inventory_treasure' }
]
},
{
nestId: 'utility',
id: 'utility',
name: coreModule.api.Utils.i18n('tokenActionHud.utility'),
groups: [
{ ...groups.combat, nestId: 'utility_combat' },
{ ...groups.token, nestId: 'utility_token' },
{ ...groups.rests, nestId: 'utility_rests' },
{ ...groups.utility, nestId: 'utility_utility' }
]
},
{
nestId: 'attributes',
id: 'attributes',
name: coreModule.api.Utils.i18n('GURPS.attributes'),
groups: [
{ ...groups.attributes, nestId: 'attributes_attributes' }
]
}
],
groups: groupsArray
}
})

14
scripts/init.js Normal file
View file

@ -0,0 +1,14 @@
import { SystemManager } from './system-manager.js'
import { MODULE, REQUIRED_CORE_MODULE_VERSION } from './constants.js'
Hooks.on('tokenActionHudCoreApiReady', async () => {
/**
* Return the SystemManager and requiredCoreModuleVersion to Token Action HUD Core
*/
const module = game.modules.get(MODULE.ID)
module.api = {
requiredCoreModuleVersion: REQUIRED_CORE_MODULE_VERSION,
SystemManager
}
Hooks.call('tokenActionHudSystemReady', module)
})

108
scripts/roll-handler.js Normal file
View file

@ -0,0 +1,108 @@
export let RollHandler = null
Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
/**
* Extends Token Action HUD Core's RollHandler class and handles action events triggered when an action is clicked
*/
RollHandler = class RollHandler extends coreModule.api.RollHandler {
/**
* Handle action click
* Called by Token Action HUD Core when an action is left or right-clicked
* @override
* @param {object} event The event
* @param {string} encodedValue The encoded value
*/
async handleActionClick (event, encodedValue) {
const [actionTypeId, actionId] = encodedValue.split('|')
const renderable = ['item']
if (renderable.includes(actionTypeId) && this.isRenderItem()) {
return this.doRenderItem(this.actor, actionId)
}
const knownCharacters = ['character']
// If single actor is selected
if (this.actor) {
await this.#handleAction(event, this.actor, this.token, actionTypeId, actionId)
return
}
const controlledTokens = canvas.tokens.controlled
.filter((token) => knownCharacters.includes(token.actor?.type))
// If multiple actors are selected
for (const token of controlledTokens) {
const actor = token.actor
await this.#handleAction(event, actor, token, actionTypeId, actionId)
}
}
/**
* Handle action hover
* Called by Token Action HUD Core when an action is hovered on or off
* @override
* @param {object} event The event
* @param {string} encodedValue The encoded value
*/
async handleActionHover (event, encodedValue) {}
/**
* Handle group click
* Called by Token Action HUD Core when a group is right-clicked while the HUD is locked
* @override
* @param {object} event The event
* @param {object} group The group
*/
async handleGroupClick (event, group) {}
/**
* Handle action
* @private
* @param {object} event The event
* @param {object} actor The actor
* @param {object} token The token
* @param {string} actionTypeId The action type id
* @param {string} actionId The actionId
*/
async #handleAction (event, actor, token, actionTypeId, actionId) {
switch (actionTypeId) {
case 'item':
this.#handleItemAction(event, actor, actionId)
break
case 'utility':
this.#handleUtilityAction(token, actionId)
break
}
}
/**
* Handle item action
* @private
* @param {object} event The event
* @param {object} actor The actor
* @param {string} actionId The action id
*/
#handleItemAction (event, actor, actionId) {
const item = actor.items.get(actionId)
item.toChat(event)
}
/**
* Handle utility action
* @private
* @param {object} token The token
* @param {string} actionId The action id
*/
async #handleUtilityAction (token, actionId) {
switch (actionId) {
case 'endTurn':
if (game.combat?.current?.tokenId === token.id) {
await game.combat?.nextTurn()
}
break
}
}
}
})

21
scripts/settings.js Normal file
View file

@ -0,0 +1,21 @@
import { MODULE } from './constants.js'
/**
* Register module settings
* Called by Token Action HUD Core to register Token Action HUD system module settings
* @param {function} coreUpdate Token Action HUD Core update function
*/
export function register (coreUpdate) {
game.settings.register(MODULE.ID, 'displayUnequipped', {
name: game.i18n.localize('tokenActionHud.template.settings.displayUnequipped.name'),
hint: game.i18n.localize('tokenActionHud.template.settings.displayUnequipped.hint'
),
scope: 'client',
config: true,
type: Boolean,
default: true,
onChange: (value) => {
coreUpdate(value)
}
})
}

92
scripts/system-manager.js Normal file
View file

@ -0,0 +1,92 @@
// System Module Imports
import { ActionHandler } from './action-handler.js'
import { RollHandler as Core } from './roll-handler.js'
import { MODULE } from './constants.js'
import { DEFAULTS } from './defaults.js'
import * as systemSettings from './settings.js'
export let SystemManager = null
Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
/**
* Extends Token Action HUD Core's SystemManager class
*/
SystemManager = class SystemManager extends coreModule.api.SystemManager {
/**
* Returns an instance of the ActionHandler to Token Action HUD Core
* Called by Token Action HUD Core
* @override
* @returns {class} The ActionHandler instance
*/
getActionHandler () {
return new ActionHandler()
}
/**
* Returns a list of roll handlers to Token Action HUD Core
* Used to populate the Roll Handler module setting choices
* Called by Token Action HUD Core
* @override
* @returns {object} The available roll handlers
*/
getAvailableRollHandlers () {
const coreTitle = 'Core Template'
const choices = { core: coreTitle }
return choices
}
/**
* Returns an instance of the RollHandler to Token Action HUD Core
* Called by Token Action HUD Core
* @override
* @param {string} rollHandlerId The roll handler ID
* @returns {class} The RollHandler instance
*/
getRollHandler (rollHandlerId) {
let rollHandler
switch (rollHandlerId) {
case 'core':
default:
rollHandler = new Core()
break
}
return rollHandler
}
/**
* Returns the default layout and groups to Token Action HUD Core
* Called by Token Action HUD Core
* @returns {object} The default layout and groups
*/
async registerDefaults () {
return DEFAULTS
}
/**
* Register Token Action HUD system module settings
* Called by Token Action HUD Core
* @override
* @param {function} coreUpdate The Token Action HUD Core update function
*/
registerSettings (coreUpdate) {
systemSettings.register(coreUpdate)
}
/**
* Returns styles to Token Action HUD Core
* Called by Token Action HUD Core
* @override
* @returns {object} The TAH system styles
*/
registerStyles () {
return {
template: {
class: 'tah-style-template-style', // The class to add to first DIV element
file: 'tah-template-style', // The file without the css extension
moduleId: MODULE.ID, // The module ID
name: 'Template Style' // The name to display in the Token Action HUD Core 'Style' module setting
}
}
}
}
})

40
scripts/utils.js Normal file
View file

@ -0,0 +1,40 @@
import { MODULE } from './constants.js'
export let Utils = null
Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
/**
* Utility functions
*/
Utils = class Utils {
/**
* Get setting
* @param {string} key The key
* @param {string=null} defaultValue The default value
* @returns {string} The setting value
*/
static getSetting (key, defaultValue = null) {
let value = defaultValue ?? null
try {
value = game.settings.get(MODULE.ID, key)
} catch {
coreModule.api.Logger.debug(`Setting '${key}' not found`)
}
return value
}
/**
* Set setting
* @param {string} key The key
* @param {string} value The value
*/
static async setSetting (key, value) {
try {
value = await game.settings.set(MODULE.ID, key, value)
coreModule.api.Logger.debug(`Setting '${key}' set to '${value}'`)
} catch {
coreModule.api.Logger.debug(`Setting '${key}' not found`)
}
}
}
})