Skip to content

Commit

Permalink
Add aliases for hidden
Browse files Browse the repository at this point in the history
  • Loading branch information
Eligarf committed Oct 8, 2024
1 parent 13a4463 commit 154401f
Show file tree
Hide file tree
Showing 7 changed files with 54 additions and 14 deletions.
3 changes: 3 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# v4.9.0
* Add a setting to specify additional words to recognize as 'hidden'. Useful in mixed language sessions.

# v4.8.0
* dnd5e: compatible with 3.x and 4.x

Expand Down
32 changes: 23 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,27 +12,30 @@
A module that adds perception vs stealth testing to Foundry's visibility tests. It filters out any objects with the Hidden condition if the viewing Perception value fails to beat the object's Stealth value.

[Stealthy Wiki](https://github.com/Eligarf/stealthy/wiki)
---

# Features

## Stealth and Perception rolls are banked

The last stealth and perception rolls for each token or actor is recorded (banked) and used to control token visibility on the canvas. The roll results are displayed in the token HUD for GMs to see as token buttons with an input box on the bottom: perception is on the left, stealth is on the right. Changing the values in these input boxes will alter the stored results for any future visibility tests while that roll remains active.

Perception banking has an overall token control *Bank perception rolls* which the GM uses to control when perception check banking is enabled. Toggling it off will also clear out all banked perception rolls for the current scene.

![override](https://user-images.githubusercontent.com/16523503/213258088-73098735-321f-4542-9c8a-433be26cd014.gif)
![control](https://github.com/Eligarf/avoid-notice/assets/16523503/38d512f0-27dc-4eda-9e59-4a14078ba3f4)

## Rolls banked in token or actor
## Rolls banked in token or actor

A game setting individually controls whether stealth or perception roll results are banked in the actor or token.

### Token

* Default for perception
* Banked rolls are deleted by deleting the value in the token button
* No icons are added to the token for a cleaner look

### Actor

* Default for stealth
* Banked rolls are actually stored in an effect or item on the actor.
* Banked rolls are deleted by deleting the effect they are banked in.
Expand All @@ -43,42 +46,53 @@ A game setting individually controls whether stealth or perception roll results
![perception](https://user-images.githubusercontent.com/16523503/213257350-e382f584-1c5c-41a8-bf00-60705ec89bd0.gif)

## GM Configures which detection modes can be countered by stealth

A GM can select which detection modes should be able to be affected by stealth checks. If the *Vision5e* module is active, the configuration table will include all of the additional detection modes that *Vision5e* provides.

![menu-image](https://github.com/Eligarf/stealthy/assets/16523503/01030283-781c-4cbf-8eaf-07f306a10c2e)

## Friendly tokens can still be viewed

The GM has options for allowing stealthy tokens to be seen by other tokens of the same disposition.

## Automatic Hidden Door detection
Doors can have a detection range that will hide the door control until the viewing token is within the given range. Doors can also have an optional stealth value; tokens with a sufficiently high perception effect will be able to see a hidden door if it beats that door's stealth.

Doors can have a detection range that will hide the door control until the viewing token is within the given range. Doors can also have an optional stealth value; tokens with a sufficiently high perception effect will be able to see a hidden door if it beats that door's stealth.

**THIS DOES NOT APPLY TO FOUNDRY'S SECRET DOORS!!!** I tried and failed to to get the secret doors to play nice - it turns out to be way easier to conditionally hide a regular door from players than to conditionally show a secret door to them.

![secret-doors](https://user-images.githubusercontent.com/16523503/212574216-6cc5b0ad-f432-441e-b11a-f4aa2b15cbd1.gif)
![hidden-door](https://user-images.githubusercontent.com/16523503/217671740-41aa7832-d495-49da-a149-948ebb6ccb2a.PNG)

# End Turn keybinding

It doesn't really belong in this module but I want to be able to press the *End* key to end my turn, and so I added an editable keybinding that will allow owners of the current combatant to do so.

# Systems

Stealthy supports the following systems (specific notes about a given system are in the [Wiki](https://github.com/Eligarf/stealthy/wiki)):
- [dnd5e](https://github.com/Eligarf/stealthy/wiki/D&D-5e)
- dnd4e
- [pf1](https://github.com/Eligarf/stealthy/wiki/Pathfinder-1e)

I've abandoned trying to get this to work on PF2e. Instead, I use *PF2e Perception* and built a new module to help with the stealth-as-initiative vs perception checks: [PF2e Avoid Notice](https://foundryvtt.com/packages/pf2e-avoid-notice)
* [dnd5e](https://github.com/Eligarf/stealthy/wiki/D&D-5e)
* dnd4e
* [pf1](https://github.com/Eligarf/stealthy/wiki/Pathfinder-1e)

I've abandoned trying to get this to work on PF2e. Instead, I use *PF2e Perception* and built a new module to help with the stealth-as-initiative vs perception checks: [PF2e Avoid Notice](https://foundryvtt.com/packages/pf2e-avoid-notice)

# Limitations

## Handling Hidden removal
Stealthy will not automatically remove a banked stealth roll - the dnd5e [Skulker](https://www.dndbeyond.com/feats/skulker) feat demonstrates why removing Hidden gets complicated without heavier automation support provided by modules like the excellent [Midi-QOL](https://foundryvtt.com/packages/midi-qol) which handles this for my games. I suggest [Visual Active Effects](https://foundryvtt.com/packages/visual-active-effects) as an easier way to manually remove it, especially for low automation level games.

Stealthy will not automatically remove a banked stealth roll - the dnd5e [Skulker](https://www.dndbeyond.com/feats/skulker) feat demonstrates why removing Hidden gets complicated without heavier automation support provided by modules like the excellent [Midi-QOL](https://foundryvtt.com/packages/midi-qol) which handles this for my games. I suggest [Visual Active Effects](https://foundryvtt.com/packages/visual-active-effects) as an easier way to manually remove it, especially for low automation level games.

# Required modules

* [lib-wrapper](https://foundryvtt.com/packages/lib-wrapper)
* [socketlib](https://github.com/manuelVo/foundryvtt-socketlib)

## Optional modules
Stealthy will adapt to the presence of any of the following modules should they be active

Stealthy will adapt to the presence of any of the following modules should they be active:

* [Active Token Effects](https://foundryvtt.com/packages/ATL)
* [Condition Lab & Triggler](https://foundryvtt.com/packages/condition-lab-triggler)
* [DFreds Convenient Effects](https://foundryvtt.com/packages/dfreds-convenient-effects)
Expand Down
4 changes: 3 additions & 1 deletion languages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
"hint": "This string will be sent through i18n.localize(). Changing these may affect overall automation of Stealthy's effects."
},
"icon": "Hidden icon",
"iconhint": "Default icon for Hidden effect"
"iconhint": "Default icon for Hidden effect",
"aliases": "Other names to recognize as hidden",
"aliasesHint": "Separate names with semicolons. This is useful in mixed-language situations"
},
"spot": {
"name": "Spot",
Expand Down
4 changes: 3 additions & 1 deletion languages/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
"hint": "Cette chaîne sera envoyée via i18n.localize(). Changing these may affect overall automation of Stealthy's effects."
},
"icon": "Icône cachée",
"iconhint": "Icône par défaut pour l'effet masqué"
"iconhint": "Icône par défaut pour l'effet masqué",
"aliases": "Other names to recognize as hidden",
"aliasesHint": "Separate names with semicolons. This is useful in mixed-language situations"
},
"spot": {
"name": "Détection",
Expand Down
4 changes: 3 additions & 1 deletion languages/pt-BR.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
"hint": "Esta string será enviada através de i18n.localize(). Mudar isso pode afetar a automação geral dos efeitos do Stealthy."
},
"icon": "Ícone Escondido",
"iconhint": "Ícone padrão para o efeito Escondido"
"iconhint": "Ícone padrão para o efeito Escondido",
"aliases": "Other names to recognize as hidden",
"aliasesHint": "Separate names with semicolons. This is useful in mixed-language situations"
},
"spot": {
"name": "Percebendo",
Expand Down
4 changes: 3 additions & 1 deletion languages/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
"hint": "Эта строка будет обработана через i18n.localize. Изменение может повлиять на общую автоматизацию эффектов модуля."
},
"icon": "Иконка Статуса Стелс",
"iconhint": "Значек по умолчанию для статуса Стелс"
"iconhint": "Значек по умолчанию для статуса Стелс",
"aliases": "Other names to recognize as hidden",
"aliasesHint": "Separate names with semicolons. This is useful in mixed-language situations"
},
"spot": {
"name": "Поиск",
Expand Down
17 changes: 16 additions & 1 deletion scripts/engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ export default class Engine {
game.settings.register(Stealthy.MODULE_ID, 'exposure', settings.exposure);
game.settings.register(Stealthy.MODULE_ID, 'gIDimThreshold', settings.gIDimThreshold);
game.settings.register(Stealthy.MODULE_ID, 'spotSecretDoors', settings.spotSecretDoors);
game.settings.register(Stealthy.MODULE_ID, 'hiddenAliases', settings.hiddenAliases);

game.settings.register(Stealthy.MODULE_ID, 'stealthToActor', settings.stealthToActor);
game.settings.register(Stealthy.MODULE_ID, 'perceptionToActor', settings.perceptionToActor);
Expand Down Expand Up @@ -119,8 +120,13 @@ export default class Engine {

setup() {
this.hiddenName = game.i18n.localize(game.settings.get(Stealthy.MODULE_ID, 'hiddenLabel'));
this.hiddenAliases = [this.hiddenName];
this.spotName = game.i18n.localize(game.settings.get(Stealthy.MODULE_ID, 'spotLabel'));
const aliases = game.settings.get(Stealthy.MODULE_ID, 'hiddenAliases');
if (aliases.length > 0)
this.hiddenAliases.push(...aliases.split(";"));
Stealthy.log(`hiddenName='${this.hiddenName}', spotName='${this.spotName}'`);
Stealthy.log(`hiddenAliases = `, this.hiddenAliases);
if (game.settings.get(Stealthy.MODULE_ID, 'spotSecretDoors')) {
Doors.setup();
}
Expand Down Expand Up @@ -289,6 +295,15 @@ export default class Engine {
type: Boolean,
default: false,
},
hiddenAliases: {
name: "stealthy.hidden.aliases",
hint: "stealthy.hidden.aliasesHint",
scope: 'world',
requiresReload: true,
config: true,
type: String,
default: ''
},
hiddenSource: {
name: "stealthy.hidden.source",
hint: "stealthy.source.hint",
Expand Down Expand Up @@ -554,7 +569,7 @@ export default class Engine {

findPerceptionEffect(actor) {
const beforeV11 = Math.floor(game.version) < 11;
return actor?.effects.find((e) => !e.disabled && this.spotName === (beforeV11 ? e.label : e.name));
return actor?.effects.find((e) => !e.disabled && this.hiddenAliases.includes(beforeV11 ? e.label : e.name));
}

makeStealthEffectMaker(name) {
Expand Down

0 comments on commit 154401f

Please sign in to comment.