Skip to content

Commit

Permalink
Bugfixes: unlinked tokens and OSE sources.
Browse files Browse the repository at this point in the history
Features: API for macros, help dialogs, "Reclaiming the Wild" support.
  • Loading branch information
lupestro committed Aug 12, 2023
1 parent ebb9ea6 commit c02a4c6
Show file tree
Hide file tree
Showing 16 changed files with 460 additions and 42 deletions.
11 changes: 10 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

## Middle Kingdom - v10 -> main branch

### 2.8.0 - August 12, 2022
- [FEATURE] (Daverd-GM) Provided light sources for "Reclaiming the Wild".
- [FEATURE] (Lupestro) When user has no light sources, a question mark icon comes up instead of the flame icon, opening a dialog explaining what to do.
- [FEATURE] (Lupestro) When a light source is exhausted, clicking the slashed out flame opens a dialog that describes what to do.
- [FEATURE] (Lupestro) Supplied an API of async functions that can be used by macros. Many thanks to Tarubain for the suggestion.
- [BUGFIX] (Lupestro) Fixed problem with unlinked tokens, which no longer have an actor property at all.
- [BUGFIX] (Feldherren) Corrected light source name for "Torches" for OSE.

### 2.7.0 - June 2, 2022
- [FEATURE] (Lupestro) Bumped to install on FoundryVTT 11

Expand All @@ -19,7 +27,8 @@
- [FEATURE] (Lupestro) Now supporting Dungeon Crawl Classics. Many thanks to marcusadmortati for supplying the data and testing.

### 2.2.2 - December 9, 2022
- [BUGFIX] (MrPrimate) Didn't load light sources properly if Foundry was not at root of site. (Thanks MrPrimate for the PR!)
- [BUGFIX] (MrPrimate) Didn't load light sources properly if
Foundry was not at root of site. (Thanks MrPrimate for the PR!)

### 2.2.1 - December 8, 2022
- [BUGFIX] (Lupestro) Fixed URLs in manifest to point to /main/ not /v10/. (Thanks ckdragons for heads-up.)
Expand Down
45 changes: 37 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,35 @@ Even without adding a topology, you can still use Torch with any new system - by

The easiest way I've found to do this is to set an actor's prototype token to use the types you're interested in and then export the actor from the sidebar. When you examine the file it creates, you should be able to see what it called that property on the prototype token's "light" value. That will tell you what string to use for its value in the Torch user settings to get the desired effect.

## API for macro authors

As of 2.8, macro authors can access the following functions of the module through `game.Torch`. All functions are async.

### `game.Torch.toggle(sceneId, tokenId)`
Walks the current light source of the specified token to its next state, returning the name of the state (typically 'on' or 'off' for simple two-state sources).

### `game.Torch.extinguish(sceneId, tokenId)`
Advances the current light source of the specified token to its 'off' state.

### `game.Torch.currentSource(sceneId, tokenId)`
Returns the name of the current light source for the specified token, if any.

### `game.Torch.currentState(sceneId, tokenId)`
Returns the current state of the current light source for the specified token.

### `game.Torch.equippedSources(sceneId, tokenId)`
Returns an array of the names of the light sources equipped by the specified token.

### `game.Torch.selectSource(sceneId, tokenId, source)`
Selects an equipped light source to be the current light source of the token.

### `game.Torch.inventory(sceneId, tokenId, source)`
Returns the remaining quantity of the specified light source for the specified token.


### `game.Torch.sourceExhausted(sceneId, tokenId, source)`
Returns true if the specified light source is consumable, and the instance held by the specified token has no more inventory.

## Changelog - now in [separate file](./CHANGELOG.md)

## Translation Status
Expand All @@ -124,17 +153,17 @@ The following is the current status of translation. Some features have arrived,

| Language | Completion | Contributors |
| -------- | ---------- | ------------ |
| de | `[##################]` 18/18 (100%) | ToGreedy |
| en | `[##################]` 18/18 (100%) | deuce, lupestro |
| es | `[############------]` 12/18 (67%) | lozalojo |
| fr | `[##################]` 18/18 (100%) | Aymeeric |
| pt-br | `[############------]` 12/18 (67%) | rinnocenti |
| zh-cn | `[##########--------]` 10/18 (56%) | xticime |
| zh-tw | `[############------]` 12/18 (67%) | zeteticl |
| de | `[##################----]` 18/22 (82%) | ToGreedy |
| en | `[######################]` 22/22 (100%) | deuce, lupestro |
| es | `[############----------]` 12/22 (55%) | lozanoje |
| fr | `[##################----]` 18/22 (82%) | Aymeeric |
| pt-br | `[############----------]` 12/22 (55%) | rinnocenti |
| zh-cn | `[##########------------]` 10/22 (56%) | xticime |
| zh-tw | `[############----------]` 12/22 (45%) | zeteticl |

