Compare commits
7 commits
Author | SHA1 | Date | |
---|---|---|---|
6d4c5b74dc | |||
67d4b0387a | |||
eba433cc05 | |||
b1bde69a7d | |||
3914c979b2 | |||
f6437d7884 | |||
cc7db632d1 |
9 changed files with 204 additions and 20 deletions
24
README.md
24
README.md
|
@ -1,4 +1,4 @@
|
|||
# The Mill's Fabula - v0.3.0
|
||||
# The Mill's Fabula - v0.4.0
|
||||
|
||||
This little [FoundryVTT](https://foundryvtt.com/) module is a collection of compendiums and functionalities
|
||||
to power our Fabula Ultima campaigns.
|
||||
|
@ -36,20 +36,14 @@ 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 which are drawn over the token's
|
||||
square.
|
||||
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.
|
||||
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
|
||||
|
||||
|
@ -57,6 +51,14 @@ As this is where the nameplate of the token should be, move it above the token i
|
|||
- 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,
|
||||
|
|
BIN
assets/fortune.png
Normal file
BIN
assets/fortune.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 565 B |
11
lang/en.json
11
lang/en.json
|
@ -22,7 +22,16 @@
|
|||
"Settings": {
|
||||
"Enabled": {
|
||||
"Name": "Token UI adjustments",
|
||||
"Hint": "Moves both attribute bars below the token and the nameplate above."
|
||||
"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."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
11
lang/fr.json
11
lang/fr.json
|
@ -22,7 +22,16 @@
|
|||
"Settings": {
|
||||
"Enabled": {
|
||||
"Name": "Ajustements d'interface des tokens",
|
||||
"Hint": "Déplace les barres d'attributs sous le token et le nom au dessus."
|
||||
"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."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
18
module.json
18
module.json
|
@ -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.3.0",
|
||||
"version": "0.4.0",
|
||||
"compatibility": {
|
||||
"minimum": "12",
|
||||
"verified": "12",
|
||||
|
@ -28,7 +28,8 @@
|
|||
"compatibility": {
|
||||
"verified": [
|
||||
"2.4.10",
|
||||
"3.0.2"
|
||||
"3.0.2",
|
||||
"3.1.7"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -38,7 +39,10 @@
|
|||
"id": "socketlib",
|
||||
"type": "module",
|
||||
"compatibility": {
|
||||
"verified": "1.1.2"
|
||||
"verified": [
|
||||
"1.1.2",
|
||||
"1.1.3"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -51,7 +55,11 @@
|
|||
],
|
||||
"esmodules": [
|
||||
"scripts/token_combat_border.mjs",
|
||||
"scripts/token_ui_adjust.mjs"
|
||||
"scripts/token_ui_adjust.mjs",
|
||||
"scripts/fortune_integration.mjs"
|
||||
],
|
||||
"styles": [
|
||||
"styles/mills_fabula.css"
|
||||
],
|
||||
"socket": true,
|
||||
|
||||
|
@ -82,5 +90,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.3.0.zip"
|
||||
"download": "https://git.tfk-astrodome.net/trotFunky/TheMillsFabula/archive/v0.4.0.zip"
|
||||
}
|
||||
|
|
118
scripts/fortune_integration.mjs
Normal file
118
scripts/fortune_integration.mjs
Normal file
|
@ -0,0 +1,118 @@
|
|||
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)
|
||||
}
|
||||
})
|
|
@ -161,6 +161,10 @@ 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.
|
||||
|
@ -199,7 +203,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, turn: number}} data The turn data for this update
|
||||
* @param {{round: 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*.
|
||||
|
@ -239,6 +243,31 @@ 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) {
|
||||
|
|
|
@ -21,6 +21,8 @@ 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) => {
|
||||
/*
|
||||
|
@ -49,5 +51,9 @@ 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);
|
||||
})
|
||||
})
|
||||
|
|
3
styles/mills_fabula.css
Normal file
3
styles/mills_fabula.css
Normal file
|
@ -0,0 +1,3 @@
|
|||
.mf-fortune {
|
||||
background-image: url("/modules/the-mills-fabula/assets/fortune.png");
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue