diff --git a/test/TESTCASES.md b/test/TESTCASES.md
index 02e624a..485d26a 100644
--- a/test/TESTCASES.md
+++ b/test/TESTCASES.md
@@ -61,7 +61,7 @@
### Token with No Torches, No Cantrips
-* Player aattempts to activate torch on Token
+* Player attempts to activate torch on Token
* When:
- [ ] Light Radius settings are default (20 units/ 40 units, 0 units/0 units)
- [ ] Player Torches setting are checked
@@ -69,15 +69,12 @@
- [ ] Token HUD is open in scene
- [ ] Torch button is not activated
* Expect:
- - [ ] Torch button icon shows disabled status - orange slash through it
- * Do: Player clicks torch button on token HUD
- * Expect:
- - [ ] Nothing happens
+ - [ ] Torch button does not appear
-* GM aattempts to activate torch on Token
+* GM attempts to activate torch on Token
* When:
- [ ] Light Radius settings are default (20 units/ 40 units, 0 units/0 units)
- - [ ] Player Torches setting are checked
+ - [ ] Player Torches setting is checked
- [ ] GM Uses Inventory is checked
- [ ] Joined as GM
- [ ] Token HUD is open in scene
diff --git a/test/env/TESTENV.md b/test/env/TESTENV.md
index 9edab8c..8b582ce 100644
--- a/test/env/TESTENV.md
+++ b/test/env/TESTENV.md
@@ -40,7 +40,7 @@ For each version of Foundry you'll be testing with, set it up for testing:
3. Install the systems, then the modules, and then the test worlds.
* For Torch:
* Systems: `DnD5e` and `Simple Worldbuilding System`
- * Modules: `Translation: Spanish \[Core]` and the module under test
+ * Modules: `Translation: Spanish \[Core]`, `Quench`, and the module under test
* Worlds: `torch-test-simple` and `torch-test-dnd5e`:
* https://raw.githubusercontent.com/League-of-Foundry-Developers/torch/master/test/torch-test-simple/world.json
* https://raw.githubusercontent.com/League-of-Foundry-Developers/torch/master/test/torch-test-5e/world.json
diff --git a/test/env/vttstart.bat b/test/env/vttstart.bat
index 5560ded..7e6975f 100644
--- a/test/env/vttstart.bat
+++ b/test/env/vttstart.bat
@@ -4,6 +4,7 @@ rem Set up structure for keeping data paths
if not exist %~dp0Data mkdir %~dp0Data
rem Determine Foundry subtree to use for this major version
IF "%1"=="" ( SET "VTTNUM=8" ) ELSE ( SET "VTTNUM=%1" )
+if "%VTTNUM%"=="9" SET VTTVER=foundryvtt-0.9.226
if "%VTTNUM%"=="8" SET VTTVER=foundryvtt-0.8.8
if "%VTTNUM%"=="7" SET VTTVER=foundryvtt-0.7.10
if "%VTTVER%"=="" ECHO "Invalid Foundry major version specified" && EXIT /B -1
diff --git a/test/env/vttstart.sh b/test/env/vttstart.sh
index f84e26b..effc5cc 100755
--- a/test/env/vttstart.sh
+++ b/test/env/vttstart.sh
@@ -6,6 +6,7 @@ fi
case ${1:-8} in
7) vttver="foundryvtt-0.7.10";;
8) vttver="foundryvtt-0.8.8";;
+ 9) vttver="foundryvtt-0.9.226";;
esac
if [ -z ${vttver} ]; then
echo "Invalid Foundry major version specified"
diff --git a/test/generic-basic-tests.js b/test/generic-basic-tests.js
index 822724e..7f70ded 100644
--- a/test/generic-basic-tests.js
+++ b/test/generic-basic-tests.js
@@ -12,12 +12,12 @@ export let torchGenericBasicTests = (context) => {
describe('Tests Run As Gamemaster', () => {
it('gamemaster controls the token light levels when playerTorches is false',
async () => {
- await game.settings.set('torch','playerTorches', true);
+ await game.settings.set('torch', 'playerTorches', false);
await torchButtonToggles(assert, game, ACTOR, 20, 40);
});
it('gamemaster controls the token light levels when playerTorches is true',
async () => {
- await game.settings.set('torch','playerTorches', true);
+ await game.settings.set('torch', 'playerTorches', true);
await torchButtonToggles(assert, game, ACTOR, 20, 40);
});
});
diff --git a/test/test-cases.js b/test/test-cases.js
index 06922a1..e22f16e 100644
--- a/test/test-cases.js
+++ b/test/test-cases.js
@@ -1,59 +1,122 @@
import { waitUntil } from './test-utils.js';
+
+let getLightRadii = (data) => {
+ return data.light
+ ? { bright: data.light.bright, dim: data.light.dim }
+ : { bright: data.brightLight, dim: data.dimLight };
+}
+let lightRadiiForUpdate = async (data, bright, dim) => {
+ return data.light
+ ? { "light.bright": bright, "ight.dim": dim }
+ : { "brightLight": bright,"dimLight": dim };
+}
+
export let torchButtonToggles = async (
- assert, game, actor, brightOnRadius, dimOnRadius, brightOffRadius = 0, dimOffRadius = 0
+ assert, game, actor, brightOnRadius, dimOnRadius,
+ brightOffRadius = 0, dimOffRadius = 0
) => {
- let token = game.scenes.current.tokens.find(token => token.name === actor);
- game.canvas.hud.token.bind(token.object);
+ let token = game.scenes.current.tokens.find(
+ token => token.name === actor);
+
+ // Open the token HUD for the targeted token
+ let tokenHUD = game.canvas.hud.token;
+ tokenHUD.bind(token.object);
await waitUntil(() => {
- return game.canvas.hud.token.element.find(`.col.left div`).length > 0;
+ return tokenHUD.element.find(`.col.left div`).length > 0;
}, "HUD is up");
- let hudButtons = game.canvas.hud.token.element.find(`.col.left div`);
- assert.isTrue(hudButtons.first().hasClass('torch'), 'First button is the Torch button');
+
+ // Examine the initial condition of the HUD
+ let hudButtons = tokenHUD.element.find(`.col.left div`);
+ assert.isTrue(
+ hudButtons.first().hasClass('torch'),
+ 'First button is the Torch button');
console.log("OldValue upon entry:", token.data.flags.torch?.oldValue);
- hudButtons = game.canvas.hud.token.element.find(`.col.left div`);
+ hudButtons = tokenHUD.element.find(`.col.left div`);
+ assert.isFalse(
+ hudButtons.first().hasClass('active'),
+ "Torch isn't active before click");
+
+ // Click to turn on light
hudButtons.first().find('i').click();
+ let expectedFlag = `${brightOffRadius}/${dimOffRadius}`;
await waitUntil(() => {
- return token.data.brightLight > brightOffRadius;
+ return getLightRadii(token.data).bright > brightOffRadius;
},"Torch is lit");
- assert.equal(token.data.brightLight, brightOnRadius, 'Bright light is the configured value for ON');
- assert.equal(token.data.dimLight, dimOnRadius, 'Dim light is the configured value for ON');
- hudButtons = game.canvas.hud.token.element.find(`.col.left div`);
+ await waitUntil(() => {
+ return token.data.flags.torch?.oldValue === expectedFlag;
+ }, "Torch flag is set");
+
+ // Check conditions after turning on light
+ assert.equal(
+ getLightRadii(token.data).bright, brightOnRadius,
+ 'Bright light is the configured value for ON');
+ assert.equal(
+ getLightRadii(token.data).dim, dimOnRadius,
+ 'Dim light is the configured value for ON');
+ hudButtons = tokenHUD.element.find(`.col.left div`);
+ await waitUntil(() => {
+ return hudButtons.first().hasClass('active');
+ }, "Torch button active after first click");
+
+ // Click to turn off light
hudButtons.first().find('i').click();
await waitUntil(() => {
- return token.data.brightLight < brightOnRadius;
+ return getLightRadii(token.data).bright < brightOnRadius;
}, "Torch is unlit");
- assert.equal(token.data.brightLight, brightOffRadius, 'Bright light is the configured value for OFF');
- assert.equal(token.data.dimLight, dimOffRadius, 'Dim light is the configured value for OFF');
await waitUntil(() => {
return token.data.flags.torch?.oldValue === null;
}, "Torch flag is cleared");
+
+ // Check conditions after turning off light
+ assert.equal(
+ getLightRadii(token.data).bright, brightOffRadius,
+ 'Bright light is the configured value for OFF');
+ assert.equal(
+ getLightRadii(token.data).dim, dimOffRadius,
+ 'Dim light is the configured value for OFF');
+ assert.isFalse(
+ hudButtons.first().hasClass('active'),
+ "Torch button inactive after second click");
}
export let torchButtonAbsent = async (
assert, game, actor, brightOffRadius = 0, dimOffRadius = 0
) => {
- let token = game.scenes.current.tokens.find(token => token.name === actor);
- game.canvas.hud.token.bind(token.object);
+ let token = game.scenes.current.tokens.find(
+ token => token.name === actor);
+ let tokenHUD = game.canvas.hud.token;
+
+ // Open the token HUD for the targeted token
+ tokenHUD.bind(token.object);
await waitUntil(() => {
- return game.canvas.hud.token.element.find(`.col.left div`).length > 0;
+ return tokenHUD.element.find(`.col.left div`).length > 0;
}, "HUD is up");
- let hudButtons = game.canvas.hud.token.element.find(`.col.left div`);
- assert.isFalse(hudButtons.first().hasClass('torch'), 'First button is the Torch button');
- assert.equal(token.data.brightLight, brightOffRadius);
- assert.equal(token.data.dimLight, dimOffRadius);
+
+ // Verify that light button isn't on HUD
+ let hudButtons = tokenHUD.element.find(`.col.left div`);
+ assert.isFalse(
+ hudButtons.first().hasClass('torch'),
+ 'First button is the Torch button');
+
+ // Verify that the lights are off
+ assert.equal(getLightRadii(token.data).bright, brightOffRadius);
+ assert.equal(getLightRadii(token.data).dim, dimOffRadius);
}
export let cleanup = async (
assert, game, actor, brightOffRadius = 0, dimOffRadius = 0
) => {
+ // Make sure playerTorches is off
if (game.users.current.name === 'Gamemaster') {
await game.settings.set('torch','playerTorches', true);
}
- let token = game.scenes.current.tokens.find(token => token.name === actor);
- await token.update({
- "data.brightLight": brightOffRadius,
- "data.dimLight": dimOffRadius
- });
+ // Make sure lights are off
+ let token = game.scenes.current.tokens.find(
+ token => token.name === actor);
+ await token.update(
+ lightRadiiForUpdate(token.data, brightOffRadius, dimOffRadius));
+
+ // Make sure token HUD is closed
await game.canvas.hud.token.clear();
}
diff --git a/test/vttlink.sh b/test/vttlink.sh
index 15ef5e3..c58124d 100755
--- a/test/vttlink.sh
+++ b/test/vttlink.sh
@@ -14,10 +14,15 @@ do
rm $targetdir/$(basename $file)
ln -s $file $targetdir/$(basename $file)
done
+if [ ! -d $targetdir/test ]; then
+ mkdir $targetdir/test
+fi
# Replace javascript in test directory with link
for file in $clonedir/test/*.js
do
echo test/$(basename $file)
- rm $targetdir/test/$(basename $file)
+ if [ -f "$targetdir/test/$(basename $file)" ]; then
+ rm $targetdir/test/$(basename $file)
+ fi
ln -s $file $targetdir/test/$(basename $file)
done
diff --git a/torch.js b/torch.js
index 11a9d39..97050ac 100644
--- a/torch.js
+++ b/torch.js
@@ -7,13 +7,42 @@
* ----------------------------------------------------------------------------
*/
-let DEBUG = false;
+let DEBUG = true;
let debugLog = (...args) => {
if (DEBUG) {
console.log (...args);
}
}
+
+const BUTTON_HTML =
+ `
`;
+const DISABLED_ICON_HTML =
+ ``;
+const CTRL_REF_HTML = (turnOffLights, ctrlOnClick) => {
+ return `
+Torch
+
+ -
+
${turnOffLights}
+ ${ctrlOnClick}
+
+
+`
+}
+
+// Breaking out light data into its own object is a FoundryVTT 9 feature change
+let getLightRadii = (tokenData) => {
+ return {
+ bright: tokenData.light ? tokenData.light.bright : tokenData.brightLight,
+ dim: tokenData.light ? tokenData.light.dim : tokenData.dimLight
+ };
+}
+let newLightRadii = (tokenData, bright, dim) => {
+ return tokenData.light
+ ? { "light.bright": bright, "light.dim": dim }
+ : { brightLight: bright, dimLight: dim };
+}
class Torch {
static async createDancingLights(tokenId) {
@@ -88,15 +117,18 @@ class Torch {
/*
* Identify the type of light source we will be using.
- * If not D&D5e, either a player or GM "fiat-lux".
- * IF DND5e:
+ * Outside of D&D5e, either a player or GM can call for "fiat-lux".
+ * Within DND5e, it invokes:
* - One of the spells if you've got it - first Dancing Lights then Light.
* - Otherwise, the specified torch item if you've got it.
- * - Failing all of those, a GM "fiat-lux" or none.
+ * - An indicator if you ran out of torches.
+ * - Failing all of those, a player doesn't even get a button to click.
+ * - However, a GM can always call for "fiat-lux".
*/
static getLightSourceType(actorId, itemName) {
if (game.system.id !== 'dnd5e') {
- let playersControlTorches = game.settings.get("torch", "playerTorches");
+ let playersControlTorches =
+ game.settings.get("torch", "playerTorches");
return game.user.isGM ? 'GM' : playersControlTorches ? 'Player' : '';
} else {
let items = Array.from(game.actors.get(actorId).data.items);
@@ -120,8 +152,7 @@ class Torch {
return item.name.toLowerCase() === itemName.toLowerCase();
});
let quantity = torchItem.data.data
- ? torchItem.data.data.quantity
- : item.data.quantity;
+ ? torchItem.data.data.quantity : item.data.quantity;
return quantity > 0 ? itemName : '0';
}
// GM can always deliver light by fiat without an item
@@ -130,7 +161,7 @@ class Torch {
}
/*
- * Track inventory for torch uses if we are using a torch as our light source.
+ * Track torch inventory if we are using a torch as our light source.
*/
static async consumeTorch(actorId) {
// Protect against all conditions where we should not consume a torch
@@ -156,9 +187,10 @@ class Torch {
}
} else { //0.7 and down
if (torchItem.data.quantity > 0) {
- await game.actors.get(actorId).updateOwnedItem(
- {"_id": torchItem._id, "data.quantity": torchItem.data.quantity - 1}
- );
+ await game.actors.get(actorId).updateOwnedItem({
+ "_id": torchItem._id,
+ "data.quantity": torchItem.data.quantity - 1
+ });
}
}
}
@@ -170,39 +202,42 @@ class Torch {
static async addTorchButton(tokenHUD, hudHtml, hudData) {
let tokenId = tokenHUD.object.id;
- let tokenDoc = tokenHUD.object.document ? tokenHUD.object.document : tokenHUD.object;
+ let tokenDoc = tokenHUD.object.document
+ ? tokenHUD.object.document : tokenHUD.object;
let tokenData = tokenDoc.data;
- let itemName = game.system.id === 'dnd5e' ? game.settings.get("torch", "gmInventoryItemName") : "";
+ let itemName = game.system.id === 'dnd5e'
+ ? game.settings.get("torch", "gmInventoryItemName") : "";
let torchDimRadius = game.settings.get("torch", "dimRadius");
let torchBrightRadius = game.settings.get("torch", "brightRadius");
+ let currentRadius = getLightRadii(tokenData);
- // Don't let the tokens we create for Dancing Lights have or use torches. :D
- if (tokenData.name === 'Dancing Light' &&
- tokenData.dimLight === 10 && tokenData.brightLight === 0) {
+ // Don't let the tokens we create for Dancing Lights have or use torches.
+ if (tokenData.name === 'Dancing Light'
+ && currentRadius.dim === 10 && currentRadius.bright === 0
+ ) {
return;
}
let lightSource = Torch.getLightSourceType(tokenData.actorId, itemName);
if (lightSource !== '') {
- let tbutton = $(
- `
`);
+ let tbutton = $(BUTTON_HTML);
let allowEvent = true;
let oldTorch = tokenDoc.getFlag("torch", "oldValue");
let newTorch = tokenDoc.getFlag("torch", "newValue");
let tokenTooBright = lightSource !== 'Dancing Lights'
- && tokenData.brightLight > torchBrightRadius
- && tokenData.dimLight > torchDimRadius;
+ && currentRadius.bright > torchBrightRadius
+ && currentRadius.dim > torchDimRadius;
// Clear torch flags if light has been changed somehow.
- let expectedTorch = tokenData.brightLight + '/' + tokenData.dimLight;
+ let expectedTorch = currentRadius.bright + '/' + currentRadius.dim;
if (newTorch !== undefined && newTorch !== null &&
newTorch !== 'Dancing Lights' && newTorch !== expectedTorch) {
await tokenDoc.setFlag("torch", "oldValue", null);
await tokenDoc.setFlag("torch", "newValue", null);
oldTorch = null;
newTorch = null;
- ui.notifications.warn(
- `Torch: Resetting out-of-sync torch - current light: ${expectedTorch}, light in flag: ${newTorch}`);
+ console.warn(
+ `Torch: Resynchronizing - ${expectedTorch}, ${newTorch}`);
}
if (newTorch !== undefined && newTorch !== null) {
@@ -211,8 +246,7 @@ class Torch {
}
else if (
lightSource === '0' || tokenTooBright) {
- let disabledIcon = $(
- ``);
+ let disabledIcon = $(DISABLED_ICON_HTML);
tbutton.addClass("fa-stack");
tbutton.find('i').addClass('fa-stack-1x');
disabledIcon.addClass('fa-stack-1x');
@@ -235,7 +269,9 @@ class Torch {
/*
* Called when the torch button is clicked
*/
- static async clickedTorchButton(button, forceOff, tokenId, tokenDoc, lightSource) {
+ static async clickedTorchButton(
+ button, forceOff, tokenId, tokenDoc, lightSource
+ ) {
debugLog("Torch clicked");
let torchOnDimRadius = game.settings.get("torch", "dimRadius");
let torchOnBrightRadius = game.settings.get("torch", "brightRadius");
@@ -243,43 +279,54 @@ class Torch {
let torchOffBrightRadius = game.settings.get("torch", "offBrightRadius");
let oldTorch = tokenDoc.getFlag("torch", "oldValue");
let tokenData = tokenDoc.data;
+ let currentRadius = getLightRadii(tokenData);
if (forceOff) { // Forcing light off...
await tokenDoc.setFlag("torch", "oldValue", null);
await tokenDoc.setFlag("torch", "newValue", null);
- await Torch.sendRequest(tokenId, {"requestType": "removeDancingLights"});
+ await Torch.sendRequest(
+ tokenId, {"requestType": "removeDancingLights"});
button.removeClass("active");
- await tokenDoc.update(
- { brightLight: torchOffBrightRadius, dimLight: torchOffDimRadius });
- debugLog("Force torch off");
+ await tokenDoc.update(newLightRadii(
+ tokenData, torchOffBrightRadius, torchOffDimRadius
+ ));
+ debugLog("Force torch off");
- } else if (oldTorch === null || oldTorch === undefined) { // Turning light on...
- if (tokenData.brightLight === torchOnBrightRadius && tokenData.dimLight === torchOnDimRadius) {
+ // Turning light on...
+ } else if (oldTorch === null || oldTorch === undefined) {
+ if (currentRadius.bright === torchOnBrightRadius
+ && currentRadius.dim === torchOnDimRadius
+ ) {
await tokenDoc.setFlag(
- "torch", "oldValue", torchOffBrightRadius + '/' + torchOnDimRadius);
- ui.notifications.warn(`Torch: Turning on torch already turned on?`);
+ "torch", "oldValue",
+ torchOffBrightRadius + '/' + torchOffDimRadius);
+ console.warn(`Torch: Turning on torch that's already turned on?`);
} else {
await tokenDoc.setFlag(
- "torch", "oldValue", tokenData.brightLight + '/' + tokenData.dimLight);
+ "torch", "oldValue",
+ currentRadius.bright + '/' + currentRadius.dim);
}
if (lightSource === 'Dancing Lights') {
await Torch.createDancingLights(tokenId);
await tokenDoc.setFlag("torch", "newValue", 'Dancing Lights');
debugLog("Torch dance on");
} else {
- let newBrightLight = Math.max(torchOnBrightRadius, tokenData.brightLight);
- let newDimLight = Math.max(torchOnDimRadius, tokenData.dimLight);
+ let newBrightLight =
+ Math.max(torchOnBrightRadius, currentRadius.bright);
+ let newDimLight =
+ Math.max(torchOnDimRadius, currentRadius.dim);
await tokenDoc.setFlag(
"torch", "newValue", newBrightLight + '/' + newDimLight);
- await tokenDoc.update({
- brightLight: newBrightLight, dimLight: newDimLight
- });
+ await tokenDoc.update(newLightRadii(
+ tokenData, newBrightLight, newDimLight
+ ));
debugLog("Torch on");
}
- // Any token light data update must happen before we call consumeTorch(),
- // because the quantity change in consumeTorch() triggers the HUD to re-render,
- // which triggers addTorchButton again. addTorchButton won't work right unless
- // the change in light from the click is already a "done deal".
+ // Any token light data update must happen before we call
+ // consumeTorch(), because the quantity change in consumeTorch()
+ // triggers the HUD to re-render, which triggers addTorchButton again.
+ // addTorchButton won't work right unless the change in light from
+ // the click is already a "done deal".
button.addClass("active");
await Torch.consumeTorch(tokenData.actorId);
@@ -287,20 +334,22 @@ class Torch {
let oldTorch = tokenDoc.getFlag("torch", "oldValue");
let newTorch = tokenDoc.getFlag("torch", "newValue");
if (newTorch === 'Dancing Lights') {
- await Torch.sendRequest(tokenId, {"requestType": "removeDancingLights"});
+ await Torch.sendRequest(
+ tokenId, {"requestType": "removeDancingLights"});
debugLog("Torch dance off");
} else {
- let thereBeLight = oldTorch.split('/');
- if (oldTorch === newTorch) { // Something got lost - avoiding getting stuck
- await tokenDoc.update({
- brightLight: torchOffBrightRadius,
- dimLight: torchOffDimRadius
- });
+ // Something got lost - avoiding getting stuck
+ if (oldTorch === newTorch) {
+ await tokenDoc.update(newLightRadii(
+ tokenData, torchOffBrightRadius, torchOffDimRadius
+ ));
} else {
- await tokenDoc.update({
- brightLight: parseFloat(thereBeLight[0]),
- dimLight: parseFloat(thereBeLight[1])
- });
+ let thereBeLight = oldTorch.split('/');
+ await tokenDoc.update(newLightRadii(
+ tokenData,
+ parseFloat(thereBeLight[0]),
+ parseFloat(thereBeLight[1])
+ ));
}
debugLog("Torch off");
}
@@ -320,7 +369,9 @@ class Torch {
if (req.addressTo === undefined || req.addressTo === game.user._id) {
let scene = game.scenes.get(req.sceneId);
let reqToken = scene.data.tokens.find((token) => {
- return token.id ? (token.id === req.tokenId) : (token._id === req.tokenId);
+ return token.id
+ ? (token.id === req.tokenId)
+ : (token._id === req.tokenId);
});
let actorId = reqToken.actor ? reqToken.actor.id : reqToken.actorId;
let dltoks=[];
@@ -329,10 +380,16 @@ class Torch {
case 'removeDancingLights':
scene.data.tokens.forEach(token => {
let tokenData = token.data ? token.data : token;
- let tokenActorId = (token.actor ? token.actor.id : token.actorId);
+ let tokenActorId = token.actor
+ ? token.actor.id : token.actorId;
+ let currentRadius = getLightRadii(tokenData);
+
// If the token is a dancing light owned by this actor
- if (actorId === tokenActorId && token.name === 'Dancing Light' &&
- 10 === tokenData.dimLight && 0 === tokenData.brightLight) {
+ if (actorId === tokenActorId
+ && token.name === 'Dancing Light'
+ && 10 === currentRadius.dim
+ && 0 === currentRadius.bright
+ ) {
if (scene.getEmbeddedDocument) { // 0.8 or higher
dltoks.push(scene.getEmbeddedDocument("Token", token.id).id);
} else { // 0.7 or lower
@@ -356,12 +413,11 @@ Hooks.on('ready', () => {
Torch.addTorchButton(app, html, data)
});
Hooks.on('renderControlsReference', (app, html, data) => {
+ let turnOffLights = game.i18n.localize("torch.turnOffAllLights");
+ let ctrlOnClick = game.i18n.localize("torch.holdCtrlOnClick");
html.find('div').first().append(
- 'Torch
'+
- game.i18n.localize("torch.turnOffAllLights")+
- '
'+
- game.i18n.localize("torch.holdCtrlOnClick")+
- '
');
+ CTRL_REF_HTML(turnOffLights, ctrlOnClick)
+ );
});
game.socket.on("module.torch", request => {
Torch.handleSocketRequest(request);