PRs for further translations will be dealt with promptly. While Japanese, and Korean are most especially desired - our translation story seems deeply incomplete without them - all others are welcome.

It's only 18 strings so far, a satisfying afternoon, even for someone who's never committed to an open source project before, and your name will go into the readme right here next to the language. Fork, clone, update, _test locally_, commit, and then submit a PR. Holler for @lupestro on Discord if you need help getting started.
Even now, it's only 22 strings, a satisfying afternoon, even for someone who's never committed to an open source project before, and your name will go into the readme right here next to the language. Fork, clone, update, _test locally_, commit, and then submit a PR. Holler for `@lupestro` on Discord if you need help getting started.

## History

Expand Down
100 changes: 100 additions & 0 deletions api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import Settings from "./settings.js";
import SourceLibrary from "./library.js";
import TorchToken from './token.js';

export default class TorchAPI {
async #setup(sceneId, tokenId) {
let scene = game.scenes.get(sceneId);
let tokenDoc = scene.tokens.get(tokenId);
let actor = game.actors.get(tokenDoc.actorId);

let library = await SourceLibrary.load(
game.system.id,
Settings.lightRadii.bright,
Settings.lightRadii.dim,
Settings.inventoryItemName,
Settings.gameLightSources,
actor.prototypeToken.light,
);
return new TorchToken(tokenDoc, library);
}
#parmCheck2(fnname, sceneId, tokenId){
const idPattern = /[A-Za-z0-9]+/;
let result;
if (typeof sceneId !== "string" || !idPattern.test(sceneId)) {
result = "first parm - scene id - isn't an id string";
}
if (typeof tokenId !== "string" || !idPattern.test(tokenId)) {
result = "second parm - token id - isn't an id string";
}
if (result) {
throw (`${fnname} : ${result}`);
}
}

#parmCheck3(fnname, sceneId, tokenId, source){
const idPattern = /[A-Za-z0-9]+/;
let result;
if (typeof sceneId !== "string" || !idPattern.test(sceneId)) {
rresult = "first parm - scene id - isn't an id string";
}
if (typeof tokenId !== "string" || !idPattern.test(tokenId)) {
result = "second parm - token id - isn't an id string";
}
if (typeof source !== "string" || source.length < 1) {
result = "third parm - source name - isn't the name of a light source";
}
if (result) {
throw (`${fnname} : ${result}`);
}
}

async toggle(sceneId, tokenId) {
this.#parmCheck2("toggle", sceneId, tokenId);
let token = await this.#setup(sceneId, tokenId);
return await token.advanceState();
};

async extinguish(sceneId, tokenId) {
this.#parmCheck2("extinguish", sceneId, tokenId);
let token = await this.#setup(sceneId, tokenId);
return await token.forceStateOff();
}

async currentSource(sceneId, tokenId) {
this.#parmCheck2("currentSource", sceneId, tokenId);
let token = await this.#setup(sceneId, tokenId);
return await token.currentLightSource;
}

async currentState(sceneId, tokenId) {
this.#parmCheck2("currentState", sceneId, tokenId);
let token = await this.#setup(sceneId, tokenId);
return await token.lightSourceState;
};

async equippedSources(sceneId, tokenId) {
this.#parmCheck2("equippedSources", sceneId, tokenId);
let token = await this.#setup(sceneId, tokenId);
return await token.ownedLightSources.map(item => item.name);
}

async selectSource(sceneId, tokenId, source) {
this.#parmCheck3("selectSource", sceneId, tokenId, source);
let token = await this.#setup(sceneId, tokenId);
return await token.setCurrentLightSource(source);
};

async inventory(sceneId, tokenId, source) {
this.#parmCheck3("inventory", sceneId, tokenId, source);
let token = await this.#setup(sceneId, tokenId);
return await token.getInventory(source);
}

