diff --git a/README.md b/README.md index 7761a95..301389f 100644 --- a/README.md +++ b/README.md @@ -64,13 +64,18 @@ To interact with a door, journal, ecc., the player need to have a token selected * Add distance calculation for note and journal on the canvas * Automatically flag journal notes to show on the map without having to have your players turn it on themselves. -### Token Feature (On developing) +### Token Feature (Beta need feedback) -* Add distance calculation for owned source token and generic target token on the canvas for open the sheet and emualte a loot chest +* Add distance calculation for owned source token and generic target token on the canvas for open the sheet and emulate a loot chest * GM can't use this feature because they owned every token so you must set the explicit the source token on module setting * This feature work with only one owned source token on the canvas at the time * You must set the name of your source token (not the character name) on the module setting * If no source token is setted on the module setting the module take the first owned token of the player + +### Light Feature (Beta need feedback) + +* This feature make sense only with one of this module active [Lightswitch by theripper93](https://www.reddit.com/r/FoundryVTT/comments/pmu4z0/lightswitch_a_user_frendly_way_to_present/) (from [theripper93](https://www.patreon.com/theripper93) only patreon page) or [LightSwitch](https://github.com/zarmstrong/fvtt-lightswitch) +* Add distance calculation for light on the canvas ### Reset Doors and Fog feature Feature diff --git a/changelog.md b/changelog.md index 344d818..d2057ed 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,10 @@ # CHANGELOG +# 2.0.11 + +- Little bug fix on the socket listener +- Add the first beta version of the Light Reach feature + # 2.0.10 - Added github workflow diff --git a/package.json b/package.json index 427694a..bc9fdf9 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "name": "foundryvtt-arms-reach", "title": "FoundryVTT Arms Reach", "description": "Allows the GM to limit the distance that a player can interate with a placeable object like door, journal, stairway, token, ecc..", - "version": "2.0.10", + "version": "2.0.11", "scripts": { "package": "gulp package", "build": "gulp build && gulp link", diff --git a/src/lang/en.json b/src/lang/en.json index f6e4ce3..dfae469 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -25,6 +25,11 @@ "foundryvtt-arms-reach.tokensNotInReach": "Token not in reach or is locked", "foundryvtt-arms-reach.tokensNotInReachFor": "Token not within {tokenName}'s reach or is locked", + "foundryvtt-arms-reach.lightsNotFoundInReach": "No light was found within reach or is locked.", + "foundryvtt-arms-reach.lightsNotFoundInReachFor": "No light was found within {tokenName}'s reach or is locked", + "foundryvtt-arms-reach.lightsNotInReach": "Light not in reach or is locked", + "foundryvtt-arms-reach.lightsNotInReachFor": "Light not within {tokenName}'s reach or is locked", + "foundryvtt-arms-reach.warningNoSelectMoreThanOneToken": "Please selected a single token", "foundryvtt-arms-reach.errorNoDsProperty": "No 'ds' property found for value '${wallDataDs}' for id : '${wallDDataId}'", @@ -42,11 +47,11 @@ "foundryvtt-arms-reach.settingNameGlobalMaximumInteractionMeasurement": "Global maximum interaction distance measurement (ft, mt, ...), support Hex Grid,Gridless and Difficult Terrain Ruler", "foundryvtt-arms-reach.settingHintGlobalMaximumInteractionMeasurement": "Max distance (in feet, meter, or the default system unit grid you are using) that a token can interact with aplaceable object (door, journal, ...), 0 will disable the limit (needs app reload). GM's ignore this distance limitation.", - "foundryvtt-arms-reach.settingNameHotKeyForInteraction": "Interaction door with the hotkey 'e'", - "foundryvtt-arms-reach.settingHintHotKeyForInteraction": "Pressing 'e' will open or close nearest door. Holding 'e' will center camera on current token.", + "foundryvtt-arms-reach.settingNameHotKeyForInteraction": "[Deprecated] Interaction door with the hotkey 'e'", + "foundryvtt-arms-reach.settingHintHotKeyForInteraction": "[I do not recommend this feature because of some incpmaptibility with other movement verification modules, but otherwise it works] Pressing 'e' will open or close nearest door. Holding 'e' will center camera on current token.", - "foundryvtt-arms-reach.settingNameDoubleTapInteraction": "Interaction door with double tap delay", - "foundryvtt-arms-reach.settingHintDoubleTapInteraction": "Double tapping a move key on the direction of a door will interact with it. This option sets the delay between required key presses (the lower the faster you need to tap). Setting this option to zero will disable interaction with double tap.", + "foundryvtt-arms-reach.settingNameDoubleTapInteraction": "[Deprecated] Interaction door with double tap delay", + "foundryvtt-arms-reach.settingHintDoubleTapInteraction": "[I do not recommend this feature because of some incpmaptibility with other movement verification modules, but otherwise it works] Double tapping a move key on the direction of a door will interact with it. This option sets the delay between required key presses (the lower the faster you need to tap). Setting this option to zero will disable interaction with double tap.", "foundryvtt-arms-reach.settingNameMaximumDoorDistanceInteraction": "[Deprecated] Maximum door interaction distance in tiles", "foundryvtt-arms-reach.settingHintMaximumDoorDistanceInteraction": "[Use instead 'Maximum door interaction distance measurement'], 0 will disable this setting limit (needs app reload).", @@ -54,8 +59,8 @@ "foundryvtt-arms-reach.settingNameMaximumDoorMeasurementInteraction": "Maximum door interaction distance measurement (ft, mt, ...), support Hex Grid,Gridless and Difficult Terrain Ruler", "foundryvtt-arms-reach.settingHintMaximumDoorMeasurementInteraction": "Maximum door interaction distance measurement (in feet, meter, or the default system unit grid you are using)", - "foundryvtt-arms-reach.settingNameHotKeyToCenterCamera": "Hotkey 'e' to center camera", - "foundryvtt-arms-reach.settingHintHotKeyToCenterCamera": "Holding 'e' will center the camera on current selected token.", + "foundryvtt-arms-reach.settingNameHotKeyToCenterCamera": "[Deprecated] Hotkey 'e' to center camera", + "foundryvtt-arms-reach.settingHintHotKeyToCenterCamera": "[I do not recommend this feature because of some incpmaptibility with other movement verification modules, but otherwise it works] Holding 'e' will center the camera on current selected token.", "foundryvtt-arms-reach.settingNameNotificationsFailedInteractionEvenForGM": "Notifications failed interactions even for GM", "foundryvtt-arms-reach.settingHintNotificationsFailedInteractionEvenForGM": "Emit notifications for when a player fails to interact with a door. Good for debugging even for GM.", @@ -97,5 +102,8 @@ "foundryvtt-arms-reach.settingHintTokensIntegrationByPrefix": "If true by default enable the distance integration for all the target token with the prefix setted on the name of the token (not the character name)", "foundryvtt-arms-reach.settingNametokensIntegrationExplicitName": "Set the name of the source token you want to use for the iteraction", - "foundryvtt-arms-reach.settingHinttokensIntegrationExplicitName": "The name of the source token setted here is the one used for the distance interaction with the target token (not the character name)" + "foundryvtt-arms-reach.settingHinttokensIntegrationExplicitName": "The name of the source token setted here is the one used for the distance interaction with the target token (not the character name)", + + "foundryvtt-arms-reach.settingNameLightsIntegrationFeature": "Enable/Disable Lights integration", + "foundryvtt-arms-reach.settingHintLightsIntegrationFeature": "Max distance that a Light can interact with a other token... 0 will disable the limit (needs app reload). GM's ignore this distance limitation." } diff --git a/src/module.json b/src/module.json index c25b0bc..b5b5855 100644 --- a/src/module.json +++ b/src/module.json @@ -2,7 +2,7 @@ "name": "foundryvtt-arms-reach", "title": "FoundryVTT Arms Reach", "description": "Allows the GM to limit the distance that a player can interate with a placeable object like door, journal, stairway, token, ecc..", - "version": "2.0.10", + "version": "2.0.11", "author": "Psyny, p4535992", "type": "module", "socket": true, @@ -46,9 +46,9 @@ "manifestPlusVersion": "1.2.1", "url": "https://github.com/p4535992/foundryvtt-arms-reach", "manifest": "https://github.com/p4535992/foundryvtt-arms-reach/releases/latest/download/module.json", - "download": "https://github.com/p4535992/foundryvtt-arms-reach/releases/download/v2.0.10/module.zip", - "readme": "https://github.com/p4535992/foundryvtt-arms-reach/blob/v2.0.10/README.md", - "changelog": "https://github.com/p4535992/foundryvtt-arms-reach/blob/v2.0.10/changelog.md", + "download": "https://github.com/p4535992/foundryvtt-arms-reach/releases/download/v2.0.11/module.zip", + "readme": "https://github.com/p4535992/foundryvtt-arms-reach/blob/v2.0.11/README.md", + "changelog": "https://github.com/p4535992/foundryvtt-arms-reach/blob/v2.0.11/changelog.md", "bugs": "https://github.com/p4535992/foundryvtt-arms-reach/issues", "allowBugReporter": true, "dependencies": [ diff --git a/src/module/ArmsReachSocket.ts b/src/module/ArmsReachSocket.ts index 38f31b9..663fe67 100644 --- a/src/module/ArmsReachSocket.ts +++ b/src/module/ArmsReachSocket.ts @@ -8,7 +8,7 @@ export function recalculate(tokens) { } export function _socketRecalculate(tokenIds) { - // DO NOTHING JUST REGISTER THE TOKEN FOR STRANGE BUG WITH SOCKETLIB + // DO NOTHING JUST REGISTER THE SOCKET FOR A STRANGE BUG WITH SOCKETLIB ? //@ts-ignore - // return getCanvas().controls?.ruler?.dragRulerRecalculate(tokenIds); + // return getCanvas().controls?.ruler?.dragRulerRecalculate(tokenIds); } diff --git a/src/module/Hooks.ts b/src/module/Hooks.ts index c732da7..5e71489 100644 --- a/src/module/Hooks.ts +++ b/src/module/Hooks.ts @@ -7,6 +7,7 @@ import { ArmsReachVariables, DoorsReach } from './DoorsReach'; import { JournalsReach } from './JournalsReach'; import { TokensReach } from './TokensReach'; import { socket, _socketRecalculate } from './ArmsReachSocket'; +import { LightsReach } from './LightsReach'; //@ts-ignore // import { KeybindLib } from "/modules/keybind-lib/keybind-lib.js"; @@ -121,7 +122,12 @@ export const initHooks = () => { if (getGame().settings.get(ARMS_REACH_MODULE_NAME, 'enableJournalsIntegration')) { //@ts-ignore - // libWrapper.register(ARMS_REACH_MODULE_NAME, 'Note.prototype._onClickLeft', NotePrototypeOnClickLeftHandler, 'MIXED'); + // libWrapper.register( + // ARMS_REACH_MODULE_NAME, + // 'Note.prototype._onClickLeft', + // NotePrototypeOnClickLeftHandler, + // 'MIXED'); + //@ts-ignore libWrapper.register( ARMS_REACH_MODULE_NAME, @@ -147,6 +153,16 @@ export const initHooks = () => { 'MIXED', ); } + + if (getGame().settings.get(ARMS_REACH_MODULE_NAME, 'enableLightsIntegration')) { + //@ts-ignore + libWrapper.register( + ARMS_REACH_MODULE_NAME, + 'AmbientLight.prototype._onClickRight', + AmbientLightPrototypeOnClickRightHandler, + 'MIXED', + ); + } } }; @@ -267,3 +283,23 @@ export const DoorControlPrototypeOnRightDownHandler = async function (wrapped, . } return wrapped(...args); }; + +export const AmbientLightPrototypeOnClickRightHandler = async function (wrapped, ...args) { + if (getGame().settings.get(ARMS_REACH_MODULE_NAME, 'enableJournalsIntegration')) { + const [target] = args; + const light = this as AmbientLight; + let tokenSelected; + // if (getGame().settings.get(ARMS_REACH_MODULE_NAME, 'forceReSelection')) { + tokenSelected = getFirstPlayerTokenSelected(); + if (!tokenSelected) { + tokenSelected = getFirstPlayerToken(); + } + // } + const isInReach = await LightsReach.globalInteractionDistance(tokenSelected, light); + reselectTokenAfterInteraction(tokenSelected); + if (!isInReach) { + return; + } + } + return wrapped(...args); +}; diff --git a/src/module/JournalsReach.ts b/src/module/JournalsReach.ts index 11788dc..0a8f678 100644 --- a/src/module/JournalsReach.ts +++ b/src/module/JournalsReach.ts @@ -12,7 +12,6 @@ import { getCanvas, ARMS_REACH_MODULE_NAME, getGame } from './settings'; export const JournalsReach = { globalInteractionDistance: function (character: Token, note: Note): boolean { - // let character:Token = getFirstPlayerTokenSelected(); let isOwned = false; if (!character) { character = getFirstPlayerToken(); @@ -81,8 +80,8 @@ export const JournalsReach = { return false; }, - getJournalsCenter: function (token: Note) { - const tokenCenter = { x: token.x, y: token.y }; - return tokenCenter; + getJournalsCenter: function (note: Note) { + const noteCenter = { x: note.x, y: note.y }; + return noteCenter; }, }; diff --git a/src/module/LightsReach.ts b/src/module/LightsReach.ts new file mode 100644 index 0000000..830c649 --- /dev/null +++ b/src/module/LightsReach.ts @@ -0,0 +1,87 @@ +import { i18n, i18nFormat } from '../foundryvtt-arms-reach'; +import { + computeDistanceBetweenCoordinates, + computeDistanceBetweenCoordinatesOLD, + getCharacterName, + getFirstPlayerToken, + getFirstPlayerTokenSelected, + getTokenByTokenID, + iteractionFailNotification, +} from './ArmsReachHelper'; +import { getCanvas, ARMS_REACH_MODULE_NAME, getGame } from './settings'; + +export const LightsReach = { + globalInteractionDistance: function (character: Token, light: AmbientLight): boolean { + let isOwned = false; + if (!character) { + character = getFirstPlayerToken(); + if (character) { + isOwned = true; + } + } + if (!character) { + if (getGame().user?.isGM) { + return true; + } else { + return false; + } + } + + // Sets the global maximum interaction distance + // OLD SETTING + let globalInteraction = getGame().settings.get(ARMS_REACH_MODULE_NAME, 'globalInteractionDistance'); + if (globalInteraction <= 0) { + globalInteraction = getGame().settings.get(ARMS_REACH_MODULE_NAME, 'globalInteractionMeasurement'); + } + // Global interaction distance control. Replaces prototype function of Stairways. Danger... + if (globalInteraction > 0) { + // Check distance + //let character:Token = getFirstPlayerToken(); + if ( + !getGame().user?.isGM || + (getGame().user?.isGM && + getGame().settings.get(ARMS_REACH_MODULE_NAME, 'globalInteractionDistanceForGM')) + ) { + if (!character) { + iteractionFailNotification(i18n(`${ARMS_REACH_MODULE_NAME}.noCharacterSelectedForLight`)); + return false; + } else { + let isNotNearEnough = false; + // OLD SETTING + if (getGame().settings.get(ARMS_REACH_MODULE_NAME, 'globalInteractionDistance') > 0) { + const dist = computeDistanceBetweenCoordinatesOLD(LightsReach.getLightsCenter(light), character); + isNotNearEnough = + dist > getGame().settings.get(ARMS_REACH_MODULE_NAME, 'globalInteractionDistance'); + } else { + const dist = computeDistanceBetweenCoordinates(LightsReach.getLightsCenter(light), character); + isNotNearEnough = + dist > getGame().settings.get(ARMS_REACH_MODULE_NAME, 'globalInteractionMeasurement'); + } + if (isNotNearEnough) { + const tokenName = getCharacterName(character); + if (tokenName) { + iteractionFailNotification( + i18nFormat(`${ARMS_REACH_MODULE_NAME}.lightsNotInReachFor`, { tokenName: tokenName }), + ); + } else { + iteractionFailNotification(i18n(`${ARMS_REACH_MODULE_NAME}.lightsNotInReach`)); + } + return false; + } else { + return true; + } + } + } else if (getGame().user?.isGM) { + // DO NOTHING + return true; + } + } + + return false; + }, + + getLightsCenter: function (light: AmbientLight) { + const lightCenter = { x: light.x, y: light.y }; + return lightCenter; + }, +}; diff --git a/src/module/TokensReach.ts b/src/module/TokensReach.ts index 8ad41ff..56b6112 100644 --- a/src/module/TokensReach.ts +++ b/src/module/TokensReach.ts @@ -12,7 +12,6 @@ import { getCanvas, ARMS_REACH_MODULE_NAME, getGame } from './settings'; export const TokensReach = { globalInteractionDistance: function (character: Token, token: Token): boolean { - // let character:Token = getFirstPlayerTokenSelected(); let isOwned = false; if (!character) { character = getFirstPlayerToken(); diff --git a/src/module/settings.ts b/src/module/settings.ts index 832acef..7aabcfa 100644 --- a/src/module/settings.ts +++ b/src/module/settings.ts @@ -256,6 +256,8 @@ export const registerSettings = function () { range: { min: 0, max: 50, step: 0.5 }, }); + // DEPRECATED + getGame().settings.register(ARMS_REACH_MODULE_NAME, 'hotkeyDoorInteraction', { name: i18n(`${ARMS_REACH_MODULE_NAME}.settingNameHotKeyForInteraction`), hint: i18n(`${ARMS_REACH_MODULE_NAME}.settingHintHotKeyForInteraction`), @@ -265,23 +267,27 @@ export const registerSettings = function () { type: Boolean, }); + // DEPRECATED (double tap) + getGame().settings.register(ARMS_REACH_MODULE_NAME, 'hotkeyDoorInteractionDelay', { name: i18n(`${ARMS_REACH_MODULE_NAME}.settingNameDoubleTapInteraction`), hint: i18n(`${ARMS_REACH_MODULE_NAME}.settingHintDoubleTapInteraction`), scope: 'world', config: true, - default: 200, + default: 0, // 200 type: Number, //@ts-ignore range: { min: 0, max: 750, step: 50 }, }); + // DEPRECATED + getGame().settings.register(ARMS_REACH_MODULE_NAME, 'hotkeyDoorInteractionCenter', { name: i18n(`${ARMS_REACH_MODULE_NAME}.settingNameHotKeyToCenterCamera`), hint: i18n(`${ARMS_REACH_MODULE_NAME}.settingHintHotKeyToCenterCamera`), scope: 'world', config: true, - default: true, + default: false, type: Boolean, }); @@ -353,6 +359,19 @@ export const registerSettings = function () { type: String, }); + // ======================================================== + // LIGHT SUPPORT + // ======================================================== + + getGame().settings.register(ARMS_REACH_MODULE_NAME, 'enableLightsIntegration', { + name: i18n(`${ARMS_REACH_MODULE_NAME}.settingNameLightsIntegrationFeature`), + hint: i18n(`${ARMS_REACH_MODULE_NAME}.settingHintLightsIntegrationFeature`), + scope: 'world', + config: true, + default: false, + type: Boolean, + }); + // ======================================================== // Reset Doors and Fog // ========================================================