Compare commits

..

No commits in common. "main" and "v0.3.0" have entirely different histories.
main ... v0.3.0

9 changed files with 20 additions and 204 deletions

View file

@ -1,4 +1,4 @@
# The Mill's Fabula - v0.4.0
# The Mill's Fabula - v0.3.0
This little [FoundryVTT](https://foundryvtt.com/) module is a collection of compendiums and functionalities
to power our Fabula Ultima campaigns.
@ -36,14 +36,20 @@ The module supports going back and forth in the combat rounds, as well as going
- An image to use for the default/idle border
- An image to use for the took turn/played/inactive border
### Limitations
There are currently one minor issue that might be fixed :
1. The token borders will be incorrect when switching between different encounters in the same scene
- Producing a combat event or switching away and back to the scene will fix it.
- It doesn't appear that there is an event on combat switch that could be hooked into, which makes fixing the
issue uncertain.
## Token UI adjustments
Given that we add a border *on* the tokens, it conflicts with the base attribute bars and status effect indicators which
are drawn over the token's square.
Given that we add a border *on* the tokens, it conflicts with the base attribute bars which are drawn over the token's
square.
The token UI adjustments move the two attribute bars below the token, outside its space, first HP then mana.
As this is where the nameplate of the token should be, move it above the token instead.
The status effect indicators are moved entirely outside the token space as well, to the right, but as it is not useful
for NPCs this is only done for PC tokens.
### Limitations
@ -51,14 +57,6 @@ for NPCs this is only done for PC tokens.
- The current implementation relies on monkey patching, which make it vulnerable to compatibility issues with
other modules manipulating the same methods.
## Fortune display
In our game, "Fortune" is a key currency in the world.
This adds an interactible display in the character sheets, allowing it to be tracked, and in the party sheet,
for a nice overview.
The value is stored in flags, and will not be lost when disabling the module or option.
# Compendia
- The only thing in the compendium pack is a macro automating the tinkerer's alchemy potions,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 565 B

View file

@ -22,16 +22,7 @@
"Settings": {
"Enabled": {
"Name": "Token UI adjustments",
"Hint": "Moves both attribute bars below the token, the nameplate above and, for PCs, the status icons to the right."
}
}
},
"Fortune": {
"Name": "Fortune",
"Settings": {
"DisplayEnabled": {
"Name": "Fortune display",
"Hint": "Display and track \"Fortune\" currency in the character and party sheets."
"Hint": "Moves both attribute bars below the token and the nameplate above."
}
}
}

View file

@ -22,16 +22,7 @@
"Settings": {
"Enabled": {
"Name": "Ajustements d'interface des tokens",
"Hint": "Déplace les barres d'attributs sous le token, le nom au dessus et, pour les PJs, les indicateurs de statut à droite."
}
}
},
"Fortune": {
"Name": "Fortune",
"Settings": {
"DisplayEnabled": {
"Name": "Affichage de la Fortune",
"Hint": "Affiche et gère une monnaie, la \"Fortune\", dans les fiches de personnage et de groupe."
"Hint": "Déplace les barres d'attributs sous le token et le nom au dessus."
}
}
}

View file

@ -2,7 +2,7 @@
"id": "the-mills-fabula",
"title": "Fabula Moletrina",
"description": "A module implementing our idiosyncratic ideas for the Mill's campaigns.",
"version": "0.4.0",
"version": "0.3.0",
"compatibility": {
"minimum": "12",
"verified": "12",
@ -28,8 +28,7 @@
"compatibility": {
"verified": [
"2.4.10",
"3.0.2",
"3.1.7"
"3.0.2"
]
}
}
@ -39,10 +38,7 @@
"id": "socketlib",
"type": "module",
"compatibility": {
"verified": [
"1.1.2",
"1.1.3"
]
"verified": "1.1.2"
}
}
]
@ -55,11 +51,7 @@
],
"esmodules": [
"scripts/token_combat_border.mjs",
"scripts/token_ui_adjust.mjs",
"scripts/fortune_integration.mjs"
],
"styles": [
"styles/mills_fabula.css"
"scripts/token_ui_adjust.mjs"
],
"socket": true,
@ -90,5 +82,5 @@
"readme": "README.md",
"url": "https://git.tfk-astrodome.net/trotFunky/TheMillsFabula/src/branch/release",
"manifest": "https://git.tfk-astrodome.net/trotFunky/TheMillsFabula/raw/branch/release/module.json",
"download": "https://git.tfk-astrodome.net/trotFunky/TheMillsFabula/archive/v0.4.0.zip"
"download": "https://git.tfk-astrodome.net/trotFunky/TheMillsFabula/archive/v0.3.0.zip"
}

