203 lines
9.5 KiB
JavaScript
203 lines
9.5 KiB
JavaScript
import { SYSTEM, STATUS_EFFECTS } from "./module/config/system.mjs"
|
||
globalThis.SYSTEM = SYSTEM
|
||
|
||
import * as models from "./module/models/_module.mjs"
|
||
import * as documents from "./module/documents/_module.mjs"
|
||
import * as applications from "./module/applications/_module.mjs"
|
||
import OathHammerUtils from "./module/utils.mjs"
|
||
import OathHammerWeaponDialog from "./module/applications/weapon-dialog.mjs"
|
||
import OathHammerCombat from "./module/combat.mjs"
|
||
import { rollWeaponDamage } from "./module/rolls.mjs"
|
||
import { injectFreeRollBar } from "./module/applications/free-roll.mjs"
|
||
|
||
Hooks.once("init", function () {
|
||
console.info(SYSTEM.ASCII)
|
||
console.info("Oath Hammer | Initializing System")
|
||
|
||
globalThis.oathHammer = game.system
|
||
game.system.CONST = SYSTEM
|
||
|
||
game.system.api = { applications, models, documents }
|
||
|
||
CONFIG.Actor.documentClass = documents.OathHammerActor
|
||
CONFIG.Combat.documentClass = OathHammerCombat
|
||
CONFIG.Actor.dataModels = {
|
||
character: models.OathHammerCharacter,
|
||
npc: models.OathHammerNPC,
|
||
settlement: models.OathHammerSettlement,
|
||
regiment: models.OathHammerRegiment,
|
||
party: models.OathHammerParty,
|
||
army: models.OathHammerArmy,
|
||
}
|
||
|
||
CONFIG.Item.documentClass = documents.OathHammerItem
|
||
CONFIG.Item.dataModels = {
|
||
weapon: models.OathHammerWeapon,
|
||
armor: models.OathHammerArmor,
|
||
ammunition: models.OathHammerAmmunition,
|
||
equipment: models.OathHammerEquipment,
|
||
spell: models.OathHammerSpell,
|
||
miracle: models.OathHammerMiracle,
|
||
"magic-item": models.OathHammerMagicItem,
|
||
trait: models.OathHammerTrait,
|
||
oath: models.OathHammerOath,
|
||
"class": models.OathHammerClass,
|
||
building: models.OathHammerBuilding,
|
||
skillnpc: models.OathHammerSkillNPC,
|
||
npcattack: models.OathHammerNpcAttack,
|
||
}
|
||
|
||
foundry.documents.collections.Actors.unregisterSheet("core", foundry.appv1.sheets.ActorSheet)
|
||
foundry.documents.collections.Actors.registerSheet("fvtt-oath-hammer", applications.OathHammerCharacterSheet, {
|
||
types: ["character"],
|
||
makeDefault: true,
|
||
label: "OATHHAMMER.Sheet.Character"
|
||
})
|
||
foundry.documents.collections.Actors.registerSheet("fvtt-oath-hammer", applications.OathHammerNPCSheet, {
|
||
types: ["npc"],
|
||
makeDefault: true,
|
||
label: "OATHHAMMER.Sheet.NPC"
|
||
})
|
||
foundry.documents.collections.Actors.registerSheet("fvtt-oath-hammer", applications.OathHammerSettlementSheet, {
|
||
types: ["settlement"],
|
||
makeDefault: true,
|
||
label: "OATHHAMMER.Sheet.Settlement"
|
||
})
|
||
foundry.documents.collections.Actors.registerSheet("fvtt-oath-hammer", applications.OathHammerRegimentSheet, {
|
||
types: ["regiment"],
|
||
makeDefault: true,
|
||
label: "OATHHAMMER.Sheet.Regiment"
|
||
})
|
||
foundry.documents.collections.Actors.registerSheet("fvtt-oath-hammer", applications.OathHammerPartySheet, {
|
||
types: ["party"],
|
||
makeDefault: true,
|
||
label: "OATHHAMMER.Sheet.Party"
|
||
})
|
||
foundry.documents.collections.Actors.registerSheet("fvtt-oath-hammer", applications.OathHammerArmySheet, {
|
||
types: ["army"],
|
||
makeDefault: true,
|
||
label: "OATHHAMMER.Sheet.Army"
|
||
})
|
||
|
||
foundry.documents.collections.Items.unregisterSheet("core", foundry.appv1.sheets.ItemSheet)
|
||
foundry.documents.collections.Items.registerSheet("fvtt-oath-hammer", applications.OathHammerWeaponSheet, { types: ["weapon"], makeDefault: true, label: "OATHHAMMER.Sheet.Weapon" })
|
||
foundry.documents.collections.Items.registerSheet("fvtt-oath-hammer", applications.OathHammerArmorSheet, { types: ["armor"], makeDefault: true, label: "OATHHAMMER.Sheet.Armor" })
|
||
foundry.documents.collections.Items.registerSheet("fvtt-oath-hammer", applications.OathHammerAmmunitionSheet, { types: ["ammunition"], makeDefault: true, label: "OATHHAMMER.Sheet.Ammunition" })
|
||
foundry.documents.collections.Items.registerSheet("fvtt-oath-hammer", applications.OathHammerEquipmentSheet, { types: ["equipment"], makeDefault: true, label: "OATHHAMMER.Sheet.Equipment" })
|
||
foundry.documents.collections.Items.registerSheet("fvtt-oath-hammer", applications.OathHammerSpellSheet, { types: ["spell"], makeDefault: true, label: "OATHHAMMER.Sheet.Spell" })
|
||
foundry.documents.collections.Items.registerSheet("fvtt-oath-hammer", applications.OathHammerMiracleSheet, { types: ["miracle"], makeDefault: true, label: "OATHHAMMER.Sheet.Miracle" })
|
||
foundry.documents.collections.Items.registerSheet("fvtt-oath-hammer", applications.OathHammerMagicItemSheet, { types: ["magic-item"], makeDefault: true, label: "OATHHAMMER.Sheet.MagicItem" })
|
||
foundry.documents.collections.Items.registerSheet("fvtt-oath-hammer", applications.OathHammerTraitSheet, { types: ["trait"], makeDefault: true, label: "OATHHAMMER.Sheet.Trait" })
|
||
foundry.documents.collections.Items.registerSheet("fvtt-oath-hammer", applications.OathHammerOathSheet, { types: ["oath"], makeDefault: true, label: "OATHHAMMER.Sheet.Oath" })
|
||
foundry.documents.collections.Items.registerSheet("fvtt-oath-hammer", applications.OathHammerClassSheet, { types: ["class"], makeDefault: true, label: "OATHHAMMER.Sheet.Class" })
|
||
foundry.documents.collections.Items.registerSheet("fvtt-oath-hammer", applications.OathHammerBuildingSheet, { types: ["building"], makeDefault: true, label: "OATHHAMMER.Sheet.Building" })
|
||
foundry.documents.collections.Items.registerSheet("fvtt-oath-hammer", applications.OathHammerSkillNPCSheet, { types: ["skillnpc"], makeDefault: true, label: "OATHHAMMER.Sheet.SkillNPC" })
|
||
foundry.documents.collections.Items.registerSheet("fvtt-oath-hammer", applications.OathHammerNpcAttackSheet, { types: ["npcattack"], makeDefault: true, label: "OATHHAMMER.Sheet.NpcAttack" })
|
||
|
||
CONFIG.statusEffects = STATUS_EFFECTS
|
||
|
||
OathHammerUtils.registerHandlebarsHelpers()
|
||
|
||
// Pre-register Handlebars partials so {{> "path"}} works in item templates
|
||
foundry.applications.handlebars.loadTemplates([
|
||
"systems/fvtt-oath-hammer/templates/item/rune-zone.hbs",
|
||
])
|
||
|
||
console.info("Oath Hammer | System Initialized")
|
||
})
|
||
|
||
Hooks.once("ready", async function () {
|
||
console.info("Oath Hammer | System Ready")
|
||
|
||
// Migration: remove orphaned items with removed types (lineage → actor field, ability → trait, regiment → actor type)
|
||
const removedTypes = new Set(["lineage", "ability", "regiment"])
|
||
for (const actor of game.actors) {
|
||
const toDelete = []
|
||
|
||
// Catch items that failed validation and landed in invalidDocumentIds
|
||
for (const id of (actor.items.invalidDocumentIds ?? [])) {
|
||
const raw = actor.items.getInvalid(id)
|
||
if (raw && removedTypes.has(raw._source?.type)) toDelete.push(id)
|
||
}
|
||
|
||
// Also catch any that slipped through in _source (belt-and-suspenders)
|
||
for (const src of (actor._source.items ?? [])) {
|
||
if (removedTypes.has(src.type) && !toDelete.includes(src._id)) toDelete.push(src._id)
|
||
}
|
||
|
||
if (toDelete.length) {
|
||
console.info(`Oath Hammer | Migrating ${actor.name}: removing ${toDelete.length} obsolete item(s)`)
|
||
await actor.deleteEmbeddedDocuments("Item", toDelete)
|
||
}
|
||
}
|
||
|
||
// Purge invalid world items of removed types
|
||
for (const id of game.items.invalidDocumentIds) {
|
||
const item = game.items.getInvalid(id)
|
||
if (item && removedTypes.has(item._source?.type)) {
|
||
console.info(`Oath Hammer | Deleting world item: ${item._source.name} (${item._source.type})`)
|
||
await item.delete()
|
||
}
|
||
}
|
||
|
||
// Auto-import the welcome scene if GM and not already present
|
||
if (game.user.isGM) await _importWelcomeScene()
|
||
})
|
||
|
||
// Auto-link regiment (and army) actor tokens so they can be added to garrisons/armies
|
||
Hooks.on("preCreateActor", (actor, _data, _options, _userId) => {
|
||
if (actor.type === "regiment" || actor.type === "army") {
|
||
actor.updateSource({ "prototypeToken.actorLink": true })
|
||
}
|
||
})
|
||
|
||
// Handle "Roll Damage" button in weapon attack chat cards
|
||
Hooks.on("renderChatMessageHTML", (message, html) => {
|
||
const btn = html.querySelector("[data-action=\"rollWeaponDamage\"]")
|
||
if (!btn) return
|
||
btn.addEventListener("click", async () => {
|
||
const flagData = message.getFlag("fvtt-oath-hammer", "weaponAttack")
|
||
if (!flagData) return
|
||
const { actorUuid, weaponUuid, attackSuccesses } = flagData
|
||
const actor = await fromUuid(actorUuid)
|
||
const weapon = await fromUuid(weaponUuid)
|
||
if (!actor || !weapon) return ui.notifications.warn(game.i18n.localize("OATHHAMMER.Roll.NoActor"))
|
||
const opts = await OathHammerWeaponDialog.promptDamage(actor, weapon, attackSuccesses ?? 0)
|
||
if (opts) await rollWeaponDamage(actor, weapon, opts)
|
||
})
|
||
})
|
||
|
||
// Inject Free Roll bar into the chat sidebar
|
||
Hooks.on("renderChatLog", (_chatLog, html) => injectFreeRollBar(_chatLog, html))
|
||
|
||
|
||
// ============================================================
|
||
// WELCOME SCENE — auto-create on first world load (GM only)
|
||
// ============================================================
|
||
const WELCOME_SCENE_NAME = "Oath Hammer"
|
||
const WELCOME_SCENE_MAP = "systems/fvtt-oath-hammer/assets/images/oathhammer_map.webp"
|
||
|
||
/** Scene data for the welcome map (3600×5400 px, no grid — world map). */
|
||
function _welcomeSceneData() {
|
||
return {
|
||
name: WELCOME_SCENE_NAME,
|
||
background: { src: WELCOME_SCENE_MAP },
|
||
width: 3600,
|
||
height: 5400,
|
||
grid: { type: 0, size: 100 }, // gridless
|
||
padding: 0,
|
||
initial: { x: 1800, y: 2700, scale: 0.25 },
|
||
tokenVision: false,
|
||
flags: { "fvtt-oath-hammer": { welcomeScene: true } },
|
||
}
|
||
}
|
||
|
||
async function _importWelcomeScene() {
|
||
// Skip if the scene already exists in the world
|
||
if (game.scenes.find(s => s.name === WELCOME_SCENE_NAME)) return
|
||
console.info("Oath Hammer | Creating welcome scene…")
|
||
const scene = await Scene.create(_welcomeSceneData())
|
||
await scene.activate()
|
||
console.info("Oath Hammer | Welcome scene created and activated.")
|
||
}
|