Schema & Documentation: - Extended EFFECT_KEYS with 24 new mappings: senses (6), movement capabilities (5), skill training (12), focus tracking - Created docs/ACTIVE_EFFECTS_REFERENCE.md with comprehensive guide for effect keys, modes, JSON format, and formula support Ancestry Automation: - Goblin: Darksight (darkvision), Nimble (+5 speed) - Orc: Darksight (darkvision), Hulking (+2 item slots) - Halfling: Nimble (+5 speed) - Draken: Scale (+1 armor) - Dwarf already had automation from earlier work Class Automation: - Wizard: Manifold Mind I/II (+1 focus.maxConcurrent each) - Fighter Valor already automated (proof of concept) - Gunslinger Deadeye deferred (dynamic, not static bonus) Added Phase 11 to PROJECT_ROADMAP.json with 18 tasks (10 complete, 8 deferred for conditional flags/UI/state tracking). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
274 lines
13 KiB
Markdown
274 lines
13 KiB
Markdown
# Active Effects Reference
|
|
|
|
This document describes how to use Active Effects to automate mechanical bonuses from ancestries, perks, and class features in the Vagabond RPG Foundry VTT system.
|
|
|
|
## Overview
|
|
|
|
Active Effects are Foundry's mechanism for items (classes, perks, ancestries) to modify actor data. When an item with a `changes` array is added to an actor, the system automatically creates Active Effects that modify the actor's stats, resources, senses, etc.
|
|
|
|
## Effect Modes
|
|
|
|
| Mode | Constant | Value | Description |
|
|
| --------- | ------------------------ | ----- | ----------------------------------- |
|
|
| CUSTOM | `EFFECT_MODES.CUSTOM` | 0 | Custom logic (not commonly used) |
|
|
| MULTIPLY | `EFFECT_MODES.MULTIPLY` | 1 | Multiply the base value |
|
|
| ADD | `EFFECT_MODES.ADD` | 2 | Add to the base value (most common) |
|
|
| DOWNGRADE | `EFFECT_MODES.DOWNGRADE` | 3 | Use lower of base and effect value |
|
|
| UPGRADE | `EFFECT_MODES.UPGRADE` | 4 | Use higher of base and effect value |
|
|
| OVERRIDE | `EFFECT_MODES.OVERRIDE` | 5 | Replace the base value entirely |
|
|
|
|
### When to Use Each Mode
|
|
|
|
- **ADD (2)**: Numeric bonuses like +HP, +Speed, +Armor, crit threshold reductions
|
|
- **OVERRIDE (5)**: Boolean toggles like senses (darkvision), movement capabilities (fly), skill training
|
|
|
|
## Available Effect Keys
|
|
|
|
### Stats
|
|
|
|
| Shorthand Key | Full Path | Type | Typical Mode |
|
|
| ---------------- | ------------------------------ | ------ | ------------ |
|
|
| `stat.might` | `system.stats.might.value` | Number | ADD |
|
|
| `stat.dexterity` | `system.stats.dexterity.value` | Number | ADD |
|
|
| `stat.awareness` | `system.stats.awareness.value` | Number | ADD |
|
|
| `stat.reason` | `system.stats.reason.value` | Number | ADD |
|
|
| `stat.presence` | `system.stats.presence.value` | Number | ADD |
|
|
| `stat.luck` | `system.stats.luck.value` | Number | ADD |
|
|
|
|
### Resources
|
|
|
|
| Shorthand Key | Full Path | Type | Typical Mode |
|
|
| ----------------- | ---------------------------------- | ------ | ------------ |
|
|
| `hp.bonus` | `system.resources.hp.bonus` | Number | ADD |
|
|
| `mana.bonus` | `system.resources.mana.bonus` | Number | ADD |
|
|
| `mana.castingMax` | `system.resources.mana.castingMax` | Number | ADD |
|
|
| `luck.max` | `system.resources.luck.max` | Number | ADD |
|
|
| `studiedDice.max` | `system.resources.studiedDice.max` | Number | ADD |
|
|
|
|
### Combat Stats
|
|
|
|
| Shorthand Key | Full Path | Type | Typical Mode |
|
|
| ----------------- | ------------------------ | ------ | ------------ |
|
|
| `armor` | `system.armor` | Number | ADD |
|
|
| `itemSlots.bonus` | `system.itemSlots.bonus` | Number | ADD |
|
|
| `speed.bonus` | `system.speed.bonus` | Number | ADD |
|
|
|
|
### Save Bonuses
|
|
|
|
| Shorthand Key | Full Path | Type | Typical Mode |
|
|
| ------------- | --------------------------- | ------ | ------------ |
|
|
| `save.reflex` | `system.saves.reflex.bonus` | Number | ADD |
|
|
| `save.endure` | `system.saves.endure.bonus` | Number | ADD |
|
|
| `save.will` | `system.saves.will.bonus` | Number | ADD |
|
|
|
|
### Skill Crit Thresholds
|
|
|
|
| Shorthand Key | Full Path | Type | Typical Mode |
|
|
| ------------------ | ----------------------------------------- | ------ | ------------ |
|
|
| `crit.arcana` | `system.skills.arcana.critThreshold` | Number | ADD |
|
|
| `crit.brawl` | `system.skills.brawl.critThreshold` | Number | ADD |
|
|
| `crit.craft` | `system.skills.craft.critThreshold` | Number | ADD |
|
|
| `crit.detect` | `system.skills.detect.critThreshold` | Number | ADD |
|
|
| `crit.finesse` | `system.skills.finesse.critThreshold` | Number | ADD |
|
|
| `crit.influence` | `system.skills.influence.critThreshold` | Number | ADD |
|
|
| `crit.leadership` | `system.skills.leadership.critThreshold` | Number | ADD |
|
|
| `crit.medicine` | `system.skills.medicine.critThreshold` | Number | ADD |
|
|
| `crit.mysticism` | `system.skills.mysticism.critThreshold` | Number | ADD |
|
|
| `crit.performance` | `system.skills.performance.critThreshold` | Number | ADD |
|
|
| `crit.sneak` | `system.skills.sneak.critThreshold` | Number | ADD |
|
|
| `crit.survival` | `system.skills.survival.critThreshold` | Number | ADD |
|
|
|
|
### Attack Crit Thresholds
|
|
|
|
| Shorthand Key | Full Path | Type | Typical Mode |
|
|
| --------------------- | -------------------------------------- | ------ | ------------ |
|
|
| `crit.attack.melee` | `system.attacks.melee.critThreshold` | Number | ADD |
|
|
| `crit.attack.brawl` | `system.attacks.brawl.critThreshold` | Number | ADD |
|
|
| `crit.attack.ranged` | `system.attacks.ranged.critThreshold` | Number | ADD |
|
|
| `crit.attack.finesse` | `system.attacks.finesse.critThreshold` | Number | ADD |
|
|
|
|
### Senses (Boolean)
|
|
|
|
| Shorthand Key | Full Path | Type | Typical Mode |
|
|
| -------------------- | ---------------------------- | ------- | ------------ |
|
|
| `sense.darkvision` | `system.senses.darkvision` | Boolean | OVERRIDE |
|
|
| `sense.blindsight` | `system.senses.blindsight` | Boolean | OVERRIDE |
|
|
| `sense.allsight` | `system.senses.allsight` | Boolean | OVERRIDE |
|
|
| `sense.echolocation` | `system.senses.echolocation` | Boolean | OVERRIDE |
|
|
| `sense.seismicsense` | `system.senses.seismicsense` | Boolean | OVERRIDE |
|
|
| `sense.telepathy` | `system.senses.telepathy` | Boolean | OVERRIDE |
|
|
|
|
### Movement Capabilities (Boolean)
|
|
|
|
| Shorthand Key | Full Path | Type | Typical Mode |
|
|
| ---------------- | ----------------------- | ------- | ------------ |
|
|
| `movement.fly` | `system.movement.fly` | Boolean | OVERRIDE |
|
|
| `movement.swim` | `system.movement.swim` | Boolean | OVERRIDE |
|
|
| `movement.climb` | `system.movement.climb` | Boolean | OVERRIDE |
|
|
| `movement.cling` | `system.movement.cling` | Boolean | OVERRIDE |
|
|
| `movement.phase` | `system.movement.phase` | Boolean | OVERRIDE |
|
|
|
|
### Skill Training (Boolean)
|
|
|
|
| Shorthand Key | Full Path | Type | Typical Mode |
|
|
| --------------------------- | ----------------------------------- | ------- | ------------ |
|
|
| `skill.arcana.trained` | `system.skills.arcana.trained` | Boolean | OVERRIDE |
|
|
| `skill.brawl.trained` | `system.skills.brawl.trained` | Boolean | OVERRIDE |
|
|
| `skill.craft.trained` | `system.skills.craft.trained` | Boolean | OVERRIDE |
|
|
| `skill.detect.trained` | `system.skills.detect.trained` | Boolean | OVERRIDE |
|
|
| `skill.finesse.trained` | `system.skills.finesse.trained` | Boolean | OVERRIDE |
|
|
| `skill.influence.trained` | `system.skills.influence.trained` | Boolean | OVERRIDE |
|
|
| `skill.leadership.trained` | `system.skills.leadership.trained` | Boolean | OVERRIDE |
|
|
| `skill.medicine.trained` | `system.skills.medicine.trained` | Boolean | OVERRIDE |
|
|
| `skill.mysticism.trained` | `system.skills.mysticism.trained` | Boolean | OVERRIDE |
|
|
| `skill.performance.trained` | `system.skills.performance.trained` | Boolean | OVERRIDE |
|
|
| `skill.sneak.trained` | `system.skills.sneak.trained` | Boolean | OVERRIDE |
|
|
| `skill.survival.trained` | `system.skills.survival.trained` | Boolean | OVERRIDE |
|
|
|
|
### Focus Tracking
|
|
|
|
| Shorthand Key | Full Path | Type | Typical Mode |
|
|
| --------------------- | ---------------------------- | ------ | ------------ |
|
|
| `focus.maxConcurrent` | `system.focus.maxConcurrent` | Number | ADD |
|
|
|
|
## JSON Format
|
|
|
|
### Ancestry Trait Example
|
|
|
|
```json
|
|
{
|
|
"name": "Darksight",
|
|
"description": "<p>You can see in darkness as if it were dim light.</p>",
|
|
"changes": [
|
|
{
|
|
"key": "system.senses.darkvision",
|
|
"mode": 5,
|
|
"value": "true"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### Perk Example
|
|
|
|
```json
|
|
{
|
|
"system": {
|
|
"changes": [
|
|
{
|
|
"key": "system.resources.hp.bonus",
|
|
"mode": 2,
|
|
"value": "@level"
|
|
}
|
|
]
|
|
}
|
|
}
|
|
```
|
|
|
|
### Class Feature Example
|
|
|
|
```json
|
|
{
|
|
"name": "Valor I",
|
|
"level": 1,
|
|
"description": "<p>The roll required for you to Crit on Attack Checks is reduced by 1.</p>",
|
|
"passive": true,
|
|
"changes": [
|
|
{
|
|
"key": "system.attacks.melee.critThreshold",
|
|
"mode": 2,
|
|
"value": "-1",
|
|
"priority": 10
|
|
},
|
|
{
|
|
"key": "system.attacks.ranged.critThreshold",
|
|
"mode": 2,
|
|
"value": "-1",
|
|
"priority": 10
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
## Formula Support
|
|
|
|
Values can use Roll Data formulas for dynamic calculations:
|
|
|
|
| Formula | Description |
|
|
| ------------------------ | -------------------------- |
|
|
| `@level` | Character's current level |
|
|
| `@stats.might.value` | Character's Might stat |
|
|
| `@stats.dexterity.value` | Character's Dexterity stat |
|
|
| `@stats.awareness.value` | Character's Awareness stat |
|
|
| `@stats.reason.value` | Character's Reason stat |
|
|
| `@stats.presence.value` | Character's Presence stat |
|
|
| `@stats.luck.value` | Character's Luck stat |
|
|
|
|
### Formula Examples
|
|
|
|
```json
|
|
// HP bonus equal to level (Dwarf Tough, Tough Perk)
|
|
{ "key": "system.resources.hp.bonus", "mode": 2, "value": "@level" }
|
|
|
|
// HP bonus equal to Might stat
|
|
{ "key": "system.resources.hp.bonus", "mode": 2, "value": "@stats.might.value" }
|
|
```
|
|
|
|
## Implementation Details
|
|
|
|
### Where Changes Are Applied
|
|
|
|
1. **Ancestry Traits**: `VagabondItem.applyAncestryTraits()` in `module/documents/item.mjs`
|
|
2. **Perk Effects**: `VagabondItem.applyPerkEffects()` in `module/documents/item.mjs`
|
|
3. **Class Features**: `VagabondItem.applyClassFeatures()` in `module/documents/item.mjs`
|
|
|
|
### Key Mapping
|
|
|
|
The system supports both full paths (`system.senses.darkvision`) and shorthand keys (`sense.darkvision`). Shorthand keys are mapped to full paths via `EFFECT_KEYS` in `module/helpers/effects.mjs`.
|
|
|
|
### Priority
|
|
|
|
Effects with higher priority values are applied later (and thus can override earlier effects). Default priority is `null`. Use explicit priority (e.g., `10`) when order matters.
|
|
|
|
## Adding New Automatable Effects
|
|
|
|
1. Add the key mapping to `EFFECT_KEYS` in `module/helpers/effects.mjs`
|
|
2. Ensure the target path exists in the actor data model (`module/data/actor/character.mjs`)
|
|
3. Add the `changes` array to the relevant compendium JSON file
|
|
4. Test by adding the item to a character and verifying the effect applies
|
|
|
|
## Current Automated Effects
|
|
|
|
### Ancestries
|
|
|
|
| Ancestry | Trait | Effect |
|
|
| -------- | --------- | ------------------------------------- |
|
|
| Dwarf | Darksight | `system.senses.darkvision = true` |
|
|
| Dwarf | Tough | `system.resources.hp.bonus += @level` |
|
|
| Goblin | Darksight | `system.senses.darkvision = true` |
|
|
| Goblin | Nimble | `system.speed.bonus += 5` |
|
|
| Orc | Darksight | `system.senses.darkvision = true` |
|
|
| Orc | Hulking | `system.itemSlots.bonus += 2` |
|
|
| Halfling | Nimble | `system.speed.bonus += 5` |
|
|
| Draken | Scale | `system.armor += 1` |
|
|
|
|
### Perks
|
|
|
|
| Perk | Effect |
|
|
| ----- | ------------------------------------------------- |
|
|
| Tough | `system.resources.hp.bonus += @level` (stackable) |
|
|
|
|
### Class Features
|
|
|
|
| Class | Feature | Effect |
|
|
| ------- | ------------------ | -------------------------------------------------------------------------------------------------- |
|
|
| Fighter | Valor I/II/III | `system.attacks.melee.critThreshold -= 1`, `system.attacks.ranged.critThreshold -= 1` (cumulative) |
|
|
| Wizard | Manifold Mind I/II | `system.focus.maxConcurrent += 1` (cumulative, base 1 → 2 → 3) |
|
|
|
|
### Not Automated (Complex Mechanics)
|
|
|
|
| Class | Feature | Reason |
|
|
| ---------- | ------- | ------------------------------------------------------------------ |
|
|
| Gunslinger | Deadeye | Dynamic crit reduction based on consecutive hits, resets each turn |
|
|
| Magus | (none) | No simple numeric bonuses; features are spell-block related |
|