Initial import
This commit is contained in:
		
							
								
								
									
										295
									
								
								lethal-fantasy.mjs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										295
									
								
								lethal-fantasy.mjs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,295 @@ | ||||
| /** | ||||
|  * Lethal Fantasy RPG System | ||||
|  * Author: LeRatierBretonnien/Uberwald | ||||
|  */ | ||||
|  | ||||
| import { SYSTEM } from "./module/config/system.mjs" | ||||
| globalThis.SYSTEM = SYSTEM // Expose the SYSTEM object to the global scope | ||||
|  | ||||
| // Import modules | ||||
| 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 { handleSocketEvent } from "./module/socket.mjs" | ||||
| import { configureDiceSoNice } from "./module/dice.mjs" | ||||
| import { Macros } from "./module/macros.mjs" | ||||
| import { initControlButtons } from "./module/control-buttons.mjs" | ||||
| import { setupTextEnrichers } from "./module/enrichers.mjs" | ||||
|  | ||||
| Hooks.once("init", function () { | ||||
|   console.info("Lethal Fantasy RPG | Initializing System") | ||||
|   console.info(SYSTEM.ASCII) | ||||
|  | ||||
|   globalThis.lethalFantasy = game.system | ||||
|   game.system.CONST = SYSTEM | ||||
|  | ||||
|   // Expose the system API | ||||
|   game.system.api = { | ||||
|     applications, | ||||
|     models, | ||||
|     documents, | ||||
|   } | ||||
|  | ||||
|   CONFIG.Actor.documentClass = documents.LethalFantasyActor | ||||
|   CONFIG.Actor.dataModels = { | ||||
|     character: models.LethalFantasyCharacter, | ||||
|     opponent: models.LethalFantasyOpponent, | ||||
|   } | ||||
|  | ||||
|   CONFIG.Item.documentClass = documents.LethalFantasyItem | ||||
|   CONFIG.Item.dataModels = { | ||||
|     path: models.LethalFantasyPath, | ||||
|     talent: models.LethalFantasyTalent, | ||||
|     weapon: models.LethalFantasyWeapon, | ||||
|     armor: models.LethalFantasyArmor, | ||||
|     spell: models.LethalFantasySpell, | ||||
|     attack: models.LethalFantasyAttack, | ||||
|   } | ||||
|  | ||||
|   // Register sheet application classes | ||||
|   Actors.unregisterSheet("core", ActorSheet) | ||||
|   Actors.registerSheet("lethalFantasy", applications.LethalFantasyCharacterSheet, { types: ["character"], makeDefault: true }) | ||||
|   Actors.registerSheet("lethalFantasy", applications.LethalFantasyOpponentSheet, { types: ["opponent"], makeDefault: true }) | ||||
|  | ||||
|   Items.unregisterSheet("core", ItemSheet) | ||||
|   Items.registerSheet("lethalFantasy", applications.LethalFantasyTalentSheet, { types: ["talent"], makeDefault: true }) | ||||
|   Items.registerSheet("lethalFantasy", applications.LethalFantasyPathSheet, { types: ["path"], makeDefault: true }) | ||||
|   Items.registerSheet("lethalFantasy", applications.LethalFantasyWeaponSheet, { types: ["weapon"], makeDefault: true }) | ||||
|   Items.registerSheet("lethalFantasy", applications.LethalFantasySpellSheet, { types: ["spell"], makeDefault: true }) | ||||
|   Items.registerSheet("lethalFantasy", applications.LethalFantasyArmorSheet, { types: ["armor"], makeDefault: true }) | ||||
|   Items.registerSheet("lethalFantasy", applications.LethalFantasyAttackSheet, { types: ["attack"], makeDefault: true }) | ||||
|  | ||||
|   // Other Document Configuration | ||||
|   CONFIG.ChatMessage.documentClass = documents.LethalFantasyChatMessage | ||||
|  | ||||
|   // Dice system configuration | ||||
|   CONFIG.Dice.rolls.push(documents.LethalFantasyRoll) | ||||
|  | ||||
|   // Register system settings | ||||
|   game.settings.register("lethalFantasy", "displayOpponentMalus", { | ||||
|     name: "TENEBRIS.Setting.displayOpponentMalus", | ||||
|     hint: "TENEBRIS.Setting.displayOpponentMalusHint", | ||||
|     scope: "world", | ||||
|     config: true, | ||||
|     type: Boolean, | ||||
|     default: true, | ||||
|   }) | ||||
|  | ||||
|   game.settings.register("lethalFantasy", "fortune", { | ||||
|     name: "TENEBRIS.Setting.fortune", | ||||
|     hint: "TENEBRIS.Setting.fortuneHint", | ||||
|     scope: "world", | ||||
|     config: true, | ||||
|     type: Number, | ||||
|     default: 0, | ||||
|     requiresReload: true, | ||||
|   }) | ||||
|  | ||||
|   game.settings.register("lethalFantasy", "worldKey", { | ||||
|     name: "Unique world key", | ||||
|     scope: "world", | ||||
|     config: false, | ||||
|     type: String, | ||||
|     default: "", | ||||
|   }) | ||||
|  | ||||
|   // Activate socket handler | ||||
|   game.socket.on(`system.${SYSTEM.id}`, handleSocketEvent) | ||||
|  | ||||
|   // Pre-localize configuration objects | ||||
|   // TODO : encore d'actualité ? | ||||
|   // preLocalizeConfig() | ||||
|  | ||||
|   initControlButtons() | ||||
|  | ||||
|   setupTextEnrichers() | ||||
|  | ||||
|   // Gestion des jets de dés depuis les journaux | ||||
|   document.addEventListener("click", (event) => { | ||||
|     const anchor = event.target.closest("a.ask-roll-journal") | ||||
|     if (!anchor) return | ||||
|     event.preventDefault() | ||||
|     event.stopPropagation() | ||||
|     const type = anchor.dataset.rollType | ||||
|     const target = anchor.dataset.rollTarget | ||||
|     const title = anchor.dataset.rollTitle | ||||
|     const avantage = anchor.dataset.rollAvantage | ||||
|     applications.LethalFantasyManager.askRollForAll(type, target, title, avantage) | ||||
|   }) | ||||
|  | ||||
|   console.info("CTHULHU TENEBRIS | System Initialized") | ||||
| }) | ||||
|  | ||||
| /** | ||||
|  * Perform one-time configuration of system configuration objects. | ||||
|  */ | ||||
| function preLocalizeConfig() { | ||||
|   const localizeConfigObject = (obj, keys) => { | ||||
|     for (let o of Object.values(obj)) { | ||||
|       for (let k of keys) { | ||||
|         o[k] = game.i18n.localize(o[k]) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   // CONFIG.Dice.rollModes = Object.fromEntries(Object.entries(CONFIG.Dice.rollModes).map(([key, value]) => [key, game.i18n.localize(value)])) | ||||
|  | ||||
|   // localizeConfigObject(SYSTEM.ACTION.TAG_CATEGORIES, ["label"]) | ||||
|   // localizeConfigObject(CONFIG.Dice.rollModes, ["label"]) | ||||
| } | ||||
|  | ||||
| Hooks.once("ready", function () { | ||||
|   console.info("CTHULHU TENEBRIS | Ready") | ||||
|   game.system.applicationFortune = new applications.LethalFantasyFortune() | ||||
|   game.system.applicationFortune.render(true) | ||||
|   game.system.applicationManager = new applications.LethalFantasyManager() | ||||
|   if (game.user.isGM) { | ||||
|     game.system.applicationManager.render(true) | ||||
|   } | ||||
|  | ||||
|   if (!SYSTEM.DEV_MODE) { | ||||
|     registerWorldCount("lethalFantasy") | ||||
|   } | ||||
|   _showUserGuide() | ||||
|  | ||||
|   /** | ||||
|    * | ||||
|    */ | ||||
|   async function _showUserGuide() { | ||||
|     if (game.user.isGM) { | ||||
|       const newVer = game.system.version | ||||
|       const userGuideJournalName = "Guide du système" | ||||
|       const userGuideCompendiumLabel = "userguide" | ||||
|  | ||||
|       let currentVer = "0" | ||||
|       let oldUserGuide = game.journal.getName(userGuideJournalName) | ||||
|       if (oldUserGuide !== undefined && oldUserGuide !== null && oldUserGuide.getFlag("lethalFantasy", "UserGuideVersion") !== undefined) { | ||||
|         currentVer = oldUserGuide.getFlag("lethalFantasy", "UserGuideVersion") | ||||
|       } | ||||
|       if (newVer === currentVer) { | ||||
|         // Up to date | ||||
|         return | ||||
|       } | ||||
|  | ||||
|       let newReleasePack = game.packs.find((p) => p.metadata.name === userGuideCompendiumLabel) | ||||
|       if (newReleasePack === null || newReleasePack === undefined) { | ||||
|         console.info("CTHULHU TENEBRIS | No compendium found for the system guide") | ||||
|         return | ||||
|       } | ||||
|       await newReleasePack.getIndex() | ||||
|  | ||||
|       let newUserGuide = newReleasePack.index.find((j) => j.name === userGuideJournalName) | ||||
|       if (newUserGuide === undefined || newUserGuide === null) { | ||||
|         console.info("CTHULHU TENEBRIS | No system guide found in the compendium") | ||||
|         return | ||||
|       } | ||||
|  | ||||
|       // Don't delete until we have new release Pack | ||||
|       if (oldUserGuide !== null && oldUserGuide !== undefined) { | ||||
|         await oldUserGuide.delete() | ||||
|       } | ||||
|  | ||||
|       await game.journal.importFromCompendium(newReleasePack, newUserGuide._id) | ||||
|       let newReleaseJournal = game.journal.getName(newUserGuide.name) | ||||
|  | ||||
|       await newReleaseJournal.setFlag("lethalFantasy", "UserGuideVersion", newVer) | ||||
|  | ||||
|       // Show journal | ||||
|       await newReleaseJournal.sheet.render(true, { sheetMode: "text" }) | ||||
|     } | ||||
|   } | ||||
| }) | ||||
|  | ||||
| Hooks.on("renderChatMessage", (message, html, data) => { | ||||
|   const typeMessage = data.message.flags.lethalFantasy?.typeMessage | ||||
|   // Message de fortune | ||||
|   if (typeMessage === "fortune") { | ||||
|     if (game.user.isGM && !data.message.flags.lethalFantasy?.accepted) { | ||||
|       html.find(".button").click((event) => applications.LethalFantasyFortune.acceptRequest(event, html, data)) | ||||
|     } else { | ||||
|       html.find(".button").each((i, btn) => { | ||||
|         btn.style.display = "none" | ||||
|       }) | ||||
|       if (game.user.isGM) { | ||||
|         html.find(".fortune-accepted").each((i, btn) => (btn.style.display = "flex")) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   // Message de demande de jet de dés | ||||
|   else if (typeMessage === "askRoll") { | ||||
|     // Affichage des boutons de jet de dés uniquement pour les joueurs | ||||
|     if (game.user.isGM) { | ||||
|       html.find(".ask-roll-dice").each((i, btn) => { | ||||
|         btn.style.display = "none" | ||||
|       }) | ||||
|     } else { | ||||
|       html.find(".ask-roll-dice").click((event) => { | ||||
|         const btn = $(event.currentTarget) | ||||
|         const type = btn.data("type") | ||||
|         const value = btn.data("value") | ||||
|         const avantage = btn.data("avantage") ?? "=" | ||||
|         const character = game.user.character | ||||
|         if (type === SYSTEM.ROLL_TYPE.RESOURCE) character.rollResource(value) | ||||
|         else if (type === SYSTEM.ROLL_TYPE.SAVE) character.rollSave(value, avantage) | ||||
|       }) | ||||
|     } | ||||
|   } | ||||
| }) | ||||
|  | ||||
| Hooks.on("updateSetting", async (setting, update, options, id) => { | ||||
|   if (setting.key === "lethalFantasy.fortune") { | ||||
|     game.system.applicationFortune.render(true) | ||||
|   } | ||||
| }) | ||||
|  | ||||
| // Dice-so-nice Ready | ||||
| Hooks.once("diceSoNiceReady", (dice3d) => { | ||||
|   configureDiceSoNice(dice3d) | ||||
| }) | ||||
|  | ||||
| /** | ||||
|  * Create a macro when dropping an entity on the hotbar | ||||
|  * Item      - open roll dialog | ||||
|  * Actor     - open actor sheet | ||||
|  * Journal   - open journal sheet | ||||
|  */ | ||||
| Hooks.on("hotbarDrop", (bar, data, slot) => { | ||||
|   if (["Actor", "Item", "JournalEntry", "roll", "rollDamage", "rollAttack"].includes(data.type)) { | ||||
|     Macros.createLethalFantasyMacro(data, slot) | ||||
|     return false | ||||
|   } | ||||
| }) | ||||
|  | ||||
| /** | ||||
|  * Register world usage statistics | ||||
|  * @param {string} registerKey | ||||
|  */ | ||||
| function registerWorldCount(registerKey) { | ||||
|   if (game.user.isGM) { | ||||
|     let worldKey = game.settings.get(registerKey, "worldKey") | ||||
|     if (worldKey === undefined || worldKey === "") { | ||||
|       worldKey = foundry.utils.randomID(32) | ||||
|       game.settings.set(registerKey, "worldKey", worldKey) | ||||
|     } | ||||
|  | ||||
|     // Simple API counter | ||||
|     const worldData = { | ||||
|       register_key: registerKey, | ||||
|       world_key: worldKey, | ||||
|       foundry_version: `${game.release.generation}.${game.release.build}`, | ||||
|       system_name: game.system.id, | ||||
|       system_version: game.system.version, | ||||
|     } | ||||
|  | ||||
|     let apiURL = "https://worlds.qawstats.info/worlds-counter" | ||||
|     $.ajax({ | ||||
|       url: apiURL, | ||||
|       type: "POST", | ||||
|       data: JSON.stringify(worldData), | ||||
|       contentType: "application/json; charset=utf-8", | ||||
|       dataType: "json", | ||||
|       async: false, | ||||
|     }) | ||||
|   } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user