async sourceExhausted(sceneId, tokenId, source) {
this.#parmCheck3("sourceExhausted", sceneId, tokenId, source);
let token = await this.#setup(sceneId, tokenId);
return await token.lightSourceIsExhausted(source);
};

}
55 changes: 46 additions & 9 deletions hud.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const BUTTON_HTML = `<div class="control-icon torch"><i class="fas fa-fire"></i></div>`;
const QUERY_BUTTON_HTML = `<div class="control-icon torch"><i class="fas fa-question"></i></div>`;
const DISABLED_ICON_HTML = `<i class="fas fa-slash"></i>`;
const SOURCE_MENU = `<div class="control-icon light-source-menu"></div>`;
const SOURCE_MENU_ITEM = (img, tooltip) => {
Expand All @@ -8,6 +9,31 @@ const SOURCE_MENU_ITEM = (img, tooltip) => {
};

export default class TokenHUD {
/*
* Add a button to instruct users how to use the module
*/
static async addQueryButton(
token,
hudHtml
) {
let tbutton = $(QUERY_BUTTON_HTML);
hudHtml.find(".col.left").prepend(tbutton);
tbutton.find("i").click(async (event) => {
event.preventDefault();
event.stopPropagation();
new Dialog({
title: game.i18n.localize("torch.help.setupSources.title"),
content: game.i18n.localize("torch.help.setupSources.body"),
buttons: {
close: {
icon: '<i class="fas fa-check"></i>',
label: "Close"
}
},
default: "close"
}).render(true);
});
}
/*
* Add a torch button to the Token HUD - called from TokenHUD render hook
*/
Expand All @@ -21,7 +47,6 @@ export default class TokenHUD {
) {
let state = token.lightSourceState;
let disabled = token.lightSourceIsExhausted(token.currentLightSource);
let allowEvent = !disabled;
let tbutton = $(BUTTON_HTML);
if (state === token.STATE_ON) {
tbutton.addClass("active");
Expand All @@ -42,11 +67,23 @@ export default class TokenHUD {
TokenHUD.toggleSourceMenu(tbutton, token, changeLightSource);
}
});
if (allowEvent) {
tbutton.find("i").click(async (event) => {
event.preventDefault();
event.stopPropagation();
if (!tbutton.next().hasClass("light-source-menu")) {
tbutton.find("i").click(async (event) => {
event.preventDefault();
event.stopPropagation();
if (!tbutton.next().hasClass("light-source-menu")) {
if (token.lightSourceIsExhausted(token.currentLightSource)) {
new Dialog({
title: game.i18n.localize("torch.help.supplyExhausted.title"),
content: game.i18n.localize("torch.help.supplyExhausted.body"),
buttons: {
close: {
icon: '<i class="fas fa-check"></i>',
label: "Close"
}
},
default: "close"
}).render(true);
} else {
if (event.shiftKey) {
togglelightHeld(token);
} else if (event.altKey) {
Expand All @@ -55,10 +92,10 @@ export default class TokenHUD {
} else {
await toggleLightSource(token);
TokenHUD.syncFlameButtonState(tbutton, token);
}
}
}
});
}
}
});
}

static toggleSourceMenu(button, token, changeLightSource) {
Expand Down
6 changes: 5 additions & 1 deletion lang/cn.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,9 @@
"torch.gameLightSources.name": "Additional Light Sources",
"torch.gameLightSources.hint": "JSON file containing additional light sources to use beyond those supplied",
"torch.brightRadius.name": "Bright Light Radius",
"torch.dimRadius.name": "Dim Light Radius"
"torch.dimRadius.name": "Dim Light Radius",
"torch.help.supplyExhausted.title": "Supply Exhausted",
"torch.help.supplyExhausted.body": "<p>Your light source is consumable and your quantity has dropped to zero. Increase the quantity of the item to light a fresh one.</p>",
"torch.help.setupSources.title": "Setting Up Light Sources",
"torch.help.setupSources.body": "<p>Your character currently has no light sources in their inventory, either as items or as spells.</p><p>For recognized systems, the light sources offered are based on inventory items - by name. Placing known light sources in your inventory will make them available to you. </p><p>Some light sources are consumable, like candles and torches. For these, using a light source decreases its quantity by one.</p><p>For systems that have no inventory-based light sources configured, you can configure light sources through module settings. In this case, all actors get the same light source.</p><p>You can make a system recognized by supplying a JSON file of light sources, as described in the README.md.</p><p>If you have multiple light sources in your inventory, you can choose among them by right-clicking the Torch button on the HUD when you do not have a light source lit.</p>"
}
6 changes: 5 additions & 1 deletion lang/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,9 @@
"torch.gameLightSources.name": "Zusätzliche Lichtquellen",
"torch.gameLightSources.hint": "JSON Datei mit zusätzlichen Lichtquellen, die über die mitgelieferten hinaus verwendet werden sollen",
"torch.brightRadius.name": "Radius des hellen Licht",
"torch.dimRadius.name": "Radius des gedämpften Licht"
"torch.dimRadius.name": "Radius des gedämpften Licht",
"torch.help.supplyExhausted.title": "Supply Exhausted",
"torch.help.supplyExhausted.body": "<p>Your light source is consumable and your quantity has dropped to zero. Increase the quantity of the item to light a fresh one.</p>",
"torch.help.setupSources.title": "Setting Up Light Sources",
"torch.help.setupSources.body": "<p>Your character currently has no light sources in their inventory, either as items or as spells.</p><p>For recognized systems, the light sources offered are based on inventory items - by name. Placing known light sources in your inventory will make them available to you. </p><p>Some light sources are consumable, like candles and torches. For these, using a light source decreases its quantity by one.</p><p>For systems that have no inventory-based light sources configured, you can configure light sources through module settings. In this case, all actors get the same light source.</p><p>You can make a system recognized by supplying a JSON file of light sources, as described in the README.md.</p><p>If you have multiple light sources in your inventory, you can choose among them by right-clicking the Torch button on the HUD when you do not have a light source lit.</p>"
}
6 changes: 5 additions & 1 deletion lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,9 @@
"torch.gameLightSources.name": "Additional Light Sources",
"torch.gameLightSources.hint": "JSON file containing additional light sources to use beyond those supplied",
"torch.brightRadius.name": "Bright Light Radius",
"torch.dimRadius.name": "Dim Light Radius"
"torch.dimRadius.name": "Dim Light Radius",
"torch.help.supplyExhausted.title": "Supply Exhausted",
"torch.help.supplyExhausted.body": "<p>Your light source is consumable and your quantity has dropped to zero. Increase the quantity of the item to light a fresh one.</p>",
"torch.help.setupSources.title": "Setting Up Light Sources",
"torch.help.setupSources.body": "<p>Your character currently has no light sources in their inventory, either as items or as spells.</p><p>For recognized systems, the light sources offered are based on inventory items - by name. Placing known light sources in your inventory will make them available to you. </p><p>Some light sources are consumable, like candles and torches. For these, using a light source decreases its quantity by one.</p><p>For systems that have no inventory-based light sources configured, you can configure light sources through module settings. In this case, all actors get the same light source.</p><p>You can make a system recognized by supplying a JSON file of light sources, as described in the README.md.</p><p>If you have multiple light sources in your inventory, you can choose among them by right-clicking the Torch button on the HUD when you do not have a light source lit.</p>"
}
6 changes: 5 additions & 1 deletion lang/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,9 @@
"torch.gameLightSources.name": "Additional Light Sources",
"torch.gameLightSources.hint": "JSON file containing additional light sources to use beyond those supplied",
"torch.brightRadius.name": "Bright Light Radius",
"torch.dimRadius.name": "Dim Light Radius"
"torch.dimRadius.name": "Dim Light Radius",
"torch.help.supplyExhausted.title": "Supply Exhausted",
"torch.help.supplyExhausted.body": "<p>Your light source is consumable and your quantity has dropped to zero. Increase the quantity of the item to light a fresh one.</p>",
"torch.help.setupSources.title": "Setting Up Light Sources",
"torch.help.setupSources.body": "<p>Your character currently has no light sources in their inventory, either as items or as spells.</p><p>For recognized systems, the light sources offered are based on inventory items - by name. Placing known light sources in your inventory will make them available to you. </p><p>Some light sources are consumable, like candles and torches. For these, using a light source decreases its quantity by one.</p><p>For systems that have no inventory-based light sources configured, you can configure light sources through module settings. In this case, all actors get the same light source.</p><p>You can make a system recognized by supplying a JSON file of light sources, as described in the README.md.</p><p>If you have multiple light sources in your inventory, you can choose among them by right-clicking the Torch button on the HUD when you do not have a light source lit.</p>"
}
6 changes: 5 additions & 1 deletion lang/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,9 @@
"torch.gameLightSources.name": "Sources de lumière additionnelles",
"torch.gameLightSources.hint": "Fichier JSON contenant des sources de lumière supplémentaires à utiliser en plus de celles fournies",
"torch.brightRadius.name": "Étendue lumière vive",
"torch.dimRadius.name": "Étendue lumière faible"
"torch.dimRadius.name": "Étendue lumière faible",
"torch.help.supplyExhausted.title": "Supply Exhausted",
"torch.help.supplyExhausted.body": "<p>Your light source is consumable and your quantity has dropped to zero. Increase the quantity of the item to light a fresh one.</p>",
"torch.help.setupSources.title": "Setting Up Light Sources",
"torch.help.setupSources.body": "<p>Your character currently has no light sources in their inventory, either as items or as spells.</p><p>For recognized systems, the light sources offered are based on inventory items - by name. Placing known light sources in your inventory will make them available to you. </p><p>Some light sources are consumable, like candles and torches. For these, using a light source decreases its quantity by one.</p><p>For systems that have no inventory-based light sources configured, you can configure light sources through module settings. In this case, all actors get the same light source.</p><p>You can make a system recognized by supplying a JSON file of light sources, as described in the README.md.</p><p>If you have multiple light sources in your inventory, you can choose among them by right-clicking the Torch button on the HUD when you do not have a light source lit.</p>"
}
Loading

0 comments on commit c02a4c6

Please sign in to comment.