View file

@ -1,118 +0,0 @@
import * as MillsFabula from "./mills_fabula.mjs";
const fortune_flag = "char_fortune"
const FortuneSettings = Object.freeze({
EnableFortuneDisplay: "enableFortuneDisplay",
})
/**
* Find all the characters in the group sheet and insert their Fortune amount
* within the resources, copying the system's style.
* @param {DocumentSheet|foundry.applications.api.DocumentSheetV2} app The source Application
* @param {HTMLElement} html The rendered HTML
* @returns {Promise<void>} Does not return
*/
async function party_sheet_fortune(app, html) {
if (!(app instanceof foundry.applications.api.DocumentSheetV2))
html = html[0] /* Retrieve the internal DOM element */
else
console.warn("AppV2 is not properly tested yet")
let character_divs = html.querySelectorAll(".section-container.plate.character")
for (let char_div of character_divs) {
/** @type{FUActor} */
let actor = await fromUuid(char_div.getAttribute("data-uuid"))
let resources = char_div.getElementsByClassName("resources")[0]
let icon = document.createElement("i");
icon.classList.add("fuk", "icon-aff", "mf-fortune")
icon.setAttribute("data-tooltip", game.i18n.localize('MF.Fortune.Name'))
/* Insert the Fortune elements before Fabula points, so find it */
let fp_icon = resources.getElementsByClassName("fu-fp")[0]
resources.insertBefore(icon, fp_icon)
/* The system also has whitespace for spacing */
resources.insertBefore(
document.createTextNode(` ${actor.getFlag(MillsFabula.id, fortune_flag) ?? 0} `),
fp_icon)
}
}
/**
* Insert a Fortune input at the top of the character sheet,
* following the same styling as the system for Fabula points.
* @param {DocumentSheet|foundry.applications.api.DocumentSheetV2} app The source Application
* @param {HTMLElement} html The rendered HTML
*/
function character_sheet_fortune(app, html) {
/* Only player characters have Fortune. */
if (app.actor.type !== "character")
return
if (!(app instanceof foundry.applications.api.DocumentSheetV2))
html = html[0] /* Retrieve the internal DOM element */
else
console.warn("AppV2 is not properly tested yet")
let resources_div = html.getElementsByClassName("header-center")[0].lastElementChild
resources_div.classList.replace("grid-3col", "grid-4col")
/*
* We want the Fortune to have the same importance/weight as Fabula points,
* so we'll copy the style and bundle them in a 2 column div.
*/
/* TODO: This all should probably be some form of template ? */
let fortune_fabula_div = document.createElement("div")
fortune_fabula_div.classList.add("grid", "grid-2col")
let fortune_div = document.createElement("div")
fortune_div.classList.add("flex-group-center", "resource-content")
let fortune_label = document.createElement("span")
fortune_label.classList.add("resource-label-l")
let fortune_icon = document.createElement("i")
fortune_icon.classList.add("fas", "fa-leaf", "icon")
fortune_label.appendChild(fortune_icon)
fortune_label.appendChild(document.createTextNode(game.i18n.localize('MF.Fortune.Name')))
fortune_div.appendChild(fortune_label)
let fortune_data_div = document.createElement("div")
fortune_data_div.classList.add("buttons-inc")
let fortune_input = foundry.applications.fields.createNumberInput({
/*
* By setting the name of the field using this format, the backing
* flag will automatically be picked up by Foundry's code and updated
* when the field is changed on the sheet.
* This works even if it wasn't set previously !
*/
name: `flags.${MillsFabula.id}.${fortune_flag}`,
value: app.document.getFlag(MillsFabula.id, fortune_flag) ?? 0,
step: 1,
min: 0,
type: "number"
})
fortune_input.classList.add("fp-resource-inputs")
fortune_data_div.appendChild(fortune_input)
fortune_div.appendChild(fortune_data_div)
fortune_fabula_div.appendChild(fortune_div)
/* The last element should always be the Fabula Points div. */
fortune_fabula_div.appendChild(resources_div.lastElementChild)
resources_div.appendChild(fortune_fabula_div)
}
Hooks.once("init", () => {
game.settings.register(MillsFabula.id, FortuneSettings.EnableFortuneDisplay, {
name: game.i18n.localize('MF.Fortune.Settings.DisplayEnabled.Name'),
hint: game.i18n.localize('MF.Fortune.Settings.DisplayEnabled.Hint'),
type: Boolean,
config: true,
scope: 'world',
requiresReload: true,
default: true
});
if (game.settings.get(MillsFabula.id, FortuneSettings.EnableFortuneDisplay)) {
Hooks.on("renderFUPartySheet", party_sheet_fortune)
Hooks.on("renderFUStandardActorSheet", character_sheet_fortune)
}
})

