Initial Foundry module scaffold

This commit is contained in:
ChatGPT
2026-06-04 16:07:28 +00:00
commit 927ea528b7
12 changed files with 517 additions and 0 deletions
+54
View File
@@ -0,0 +1,54 @@
export const MODULE_ID = "configurable-reactions";
export const MODULE_TITLE = "Configurable Reactions";
export const SETTINGS = Object.freeze({
REACTIONS: "reactions",
ASSIGNMENTS: "assignments",
SHOW_FAILED_TELEPORT_MESSAGES: "showFailedTeleportMessages",
CREATE_MANAGED_EFFECTS_ON_ASSIGNMENT: "createManagedEffectsOnAssignment"
});
export const TRIGGER_TYPES = Object.freeze({
DAMAGE_RECEIVED: "damageReceived",
TARGET_SELECTED: "targetSelected",
SPELL_CAST_START: "spellCastStart",
SPELL_CAST_COMPLETE: "spellCastComplete",
FEATURE_USED: "featureUsed"
});
export const ACTION_TYPES = Object.freeze({
APPLY_STATUS: "applyStatus",
TELEPORT: "teleport",
CAST_SPELL_FROM_TOKEN: "castSpellFromToken",
USE_INVENTORY_ITEM: "useInventoryItem"
});
export const DEFAULT_REACTION = Object.freeze({
name: "Neue Reaktion",
enabled: true,
trigger: {
type: TRIGGER_TYPES.DAMAGE_RECEIVED
},
conditions: {
damage: {
enabled: true,
amountMode: "damageOnly",
types: [],
typeMode: "any",
minAmount: 1
},
hpAfterDamage: {
enabled: false,
operator: "lte",
mode: "percent",
value: 50
}
},
consumption: {
enabled: false,
mode: "none",
maxUses: 1,
consumeOnFailure: false
},
actions: []
});
+36
View File
@@ -0,0 +1,36 @@
import { MODULE_ID } from "./constants.js";
import { registerSettings } from "./settings.js";
import { registerSocket } from "./sockets.js";
import { ConfigurableReactionsConfigApp } from "./apps/reaction-config-app.js";
import { registerDnd5eDamageTrigger } from "./triggers/damage-received.js";
import { registerTargetSelectedTrigger } from "./triggers/target-selected.js";
Hooks.once("init", () => {
registerSettings();
console.log(`${MODULE_ID} | Settings registered`);
});
Hooks.once("ready", () => {
registerSocket();
registerDnd5eDamageTrigger();
registerTargetSelectedTrigger();
console.log(`${MODULE_ID} | Ready`);
});
Hooks.on("getSceneControlButtons", controls => {
if (!game.user.isGM) return;
const tokenControls = controls.tokens ?? controls.find?.(c => c.name === "token");
if (!tokenControls) return;
const tool = {
name: "configurable-reactions",
title: game.i18n.localize("CONFIGURABLE_REACTIONS.Controls.OpenConfig"),
icon: "fa-solid fa-bolt",
button: true,
onChange: () => new ConfigurableReactionsConfigApp().render(true)
};
if (Array.isArray(tokenControls.tools)) tokenControls.tools.push(tool);
else if (tokenControls.tools instanceof Object) tokenControls.tools[tool.name] = tool;
});
+39
View File
@@ -0,0 +1,39 @@
import { MODULE_ID, SETTINGS } from "./constants.js";
export function registerSettings() {
game.settings.register(MODULE_ID, SETTINGS.REACTIONS, {
name: game.i18n.localize("CONFIGURABLE_REACTIONS.Settings.Reactions.Name"),
hint: game.i18n.localize("CONFIGURABLE_REACTIONS.Settings.Reactions.Hint"),
scope: "world",
config: false,
type: Array,
default: []
});
game.settings.register(MODULE_ID, SETTINGS.ASSIGNMENTS, {
name: game.i18n.localize("CONFIGURABLE_REACTIONS.Settings.Assignments.Name"),
hint: game.i18n.localize("CONFIGURABLE_REACTIONS.Settings.Assignments.Hint"),
scope: "world",
config: false,
type: Array,
default: []
});
game.settings.register(MODULE_ID, SETTINGS.SHOW_FAILED_TELEPORT_MESSAGES, {
name: game.i18n.localize("CONFIGURABLE_REACTIONS.Settings.ShowFailedTeleportMessages.Name"),
hint: game.i18n.localize("CONFIGURABLE_REACTIONS.Settings.ShowFailedTeleportMessages.Hint"),
scope: "world",
config: true,
type: Boolean,
default: true
});
game.settings.register(MODULE_ID, SETTINGS.CREATE_MANAGED_EFFECTS_ON_ASSIGNMENT, {
name: game.i18n.localize("CONFIGURABLE_REACTIONS.Settings.CreateManagedEffects.Name"),
hint: game.i18n.localize("CONFIGURABLE_REACTIONS.Settings.CreateManagedEffects.Hint"),
scope: "world",
config: true,
type: Boolean,
default: true
});
}
+23
View File
@@ -0,0 +1,23 @@
import { MODULE_ID } from "./constants.js";
import { handleTeleportTargetRequest, handleTeleportTargetChosen } from "./actions/teleport-action.js";
export function registerSocket() {
game.socket.on(`module.${MODULE_ID}`, async message => {
if (!message?.type) return;
switch (message.type) {
case "requestTeleportTarget":
return handleTeleportTargetRequest(message);
case "teleportTargetChosen":
return handleTeleportTargetChosen(message);
default:
console.warn(`${MODULE_ID} | Unknown socket message`, message);
}
});
}
export function emitSocket(message) {
game.socket.emit(`module.${MODULE_ID}`, message);
}