View file

@ -161,10 +161,6 @@ function token_has_played(token, round = -1) {
}
}
// The token can't have played if the combat hasn't started yet.
if (!combat.started)
return false;
let round_turns_taken = combat?.flags.projectfu.CombatantsTurnTaken[round < 0 ? combat?.round : round]
// No token has taken a turn, or all turns were reverted.
@ -203,7 +199,7 @@ function token_combat_visibility_remote_update(scene_id, token_id, round) {
/**
* Called by turn and round hooks, so the borders can be updated when going backwards as well as forwards.
* @param {Combat} combat The combat in which the token is active
* @param {{round: number}} data The turn data for this update
* @param {{round: number, turn: number}} data The turn data for this update
*/
function combat_hook_update_token_borders(combat, data) {
// Turns is the array of *tokens having turns in this encounter*.
@ -243,31 +239,6 @@ function combat_border_main() {
Hooks.on("combatTurn", combat_hook_update_token_borders);
Hooks.on("combatRound", combat_hook_update_token_borders);
// Hook on the combat document update directly to handle active combat switches.
Hooks.on("updateCombat", (combat, changed) => {
// We only care about switching active combats
if (!("active" in changed)) {
return;
}
/*
* The *previous* active combat is switched to inactive *first*, so we can
* just revert all borders to the default state.
* When the new combat becomes active, we can just check as if it were a
* regular combat update.
* This makes sure to handle tokens which were in the previous combat, but not
* in the new one.
*/
if (!changed.active) {
for (let combatant of combat.combatants) {
socket.executeForEveryone(SocketMessages.SetBorder,
combatant.sceneId, combatant.tokenId, false).then();
}
} else {
combat_hook_update_token_borders(combat, {round: combat.round})
}
})
// No Foundry hook on end of combat, so use Fabula Ultima's.
Hooks.on(FUHooks.COMBAT_EVENT, (combat_event) => {
if (combat_event.type === FU.combatEvent.endOfCombat) {

View file

@ -21,8 +21,6 @@ Hooks.once("setup", () => {
/** Padding above and below the token, percentage of a grid square. */
const top_bot_padding = 5;
/** Padding left and right the token, percentage of a grid square. */
const left_right_padding = 5;
Hooks.on("drawToken", (drawn_token) => {
/*
@ -51,9 +49,5 @@ Hooks.once("setup", () => {
base_refreshNameplate()
drawn_token.nameplate.position.set(token_width/2, -(padding + drawn_token.nameplate.height))
}
if (drawn_token.document.hasPlayerOwner)
drawn_token.effects.position.x += drawn_token.getSize().width +
drawn_token.scene.grid.size * (left_right_padding/100);
})
})

View file

@ -1,3 +0,0 @@
.mf-fortune {
background-image: url("/modules/the-mills-fabula/assets/fortune.png");
}