Add Status item system and separate attack/damage rolls
Status System: - Add StatusData model with mechanical modifiers (damageDealt, healingReceived) - Add status item sheet with modifier configuration - Add status-bar.hbs for displaying status chips on actor sheets - Status chips show tooltip on hover, can be removed via click - Add 17 status items to compendium (Blinded, Burning, Charmed, etc.) - Frightened applies -2 damage dealt, Sickened applies -2 healing received Attack Roll Changes: - Separate attack and damage into two discrete rolls - Attack hit now shows "Roll Damage" button instead of auto-rolling - Button click rolls damage and updates the chat message in-place - Store weapon/attack data in message flags for later damage rolling - Fix favor/hinder and modifier preset buttons in attack dialog - Show individual damage dice results in chat card breakdown Mechanical Integration: - Add _applyStatusModifiers() to VagabondActor for aggregating status effects - Update getRollData() to include statusModifiers for roll formulas - Update damageRoll() to automatically apply damageDealt modifier - Update applyHealing() to respect healingReceived modifier 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
8d44b06f40
commit
bf2cd92e93
@ -237,6 +237,16 @@
|
|||||||
"priority": "low",
|
"priority": "low",
|
||||||
"dependencies": ["1.11", "1.12"],
|
"dependencies": ["1.11", "1.12"],
|
||||||
"notes": "Investigate what materials exist in Vagabond RPG and their mechanical effects. May need to update compendium items (6.6, 6.7) after implementation."
|
"notes": "Investigate what materials exist in Vagabond RPG and their mechanical effects. May need to update compendium items (6.6, 6.7) after implementation."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1.17",
|
||||||
|
"name": "Create Status item data model",
|
||||||
|
"description": "Status conditions as items: name, description, mechanical effects via embedded Active Effect data. 17 statuses from Core Rulebook: Berserk, Blinded, Burning, Charmed, Confused, Dazed, Fatigued, Frightened, Incapacitated, Invisible, Paralyzed, Prone, Restrained, Sickened, Suffocating, Unconscious, Vulnerable.",
|
||||||
|
"completed": true,
|
||||||
|
"tested": false,
|
||||||
|
"priority": "high",
|
||||||
|
"dependencies": ["1.6", "1.15"],
|
||||||
|
"notes": "Implemented StatusData with: changes array for Active Effects, includesStatuses for composites, flags for rule hints (cantMove, cantFocus, isVulnerable, etc.), favorHinder for roll modifiers, modifiers for damage/healing penalties, periodic for turn-based effects, duration tracking, stacking support."
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -553,6 +563,16 @@
|
|||||||
"priority": "medium",
|
"priority": "medium",
|
||||||
"dependencies": ["3.13", "2.13"],
|
"dependencies": ["3.13", "2.13"],
|
||||||
"notes": "Morale roll button in header, disabled when morale broken."
|
"notes": "Morale roll button in header, disabled when morale broken."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "3.17",
|
||||||
|
"name": "Implement Status display section on Actor sheets",
|
||||||
|
"description": "Add status condition display to both Character and NPC sheets. Show active statuses as icons/badges with tooltips. Allow adding/removing statuses via drag-drop or context menu. Display on Main tab for quick visibility during combat.",
|
||||||
|
"completed": true,
|
||||||
|
"tested": false,
|
||||||
|
"priority": "high",
|
||||||
|
"dependencies": ["3.2", "3.13", "1.17"],
|
||||||
|
"notes": "Consider icon-based display similar to token status effects. Statuses should be visible at a glance. May integrate with Foundry's built-in status effect system for token overlay icons."
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -641,6 +661,16 @@
|
|||||||
"tested": false,
|
"tested": false,
|
||||||
"priority": "high",
|
"priority": "high",
|
||||||
"dependencies": ["4.1", "1.14"]
|
"dependencies": ["4.1", "1.14"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "4.10",
|
||||||
|
"name": "Implement Status item sheet",
|
||||||
|
"description": "Status name, icon selector, description editor, embedded Active Effect configuration for mechanical effects. Show which effects the status applies (e.g., Vulnerable adds Hinder to saves).",
|
||||||
|
"completed": true,
|
||||||
|
"tested": false,
|
||||||
|
"priority": "high",
|
||||||
|
"dependencies": ["4.1", "1.17"],
|
||||||
|
"notes": "Implemented with: icon selector with preview, flags section (movement/action/sense/combat/morale restrictions), favor/hinder modifiers, damage/healing modifiers, periodic effects (trigger/type/value), duration tracking, stacking config, included statuses for composites, reference field. Uses existing base item sheet infrastructure with type-specific status.hbs template."
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -849,6 +879,16 @@
|
|||||||
"priority": "medium",
|
"priority": "medium",
|
||||||
"dependencies": ["6.1", "1.3"],
|
"dependencies": ["6.1", "1.3"],
|
||||||
"notes": "In progress: 21/289+ creatures. Humanlike category complete (21 NPCs). Remaining: Artificials (23), Beasts (75+), Cryptids (75+), Fae (16), Outers (32), Primordials (28), Undead (21). Source: Core Rulebook pp.112-181."
|
"notes": "In progress: 21/289+ creatures. Humanlike category complete (21 NPCs). Remaining: Artificials (23), Beasts (75+), Cryptids (75+), Fae (16), Outers (32), Primordials (28), Undead (21). Source: Core Rulebook pp.112-181."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "6.10",
|
||||||
|
"name": "Populate Statuses compendium",
|
||||||
|
"description": "All 17 status conditions from Core Rulebook with icons and Active Effects: Berserk, Blinded, Burning, Charmed, Confused, Dazed, Fatigued, Frightened, Incapacitated, Invisible, Paralyzed, Prone, Restrained, Sickened, Suffocating, Unconscious, Vulnerable.",
|
||||||
|
"completed": true,
|
||||||
|
"tested": false,
|
||||||
|
"priority": "high",
|
||||||
|
"dependencies": ["6.1", "1.17"],
|
||||||
|
"notes": "Each status needs: icon, description from rulebook, Active Effects for mechanical changes. Key effects: Vulnerable (Hinder on saves, Favor for attackers), Confused (Hinder on checks/saves), Frightened (-2 damage), Sickened (-2 healing), Incapacitated (fail Might/Dex checks, is Vulnerable). Composite statuses: Unconscious (Blinded+Incapacitated+Prone), Paralyzed (Incapacitated+Speed 0), Restrained (Vulnerable+Speed 0)."
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -1279,7 +1319,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"summary": {
|
"summary": {
|
||||||
"total_tasks": 125,
|
"total_tasks": 129,
|
||||||
"phases": 12,
|
"phases": 12,
|
||||||
"critical_path": [
|
"critical_path": [
|
||||||
"0.1 -> 1.1 -> 2.1 -> 2.2 -> 3.1 -> 3.2 -> 7.1 -> 9.2",
|
"0.1 -> 1.1 -> 2.1 -> 2.2 -> 3.1 -> 3.2 -> 7.1 -> 9.2",
|
||||||
|
|||||||
71
lang/en.json
71
lang/en.json
@ -169,6 +169,7 @@
|
|||||||
"VAGABOND.Fumble": "Fumble!",
|
"VAGABOND.Fumble": "Fumble!",
|
||||||
|
|
||||||
"VAGABOND.Damage": "Damage",
|
"VAGABOND.Damage": "Damage",
|
||||||
|
"VAGABOND.RollDamage": "Roll Damage",
|
||||||
"VAGABOND.DamageType": "Damage Type",
|
"VAGABOND.DamageType": "Damage Type",
|
||||||
"VAGABOND.Effect": "Effect",
|
"VAGABOND.Effect": "Effect",
|
||||||
"VAGABOND.CritEffect": "Crit Effect",
|
"VAGABOND.CritEffect": "Crit Effect",
|
||||||
@ -395,6 +396,7 @@
|
|||||||
"VAGABOND.ItemNew": "New {type}",
|
"VAGABOND.ItemNew": "New {type}",
|
||||||
"VAGABOND.ItemDeleteTitle": "Delete {name}",
|
"VAGABOND.ItemDeleteTitle": "Delete {name}",
|
||||||
"VAGABOND.ItemDeleteConfirm": "Are you sure you want to delete {name}?",
|
"VAGABOND.ItemDeleteConfirm": "Are you sure you want to delete {name}?",
|
||||||
|
"VAGABOND.RemoveStatus": "Remove Status",
|
||||||
"VAGABOND.ItemName": "Item Name",
|
"VAGABOND.ItemName": "Item Name",
|
||||||
|
|
||||||
"VAGABOND.DamageTypeBlunt": "Blunt",
|
"VAGABOND.DamageTypeBlunt": "Blunt",
|
||||||
@ -533,5 +535,72 @@
|
|||||||
"VAGABOND.ClassFeatures": "Class Features",
|
"VAGABOND.ClassFeatures": "Class Features",
|
||||||
"VAGABOND.NoProgression": "No progression entries",
|
"VAGABOND.NoProgression": "No progression entries",
|
||||||
"VAGABOND.FeatureName": "Feature Name",
|
"VAGABOND.FeatureName": "Feature Name",
|
||||||
"VAGABOND.FeatureDescription": "Description"
|
"VAGABOND.FeatureDescription": "Description",
|
||||||
|
|
||||||
|
"VAGABOND.ItemTypeStatus": "Status",
|
||||||
|
"VAGABOND.StatusIcon": "Status Icon",
|
||||||
|
"VAGABOND.StatusRestrictions": "Status Restrictions",
|
||||||
|
|
||||||
|
"VAGABOND.MovementRestrictions": "Movement",
|
||||||
|
"VAGABOND.CantMove": "Cannot Move",
|
||||||
|
"VAGABOND.CantRush": "Cannot Rush",
|
||||||
|
"VAGABOND.SpeedZero": "Speed is 0",
|
||||||
|
"VAGABOND.CrawlOnly": "Crawl Only",
|
||||||
|
|
||||||
|
"VAGABOND.ActionRestrictions": "Actions",
|
||||||
|
"VAGABOND.CantFocus": "Cannot Focus",
|
||||||
|
"VAGABOND.CantUseActions": "Cannot Use Actions",
|
||||||
|
"VAGABOND.OnlyAttackMoveRush": "Only Attack, Move, Rush",
|
||||||
|
|
||||||
|
"VAGABOND.SenseRestrictions": "Senses",
|
||||||
|
"VAGABOND.CantSee": "Cannot See",
|
||||||
|
|
||||||
|
"VAGABOND.CombatModifiers": "Combat",
|
||||||
|
"VAGABOND.IsVulnerable": "Is Vulnerable",
|
||||||
|
"VAGABOND.CloseAttacksAutoCrit": "Close Attacks Auto-Crit",
|
||||||
|
"VAGABOND.FailsMightDexChecks": "Fails MIT/DEX Checks",
|
||||||
|
|
||||||
|
"VAGABOND.MoraleSpecial": "Morale & Special",
|
||||||
|
"VAGABOND.NoMoraleChecks": "No Morale Checks",
|
||||||
|
"VAGABOND.ImmuneToFrightened": "Immune to Frightened",
|
||||||
|
"VAGABOND.CantAttackCharmer": "Cannot Attack Charmer",
|
||||||
|
"VAGABOND.ReducesItemSlots": "Reduces Item Slots",
|
||||||
|
|
||||||
|
"VAGABOND.FavorHinderModifiers": "Favor/Hinder Modifiers",
|
||||||
|
"VAGABOND.HinderOnAfflicted": "Afflicted Has Hinder On",
|
||||||
|
"VAGABOND.FavorAgainstAfflicted": "Others Have Favor Against",
|
||||||
|
"VAGABOND.Checks": "Checks",
|
||||||
|
"VAGABOND.FavorHinderContext": "Context (optional)",
|
||||||
|
|
||||||
|
"VAGABOND.DamageHealingModifiers": "Damage/Healing Modifiers",
|
||||||
|
"VAGABOND.DamageDealtModifier": "Damage Dealt",
|
||||||
|
"VAGABOND.HealingReceivedModifier": "Healing Received",
|
||||||
|
|
||||||
|
"VAGABOND.PeriodicEffects": "Periodic Effects",
|
||||||
|
"VAGABOND.Trigger": "Trigger",
|
||||||
|
"VAGABOND.StartOfTurn": "Start of Turn",
|
||||||
|
"VAGABOND.EndOfTurn": "End of Turn",
|
||||||
|
"VAGABOND.EachRound": "Each Round",
|
||||||
|
"VAGABOND.EffectType": "Effect Type",
|
||||||
|
"VAGABOND.Healing": "Healing",
|
||||||
|
"VAGABOND.EffectDescription": "Effect Description",
|
||||||
|
"VAGABOND.None": "None",
|
||||||
|
|
||||||
|
"VAGABOND.DurationType": "Duration Type",
|
||||||
|
"VAGABOND.DurationValue": "Duration Value",
|
||||||
|
"VAGABOND.Rounds": "Rounds",
|
||||||
|
"VAGABOND.Minutes": "Minutes",
|
||||||
|
"VAGABOND.Hours": "Hours",
|
||||||
|
"VAGABOND.UntilRest": "Until Rest",
|
||||||
|
"VAGABOND.UntilRemoved": "Until Removed",
|
||||||
|
|
||||||
|
"VAGABOND.Stacking": "Stacking",
|
||||||
|
"VAGABOND.Stackable": "Stackable",
|
||||||
|
"VAGABOND.MaxStacks": "Max Stacks",
|
||||||
|
|
||||||
|
"VAGABOND.IncludedStatuses": "Included Statuses",
|
||||||
|
"VAGABOND.IncludedStatusesHint": "For composite statuses (e.g., Unconscious includes Blinded, Incapacitated, Prone)",
|
||||||
|
"VAGABOND.AddIncludedStatus": "Add Included Status",
|
||||||
|
|
||||||
|
"VAGABOND.Reference": "Reference"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -204,6 +204,29 @@ export default class AttackRollDialog extends VagabondRollDialog {
|
|||||||
return weapon.system.getDamageFormula?.(this.twoHanded) || weapon.system.damage || "1d6";
|
return weapon.system.getDamageFormula?.(this.twoHanded) || weapon.system.damage || "1d6";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract dice results from a Roll for display.
|
||||||
|
* @param {Roll|null} roll - The roll to extract results from
|
||||||
|
* @returns {Array<{faces: number, result: number}>} Array of dice results
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_extractDiceResults(roll) {
|
||||||
|
if (!roll) return [];
|
||||||
|
|
||||||
|
const results = [];
|
||||||
|
for (const term of roll.terms) {
|
||||||
|
if (term instanceof foundry.dice.terms.Die) {
|
||||||
|
for (const r of term.results) {
|
||||||
|
results.push({
|
||||||
|
faces: term.faces,
|
||||||
|
result: r.result,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
/* Data Preparation */
|
/* Data Preparation */
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
@ -318,18 +341,8 @@ export default class AttackRollDialog extends VagabondRollDialog {
|
|||||||
modifier: this.rollConfig.modifier,
|
modifier: this.rollConfig.modifier,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Roll damage if the attack hit
|
// Send to chat (damage is rolled separately via button click)
|
||||||
let damageResult = null;
|
await this._sendToChat(result);
|
||||||
if (result.success) {
|
|
||||||
const damageFormula = this._getDamageFormula();
|
|
||||||
damageResult = await damageRoll(damageFormula, {
|
|
||||||
isCrit: result.isCrit,
|
|
||||||
rollData: this.actor.getRollData(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send to chat with custom template
|
|
||||||
await this._sendToChat(result, damageResult);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -340,9 +353,10 @@ export default class AttackRollDialog extends VagabondRollDialog {
|
|||||||
* @returns {Promise<ChatMessage>}
|
* @returns {Promise<ChatMessage>}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
async _sendToChat(result, damageResult) {
|
async _sendToChat(result, damageResult = null) {
|
||||||
const weapon = this.weapon;
|
const weapon = this.weapon;
|
||||||
const attackData = this.attackData;
|
const attackData = this.attackData;
|
||||||
|
const damageFormula = this._getDamageFormula();
|
||||||
|
|
||||||
// Prepare template data
|
// Prepare template data
|
||||||
const templateData = {
|
const templateData = {
|
||||||
@ -372,11 +386,15 @@ export default class AttackRollDialog extends VagabondRollDialog {
|
|||||||
netFavorHinder: this.netFavorHinder,
|
netFavorHinder: this.netFavorHinder,
|
||||||
favorSources: this.rollConfig.autoFavorHinder.favorSources,
|
favorSources: this.rollConfig.autoFavorHinder.favorSources,
|
||||||
hinderSources: this.rollConfig.autoFavorHinder.hinderSources,
|
hinderSources: this.rollConfig.autoFavorHinder.hinderSources,
|
||||||
// Damage info
|
// Damage info (only present if damage was rolled)
|
||||||
hasDamage: !!damageResult,
|
hasDamage: !!damageResult,
|
||||||
damageTotal: damageResult?.total,
|
damageTotal: damageResult?.total,
|
||||||
damageFormula: damageResult?.formula,
|
damageFormula: damageResult?.formula,
|
||||||
|
damageDiceResults: this._extractDiceResults(damageResult),
|
||||||
twoHanded: this.twoHanded,
|
twoHanded: this.twoHanded,
|
||||||
|
// Show damage button if hit but damage not yet rolled
|
||||||
|
showDamageButton: result.success && !damageResult,
|
||||||
|
pendingDamageFormula: damageFormula,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Render the chat card template
|
// Render the chat card template
|
||||||
@ -389,13 +407,30 @@ export default class AttackRollDialog extends VagabondRollDialog {
|
|||||||
const rolls = [result.roll];
|
const rolls = [result.roll];
|
||||||
if (damageResult) rolls.push(damageResult);
|
if (damageResult) rolls.push(damageResult);
|
||||||
|
|
||||||
// Create the chat message
|
// Create the chat message with flags for later damage rolling
|
||||||
const chatData = {
|
const chatData = {
|
||||||
user: game.user.id,
|
user: game.user.id,
|
||||||
speaker: ChatMessage.getSpeaker({ actor: this.actor }),
|
speaker: ChatMessage.getSpeaker({ actor: this.actor }),
|
||||||
content,
|
content,
|
||||||
rolls,
|
rolls,
|
||||||
sound: CONFIG.sounds.dice,
|
sound: CONFIG.sounds.dice,
|
||||||
|
flags: {
|
||||||
|
vagabond: {
|
||||||
|
type: "attack-roll",
|
||||||
|
actorId: this.actor.id,
|
||||||
|
weaponId: weapon.id,
|
||||||
|
weaponName: weapon.name,
|
||||||
|
damageFormula,
|
||||||
|
damageType: weapon.system.damageType,
|
||||||
|
damageTypeLabel: game.i18n.localize(
|
||||||
|
CONFIG.VAGABOND?.damageTypes?.[weapon.system.damageType] || weapon.system.damageType
|
||||||
|
),
|
||||||
|
twoHanded: this.twoHanded,
|
||||||
|
isCrit: result.isCrit,
|
||||||
|
success: result.success,
|
||||||
|
damageRolled: !!damageResult,
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
return ChatMessage.create(chatData);
|
return ChatMessage.create(chatData);
|
||||||
|
|||||||
@ -24,4 +24,5 @@ export {
|
|||||||
ArmorData,
|
ArmorData,
|
||||||
EquipmentData,
|
EquipmentData,
|
||||||
FeatureData,
|
FeatureData,
|
||||||
|
StatusData,
|
||||||
} from "./item/_module.mjs";
|
} from "./item/_module.mjs";
|
||||||
|
|||||||
@ -13,3 +13,4 @@ export { default as WeaponData } from "./weapon.mjs";
|
|||||||
export { default as ArmorData } from "./armor.mjs";
|
export { default as ArmorData } from "./armor.mjs";
|
||||||
export { default as EquipmentData } from "./equipment.mjs";
|
export { default as EquipmentData } from "./equipment.mjs";
|
||||||
export { default as FeatureData } from "./feature.mjs";
|
export { default as FeatureData } from "./feature.mjs";
|
||||||
|
export { default as StatusData } from "./status.mjs";
|
||||||
|
|||||||
264
module/data/item/status.mjs
Normal file
264
module/data/item/status.mjs
Normal file
@ -0,0 +1,264 @@
|
|||||||
|
/**
|
||||||
|
* Status Item Data Model
|
||||||
|
*
|
||||||
|
* Defines the data schema for status conditions in Vagabond RPG.
|
||||||
|
* Statuses represent temporary conditions like Blinded, Prone, Frightened, etc.
|
||||||
|
* that can be applied to actors and modify their capabilities.
|
||||||
|
*
|
||||||
|
* Core Rulebook Reference: Status conditions (p.36)
|
||||||
|
*
|
||||||
|
* @extends VagabondItemBase
|
||||||
|
*/
|
||||||
|
import VagabondItemBase from "./base-item.mjs";
|
||||||
|
|
||||||
|
export default class StatusData extends VagabondItemBase {
|
||||||
|
/**
|
||||||
|
* Define the schema for status items.
|
||||||
|
*
|
||||||
|
* @returns {Object} The schema definition
|
||||||
|
*/
|
||||||
|
static defineSchema() {
|
||||||
|
const fields = foundry.data.fields;
|
||||||
|
const baseSchema = super.defineSchema();
|
||||||
|
|
||||||
|
return {
|
||||||
|
...baseSchema,
|
||||||
|
|
||||||
|
// Icon for display on actor sheets and tokens
|
||||||
|
// Uses Foundry's built-in icon path format
|
||||||
|
icon: new fields.StringField({
|
||||||
|
required: false,
|
||||||
|
blank: true,
|
||||||
|
initial: "icons/svg/hazard.svg",
|
||||||
|
}),
|
||||||
|
|
||||||
|
// Active Effect changes this status applies when added to an actor
|
||||||
|
// These are the mechanical effects that can be automated
|
||||||
|
changes: new fields.ArrayField(
|
||||||
|
new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ required: true }),
|
||||||
|
mode: new fields.NumberField({
|
||||||
|
integer: true,
|
||||||
|
initial: 2, // CONST.ACTIVE_EFFECT_MODES.ADD
|
||||||
|
}),
|
||||||
|
value: new fields.StringField({ required: true }),
|
||||||
|
priority: new fields.NumberField({ integer: true, nullable: true }),
|
||||||
|
}),
|
||||||
|
{ initial: [] }
|
||||||
|
),
|
||||||
|
|
||||||
|
// Statuses that this status includes (composite statuses)
|
||||||
|
// e.g., Unconscious includes Blinded, Incapacitated, Prone
|
||||||
|
// Store as array of status names for lookup
|
||||||
|
includesStatuses: new fields.ArrayField(new fields.StringField(), { initial: [] }),
|
||||||
|
|
||||||
|
// Special flags for rules that can't be expressed as Active Effects
|
||||||
|
// These serve as hints for the GM and can be checked programmatically
|
||||||
|
flags: new fields.SchemaField({
|
||||||
|
// Movement restrictions
|
||||||
|
cantMove: new fields.BooleanField({ initial: false }),
|
||||||
|
cantRush: new fields.BooleanField({ initial: false }),
|
||||||
|
speedZero: new fields.BooleanField({ initial: false }),
|
||||||
|
crawlOnly: new fields.BooleanField({ initial: false }),
|
||||||
|
|
||||||
|
// Action restrictions
|
||||||
|
cantFocus: new fields.BooleanField({ initial: false }),
|
||||||
|
cantUseActions: new fields.BooleanField({ initial: false }),
|
||||||
|
onlyAttackMoveRush: new fields.BooleanField({ initial: false }),
|
||||||
|
|
||||||
|
// Sense restrictions
|
||||||
|
cantSee: new fields.BooleanField({ initial: false }),
|
||||||
|
|
||||||
|
// Combat modifiers
|
||||||
|
isVulnerable: new fields.BooleanField({ initial: false }),
|
||||||
|
closeAttacksAutoCrit: new fields.BooleanField({ initial: false }),
|
||||||
|
failsMightDexChecks: new fields.BooleanField({ initial: false }),
|
||||||
|
|
||||||
|
// Morale
|
||||||
|
noMoraleChecks: new fields.BooleanField({ initial: false }),
|
||||||
|
immuneToFrightened: new fields.BooleanField({ initial: false }),
|
||||||
|
|
||||||
|
// Other
|
||||||
|
cantAttackCharmer: new fields.BooleanField({ initial: false }),
|
||||||
|
reducesItemSlots: new fields.BooleanField({ initial: false }),
|
||||||
|
}),
|
||||||
|
|
||||||
|
// Favor/Hinder modifiers (for roll dialogs to check)
|
||||||
|
favorHinder: new fields.SchemaField({
|
||||||
|
// Applies Hinder to the afflicted creature's rolls
|
||||||
|
hinderChecks: new fields.BooleanField({ initial: false }),
|
||||||
|
hinderSaves: new fields.BooleanField({ initial: false }),
|
||||||
|
hinderAttacks: new fields.BooleanField({ initial: false }),
|
||||||
|
|
||||||
|
// Applies Favor to rolls against the afflicted creature
|
||||||
|
favorAgainstChecks: new fields.BooleanField({ initial: false }),
|
||||||
|
favorAgainstSaves: new fields.BooleanField({ initial: false }),
|
||||||
|
favorAgainstAttacks: new fields.BooleanField({ initial: false }),
|
||||||
|
|
||||||
|
// Specific contexts (for conditional application)
|
||||||
|
context: new fields.StringField({
|
||||||
|
required: false,
|
||||||
|
blank: true,
|
||||||
|
initial: "",
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
|
||||||
|
// Damage or healing modifiers (flat bonuses/penalties)
|
||||||
|
modifiers: new fields.SchemaField({
|
||||||
|
damageDealt: new fields.NumberField({ integer: true, initial: 0 }),
|
||||||
|
healingReceived: new fields.NumberField({ integer: true, initial: 0 }),
|
||||||
|
}),
|
||||||
|
|
||||||
|
// Periodic effects (for statuses like Burning, Suffocating)
|
||||||
|
periodic: new fields.SchemaField({
|
||||||
|
// When does the effect trigger?
|
||||||
|
trigger: new fields.StringField({
|
||||||
|
required: false,
|
||||||
|
nullable: true,
|
||||||
|
blank: false,
|
||||||
|
initial: null,
|
||||||
|
choices: ["startOfTurn", "endOfTurn", "eachRound"],
|
||||||
|
}),
|
||||||
|
// What type of effect?
|
||||||
|
type: new fields.StringField({
|
||||||
|
required: false,
|
||||||
|
nullable: true,
|
||||||
|
blank: false,
|
||||||
|
initial: null,
|
||||||
|
choices: ["damage", "fatigue", "healing", "check"],
|
||||||
|
}),
|
||||||
|
// Dice formula or flat value
|
||||||
|
value: new fields.StringField({ required: false, blank: true }),
|
||||||
|
// Description of what happens
|
||||||
|
effectDescription: new fields.StringField({ required: false, blank: true }),
|
||||||
|
}),
|
||||||
|
|
||||||
|
// Duration tracking (for time-limited statuses)
|
||||||
|
duration: new fields.SchemaField({
|
||||||
|
type: new fields.StringField({
|
||||||
|
required: false,
|
||||||
|
nullable: true,
|
||||||
|
blank: false,
|
||||||
|
initial: null,
|
||||||
|
choices: ["rounds", "minutes", "hours", "untilRest", "untilRemoved", "special"],
|
||||||
|
}),
|
||||||
|
value: new fields.NumberField({ integer: true, nullable: true }),
|
||||||
|
remaining: new fields.NumberField({ integer: true, nullable: true }),
|
||||||
|
}),
|
||||||
|
|
||||||
|
// Stacking behavior
|
||||||
|
stackable: new fields.BooleanField({ initial: false }),
|
||||||
|
maxStacks: new fields.NumberField({ integer: true, initial: 1, min: 1 }),
|
||||||
|
|
||||||
|
// Reference to the rulebook page for quick lookup
|
||||||
|
reference: new fields.StringField({
|
||||||
|
required: false,
|
||||||
|
blank: true,
|
||||||
|
initial: "Core Rulebook p.36",
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a summary of this status's effects for display.
|
||||||
|
*
|
||||||
|
* @returns {string[]} Array of effect descriptions
|
||||||
|
*/
|
||||||
|
getEffectSummary() {
|
||||||
|
const effects = [];
|
||||||
|
|
||||||
|
// Movement effects
|
||||||
|
if (this.flags.speedZero) effects.push("Speed is 0");
|
||||||
|
if (this.flags.cantMove) effects.push("Cannot move");
|
||||||
|
if (this.flags.cantRush) effects.push("Cannot Rush");
|
||||||
|
if (this.flags.crawlOnly) effects.push("Can only crawl");
|
||||||
|
|
||||||
|
// Action effects
|
||||||
|
if (this.flags.cantFocus) effects.push("Cannot Focus");
|
||||||
|
if (this.flags.cantUseActions) effects.push("Cannot use Actions");
|
||||||
|
if (this.flags.onlyAttackMoveRush) effects.push("Can only Attack, Move, and Rush");
|
||||||
|
|
||||||
|
// Sense effects
|
||||||
|
if (this.flags.cantSee) effects.push("Cannot see");
|
||||||
|
|
||||||
|
// Combat effects
|
||||||
|
if (this.flags.isVulnerable) effects.push("Is Vulnerable");
|
||||||
|
if (this.flags.closeAttacksAutoCrit) effects.push("Close Attacks auto-crit");
|
||||||
|
if (this.flags.failsMightDexChecks) effects.push("Fails Might and Dexterity Checks");
|
||||||
|
|
||||||
|
// Favor/Hinder
|
||||||
|
if (this.favorHinder.hinderChecks) effects.push("Hinder on Checks");
|
||||||
|
if (this.favorHinder.hinderSaves) effects.push("Hinder on Saves");
|
||||||
|
if (this.favorHinder.favorAgainstAttacks) effects.push("Attacks against have Favor");
|
||||||
|
if (this.favorHinder.favorAgainstSaves) effects.push("Saves against have Favor");
|
||||||
|
|
||||||
|
// Modifiers
|
||||||
|
if (this.modifiers.damageDealt !== 0) {
|
||||||
|
effects.push(`${this.modifiers.damageDealt} to damage dealt`);
|
||||||
|
}
|
||||||
|
if (this.modifiers.healingReceived !== 0) {
|
||||||
|
effects.push(`${this.modifiers.healingReceived} to healing received`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Periodic effects
|
||||||
|
if (this.periodic.trigger && this.periodic.effectDescription) {
|
||||||
|
effects.push(this.periodic.effectDescription);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Included statuses
|
||||||
|
if (this.includesStatuses.length > 0) {
|
||||||
|
effects.push(`Includes: ${this.includesStatuses.join(", ")}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return effects;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if this status has any Active Effect changes.
|
||||||
|
*
|
||||||
|
* @returns {boolean} True if status has mechanical effects
|
||||||
|
*/
|
||||||
|
hasActiveEffects() {
|
||||||
|
return this.changes.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if this status is a composite (includes other statuses).
|
||||||
|
*
|
||||||
|
* @returns {boolean} True if this status includes other statuses
|
||||||
|
*/
|
||||||
|
isComposite() {
|
||||||
|
return this.includesStatuses.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if this status has periodic effects.
|
||||||
|
*
|
||||||
|
* @returns {boolean} True if status has periodic effects
|
||||||
|
*/
|
||||||
|
hasPeriodic() {
|
||||||
|
return this.periodic.trigger !== null && this.periodic.type !== null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get chat card data for displaying status information.
|
||||||
|
*
|
||||||
|
* @returns {Object} Chat card data
|
||||||
|
*/
|
||||||
|
getChatData() {
|
||||||
|
const data = super.getChatData();
|
||||||
|
|
||||||
|
data.icon = this.icon;
|
||||||
|
data.effects = this.getEffectSummary();
|
||||||
|
data.reference = this.reference;
|
||||||
|
|
||||||
|
if (this.duration.type) {
|
||||||
|
data.duration =
|
||||||
|
this.duration.type === "special"
|
||||||
|
? "Special"
|
||||||
|
: `${this.duration.value} ${this.duration.type}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -229,15 +229,17 @@ export async function saveRoll(actor, saveType, difficulty, options = {}) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Roll damage dice.
|
* Roll damage dice.
|
||||||
|
* Automatically applies status modifiers (e.g., Frightened's -2 damage dealt).
|
||||||
*
|
*
|
||||||
* @param {string} formula - The damage formula (e.g., "2d6", "1d8+3")
|
* @param {string} formula - The damage formula (e.g., "2d6", "1d8+3")
|
||||||
* @param {Object} options - Roll options
|
* @param {Object} options - Roll options
|
||||||
* @param {boolean} [options.isCrit=false] - Double the dice on crit
|
* @param {boolean} [options.isCrit=false] - Double the dice on crit
|
||||||
* @param {Object} [options.rollData={}] - Data for roll formula evaluation
|
* @param {Object} [options.rollData={}] - Data for roll formula evaluation
|
||||||
|
* @param {boolean} [options.applyStatusModifiers=true] - Apply status damage modifiers
|
||||||
* @returns {Promise<Roll>} The evaluated roll
|
* @returns {Promise<Roll>} The evaluated roll
|
||||||
*/
|
*/
|
||||||
export async function damageRoll(formula, options = {}) {
|
export async function damageRoll(formula, options = {}) {
|
||||||
const { isCrit = false, rollData = {} } = options;
|
const { isCrit = false, rollData = {}, applyStatusModifiers = true } = options;
|
||||||
|
|
||||||
let rollFormula = formula;
|
let rollFormula = formula;
|
||||||
|
|
||||||
@ -246,6 +248,14 @@ export async function damageRoll(formula, options = {}) {
|
|||||||
rollFormula = doubleDice(formula);
|
rollFormula = doubleDice(formula);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Apply status modifiers to damage dealt (e.g., Frightened gives -2)
|
||||||
|
if (applyStatusModifiers) {
|
||||||
|
const damageModifier = rollData.statusModifiers?.damageDealt || 0;
|
||||||
|
if (damageModifier !== 0) {
|
||||||
|
rollFormula += damageModifier > 0 ? ` + ${damageModifier}` : ` - ${Math.abs(damageModifier)}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const roll = new Roll(rollFormula, rollData);
|
const roll = new Roll(rollFormula, rollData);
|
||||||
await roll.evaluate();
|
await roll.evaluate();
|
||||||
|
|
||||||
|
|||||||
@ -204,6 +204,9 @@ export default class VagabondActor extends Actor {
|
|||||||
}
|
}
|
||||||
system.armor = totalArmor;
|
system.armor = totalArmor;
|
||||||
|
|
||||||
|
// Apply status modifiers
|
||||||
|
this._applyStatusModifiers();
|
||||||
|
|
||||||
// Calculate used item slots from inventory
|
// Calculate used item slots from inventory
|
||||||
// Each item type implements getTotalSlots() with its own logic
|
// Each item type implements getTotalSlots() with its own logic
|
||||||
let usedSlots = 0;
|
let usedSlots = 0;
|
||||||
@ -225,7 +228,39 @@ export default class VagabondActor extends Actor {
|
|||||||
*/
|
*/
|
||||||
_prepareNPCDerivedData() {
|
_prepareNPCDerivedData() {
|
||||||
// NPC derived data is handled by NPCData.prepareDerivedData()
|
// NPC derived data is handled by NPCData.prepareDerivedData()
|
||||||
// Add any document-level NPC calculations here if needed
|
// Apply status modifiers to NPCs as well
|
||||||
|
this._applyStatusModifiers();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply modifiers from status items to the actor.
|
||||||
|
* Aggregates damageDealt and healingReceived modifiers from all active statuses.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_applyStatusModifiers() {
|
||||||
|
const system = this.system;
|
||||||
|
|
||||||
|
// Initialize modifiers if not present
|
||||||
|
if (!system.statusModifiers) {
|
||||||
|
system.statusModifiers = {
|
||||||
|
damageDealt: 0,
|
||||||
|
healingReceived: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset to base values
|
||||||
|
system.statusModifiers.damageDealt = 0;
|
||||||
|
system.statusModifiers.healingReceived = 0;
|
||||||
|
|
||||||
|
// Aggregate modifiers from all status items
|
||||||
|
for (const item of this.items) {
|
||||||
|
if (item.type === "status") {
|
||||||
|
const modifiers = item.system.modifiers || {};
|
||||||
|
system.statusModifiers.damageDealt += modifiers.damageDealt || 0;
|
||||||
|
system.statusModifiers.healingReceived += modifiers.healingReceived || 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
@ -246,6 +281,12 @@ export default class VagabondActor extends Actor {
|
|||||||
// Add actor-level conveniences
|
// Add actor-level conveniences
|
||||||
data.name = this.name;
|
data.name = this.name;
|
||||||
|
|
||||||
|
// Add status modifiers for use in damage/healing formulas
|
||||||
|
data.statusModifiers = this.system.statusModifiers || {
|
||||||
|
damageDealt: 0,
|
||||||
|
healingReceived: 0,
|
||||||
|
};
|
||||||
|
|
||||||
// Type-specific roll data is added by the TypeDataModel's getRollData()
|
// Type-specific roll data is added by the TypeDataModel's getRollData()
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
@ -417,16 +458,21 @@ export default class VagabondActor extends Actor {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Heal this actor.
|
* Heal this actor.
|
||||||
|
* Applies status modifiers (e.g., Sickened reduces healing received).
|
||||||
*
|
*
|
||||||
* @param {number} amount - The amount to heal
|
* @param {number} amount - The amount to heal
|
||||||
* @returns {Promise<VagabondActor>} The updated actor
|
* @returns {Promise<VagabondActor>} The updated actor
|
||||||
*/
|
*/
|
||||||
async applyHealing(amount) {
|
async applyHealing(amount) {
|
||||||
|
// Apply status modifiers to healing (e.g., Sickened gives -2)
|
||||||
|
const healingModifier = this.system.statusModifiers?.healingReceived || 0;
|
||||||
|
const finalAmount = Math.max(0, amount + healingModifier);
|
||||||
|
|
||||||
if (this.type === "character") {
|
if (this.type === "character") {
|
||||||
return this.modifyResource("hp", amount);
|
return this.modifyResource("hp", finalAmount);
|
||||||
}
|
}
|
||||||
const max = this.system.hp.max;
|
const max = this.system.hp.max;
|
||||||
const newHP = Math.min(max, this.system.hp.value + amount);
|
const newHP = Math.min(max, this.system.hp.value + finalAmount);
|
||||||
return this.update({ "system.hp.value": newHP });
|
return this.update({ "system.hp.value": newHP });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -693,7 +739,7 @@ export default class VagabondActor extends Actor {
|
|||||||
// Find the lowest morale score (weakest link)
|
// Find the lowest morale score (weakest link)
|
||||||
const actors = tokens.map((t) => t.actor);
|
const actors = tokens.map((t) => t.actor);
|
||||||
const lowestMorale = Math.min(...actors.map((a) => a.system.morale));
|
const lowestMorale = Math.min(...actors.map((a) => a.system.morale));
|
||||||
const groupName =
|
const _groupName =
|
||||||
tokens.length === 1
|
tokens.length === 1
|
||||||
? tokens[0].name
|
? tokens[0].name
|
||||||
: `${tokens.length} enemies (lowest morale: ${lowestMorale})`;
|
: `${tokens.length} enemies (lowest morale: ${lowestMorale})`;
|
||||||
|
|||||||
@ -110,6 +110,10 @@ export const EFFECT_KEYS = {
|
|||||||
|
|
||||||
// Focus tracking
|
// Focus tracking
|
||||||
"focus.maxConcurrent": "system.focus.maxConcurrent",
|
"focus.maxConcurrent": "system.focus.maxConcurrent",
|
||||||
|
|
||||||
|
// Status-related modifiers
|
||||||
|
"damage.dealt.bonus": "system.modifiers.damageDealt",
|
||||||
|
"healing.received.bonus": "system.modifiers.healingReceived",
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -273,6 +277,7 @@ export function getEffectsBySource(actor) {
|
|||||||
perk: [],
|
perk: [],
|
||||||
feature: [],
|
feature: [],
|
||||||
equipment: [],
|
equipment: [],
|
||||||
|
status: [],
|
||||||
temporary: [],
|
temporary: [],
|
||||||
other: [],
|
other: [],
|
||||||
};
|
};
|
||||||
|
|||||||
@ -66,6 +66,7 @@ export default class VagabondActorSheet extends HandlebarsApplicationMixin(Actor
|
|||||||
changeTab: VagabondActorSheet.#onChangeTab,
|
changeTab: VagabondActorSheet.#onChangeTab,
|
||||||
modifyResource: VagabondActorSheet.#onModifyResource,
|
modifyResource: VagabondActorSheet.#onModifyResource,
|
||||||
toggleTrained: VagabondActorSheet.#onToggleTrained,
|
toggleTrained: VagabondActorSheet.#onToggleTrained,
|
||||||
|
removeStatus: VagabondActorSheet.#onRemoveStatus,
|
||||||
},
|
},
|
||||||
// Drag-drop configuration - use Foundry's built-in system
|
// Drag-drop configuration - use Foundry's built-in system
|
||||||
// Setting to empty array disables ActorSheetV2's default handling
|
// Setting to empty array disables ActorSheetV2's default handling
|
||||||
@ -184,6 +185,7 @@ export default class VagabondActorSheet extends HandlebarsApplicationMixin(Actor
|
|||||||
features: [],
|
features: [],
|
||||||
perks: [],
|
perks: [],
|
||||||
classes: [],
|
classes: [],
|
||||||
|
statuses: [],
|
||||||
ancestry: null,
|
ancestry: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -220,6 +222,9 @@ export default class VagabondActorSheet extends HandlebarsApplicationMixin(Actor
|
|||||||
case "ancestry":
|
case "ancestry":
|
||||||
items.ancestry = item;
|
items.ancestry = item;
|
||||||
break;
|
break;
|
||||||
|
case "status":
|
||||||
|
items.statuses.push(item);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -821,4 +826,20 @@ export default class VagabondActorSheet extends HandlebarsApplicationMixin(Actor
|
|||||||
const currentValue = this.actor.system.skills[skillId]?.trained ?? false;
|
const currentValue = this.actor.system.skills[skillId]?.trained ?? false;
|
||||||
await this.actor.update({ [`system.skills.${skillId}.trained`]: !currentValue });
|
await this.actor.update({ [`system.skills.${skillId}.trained`]: !currentValue });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle status removal action.
|
||||||
|
* @param {PointerEvent} event
|
||||||
|
* @param {HTMLElement} target
|
||||||
|
*/
|
||||||
|
static async #onRemoveStatus(event, target) {
|
||||||
|
event.preventDefault();
|
||||||
|
const itemId = target.closest("[data-item-id]")?.dataset.itemId;
|
||||||
|
if (!itemId) return;
|
||||||
|
|
||||||
|
const item = this.actor.items.get(itemId);
|
||||||
|
if (!item || item.type !== "status") return;
|
||||||
|
|
||||||
|
await item.delete();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
* @module vagabond
|
* @module vagabond
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* global Actors, Items */
|
/* global Actors, Items, AudioHelper */
|
||||||
|
|
||||||
// Import configuration
|
// Import configuration
|
||||||
import { VAGABOND } from "./helpers/config.mjs";
|
import { VAGABOND } from "./helpers/config.mjs";
|
||||||
@ -19,6 +19,7 @@ import {
|
|||||||
ArmorData,
|
ArmorData,
|
||||||
EquipmentData,
|
EquipmentData,
|
||||||
FeatureData,
|
FeatureData,
|
||||||
|
StatusData,
|
||||||
} from "./data/item/_module.mjs";
|
} from "./data/item/_module.mjs";
|
||||||
|
|
||||||
// Import document classes
|
// Import document classes
|
||||||
@ -63,6 +64,7 @@ async function preloadHandlebarsTemplates() {
|
|||||||
"systems/vagabond/templates/actor/character-magic.hbs",
|
"systems/vagabond/templates/actor/character-magic.hbs",
|
||||||
"systems/vagabond/templates/actor/character-biography.hbs",
|
"systems/vagabond/templates/actor/character-biography.hbs",
|
||||||
"systems/vagabond/templates/actor/parts/tabs.hbs",
|
"systems/vagabond/templates/actor/parts/tabs.hbs",
|
||||||
|
"systems/vagabond/templates/actor/parts/status-bar.hbs",
|
||||||
// NPC sheet parts
|
// NPC sheet parts
|
||||||
"systems/vagabond/templates/actor/npc-header.hbs",
|
"systems/vagabond/templates/actor/npc-header.hbs",
|
||||||
"systems/vagabond/templates/actor/npc-stats.hbs",
|
"systems/vagabond/templates/actor/npc-stats.hbs",
|
||||||
@ -83,6 +85,7 @@ async function preloadHandlebarsTemplates() {
|
|||||||
"systems/vagabond/templates/item/types/spell.hbs",
|
"systems/vagabond/templates/item/types/spell.hbs",
|
||||||
"systems/vagabond/templates/item/types/perk.hbs",
|
"systems/vagabond/templates/item/types/perk.hbs",
|
||||||
"systems/vagabond/templates/item/types/feature.hbs",
|
"systems/vagabond/templates/item/types/feature.hbs",
|
||||||
|
"systems/vagabond/templates/item/types/status.hbs",
|
||||||
];
|
];
|
||||||
|
|
||||||
return loadTemplates(templatePaths);
|
return loadTemplates(templatePaths);
|
||||||
@ -132,6 +135,7 @@ Hooks.once("init", async () => {
|
|||||||
armor: ArmorData,
|
armor: ArmorData,
|
||||||
equipment: EquipmentData,
|
equipment: EquipmentData,
|
||||||
feature: FeatureData,
|
feature: FeatureData,
|
||||||
|
status: StatusData,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Define custom Document classes
|
// Define custom Document classes
|
||||||
@ -473,6 +477,182 @@ Hooks.on("renderChatMessage", (message, html) => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
/* Attack Damage Roll Handling */
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle clicks on "Roll Damage" buttons in attack chat cards.
|
||||||
|
* Rolls damage using the stored weapon data and updates the message.
|
||||||
|
*/
|
||||||
|
Hooks.on("renderChatMessage", (message, html) => {
|
||||||
|
// Find damage roll buttons in this message
|
||||||
|
html.find(".roll-damage-btn").on("click", async (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
const button = event.currentTarget;
|
||||||
|
const flags = message.flags?.vagabond;
|
||||||
|
|
||||||
|
// Verify this is an attack roll message with pending damage
|
||||||
|
if (!flags || flags.type !== "attack-roll" || flags.damageRolled) {
|
||||||
|
ui.notifications.warn("Cannot roll damage for this message");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disable button immediately to prevent double-clicks
|
||||||
|
button.disabled = true;
|
||||||
|
button.innerHTML = '<i class="fa-solid fa-spinner fa-spin"></i> Rolling...';
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Get the actor for roll data
|
||||||
|
const actor = game.actors.get(flags.actorId);
|
||||||
|
if (!actor) {
|
||||||
|
ui.notifications.error("Could not find actor for damage roll");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Import damageRoll function
|
||||||
|
const { damageRoll } = await import("./dice/rolls.mjs");
|
||||||
|
|
||||||
|
// Roll damage
|
||||||
|
const roll = await damageRoll(flags.damageFormula, {
|
||||||
|
isCrit: flags.isCrit,
|
||||||
|
rollData: actor.getRollData(),
|
||||||
|
});
|
||||||
|
|
||||||
|
// Extract dice results for display
|
||||||
|
const damageDiceResults = [];
|
||||||
|
for (const term of roll.terms) {
|
||||||
|
if (term instanceof foundry.dice.terms.Die) {
|
||||||
|
for (const r of term.results) {
|
||||||
|
damageDiceResults.push({
|
||||||
|
faces: term.faces,
|
||||||
|
result: r.result,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render updated content with damage
|
||||||
|
const content = await renderTemplate("systems/vagabond/templates/chat/attack-roll.hbs", {
|
||||||
|
// Original attack data from message content
|
||||||
|
...(await _extractAttackDataFromMessage(message)),
|
||||||
|
// Damage data
|
||||||
|
hasDamage: true,
|
||||||
|
damageTotal: roll.total,
|
||||||
|
damageFormula: roll.formula,
|
||||||
|
damageDiceResults,
|
||||||
|
twoHanded: flags.twoHanded,
|
||||||
|
isCrit: flags.isCrit,
|
||||||
|
showDamageButton: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update the message with damage rolled
|
||||||
|
await message.update({
|
||||||
|
content,
|
||||||
|
rolls: [...message.rolls, roll],
|
||||||
|
"flags.vagabond.damageRolled": true,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Play dice sound
|
||||||
|
AudioHelper.play({ src: CONFIG.sounds.dice }, true);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Vagabond RPG | Error rolling damage:", error);
|
||||||
|
ui.notifications.error("Failed to roll damage");
|
||||||
|
button.disabled = false;
|
||||||
|
button.innerHTML = '<i class="fa-solid fa-burst"></i> Roll Damage';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract attack data from an existing chat message for re-rendering.
|
||||||
|
* @param {ChatMessage} message - The chat message
|
||||||
|
* @returns {Promise<Object>} Template data extracted from the message
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
async function _extractAttackDataFromMessage(message) {
|
||||||
|
const flags = message.flags?.vagabond || {};
|
||||||
|
const content = message.content;
|
||||||
|
|
||||||
|
// Parse values from the message HTML
|
||||||
|
const parser = new DOMParser();
|
||||||
|
const doc = parser.parseFromString(content, "text/html");
|
||||||
|
|
||||||
|
// Extract weapon info
|
||||||
|
const weaponImg = doc.querySelector(".weapon-icon")?.getAttribute("src") || "";
|
||||||
|
const weaponName =
|
||||||
|
doc.querySelector(".weapon-name")?.textContent || flags.weaponName || "Unknown";
|
||||||
|
const attackLabel = doc.querySelector(".attack-type-badge")?.textContent || "";
|
||||||
|
|
||||||
|
// Extract roll result
|
||||||
|
const total = doc.querySelector(".roll-total")?.textContent || "0";
|
||||||
|
const status = doc.querySelector(".roll-status .status")?.classList;
|
||||||
|
const isCrit = status?.contains("critical") || false;
|
||||||
|
const isFumble = status?.contains("fumble") || false;
|
||||||
|
const success = status?.contains("success") || status?.contains("critical") || false;
|
||||||
|
|
||||||
|
// Extract formula and breakdown
|
||||||
|
const formula = doc.querySelector(".roll-formula .value")?.textContent || "";
|
||||||
|
const d20Result = doc.querySelector(".d20-result")?.textContent?.replace(/[^\d]/g, "") || "0";
|
||||||
|
const favorDieEl = doc.querySelector(".favor-die");
|
||||||
|
const favorDie = favorDieEl?.textContent?.replace(/[^\d-]/g, "") || null;
|
||||||
|
const netFavorHinder = favorDieEl?.classList.contains("favor")
|
||||||
|
? 1
|
||||||
|
: favorDieEl?.classList.contains("hinder")
|
||||||
|
? -1
|
||||||
|
: 0;
|
||||||
|
const modifier = doc.querySelector(".modifier")?.textContent?.replace(/[^\d-]/g, "") || null;
|
||||||
|
|
||||||
|
// Extract difficulty info
|
||||||
|
const difficulty = doc.querySelector(".difficulty .value")?.textContent || "10";
|
||||||
|
const critThreshold =
|
||||||
|
doc.querySelector(".crit-threshold .value")?.textContent?.replace(/[^\d]/g, "") || "20";
|
||||||
|
|
||||||
|
// Extract weapon properties
|
||||||
|
const propertyTags = doc.querySelectorAll(".weapon-properties .property-tag");
|
||||||
|
const properties = Array.from(propertyTags).map((el) => el.textContent);
|
||||||
|
|
||||||
|
// Extract favor/hinder sources
|
||||||
|
const favorSourcesEl = doc.querySelector(".favor-sources span");
|
||||||
|
const hinderSourcesEl = doc.querySelector(".hinder-sources span");
|
||||||
|
const favorSources =
|
||||||
|
favorSourcesEl?.textContent
|
||||||
|
?.replace(/^[^:]+:\s*/, "")
|
||||||
|
.split(", ")
|
||||||
|
.filter(Boolean) || [];
|
||||||
|
const hinderSources =
|
||||||
|
hinderSourcesEl?.textContent
|
||||||
|
?.replace(/^[^:]+:\s*/, "")
|
||||||
|
.split(", ")
|
||||||
|
.filter(Boolean) || [];
|
||||||
|
|
||||||
|
return {
|
||||||
|
weapon: {
|
||||||
|
id: flags.weaponId,
|
||||||
|
name: weaponName,
|
||||||
|
img: weaponImg,
|
||||||
|
damageType: flags.damageType,
|
||||||
|
damageTypeLabel: flags.damageTypeLabel,
|
||||||
|
properties,
|
||||||
|
},
|
||||||
|
attackLabel,
|
||||||
|
total,
|
||||||
|
d20Result,
|
||||||
|
favorDie: favorDie ? parseInt(favorDie) : null,
|
||||||
|
modifier: modifier ? parseInt(modifier) : null,
|
||||||
|
formula,
|
||||||
|
difficulty,
|
||||||
|
critThreshold,
|
||||||
|
success,
|
||||||
|
isCrit,
|
||||||
|
isFumble,
|
||||||
|
netFavorHinder,
|
||||||
|
favorSources,
|
||||||
|
hinderSources,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
/* Quench Test Registration */
|
/* Quench Test Registration */
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "npm run build:css && npm run build:packs",
|
"build": "npm run build:css && npm run build:packs",
|
||||||
"build:css": "sass styles/scss/vagabond.scss styles/vagabond.css --style=compressed",
|
"build:css": "sass styles/scss/vagabond.scss styles/vagabond.css --style=compressed",
|
||||||
"build:packs": "fvtt package workon vagabond --type System && npm run build:pack:ancestries && npm run build:pack:classes && npm run build:pack:spells && npm run build:pack:perks && npm run build:pack:weapons && npm run build:pack:armor && npm run build:pack:equipment",
|
"build:packs": "fvtt package workon vagabond --type System && npm run build:pack:ancestries && npm run build:pack:classes && npm run build:pack:spells && npm run build:pack:perks && npm run build:pack:weapons && npm run build:pack:armor && npm run build:pack:equipment && npm run build:pack:statuses && npm run build:pack:bestiary",
|
||||||
"build:pack:ancestries": "fvtt package pack -n ancestries -t Item --in packs/_source/ancestries --out packs",
|
"build:pack:ancestries": "fvtt package pack -n ancestries -t Item --in packs/_source/ancestries --out packs",
|
||||||
"build:pack:classes": "fvtt package pack -n classes -t Item --in packs/_source/classes --out packs",
|
"build:pack:classes": "fvtt package pack -n classes -t Item --in packs/_source/classes --out packs",
|
||||||
"build:pack:spells": "fvtt package pack -n spells -t Item --in packs/_source/spells --out packs",
|
"build:pack:spells": "fvtt package pack -n spells -t Item --in packs/_source/spells --out packs",
|
||||||
@ -13,6 +13,8 @@
|
|||||||
"build:pack:weapons": "fvtt package pack -n weapons -t Item --in packs/_source/weapons --out packs",
|
"build:pack:weapons": "fvtt package pack -n weapons -t Item --in packs/_source/weapons --out packs",
|
||||||
"build:pack:armor": "fvtt package pack -n armor -t Item --in packs/_source/armor --out packs",
|
"build:pack:armor": "fvtt package pack -n armor -t Item --in packs/_source/armor --out packs",
|
||||||
"build:pack:equipment": "fvtt package pack -n equipment -t Item --in packs/_source/equipment --out packs",
|
"build:pack:equipment": "fvtt package pack -n equipment -t Item --in packs/_source/equipment --out packs",
|
||||||
|
"build:pack:statuses": "fvtt package pack -n statuses -t Item --in packs/_source/statuses --out packs",
|
||||||
|
"build:pack:bestiary": "fvtt package pack -n bestiary -t Actor --in packs/_source/bestiary --out packs",
|
||||||
"watch": "sass styles/scss/vagabond.scss styles/vagabond.css --watch --style=expanded --source-map",
|
"watch": "sass styles/scss/vagabond.scss styles/vagabond.css --watch --style=expanded --source-map",
|
||||||
"lint": "eslint module/",
|
"lint": "eslint module/",
|
||||||
"lint:fix": "eslint module/ --fix",
|
"lint:fix": "eslint module/ --fix",
|
||||||
|
|||||||
58
packs/_source/statuses/berserk.json
Normal file
58
packs/_source/statuses/berserk.json
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
{
|
||||||
|
"_id": "vagabondStatusBerserk",
|
||||||
|
"name": "Berserk",
|
||||||
|
"type": "status",
|
||||||
|
"img": "icons/svg/terror.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "<p>It can't Focus, and it can only Attack, Move, and Rush. It doesn't make Morale Checks, and it can't be Frightened.</p>",
|
||||||
|
"icon": "icons/svg/terror.svg",
|
||||||
|
"changes": [],
|
||||||
|
"includesStatuses": [],
|
||||||
|
"flags": {
|
||||||
|
"cantMove": false,
|
||||||
|
"cantRush": false,
|
||||||
|
"speedZero": false,
|
||||||
|
"crawlOnly": false,
|
||||||
|
"cantFocus": true,
|
||||||
|
"cantUseActions": false,
|
||||||
|
"onlyAttackMoveRush": true,
|
||||||
|
"cantSee": false,
|
||||||
|
"isVulnerable": false,
|
||||||
|
"closeAttacksAutoCrit": false,
|
||||||
|
"failsMightDexChecks": false,
|
||||||
|
"noMoraleChecks": true,
|
||||||
|
"immuneToFrightened": true,
|
||||||
|
"cantAttackCharmer": false,
|
||||||
|
"reducesItemSlots": false
|
||||||
|
},
|
||||||
|
"favorHinder": {
|
||||||
|
"hinderChecks": false,
|
||||||
|
"hinderSaves": false,
|
||||||
|
"hinderAttacks": false,
|
||||||
|
"favorAgainstChecks": false,
|
||||||
|
"favorAgainstSaves": false,
|
||||||
|
"favorAgainstAttacks": false,
|
||||||
|
"context": ""
|
||||||
|
},
|
||||||
|
"modifiers": {
|
||||||
|
"damageDealt": 0,
|
||||||
|
"healingReceived": 0
|
||||||
|
},
|
||||||
|
"periodic": {
|
||||||
|
"trigger": null,
|
||||||
|
"type": null,
|
||||||
|
"value": "",
|
||||||
|
"effectDescription": ""
|
||||||
|
},
|
||||||
|
"duration": {
|
||||||
|
"type": null,
|
||||||
|
"value": null,
|
||||||
|
"remaining": null
|
||||||
|
},
|
||||||
|
"stackable": false,
|
||||||
|
"maxStacks": 1,
|
||||||
|
"reference": "Core Rulebook p.36"
|
||||||
|
},
|
||||||
|
"effects": [],
|
||||||
|
"_key": "!items!vagabondStatusBerserk"
|
||||||
|
}
|
||||||
58
packs/_source/statuses/blinded.json
Normal file
58
packs/_source/statuses/blinded.json
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
{
|
||||||
|
"_id": "vagabondStatusBlinded",
|
||||||
|
"name": "Blinded",
|
||||||
|
"type": "status",
|
||||||
|
"img": "icons/svg/blind.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "<p>It can't see and is Vulnerable.</p>",
|
||||||
|
"icon": "icons/svg/blind.svg",
|
||||||
|
"changes": [],
|
||||||
|
"includesStatuses": ["Vulnerable"],
|
||||||
|
"flags": {
|
||||||
|
"cantMove": false,
|
||||||
|
"cantRush": false,
|
||||||
|
"speedZero": false,
|
||||||
|
"crawlOnly": false,
|
||||||
|
"cantFocus": false,
|
||||||
|
"cantUseActions": false,
|
||||||
|
"onlyAttackMoveRush": false,
|
||||||
|
"cantSee": true,
|
||||||
|
"isVulnerable": true,
|
||||||
|
"closeAttacksAutoCrit": false,
|
||||||
|
"failsMightDexChecks": false,
|
||||||
|
"noMoraleChecks": false,
|
||||||
|
"immuneToFrightened": false,
|
||||||
|
"cantAttackCharmer": false,
|
||||||
|
"reducesItemSlots": false
|
||||||
|
},
|
||||||
|
"favorHinder": {
|
||||||
|
"hinderChecks": false,
|
||||||
|
"hinderSaves": false,
|
||||||
|
"hinderAttacks": false,
|
||||||
|
"favorAgainstChecks": false,
|
||||||
|
"favorAgainstSaves": false,
|
||||||
|
"favorAgainstAttacks": false,
|
||||||
|
"context": ""
|
||||||
|
},
|
||||||
|
"modifiers": {
|
||||||
|
"damageDealt": 0,
|
||||||
|
"healingReceived": 0
|
||||||
|
},
|
||||||
|
"periodic": {
|
||||||
|
"trigger": null,
|
||||||
|
"type": null,
|
||||||
|
"value": "",
|
||||||
|
"effectDescription": ""
|
||||||
|
},
|
||||||
|
"duration": {
|
||||||
|
"type": null,
|
||||||
|
"value": null,
|
||||||
|
"remaining": null
|
||||||
|
},
|
||||||
|
"stackable": false,
|
||||||
|
"maxStacks": 1,
|
||||||
|
"reference": "Core Rulebook p.36"
|
||||||
|
},
|
||||||
|
"effects": [],
|
||||||
|
"_key": "!items!vagabondStatusBlinded"
|
||||||
|
}
|
||||||
58
packs/_source/statuses/burning.json
Normal file
58
packs/_source/statuses/burning.json
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
{
|
||||||
|
"_id": "vagabondStatusBurning",
|
||||||
|
"name": "Burning",
|
||||||
|
"type": "status",
|
||||||
|
"img": "icons/svg/fire.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "<p>A die roll indicates damage it takes at the start of its Turns, unless an appropriate action is taken to end it (such as dousing fire).</p>",
|
||||||
|
"icon": "icons/svg/fire.svg",
|
||||||
|
"changes": [],
|
||||||
|
"includesStatuses": [],
|
||||||
|
"flags": {
|
||||||
|
"cantMove": false,
|
||||||
|
"cantRush": false,
|
||||||
|
"speedZero": false,
|
||||||
|
"crawlOnly": false,
|
||||||
|
"cantFocus": false,
|
||||||
|
"cantUseActions": false,
|
||||||
|
"onlyAttackMoveRush": false,
|
||||||
|
"cantSee": false,
|
||||||
|
"isVulnerable": false,
|
||||||
|
"closeAttacksAutoCrit": false,
|
||||||
|
"failsMightDexChecks": false,
|
||||||
|
"noMoraleChecks": false,
|
||||||
|
"immuneToFrightened": false,
|
||||||
|
"cantAttackCharmer": false,
|
||||||
|
"reducesItemSlots": false
|
||||||
|
},
|
||||||
|
"favorHinder": {
|
||||||
|
"hinderChecks": false,
|
||||||
|
"hinderSaves": false,
|
||||||
|
"hinderAttacks": false,
|
||||||
|
"favorAgainstChecks": false,
|
||||||
|
"favorAgainstSaves": false,
|
||||||
|
"favorAgainstAttacks": false,
|
||||||
|
"context": ""
|
||||||
|
},
|
||||||
|
"modifiers": {
|
||||||
|
"damageDealt": 0,
|
||||||
|
"healingReceived": 0
|
||||||
|
},
|
||||||
|
"periodic": {
|
||||||
|
"trigger": "startOfTurn",
|
||||||
|
"type": "damage",
|
||||||
|
"value": "varies",
|
||||||
|
"effectDescription": "Takes damage at the start of each turn (die roll indicates amount)"
|
||||||
|
},
|
||||||
|
"duration": {
|
||||||
|
"type": "special",
|
||||||
|
"value": null,
|
||||||
|
"remaining": null
|
||||||
|
},
|
||||||
|
"stackable": false,
|
||||||
|
"maxStacks": 1,
|
||||||
|
"reference": "Core Rulebook p.36"
|
||||||
|
},
|
||||||
|
"effects": [],
|
||||||
|
"_key": "!items!vagabondStatusBurning"
|
||||||
|
}
|
||||||
58
packs/_source/statuses/charmed.json
Normal file
58
packs/_source/statuses/charmed.json
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
{
|
||||||
|
"_id": "vagabondStatusCharmed",
|
||||||
|
"name": "Charmed",
|
||||||
|
"type": "status",
|
||||||
|
"img": "icons/svg/silenced.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "<p>It can't willingly attack the charmer.</p>",
|
||||||
|
"icon": "icons/svg/silenced.svg",
|
||||||
|
"changes": [],
|
||||||
|
"includesStatuses": [],
|
||||||
|
"flags": {
|
||||||
|
"cantMove": false,
|
||||||
|
"cantRush": false,
|
||||||
|
"speedZero": false,
|
||||||
|
"crawlOnly": false,
|
||||||
|
"cantFocus": false,
|
||||||
|
"cantUseActions": false,
|
||||||
|
"onlyAttackMoveRush": false,
|
||||||
|
"cantSee": false,
|
||||||
|
"isVulnerable": false,
|
||||||
|
"closeAttacksAutoCrit": false,
|
||||||
|
"failsMightDexChecks": false,
|
||||||
|
"noMoraleChecks": false,
|
||||||
|
"immuneToFrightened": false,
|
||||||
|
"cantAttackCharmer": true,
|
||||||
|
"reducesItemSlots": false
|
||||||
|
},
|
||||||
|
"favorHinder": {
|
||||||
|
"hinderChecks": false,
|
||||||
|
"hinderSaves": false,
|
||||||
|
"hinderAttacks": false,
|
||||||
|
"favorAgainstChecks": false,
|
||||||
|
"favorAgainstSaves": false,
|
||||||
|
"favorAgainstAttacks": false,
|
||||||
|
"context": ""
|
||||||
|
},
|
||||||
|
"modifiers": {
|
||||||
|
"damageDealt": 0,
|
||||||
|
"healingReceived": 0
|
||||||
|
},
|
||||||
|
"periodic": {
|
||||||
|
"trigger": null,
|
||||||
|
"type": null,
|
||||||
|
"value": "",
|
||||||
|
"effectDescription": ""
|
||||||
|
},
|
||||||
|
"duration": {
|
||||||
|
"type": null,
|
||||||
|
"value": null,
|
||||||
|
"remaining": null
|
||||||
|
},
|
||||||
|
"stackable": false,
|
||||||
|
"maxStacks": 1,
|
||||||
|
"reference": "Core Rulebook p.36"
|
||||||
|
},
|
||||||
|
"effects": [],
|
||||||
|
"_key": "!items!vagabondStatusCharmed"
|
||||||
|
}
|
||||||
58
packs/_source/statuses/confused.json
Normal file
58
packs/_source/statuses/confused.json
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
{
|
||||||
|
"_id": "vagabondStatusConfused",
|
||||||
|
"name": "Confused",
|
||||||
|
"type": "status",
|
||||||
|
"img": "icons/svg/daze.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "<p>Its Checks and Saves have Hinder, and Saves against its Actions have Favor.</p>",
|
||||||
|
"icon": "icons/svg/daze.svg",
|
||||||
|
"changes": [],
|
||||||
|
"includesStatuses": [],
|
||||||
|
"flags": {
|
||||||
|
"cantMove": false,
|
||||||
|
"cantRush": false,
|
||||||
|
"speedZero": false,
|
||||||
|
"crawlOnly": false,
|
||||||
|
"cantFocus": false,
|
||||||
|
"cantUseActions": false,
|
||||||
|
"onlyAttackMoveRush": false,
|
||||||
|
"cantSee": false,
|
||||||
|
"isVulnerable": false,
|
||||||
|
"closeAttacksAutoCrit": false,
|
||||||
|
"failsMightDexChecks": false,
|
||||||
|
"noMoraleChecks": false,
|
||||||
|
"immuneToFrightened": false,
|
||||||
|
"cantAttackCharmer": false,
|
||||||
|
"reducesItemSlots": false
|
||||||
|
},
|
||||||
|
"favorHinder": {
|
||||||
|
"hinderChecks": true,
|
||||||
|
"hinderSaves": true,
|
||||||
|
"hinderAttacks": false,
|
||||||
|
"favorAgainstChecks": false,
|
||||||
|
"favorAgainstSaves": true,
|
||||||
|
"favorAgainstAttacks": false,
|
||||||
|
"context": ""
|
||||||
|
},
|
||||||
|
"modifiers": {
|
||||||
|
"damageDealt": 0,
|
||||||
|
"healingReceived": 0
|
||||||
|
},
|
||||||
|
"periodic": {
|
||||||
|
"trigger": null,
|
||||||
|
"type": null,
|
||||||
|
"value": "",
|
||||||
|
"effectDescription": ""
|
||||||
|
},
|
||||||
|
"duration": {
|
||||||
|
"type": null,
|
||||||
|
"value": null,
|
||||||
|
"remaining": null
|
||||||
|
},
|
||||||
|
"stackable": false,
|
||||||
|
"maxStacks": 1,
|
||||||
|
"reference": "Core Rulebook p.36"
|
||||||
|
},
|
||||||
|
"effects": [],
|
||||||
|
"_key": "!items!vagabondStatusConfused"
|
||||||
|
}
|
||||||
58
packs/_source/statuses/dazed.json
Normal file
58
packs/_source/statuses/dazed.json
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
{
|
||||||
|
"_id": "vagabondStatusDazed",
|
||||||
|
"name": "Dazed",
|
||||||
|
"type": "status",
|
||||||
|
"img": "icons/svg/stoned.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "<p>It can't Focus or Move unless it uses an Action to do so.</p>",
|
||||||
|
"icon": "icons/svg/stoned.svg",
|
||||||
|
"changes": [],
|
||||||
|
"includesStatuses": [],
|
||||||
|
"flags": {
|
||||||
|
"cantMove": false,
|
||||||
|
"cantRush": false,
|
||||||
|
"speedZero": false,
|
||||||
|
"crawlOnly": false,
|
||||||
|
"cantFocus": true,
|
||||||
|
"cantUseActions": false,
|
||||||
|
"onlyAttackMoveRush": false,
|
||||||
|
"cantSee": false,
|
||||||
|
"isVulnerable": false,
|
||||||
|
"closeAttacksAutoCrit": false,
|
||||||
|
"failsMightDexChecks": false,
|
||||||
|
"noMoraleChecks": false,
|
||||||
|
"immuneToFrightened": false,
|
||||||
|
"cantAttackCharmer": false,
|
||||||
|
"reducesItemSlots": false
|
||||||
|
},
|
||||||
|
"favorHinder": {
|
||||||
|
"hinderChecks": false,
|
||||||
|
"hinderSaves": false,
|
||||||
|
"hinderAttacks": false,
|
||||||
|
"favorAgainstChecks": false,
|
||||||
|
"favorAgainstSaves": false,
|
||||||
|
"favorAgainstAttacks": false,
|
||||||
|
"context": ""
|
||||||
|
},
|
||||||
|
"modifiers": {
|
||||||
|
"damageDealt": 0,
|
||||||
|
"healingReceived": 0
|
||||||
|
},
|
||||||
|
"periodic": {
|
||||||
|
"trigger": null,
|
||||||
|
"type": null,
|
||||||
|
"value": "",
|
||||||
|
"effectDescription": ""
|
||||||
|
},
|
||||||
|
"duration": {
|
||||||
|
"type": null,
|
||||||
|
"value": null,
|
||||||
|
"remaining": null
|
||||||
|
},
|
||||||
|
"stackable": false,
|
||||||
|
"maxStacks": 1,
|
||||||
|
"reference": "Core Rulebook p.36"
|
||||||
|
},
|
||||||
|
"effects": [],
|
||||||
|
"_key": "!items!vagabondStatusDazed"
|
||||||
|
}
|
||||||
58
packs/_source/statuses/fatigued.json
Normal file
58
packs/_source/statuses/fatigued.json
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
{
|
||||||
|
"_id": "vagabondStatusFatigued",
|
||||||
|
"name": "Fatigued",
|
||||||
|
"type": "status",
|
||||||
|
"img": "icons/svg/unconscious.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "<p>Fatigue is measured from 0 to 5. With 1 or more Fatigue, the following rules apply:</p><ul><li>Each Fatigue occupies an Item Slot.</li><li>At 3 or more Fatigue, it can't Rush.</li><li>At 5 Fatigue, it dies.</li></ul>",
|
||||||
|
"icon": "icons/svg/unconscious.svg",
|
||||||
|
"changes": [],
|
||||||
|
"includesStatuses": [],
|
||||||
|
"flags": {
|
||||||
|
"cantMove": false,
|
||||||
|
"cantRush": false,
|
||||||
|
"speedZero": false,
|
||||||
|
"crawlOnly": false,
|
||||||
|
"cantFocus": false,
|
||||||
|
"cantUseActions": false,
|
||||||
|
"onlyAttackMoveRush": false,
|
||||||
|
"cantSee": false,
|
||||||
|
"isVulnerable": false,
|
||||||
|
"closeAttacksAutoCrit": false,
|
||||||
|
"failsMightDexChecks": false,
|
||||||
|
"noMoraleChecks": false,
|
||||||
|
"immuneToFrightened": false,
|
||||||
|
"cantAttackCharmer": false,
|
||||||
|
"reducesItemSlots": true
|
||||||
|
},
|
||||||
|
"favorHinder": {
|
||||||
|
"hinderChecks": false,
|
||||||
|
"hinderSaves": false,
|
||||||
|
"hinderAttacks": false,
|
||||||
|
"favorAgainstChecks": false,
|
||||||
|
"favorAgainstSaves": false,
|
||||||
|
"favorAgainstAttacks": false,
|
||||||
|
"context": ""
|
||||||
|
},
|
||||||
|
"modifiers": {
|
||||||
|
"damageDealt": 0,
|
||||||
|
"healingReceived": 0
|
||||||
|
},
|
||||||
|
"periodic": {
|
||||||
|
"trigger": null,
|
||||||
|
"type": null,
|
||||||
|
"value": "",
|
||||||
|
"effectDescription": ""
|
||||||
|
},
|
||||||
|
"duration": {
|
||||||
|
"type": "untilRest",
|
||||||
|
"value": null,
|
||||||
|
"remaining": null
|
||||||
|
},
|
||||||
|
"stackable": true,
|
||||||
|
"maxStacks": 5,
|
||||||
|
"reference": "Core Rulebook p.36"
|
||||||
|
},
|
||||||
|
"effects": [],
|
||||||
|
"_key": "!items!vagabondStatusFatigued"
|
||||||
|
}
|
||||||
65
packs/_source/statuses/frightened.json
Normal file
65
packs/_source/statuses/frightened.json
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
{
|
||||||
|
"_id": "vagabondStatusFrightened",
|
||||||
|
"name": "Frightened",
|
||||||
|
"type": "status",
|
||||||
|
"img": "icons/svg/terror.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "<p>It has a -2 penalty to damage it deals.</p>",
|
||||||
|
"icon": "icons/svg/terror.svg",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"key": "system.modifiers.damageDealt",
|
||||||
|
"mode": 2,
|
||||||
|
"value": "-2",
|
||||||
|
"priority": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"includesStatuses": [],
|
||||||
|
"flags": {
|
||||||
|
"cantMove": false,
|
||||||
|
"cantRush": false,
|
||||||
|
"speedZero": false,
|
||||||
|
"crawlOnly": false,
|
||||||
|
"cantFocus": false,
|
||||||
|
"cantUseActions": false,
|
||||||
|
"onlyAttackMoveRush": false,
|
||||||
|
"cantSee": false,
|
||||||
|
"isVulnerable": false,
|
||||||
|
"closeAttacksAutoCrit": false,
|
||||||
|
"failsMightDexChecks": false,
|
||||||
|
"noMoraleChecks": false,
|
||||||
|
"immuneToFrightened": false,
|
||||||
|
"cantAttackCharmer": false,
|
||||||
|
"reducesItemSlots": false
|
||||||
|
},
|
||||||
|
"favorHinder": {
|
||||||
|
"hinderChecks": false,
|
||||||
|
"hinderSaves": false,
|
||||||
|
"hinderAttacks": false,
|
||||||
|
"favorAgainstChecks": false,
|
||||||
|
"favorAgainstSaves": false,
|
||||||
|
"favorAgainstAttacks": false,
|
||||||
|
"context": ""
|
||||||
|
},
|
||||||
|
"modifiers": {
|
||||||
|
"damageDealt": -2,
|
||||||
|
"healingReceived": 0
|
||||||
|
},
|
||||||
|
"periodic": {
|
||||||
|
"trigger": null,
|
||||||
|
"type": null,
|
||||||
|
"value": "",
|
||||||
|
"effectDescription": ""
|
||||||
|
},
|
||||||
|
"duration": {
|
||||||
|
"type": null,
|
||||||
|
"value": null,
|
||||||
|
"remaining": null
|
||||||
|
},
|
||||||
|
"stackable": false,
|
||||||
|
"maxStacks": 1,
|
||||||
|
"reference": "Core Rulebook p.36"
|
||||||
|
},
|
||||||
|
"effects": [],
|
||||||
|
"_key": "!items!vagabondStatusFrightened"
|
||||||
|
}
|
||||||
58
packs/_source/statuses/incapacitated.json
Normal file
58
packs/_source/statuses/incapacitated.json
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
{
|
||||||
|
"_id": "vagabondStatusIncapacitated",
|
||||||
|
"name": "Incapacitated",
|
||||||
|
"type": "status",
|
||||||
|
"img": "icons/svg/paralysis.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "<p>The following rules apply:</p><ul><li>It can't Focus or use its Actions or Move.</li><li>It fails all Might and Dexterity Checks.</li><li>It is Vulnerable.</li></ul>",
|
||||||
|
"icon": "icons/svg/paralysis.svg",
|
||||||
|
"changes": [],
|
||||||
|
"includesStatuses": ["Vulnerable"],
|
||||||
|
"flags": {
|
||||||
|
"cantMove": true,
|
||||||
|
"cantRush": false,
|
||||||
|
"speedZero": false,
|
||||||
|
"crawlOnly": false,
|
||||||
|
"cantFocus": true,
|
||||||
|
"cantUseActions": true,
|
||||||
|
"onlyAttackMoveRush": false,
|
||||||
|
"cantSee": false,
|
||||||
|
"isVulnerable": true,
|
||||||
|
"closeAttacksAutoCrit": false,
|
||||||
|
"failsMightDexChecks": true,
|
||||||
|
"noMoraleChecks": false,
|
||||||
|
"immuneToFrightened": false,
|
||||||
|
"cantAttackCharmer": false,
|
||||||
|
"reducesItemSlots": false
|
||||||
|
},
|
||||||
|
"favorHinder": {
|
||||||
|
"hinderChecks": false,
|
||||||
|
"hinderSaves": false,
|
||||||
|
"hinderAttacks": false,
|
||||||
|
"favorAgainstChecks": false,
|
||||||
|
"favorAgainstSaves": false,
|
||||||
|
"favorAgainstAttacks": false,
|
||||||
|
"context": ""
|
||||||
|
},
|
||||||
|
"modifiers": {
|
||||||
|
"damageDealt": 0,
|
||||||
|
"healingReceived": 0
|
||||||
|
},
|
||||||
|
"periodic": {
|
||||||
|
"trigger": null,
|
||||||
|
"type": null,
|
||||||
|
"value": "",
|
||||||
|
"effectDescription": ""
|
||||||
|
},
|
||||||
|
"duration": {
|
||||||
|
"type": null,
|
||||||
|
"value": null,
|
||||||
|
"remaining": null
|
||||||
|
},
|
||||||
|
"stackable": false,
|
||||||
|
"maxStacks": 1,
|
||||||
|
"reference": "Core Rulebook p.36"
|
||||||
|
},
|
||||||
|
"effects": [],
|
||||||
|
"_key": "!items!vagabondStatusIncapacitated"
|
||||||
|
}
|
||||||
58
packs/_source/statuses/invisible.json
Normal file
58
packs/_source/statuses/invisible.json
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
{
|
||||||
|
"_id": "vagabondStatusInvisible",
|
||||||
|
"name": "Invisible",
|
||||||
|
"type": "status",
|
||||||
|
"img": "icons/svg/invisible.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "<p>It can't be seen by normal senses and those that can't see it (p. 9) act as Blinded for Checks and Saves involving it.</p>",
|
||||||
|
"icon": "icons/svg/invisible.svg",
|
||||||
|
"changes": [],
|
||||||
|
"includesStatuses": [],
|
||||||
|
"flags": {
|
||||||
|
"cantMove": false,
|
||||||
|
"cantRush": false,
|
||||||
|
"speedZero": false,
|
||||||
|
"crawlOnly": false,
|
||||||
|
"cantFocus": false,
|
||||||
|
"cantUseActions": false,
|
||||||
|
"onlyAttackMoveRush": false,
|
||||||
|
"cantSee": false,
|
||||||
|
"isVulnerable": false,
|
||||||
|
"closeAttacksAutoCrit": false,
|
||||||
|
"failsMightDexChecks": false,
|
||||||
|
"noMoraleChecks": false,
|
||||||
|
"immuneToFrightened": false,
|
||||||
|
"cantAttackCharmer": false,
|
||||||
|
"reducesItemSlots": false
|
||||||
|
},
|
||||||
|
"favorHinder": {
|
||||||
|
"hinderChecks": false,
|
||||||
|
"hinderSaves": false,
|
||||||
|
"hinderAttacks": false,
|
||||||
|
"favorAgainstChecks": false,
|
||||||
|
"favorAgainstSaves": false,
|
||||||
|
"favorAgainstAttacks": false,
|
||||||
|
"context": "Others act as Blinded against this creature"
|
||||||
|
},
|
||||||
|
"modifiers": {
|
||||||
|
"damageDealt": 0,
|
||||||
|
"healingReceived": 0
|
||||||
|
},
|
||||||
|
"periodic": {
|
||||||
|
"trigger": null,
|
||||||
|
"type": null,
|
||||||
|
"value": "",
|
||||||
|
"effectDescription": ""
|
||||||
|
},
|
||||||
|
"duration": {
|
||||||
|
"type": null,
|
||||||
|
"value": null,
|
||||||
|
"remaining": null
|
||||||
|
},
|
||||||
|
"stackable": false,
|
||||||
|
"maxStacks": 1,
|
||||||
|
"reference": "Core Rulebook p.36"
|
||||||
|
},
|
||||||
|
"effects": [],
|
||||||
|
"_key": "!items!vagabondStatusInvisible"
|
||||||
|
}
|
||||||
65
packs/_source/statuses/paralyzed.json
Normal file
65
packs/_source/statuses/paralyzed.json
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
{
|
||||||
|
"_id": "vagabondStatusParalyzed",
|
||||||
|
"name": "Paralyzed",
|
||||||
|
"type": "status",
|
||||||
|
"img": "icons/svg/frozen.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "<p>It is Incapacitated and its Speed is 0.</p>",
|
||||||
|
"icon": "icons/svg/frozen.svg",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"key": "system.speed.walk",
|
||||||
|
"mode": 5,
|
||||||
|
"value": "0",
|
||||||
|
"priority": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"includesStatuses": ["Incapacitated"],
|
||||||
|
"flags": {
|
||||||
|
"cantMove": true,
|
||||||
|
"cantRush": false,
|
||||||
|
"speedZero": true,
|
||||||
|
"crawlOnly": false,
|
||||||
|
"cantFocus": true,
|
||||||
|
"cantUseActions": true,
|
||||||
|
"onlyAttackMoveRush": false,
|
||||||
|
"cantSee": false,
|
||||||
|
"isVulnerable": true,
|
||||||
|
"closeAttacksAutoCrit": false,
|
||||||
|
"failsMightDexChecks": true,
|
||||||
|
"noMoraleChecks": false,
|
||||||
|
"immuneToFrightened": false,
|
||||||
|
"cantAttackCharmer": false,
|
||||||
|
"reducesItemSlots": false
|
||||||
|
},
|
||||||
|
"favorHinder": {
|
||||||
|
"hinderChecks": false,
|
||||||
|
"hinderSaves": false,
|
||||||
|
"hinderAttacks": false,
|
||||||
|
"favorAgainstChecks": false,
|
||||||
|
"favorAgainstSaves": false,
|
||||||
|
"favorAgainstAttacks": false,
|
||||||
|
"context": ""
|
||||||
|
},
|
||||||
|
"modifiers": {
|
||||||
|
"damageDealt": 0,
|
||||||
|
"healingReceived": 0
|
||||||
|
},
|
||||||
|
"periodic": {
|
||||||
|
"trigger": null,
|
||||||
|
"type": null,
|
||||||
|
"value": "",
|
||||||
|
"effectDescription": ""
|
||||||
|
},
|
||||||
|
"duration": {
|
||||||
|
"type": null,
|
||||||
|
"value": null,
|
||||||
|
"remaining": null
|
||||||
|
},
|
||||||
|
"stackable": false,
|
||||||
|
"maxStacks": 1,
|
||||||
|
"reference": "Core Rulebook p.36"
|
||||||
|
},
|
||||||
|
"effects": [],
|
||||||
|
"_key": "!items!vagabondStatusParalyzed"
|
||||||
|
}
|
||||||
58
packs/_source/statuses/prone.json
Normal file
58
packs/_source/statuses/prone.json
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
{
|
||||||
|
"_id": "vagabondStatusProne",
|
||||||
|
"name": "Prone",
|
||||||
|
"type": "status",
|
||||||
|
"img": "icons/svg/falling.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "<p>You can either drop or stand from Prone by using 10 feet of Speed. While Prone, the following rules apply:</p><ul><li>It can only move by crawling (2 feet of Speed for 1 foot of movement) and it can't Rush.</li><li>It is Vulnerable for the purposes of Melee Attacks and Dodge Checks.</li></ul>",
|
||||||
|
"icon": "icons/svg/falling.svg",
|
||||||
|
"changes": [],
|
||||||
|
"includesStatuses": [],
|
||||||
|
"flags": {
|
||||||
|
"cantMove": false,
|
||||||
|
"cantRush": true,
|
||||||
|
"speedZero": false,
|
||||||
|
"crawlOnly": true,
|
||||||
|
"cantFocus": false,
|
||||||
|
"cantUseActions": false,
|
||||||
|
"onlyAttackMoveRush": false,
|
||||||
|
"cantSee": false,
|
||||||
|
"isVulnerable": false,
|
||||||
|
"closeAttacksAutoCrit": false,
|
||||||
|
"failsMightDexChecks": false,
|
||||||
|
"noMoraleChecks": false,
|
||||||
|
"immuneToFrightened": false,
|
||||||
|
"cantAttackCharmer": false,
|
||||||
|
"reducesItemSlots": false
|
||||||
|
},
|
||||||
|
"favorHinder": {
|
||||||
|
"hinderChecks": false,
|
||||||
|
"hinderSaves": false,
|
||||||
|
"hinderAttacks": false,
|
||||||
|
"favorAgainstChecks": false,
|
||||||
|
"favorAgainstSaves": false,
|
||||||
|
"favorAgainstAttacks": false,
|
||||||
|
"context": "Vulnerable for Melee Attacks and Dodge Checks"
|
||||||
|
},
|
||||||
|
"modifiers": {
|
||||||
|
"damageDealt": 0,
|
||||||
|
"healingReceived": 0
|
||||||
|
},
|
||||||
|
"periodic": {
|
||||||
|
"trigger": null,
|
||||||
|
"type": null,
|
||||||
|
"value": "",
|
||||||
|
"effectDescription": ""
|
||||||
|
},
|
||||||
|
"duration": {
|
||||||
|
"type": null,
|
||||||
|
"value": null,
|
||||||
|
"remaining": null
|
||||||
|
},
|
||||||
|
"stackable": false,
|
||||||
|
"maxStacks": 1,
|
||||||
|
"reference": "Core Rulebook p.36"
|
||||||
|
},
|
||||||
|
"effects": [],
|
||||||
|
"_key": "!items!vagabondStatusProne"
|
||||||
|
}
|
||||||
65
packs/_source/statuses/restrained.json
Normal file
65
packs/_source/statuses/restrained.json
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
{
|
||||||
|
"_id": "vagabondStatusRestrained",
|
||||||
|
"name": "Restrained",
|
||||||
|
"type": "status",
|
||||||
|
"img": "icons/svg/net.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "<p>It is Vulnerable, and its Speed is 0.</p>",
|
||||||
|
"icon": "icons/svg/net.svg",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"key": "system.speed.walk",
|
||||||
|
"mode": 5,
|
||||||
|
"value": "0",
|
||||||
|
"priority": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"includesStatuses": ["Vulnerable"],
|
||||||
|
"flags": {
|
||||||
|
"cantMove": false,
|
||||||
|
"cantRush": false,
|
||||||
|
"speedZero": true,
|
||||||
|
"crawlOnly": false,
|
||||||
|
"cantFocus": false,
|
||||||
|
"cantUseActions": false,
|
||||||
|
"onlyAttackMoveRush": false,
|
||||||
|
"cantSee": false,
|
||||||
|
"isVulnerable": true,
|
||||||
|
"closeAttacksAutoCrit": false,
|
||||||
|
"failsMightDexChecks": false,
|
||||||
|
"noMoraleChecks": false,
|
||||||
|
"immuneToFrightened": false,
|
||||||
|
"cantAttackCharmer": false,
|
||||||
|
"reducesItemSlots": false
|
||||||
|
},
|
||||||
|
"favorHinder": {
|
||||||
|
"hinderChecks": false,
|
||||||
|
"hinderSaves": false,
|
||||||
|
"hinderAttacks": false,
|
||||||
|
"favorAgainstChecks": false,
|
||||||
|
"favorAgainstSaves": false,
|
||||||
|
"favorAgainstAttacks": false,
|
||||||
|
"context": ""
|
||||||
|
},
|
||||||
|
"modifiers": {
|
||||||
|
"damageDealt": 0,
|
||||||
|
"healingReceived": 0
|
||||||
|
},
|
||||||
|
"periodic": {
|
||||||
|
"trigger": null,
|
||||||
|
"type": null,
|
||||||
|
"value": "",
|
||||||
|
"effectDescription": ""
|
||||||
|
},
|
||||||
|
"duration": {
|
||||||
|
"type": null,
|
||||||
|
"value": null,
|
||||||
|
"remaining": null
|
||||||
|
},
|
||||||
|
"stackable": false,
|
||||||
|
"maxStacks": 1,
|
||||||
|
"reference": "Core Rulebook p.36"
|
||||||
|
},
|
||||||
|
"effects": [],
|
||||||
|
"_key": "!items!vagabondStatusRestrained"
|
||||||
|
}
|
||||||
65
packs/_source/statuses/sickened.json
Normal file
65
packs/_source/statuses/sickened.json
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
{
|
||||||
|
"_id": "vagabondStatusSickened",
|
||||||
|
"name": "Sickened",
|
||||||
|
"type": "status",
|
||||||
|
"img": "icons/svg/poison.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "<p>The following rules apply:</p><ul><li>It has a -2 penalty to any healing it receives.</li><li>Additional effects may be indicated in parenthesis, which apply while it is Sickened.</li></ul>",
|
||||||
|
"icon": "icons/svg/poison.svg",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"key": "system.modifiers.healingReceived",
|
||||||
|
"mode": 2,
|
||||||
|
"value": "-2",
|
||||||
|
"priority": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"includesStatuses": [],
|
||||||
|
"flags": {
|
||||||
|
"cantMove": false,
|
||||||
|
"cantRush": false,
|
||||||
|
"speedZero": false,
|
||||||
|
"crawlOnly": false,
|
||||||
|
"cantFocus": false,
|
||||||
|
"cantUseActions": false,
|
||||||
|
"onlyAttackMoveRush": false,
|
||||||
|
"cantSee": false,
|
||||||
|
"isVulnerable": false,
|
||||||
|
"closeAttacksAutoCrit": false,
|
||||||
|
"failsMightDexChecks": false,
|
||||||
|
"noMoraleChecks": false,
|
||||||
|
"immuneToFrightened": false,
|
||||||
|
"cantAttackCharmer": false,
|
||||||
|
"reducesItemSlots": false
|
||||||
|
},
|
||||||
|
"favorHinder": {
|
||||||
|
"hinderChecks": false,
|
||||||
|
"hinderSaves": false,
|
||||||
|
"hinderAttacks": false,
|
||||||
|
"favorAgainstChecks": false,
|
||||||
|
"favorAgainstSaves": false,
|
||||||
|
"favorAgainstAttacks": false,
|
||||||
|
"context": ""
|
||||||
|
},
|
||||||
|
"modifiers": {
|
||||||
|
"damageDealt": 0,
|
||||||
|
"healingReceived": -2
|
||||||
|
},
|
||||||
|
"periodic": {
|
||||||
|
"trigger": null,
|
||||||
|
"type": null,
|
||||||
|
"value": "",
|
||||||
|
"effectDescription": ""
|
||||||
|
},
|
||||||
|
"duration": {
|
||||||
|
"type": null,
|
||||||
|
"value": null,
|
||||||
|
"remaining": null
|
||||||
|
},
|
||||||
|
"stackable": false,
|
||||||
|
"maxStacks": 1,
|
||||||
|
"reference": "Core Rulebook p.36"
|
||||||
|
},
|
||||||
|
"effects": [],
|
||||||
|
"_key": "!items!vagabondStatusSickened"
|
||||||
|
}
|
||||||
58
packs/_source/statuses/suffocating.json
Normal file
58
packs/_source/statuses/suffocating.json
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
{
|
||||||
|
"_id": "vagabondStatusSuffocating",
|
||||||
|
"name": "Suffocating",
|
||||||
|
"type": "status",
|
||||||
|
"img": "icons/svg/unconscious.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "<p>A creature can hold its breath for a number of rounds equal to its Might. After that, it begins Suffocating and takes 1d6 damage at the start of each of its turns until it can breathe again or dies.</p>",
|
||||||
|
"icon": "icons/svg/unconscious.svg",
|
||||||
|
"changes": [],
|
||||||
|
"includesStatuses": [],
|
||||||
|
"flags": {
|
||||||
|
"cantMove": false,
|
||||||
|
"cantRush": false,
|
||||||
|
"speedZero": false,
|
||||||
|
"crawlOnly": false,
|
||||||
|
"cantFocus": false,
|
||||||
|
"cantUseActions": false,
|
||||||
|
"onlyAttackMoveRush": false,
|
||||||
|
"cantSee": false,
|
||||||
|
"isVulnerable": false,
|
||||||
|
"closeAttacksAutoCrit": false,
|
||||||
|
"failsMightDexChecks": false,
|
||||||
|
"noMoraleChecks": false,
|
||||||
|
"immuneToFrightened": false,
|
||||||
|
"cantAttackCharmer": false,
|
||||||
|
"reducesItemSlots": false
|
||||||
|
},
|
||||||
|
"favorHinder": {
|
||||||
|
"hinderChecks": false,
|
||||||
|
"hinderSaves": false,
|
||||||
|
"hinderAttacks": false,
|
||||||
|
"favorAgainstChecks": false,
|
||||||
|
"favorAgainstSaves": false,
|
||||||
|
"favorAgainstAttacks": false,
|
||||||
|
"context": ""
|
||||||
|
},
|
||||||
|
"modifiers": {
|
||||||
|
"damageDealt": 0,
|
||||||
|
"healingReceived": 0
|
||||||
|
},
|
||||||
|
"periodic": {
|
||||||
|
"trigger": "turnStart",
|
||||||
|
"type": "damage",
|
||||||
|
"value": "1d6",
|
||||||
|
"effectDescription": "Takes 1d6 damage from suffocation"
|
||||||
|
},
|
||||||
|
"duration": {
|
||||||
|
"type": null,
|
||||||
|
"value": null,
|
||||||
|
"remaining": null
|
||||||
|
},
|
||||||
|
"stackable": false,
|
||||||
|
"maxStacks": 1,
|
||||||
|
"reference": "Core Rulebook p.36"
|
||||||
|
},
|
||||||
|
"effects": [],
|
||||||
|
"_key": "!items!vagabondStatusSuffocating"
|
||||||
|
}
|
||||||
58
packs/_source/statuses/unconscious.json
Normal file
58
packs/_source/statuses/unconscious.json
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
{
|
||||||
|
"_id": "vagabondStatusUnconscious",
|
||||||
|
"name": "Unconscious",
|
||||||
|
"type": "status",
|
||||||
|
"img": "icons/svg/sleep.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "<p>It is Blinded, Incapacitated, and Prone. In addition, close Attacks are automatically Critical Hits.</p>",
|
||||||
|
"icon": "icons/svg/sleep.svg",
|
||||||
|
"changes": [],
|
||||||
|
"includesStatuses": ["Blinded", "Incapacitated", "Prone"],
|
||||||
|
"flags": {
|
||||||
|
"cantMove": true,
|
||||||
|
"cantRush": true,
|
||||||
|
"speedZero": false,
|
||||||
|
"crawlOnly": false,
|
||||||
|
"cantFocus": true,
|
||||||
|
"cantUseActions": true,
|
||||||
|
"onlyAttackMoveRush": false,
|
||||||
|
"cantSee": true,
|
||||||
|
"isVulnerable": true,
|
||||||
|
"closeAttacksAutoCrit": true,
|
||||||
|
"failsMightDexChecks": true,
|
||||||
|
"noMoraleChecks": false,
|
||||||
|
"immuneToFrightened": false,
|
||||||
|
"cantAttackCharmer": false,
|
||||||
|
"reducesItemSlots": false
|
||||||
|
},
|
||||||
|
"favorHinder": {
|
||||||
|
"hinderChecks": false,
|
||||||
|
"hinderSaves": false,
|
||||||
|
"hinderAttacks": false,
|
||||||
|
"favorAgainstChecks": false,
|
||||||
|
"favorAgainstSaves": false,
|
||||||
|
"favorAgainstAttacks": false,
|
||||||
|
"context": ""
|
||||||
|
},
|
||||||
|
"modifiers": {
|
||||||
|
"damageDealt": 0,
|
||||||
|
"healingReceived": 0
|
||||||
|
},
|
||||||
|
"periodic": {
|
||||||
|
"trigger": null,
|
||||||
|
"type": null,
|
||||||
|
"value": "",
|
||||||
|
"effectDescription": ""
|
||||||
|
},
|
||||||
|
"duration": {
|
||||||
|
"type": null,
|
||||||
|
"value": null,
|
||||||
|
"remaining": null
|
||||||
|
},
|
||||||
|
"stackable": false,
|
||||||
|
"maxStacks": 1,
|
||||||
|
"reference": "Core Rulebook p.36"
|
||||||
|
},
|
||||||
|
"effects": [],
|
||||||
|
"_key": "!items!vagabondStatusUnconscious"
|
||||||
|
}
|
||||||
58
packs/_source/statuses/vulnerable.json
Normal file
58
packs/_source/statuses/vulnerable.json
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
{
|
||||||
|
"_id": "vagabondStatusVulnerable",
|
||||||
|
"name": "Vulnerable",
|
||||||
|
"type": "status",
|
||||||
|
"img": "icons/svg/target.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "<p>Attacks against it have Favor. It has Hinder on any Dodge Check.</p>",
|
||||||
|
"icon": "icons/svg/target.svg",
|
||||||
|
"changes": [],
|
||||||
|
"includesStatuses": [],
|
||||||
|
"flags": {
|
||||||
|
"cantMove": false,
|
||||||
|
"cantRush": false,
|
||||||
|
"speedZero": false,
|
||||||
|
"crawlOnly": false,
|
||||||
|
"cantFocus": false,
|
||||||
|
"cantUseActions": false,
|
||||||
|
"onlyAttackMoveRush": false,
|
||||||
|
"cantSee": false,
|
||||||
|
"isVulnerable": true,
|
||||||
|
"closeAttacksAutoCrit": false,
|
||||||
|
"failsMightDexChecks": false,
|
||||||
|
"noMoraleChecks": false,
|
||||||
|
"immuneToFrightened": false,
|
||||||
|
"cantAttackCharmer": false,
|
||||||
|
"reducesItemSlots": false
|
||||||
|
},
|
||||||
|
"favorHinder": {
|
||||||
|
"hinderChecks": false,
|
||||||
|
"hinderSaves": false,
|
||||||
|
"hinderAttacks": false,
|
||||||
|
"favorAgainstChecks": false,
|
||||||
|
"favorAgainstSaves": false,
|
||||||
|
"favorAgainstAttacks": true,
|
||||||
|
"context": "Hinder on Dodge Checks"
|
||||||
|
},
|
||||||
|
"modifiers": {
|
||||||
|
"damageDealt": 0,
|
||||||
|
"healingReceived": 0
|
||||||
|
},
|
||||||
|
"periodic": {
|
||||||
|
"trigger": null,
|
||||||
|
"type": null,
|
||||||
|
"value": "",
|
||||||
|
"effectDescription": ""
|
||||||
|
},
|
||||||
|
"duration": {
|
||||||
|
"type": null,
|
||||||
|
"value": null,
|
||||||
|
"remaining": null
|
||||||
|
},
|
||||||
|
"stackable": false,
|
||||||
|
"maxStacks": 1,
|
||||||
|
"reference": "Core Rulebook p.36"
|
||||||
|
},
|
||||||
|
"effects": [],
|
||||||
|
"_key": "!items!vagabondStatusVulnerable"
|
||||||
|
}
|
||||||
BIN
packs/ancestries/000195.ldb
Normal file
BIN
packs/ancestries/000195.ldb
Normal file
Binary file not shown.
@ -1 +1 @@
|
|||||||
MANIFEST-000121
|
MANIFEST-000192
|
||||||
|
|||||||
@ -1,5 +1,14 @@
|
|||||||
2025/12/17-07:01:48.746097 7fca5d8006c0 Recovering log #120
|
2025/12/17-20:32:51.540867 7fa913e006c0 Recovering log #191
|
||||||
2025/12/17-07:01:48.746210 7fca5d8006c0 Level-0 table #122: started
|
2025/12/17-20:32:51.540971 7fa913e006c0 Level-0 table #193: started
|
||||||
2025/12/17-07:01:48.747367 7fca5d8006c0 Level-0 table #122: 3493 bytes OK
|
2025/12/17-20:32:51.542004 7fa913e006c0 Level-0 table #193: 3491 bytes OK
|
||||||
2025/12/17-07:01:48.749813 7fca5d8006c0 Delete type=0 #120
|
2025/12/17-20:32:51.544454 7fa913e006c0 Delete type=0 #191
|
||||||
2025/12/17-07:01:48.749923 7fca5d8006c0 Delete type=3 #119
|
2025/12/17-20:32:51.544525 7fa913e006c0 Delete type=3 #189
|
||||||
|
2025/12/17-20:32:51.544647 7fa912a006c0 Compacting 4@0 + 1@1 files
|
||||||
|
2025/12/17-20:32:51.546114 7fa912a006c0 Generated table #195@0: 8 keys, 3720 bytes
|
||||||
|
2025/12/17-20:32:51.546208 7fa912a006c0 Compacted 4@0 + 1@1 files => 3720 bytes
|
||||||
|
2025/12/17-20:32:51.547411 7fa912a006c0 compacted to: files[ 0 1 0 0 0 0 0 ]
|
||||||
|
2025/12/17-20:32:51.547717 7fa912a006c0 Delete type=2 #182
|
||||||
|
2025/12/17-20:32:51.547857 7fa912a006c0 Delete type=2 #184
|
||||||
|
2025/12/17-20:32:51.547988 7fa912a006c0 Delete type=2 #187
|
||||||
|
2025/12/17-20:32:51.548146 7fa912a006c0 Delete type=2 #190
|
||||||
|
2025/12/17-20:32:51.548302 7fa912a006c0 Delete type=2 #193
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
2025/12/17-06:56:48.455056 7f4a862006c0 Recovering log #115
|
2025/12/17-20:24:43.671501 7f20ea2006c0 Recovering log #188
|
||||||
2025/12/17-06:56:48.457304 7f4a862006c0 Delete type=3 #111
|
2025/12/17-20:24:43.671657 7f20ea2006c0 Level-0 table #190: started
|
||||||
2025/12/17-06:56:48.457368 7f4a862006c0 Delete type=0 #115
|
2025/12/17-20:24:43.672684 7f20ea2006c0 Level-0 table #190: 3491 bytes OK
|
||||||
|
2025/12/17-20:24:43.675122 7f20ea2006c0 Delete type=0 #188
|
||||||
|
2025/12/17-20:24:43.675212 7f20ea2006c0 Delete type=3 #186
|
||||||
|
|||||||
BIN
packs/ancestries/MANIFEST-000192
Normal file
BIN
packs/ancestries/MANIFEST-000192
Normal file
Binary file not shown.
BIN
packs/armor/000077.ldb
Normal file
BIN
packs/armor/000077.ldb
Normal file
Binary file not shown.
@ -1 +1 @@
|
|||||||
MANIFEST-000006
|
MANIFEST-000074
|
||||||
|
|||||||
@ -1,3 +1,14 @@
|
|||||||
2025/12/17-07:01:48.783757 7fca5ce006c0 Recovering log #4
|
2025/12/17-20:32:51.586467 7fa918e006c0 Recovering log #73
|
||||||
2025/12/17-07:01:48.785948 7fca5ce006c0 Delete type=3 #2
|
2025/12/17-20:32:51.586558 7fa918e006c0 Level-0 table #75: started
|
||||||
2025/12/17-07:01:48.786033 7fca5ce006c0 Delete type=0 #4
|
2025/12/17-20:32:51.587354 7fa918e006c0 Level-0 table #75: 1190 bytes OK
|
||||||
|
2025/12/17-20:32:51.589913 7fa918e006c0 Delete type=0 #73
|
||||||
|
2025/12/17-20:32:51.590000 7fa918e006c0 Delete type=3 #71
|
||||||
|
2025/12/17-20:32:51.590083 7fa912a006c0 Compacting 4@0 + 1@1 files
|
||||||
|
2025/12/17-20:32:51.591405 7fa912a006c0 Generated table #77@0: 6 keys, 1275 bytes
|
||||||
|
2025/12/17-20:32:51.591532 7fa912a006c0 Compacted 4@0 + 1@1 files => 1275 bytes
|
||||||
|
2025/12/17-20:32:51.592772 7fa912a006c0 compacted to: files[ 0 1 0 0 0 0 0 ]
|
||||||
|
2025/12/17-20:32:51.593114 7fa912a006c0 Delete type=2 #64
|
||||||
|
2025/12/17-20:32:51.593305 7fa912a006c0 Delete type=2 #66
|
||||||
|
2025/12/17-20:32:51.593420 7fa912a006c0 Delete type=2 #69
|
||||||
|
2025/12/17-20:32:51.593526 7fa912a006c0 Delete type=2 #72
|
||||||
|
2025/12/17-20:32:51.593681 7fa912a006c0 Delete type=2 #75
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
2025/12/17-00:54:57.262541 7f60caffd6c0 Delete type=3 #1
|
2025/12/17-20:24:43.706676 7f20e98006c0 Recovering log #70
|
||||||
2025/12/17-00:54:57.264605 7f60ca7fc6c0 Level-0 table #5: started
|
2025/12/17-20:24:43.706780 7f20e98006c0 Level-0 table #72: started
|
||||||
2025/12/17-00:54:57.265201 7f60ca7fc6c0 Level-0 table #5: 1041 bytes OK
|
2025/12/17-20:24:43.707738 7f20e98006c0 Level-0 table #72: 1190 bytes OK
|
||||||
2025/12/17-00:54:57.266154 7f60ca7fc6c0 Delete type=0 #3
|
2025/12/17-20:24:43.710189 7f20e98006c0 Delete type=0 #70
|
||||||
2025/12/17-00:54:57.266221 7f60ca7fc6c0 Manual compaction at level-0 from '!items!vagabondArmorHeavy' @ 72057594037927935 : 1 .. '!items!vagabondArmorMedium' @ 0 : 0; will stop at (end)
|
2025/12/17-20:24:43.710289 7f20e98006c0 Delete type=3 #68
|
||||||
|
|||||||
BIN
packs/armor/MANIFEST-000074
Normal file
BIN
packs/armor/MANIFEST-000074
Normal file
Binary file not shown.
BIN
packs/classes/000126.ldb
Normal file
BIN
packs/classes/000126.ldb
Normal file
Binary file not shown.
@ -1 +1 @@
|
|||||||
MANIFEST-000052
|
MANIFEST-000123
|
||||||
|
|||||||
@ -1,5 +1,14 @@
|
|||||||
2025/12/17-07:01:48.752263 7fca5ce006c0 Recovering log #51
|
2025/12/17-20:32:51.549270 7fa918e006c0 Recovering log #122
|
||||||
2025/12/17-07:01:48.752517 7fca5ce006c0 Level-0 table #53: started
|
2025/12/17-20:32:51.549589 7fa918e006c0 Level-0 table #124: started
|
||||||
2025/12/17-07:01:48.754100 7fca5ce006c0 Level-0 table #53: 27079 bytes OK
|
2025/12/17-20:32:51.551450 7fa918e006c0 Level-0 table #124: 27082 bytes OK
|
||||||
2025/12/17-07:01:48.756444 7fca5ce006c0 Delete type=0 #51
|
2025/12/17-20:32:51.554064 7fa918e006c0 Delete type=0 #122
|
||||||
2025/12/17-07:01:48.756596 7fca5ce006c0 Delete type=3 #50
|
2025/12/17-20:32:51.554149 7fa918e006c0 Delete type=3 #120
|
||||||
|
2025/12/17-20:32:51.554269 7fa912a006c0 Compacting 4@0 + 1@1 files
|
||||||
|
2025/12/17-20:32:51.556945 7fa912a006c0 Generated table #126@0: 19 keys, 28000 bytes
|
||||||
|
2025/12/17-20:32:51.556983 7fa912a006c0 Compacted 4@0 + 1@1 files => 28000 bytes
|
||||||
|
2025/12/17-20:32:51.558103 7fa912a006c0 compacted to: files[ 0 1 0 0 0 0 0 ]
|
||||||
|
2025/12/17-20:32:51.558336 7fa912a006c0 Delete type=2 #113
|
||||||
|
2025/12/17-20:32:51.558463 7fa912a006c0 Delete type=2 #115
|
||||||
|
2025/12/17-20:32:51.558564 7fa912a006c0 Delete type=2 #118
|
||||||
|
2025/12/17-20:32:51.558667 7fa912a006c0 Delete type=2 #121
|
||||||
|
2025/12/17-20:32:51.558767 7fa912a006c0 Delete type=2 #124
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
2025/12/17-06:56:48.460549 7f4a876006c0 Recovering log #46
|
2025/12/17-20:24:43.677565 7f20e98006c0 Recovering log #119
|
||||||
2025/12/17-06:56:48.462998 7f4a876006c0 Delete type=3 #42
|
2025/12/17-20:24:43.677777 7f20e98006c0 Level-0 table #121: started
|
||||||
2025/12/17-06:56:48.463089 7f4a876006c0 Delete type=0 #46
|
2025/12/17-20:24:43.679620 7f20e98006c0 Level-0 table #121: 27082 bytes OK
|
||||||
|
2025/12/17-20:24:43.681908 7f20e98006c0 Delete type=0 #119
|
||||||
|
2025/12/17-20:24:43.681991 7f20e98006c0 Delete type=3 #117
|
||||||
|
|||||||
BIN
packs/classes/MANIFEST-000123
Normal file
BIN
packs/classes/MANIFEST-000123
Normal file
Binary file not shown.
BIN
packs/equipment/000082.ldb
Normal file
BIN
packs/equipment/000082.ldb
Normal file
Binary file not shown.
@ -1 +1 @@
|
|||||||
MANIFEST-000010
|
MANIFEST-000079
|
||||||
|
|||||||
@ -1,3 +1,14 @@
|
|||||||
2025/12/17-07:01:48.787791 7fca5ec006c0 Recovering log #8
|
2025/12/17-20:32:51.593884 7fa9198006c0 Recovering log #78
|
||||||
2025/12/17-07:01:48.790138 7fca5ec006c0 Delete type=3 #6
|
2025/12/17-20:32:51.594727 7fa9198006c0 Level-0 table #80: started
|
||||||
2025/12/17-07:01:48.790246 7fca5ec006c0 Delete type=0 #8
|
2025/12/17-20:32:51.598554 7fa9198006c0 Level-0 table #80: 74375 bytes OK
|
||||||
|
2025/12/17-20:32:51.601037 7fa9198006c0 Delete type=0 #78
|
||||||
|
2025/12/17-20:32:51.601164 7fa9198006c0 Delete type=3 #76
|
||||||
|
2025/12/17-20:32:51.601336 7fa912a006c0 Compacting 4@0 + 1@1 files
|
||||||
|
2025/12/17-20:32:51.606358 7fa912a006c0 Generated table #82@0: 371 keys, 57802 bytes
|
||||||
|
2025/12/17-20:32:51.606395 7fa912a006c0 Compacted 4@0 + 1@1 files => 57802 bytes
|
||||||
|
2025/12/17-20:32:51.607538 7fa912a006c0 compacted to: files[ 0 1 0 0 0 0 0 ]
|
||||||
|
2025/12/17-20:32:51.607782 7fa912a006c0 Delete type=2 #69
|
||||||
|
2025/12/17-20:32:51.607961 7fa912a006c0 Delete type=2 #71
|
||||||
|
2025/12/17-20:32:51.608101 7fa912a006c0 Delete type=2 #74
|
||||||
|
2025/12/17-20:32:51.608873 7fa912a006c0 Delete type=2 #77
|
||||||
|
2025/12/17-20:32:51.609020 7fa912a006c0 Delete type=2 #80
|
||||||
|
|||||||
@ -1,7 +1,5 @@
|
|||||||
2025/12/17-00:56:12.031305 7f1a07fff6c0 Recovering log #5
|
2025/12/17-20:24:43.712652 7f20eac006c0 Recovering log #75
|
||||||
2025/12/17-00:56:12.064751 7f1a07fff6c0 Delete type=0 #5
|
2025/12/17-20:24:43.713463 7f20eac006c0 Level-0 table #77: started
|
||||||
2025/12/17-00:56:12.064779 7f1a07fff6c0 Delete type=3 #4
|
2025/12/17-20:24:43.717482 7f20eac006c0 Level-0 table #77: 74433 bytes OK
|
||||||
2025/12/17-00:56:12.068203 7f1a063ff6c0 Level-0 table #9: started
|
2025/12/17-20:24:43.720016 7f20eac006c0 Delete type=0 #75
|
||||||
2025/12/17-00:56:12.069557 7f1a063ff6c0 Level-0 table #9: 56954 bytes OK
|
2025/12/17-20:24:43.720128 7f20eac006c0 Delete type=3 #73
|
||||||
2025/12/17-00:56:12.070449 7f1a063ff6c0 Delete type=0 #7
|
|
||||||
2025/12/17-00:56:12.070542 7f1a063ff6c0 Manual compaction at level-0 from '!items!vagabondEquipAccordion' @ 72057594037927935 : 1 .. '!items.effects!vagabondEquipBackpack.backpackSlotBonus' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
BIN
packs/equipment/MANIFEST-000079
Normal file
BIN
packs/equipment/MANIFEST-000079
Normal file
Binary file not shown.
BIN
packs/perks/000178.ldb
Normal file
BIN
packs/perks/000178.ldb
Normal file
Binary file not shown.
@ -1 +1 @@
|
|||||||
MANIFEST-000105
|
MANIFEST-000175
|
||||||
|
|||||||
@ -1,5 +1,14 @@
|
|||||||
2025/12/17-07:01:48.769135 7fca5e2006c0 Recovering log #104
|
2025/12/17-20:32:51.568408 7fa9134006c0 Recovering log #174
|
||||||
2025/12/17-07:01:48.769497 7fca5e2006c0 Level-0 table #106: started
|
2025/12/17-20:32:51.568779 7fa9134006c0 Level-0 table #176: started
|
||||||
2025/12/17-07:01:48.773757 7fca5e2006c0 Level-0 table #106: 32401 bytes OK
|
2025/12/17-20:32:51.570760 7fa9134006c0 Level-0 table #176: 31984 bytes OK
|
||||||
2025/12/17-07:01:48.777561 7fca5e2006c0 Delete type=0 #104
|
2025/12/17-20:32:51.572940 7fa9134006c0 Delete type=0 #174
|
||||||
2025/12/17-07:01:48.777680 7fca5e2006c0 Delete type=3 #103
|
2025/12/17-20:32:51.573032 7fa9134006c0 Delete type=3 #172
|
||||||
|
2025/12/17-20:32:51.573143 7fa912a006c0 Compacting 4@0 + 1@1 files
|
||||||
|
2025/12/17-20:32:51.576294 7fa912a006c0 Generated table #178@0: 104 keys, 28420 bytes
|
||||||
|
2025/12/17-20:32:51.576391 7fa912a006c0 Compacted 4@0 + 1@1 files => 28420 bytes
|
||||||
|
2025/12/17-20:32:51.577753 7fa912a006c0 compacted to: files[ 0 1 0 0 0 0 0 ]
|
||||||
|
2025/12/17-20:32:51.578047 7fa912a006c0 Delete type=2 #165
|
||||||
|
2025/12/17-20:32:51.578189 7fa912a006c0 Delete type=2 #167
|
||||||
|
2025/12/17-20:32:51.578304 7fa912a006c0 Delete type=2 #170
|
||||||
|
2025/12/17-20:32:51.578397 7fa912a006c0 Delete type=2 #173
|
||||||
|
2025/12/17-20:32:51.578494 7fa912a006c0 Delete type=2 #176
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
2025/12/17-06:56:48.469994 7f4a86c006c0 Recovering log #100
|
2025/12/17-20:24:43.691811 7f20eb6006c0 Recovering log #171
|
||||||
2025/12/17-06:56:48.472443 7f4a86c006c0 Delete type=3 #98
|
2025/12/17-20:24:43.692103 7f20eb6006c0 Level-0 table #173: started
|
||||||
2025/12/17-06:56:48.472537 7f4a86c006c0 Delete type=0 #100
|
2025/12/17-20:24:43.694173 7f20eb6006c0 Level-0 table #173: 31982 bytes OK
|
||||||
|
2025/12/17-20:24:43.696723 7f20eb6006c0 Delete type=0 #171
|
||||||
|
2025/12/17-20:24:43.696850 7f20eb6006c0 Delete type=3 #169
|
||||||
|
|||||||
BIN
packs/perks/MANIFEST-000175
Normal file
BIN
packs/perks/MANIFEST-000175
Normal file
Binary file not shown.
BIN
packs/spells/000141.ldb
Normal file
BIN
packs/spells/000141.ldb
Normal file
Binary file not shown.
@ -1 +1 @@
|
|||||||
MANIFEST-000067
|
MANIFEST-000138
|
||||||
|
|||||||
@ -1,5 +1,14 @@
|
|||||||
2025/12/17-07:01:48.758847 7fca5ec006c0 Recovering log #66
|
2025/12/17-20:32:51.558873 7fa9198006c0 Recovering log #137
|
||||||
2025/12/17-07:01:48.759124 7fca5ec006c0 Level-0 table #68: started
|
2025/12/17-20:32:51.559161 7fa9198006c0 Level-0 table #139: started
|
||||||
2025/12/17-07:01:48.763630 7fca5ec006c0 Level-0 table #68: 24215 bytes OK
|
2025/12/17-20:32:51.561135 7fa9198006c0 Level-0 table #139: 22928 bytes OK
|
||||||
2025/12/17-07:01:48.765999 7fca5ec006c0 Delete type=0 #66
|
2025/12/17-20:32:51.563502 7fa9198006c0 Delete type=0 #137
|
||||||
2025/12/17-07:01:48.766073 7fca5ec006c0 Delete type=3 #65
|
2025/12/17-20:32:51.563573 7fa9198006c0 Delete type=3 #135
|
||||||
|
2025/12/17-20:32:51.563654 7fa912a006c0 Compacting 4@0 + 1@1 files
|
||||||
|
2025/12/17-20:32:51.566217 7fa912a006c0 Generated table #141@0: 59 keys, 21209 bytes
|
||||||
|
2025/12/17-20:32:51.566286 7fa912a006c0 Compacted 4@0 + 1@1 files => 21209 bytes
|
||||||
|
2025/12/17-20:32:51.567497 7fa912a006c0 compacted to: files[ 0 1 0 0 0 0 0 ]
|
||||||
|
2025/12/17-20:32:51.567799 7fa912a006c0 Delete type=2 #128
|
||||||
|
2025/12/17-20:32:51.567974 7fa912a006c0 Delete type=2 #130
|
||||||
|
2025/12/17-20:32:51.568120 7fa912a006c0 Delete type=2 #133
|
||||||
|
2025/12/17-20:32:51.568252 7fa912a006c0 Delete type=2 #136
|
||||||
|
2025/12/17-20:32:51.568398 7fa912a006c0 Delete type=2 #139
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
2025/12/17-06:56:48.465393 7f4a858006c0 Recovering log #63
|
2025/12/17-20:24:43.684399 7f20eac006c0 Recovering log #134
|
||||||
2025/12/17-06:56:48.467790 7f4a858006c0 Delete type=3 #61
|
2025/12/17-20:24:43.684679 7f20eac006c0 Level-0 table #136: started
|
||||||
2025/12/17-06:56:48.467910 7f4a858006c0 Delete type=0 #63
|
2025/12/17-20:24:43.686489 7f20eac006c0 Level-0 table #136: 22930 bytes OK
|
||||||
|
2025/12/17-20:24:43.689010 7f20eac006c0 Delete type=0 #134
|
||||||
|
2025/12/17-20:24:43.689084 7f20eac006c0 Delete type=3 #132
|
||||||
|
|||||||
BIN
packs/spells/MANIFEST-000138
Normal file
BIN
packs/spells/MANIFEST-000138
Normal file
Binary file not shown.
BIN
packs/statuses/000005.ldb
Executable file
BIN
packs/statuses/000005.ldb
Executable file
Binary file not shown.
BIN
packs/statuses/000020.ldb
Normal file
BIN
packs/statuses/000020.ldb
Normal file
Binary file not shown.
BIN
packs/statuses/000022.ldb
Normal file
BIN
packs/statuses/000022.ldb
Normal file
Binary file not shown.
BIN
packs/statuses/000025.ldb
Normal file
BIN
packs/statuses/000025.ldb
Normal file
Binary file not shown.
1
packs/statuses/CURRENT
Normal file
1
packs/statuses/CURRENT
Normal file
@ -0,0 +1 @@
|
|||||||
|
MANIFEST-000024
|
||||||
0
packs/statuses/LOCK
Normal file
0
packs/statuses/LOCK
Normal file
5
packs/statuses/LOG
Normal file
5
packs/statuses/LOG
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
2025/12/17-20:32:51.607024 7fa913e006c0 Recovering log #23
|
||||||
|
2025/12/17-20:32:51.607711 7fa913e006c0 Level-0 table #25: started
|
||||||
|
2025/12/17-20:32:51.609113 7fa913e006c0 Level-0 table #25: 7582 bytes OK
|
||||||
|
2025/12/17-20:32:51.611605 7fa913e006c0 Delete type=0 #23
|
||||||
|
2025/12/17-20:32:51.611673 7fa913e006c0 Delete type=3 #21
|
||||||
5
packs/statuses/LOG.old
Normal file
5
packs/statuses/LOG.old
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
2025/12/17-20:24:43.724411 7f20ea2006c0 Recovering log #19
|
||||||
|
2025/12/17-20:24:43.724546 7f20ea2006c0 Level-0 table #22: started
|
||||||
|
2025/12/17-20:24:43.725885 7f20ea2006c0 Level-0 table #22: 7582 bytes OK
|
||||||
|
2025/12/17-20:24:43.728462 7f20ea2006c0 Delete type=0 #19
|
||||||
|
2025/12/17-20:24:43.728558 7f20ea2006c0 Delete type=3 #17
|
||||||
BIN
packs/statuses/MANIFEST-000024
Normal file
BIN
packs/statuses/MANIFEST-000024
Normal file
Binary file not shown.
BIN
packs/weapons/000077.ldb
Normal file
BIN
packs/weapons/000077.ldb
Normal file
Binary file not shown.
@ -1 +1 @@
|
|||||||
MANIFEST-000006
|
MANIFEST-000074
|
||||||
|
|||||||
@ -1,3 +1,14 @@
|
|||||||
2025/12/17-07:01:48.779786 7fca5d8006c0 Recovering log #4
|
2025/12/17-20:32:51.577820 7fa913e006c0 Recovering log #73
|
||||||
2025/12/17-07:01:48.781959 7fca5d8006c0 Delete type=3 #2
|
2025/12/17-20:32:51.578056 7fa913e006c0 Level-0 table #75: started
|
||||||
2025/12/17-07:01:48.782030 7fca5d8006c0 Delete type=0 #4
|
2025/12/17-20:32:51.579615 7fa913e006c0 Level-0 table #75: 14097 bytes OK
|
||||||
|
2025/12/17-20:32:51.582010 7fa913e006c0 Delete type=0 #73
|
||||||
|
2025/12/17-20:32:51.582097 7fa913e006c0 Delete type=3 #71
|
||||||
|
2025/12/17-20:32:51.582214 7fa912a006c0 Compacting 4@0 + 1@1 files
|
||||||
|
2025/12/17-20:32:51.584350 7fa912a006c0 Generated table #77@0: 44 keys, 11579 bytes
|
||||||
|
2025/12/17-20:32:51.584388 7fa912a006c0 Compacted 4@0 + 1@1 files => 11579 bytes
|
||||||
|
2025/12/17-20:32:51.585706 7fa912a006c0 compacted to: files[ 0 1 0 0 0 0 0 ]
|
||||||
|
2025/12/17-20:32:51.585923 7fa912a006c0 Delete type=2 #64
|
||||||
|
2025/12/17-20:32:51.586060 7fa912a006c0 Delete type=2 #66
|
||||||
|
2025/12/17-20:32:51.586166 7fa912a006c0 Delete type=2 #69
|
||||||
|
2025/12/17-20:32:51.586261 7fa912a006c0 Delete type=2 #72
|
||||||
|
2025/12/17-20:32:51.586347 7fa912a006c0 Delete type=2 #75
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
2025/12/17-00:54:56.971891 7f5c477fe6c0 Delete type=3 #1
|
2025/12/17-20:24:43.699714 7f20ea2006c0 Recovering log #70
|
||||||
2025/12/17-00:54:56.974013 7f5c453ff6c0 Level-0 table #5: started
|
2025/12/17-20:24:43.699938 7f20ea2006c0 Level-0 table #72: started
|
||||||
2025/12/17-00:54:56.975425 7f5c453ff6c0 Level-0 table #5: 11176 bytes OK
|
2025/12/17-20:24:43.701440 7f20ea2006c0 Level-0 table #72: 14100 bytes OK
|
||||||
2025/12/17-00:54:56.976648 7f5c453ff6c0 Delete type=0 #3
|
2025/12/17-20:24:43.703861 7f20ea2006c0 Delete type=0 #70
|
||||||
2025/12/17-00:54:56.976720 7f5c453ff6c0 Manual compaction at level-0 from '!items!vagabondWeaponArbalest' @ 72057594037927935 : 1 .. '!items!vagabondWeaponWhipLeather' @ 0 : 0; will stop at (end)
|
2025/12/17-20:24:43.703956 7f20ea2006c0 Delete type=3 #68
|
||||||
|
|||||||
BIN
packs/weapons/MANIFEST-000074
Normal file
BIN
packs/weapons/MANIFEST-000074
Normal file
Binary file not shown.
@ -70,6 +70,7 @@
|
|||||||
--color-badge-feature: #{mix($color-presence, $color-parchment, 15%)};
|
--color-badge-feature: #{mix($color-presence, $color-parchment, 15%)};
|
||||||
--color-badge-ancestry: #{mix($color-luck, $color-parchment, 15%)};
|
--color-badge-ancestry: #{mix($color-luck, $color-parchment, 15%)};
|
||||||
--color-badge-equipment: #{mix($color-dexterity, $color-parchment, 15%)};
|
--color-badge-equipment: #{mix($color-dexterity, $color-parchment, 15%)};
|
||||||
|
--color-badge-status: #{mix($color-danger, $color-parchment, 20%)};
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==========================================
|
// ==========================================
|
||||||
@ -143,4 +144,5 @@ body.theme-dark .vagabond:not(.theme-light),
|
|||||||
--color-badge-feature: #383028;
|
--color-badge-feature: #383028;
|
||||||
--color-badge-ancestry: #283838;
|
--color-badge-ancestry: #283838;
|
||||||
--color-badge-equipment: #283828;
|
--color-badge-equipment: #283828;
|
||||||
|
--color-badge-status: #3d2828;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -437,6 +437,30 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.damage-breakdown {
|
||||||
|
@include flex-center;
|
||||||
|
gap: $spacing-2;
|
||||||
|
margin-top: $spacing-2;
|
||||||
|
padding-top: $spacing-2;
|
||||||
|
border-top: 1px solid rgba(201, 68, 68, 0.2);
|
||||||
|
|
||||||
|
.damage-die {
|
||||||
|
@include flex-center;
|
||||||
|
gap: $spacing-1;
|
||||||
|
padding: $spacing-1 $spacing-2;
|
||||||
|
background-color: rgba(201, 68, 68, 0.15);
|
||||||
|
border-radius: $radius-md;
|
||||||
|
font-family: $font-family-mono;
|
||||||
|
font-weight: $font-weight-bold;
|
||||||
|
color: var(--color-text-primary);
|
||||||
|
|
||||||
|
i {
|
||||||
|
color: var(--color-danger);
|
||||||
|
font-size: $font-size-sm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.damage-formula {
|
.damage-formula {
|
||||||
@include flex-center;
|
@include flex-center;
|
||||||
gap: $spacing-2;
|
gap: $spacing-2;
|
||||||
@ -467,6 +491,54 @@
|
|||||||
text-transform: capitalize;
|
text-transform: capitalize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Roll Damage button
|
||||||
|
.card-buttons {
|
||||||
|
.roll-damage-btn {
|
||||||
|
@include flex-center;
|
||||||
|
gap: $spacing-2;
|
||||||
|
width: 100%;
|
||||||
|
padding: $spacing-2 $spacing-3;
|
||||||
|
background-color: rgba(201, 68, 68, 0.2);
|
||||||
|
border: 1px solid var(--color-danger);
|
||||||
|
border-radius: $radius-md;
|
||||||
|
color: var(--color-danger);
|
||||||
|
font-weight: $font-weight-semibold;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
|
||||||
|
&:hover:not(:disabled) {
|
||||||
|
background-color: rgba(201, 68, 68, 0.3);
|
||||||
|
border-color: var(--color-danger);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
opacity: 0.7;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.critical {
|
||||||
|
background-color: rgba(212, 163, 44, 0.2);
|
||||||
|
border-color: var(--color-warning);
|
||||||
|
color: var(--color-warning);
|
||||||
|
|
||||||
|
&:hover:not(:disabled) {
|
||||||
|
background-color: rgba(212, 163, 44, 0.3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.crit-label {
|
||||||
|
font-size: $font-size-sm;
|
||||||
|
color: var(--color-warning);
|
||||||
|
}
|
||||||
|
|
||||||
|
.damage-preview {
|
||||||
|
font-family: $font-family-mono;
|
||||||
|
font-size: $font-size-sm;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Spell card specific
|
// Spell card specific
|
||||||
|
|||||||
@ -325,6 +325,81 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==========================================
|
||||||
|
// STATUS BAR - Active Status Conditions
|
||||||
|
// ==========================================
|
||||||
|
.status-bar {
|
||||||
|
padding: $spacing-2 $spacing-4;
|
||||||
|
background-color: var(--color-bg-secondary);
|
||||||
|
border-bottom: 1px solid var(--color-border);
|
||||||
|
|
||||||
|
.status-list {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: $spacing-2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-chip {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: $spacing-2;
|
||||||
|
padding: $spacing-1 $spacing-2;
|
||||||
|
background-color: var(--color-badge-status);
|
||||||
|
border: 1px solid var(--color-danger);
|
||||||
|
border-radius: $radius-full;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all $transition-fast;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: rgba(139, 0, 0, 0.25);
|
||||||
|
border-color: var(--color-danger);
|
||||||
|
|
||||||
|
.status-remove {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-icon {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
object-fit: contain;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-name {
|
||||||
|
font-size: $font-size-sm;
|
||||||
|
font-weight: $font-weight-semibold;
|
||||||
|
color: var(--color-text-primary);
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-remove {
|
||||||
|
@include flex-center;
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
padding: 0;
|
||||||
|
margin-left: $spacing-1;
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
border-radius: $radius-full;
|
||||||
|
color: var(--color-danger);
|
||||||
|
opacity: 0.6;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all $transition-fast;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--color-danger);
|
||||||
|
color: white;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
i {
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==========================================
|
// ==========================================
|
||||||
|
|||||||
@ -104,6 +104,9 @@
|
|||||||
&.equipment {
|
&.equipment {
|
||||||
background-color: var(--color-badge-equipment);
|
background-color: var(--color-badge-equipment);
|
||||||
}
|
}
|
||||||
|
&.status {
|
||||||
|
background-color: var(--color-badge-status);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -876,3 +879,198 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Status item sheet styles
|
||||||
|
.vagabond.sheet.item {
|
||||||
|
.status-content {
|
||||||
|
// Icon section with preview
|
||||||
|
.status-icon-section {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
gap: $spacing-4;
|
||||||
|
margin-bottom: $spacing-3;
|
||||||
|
|
||||||
|
.stat-group {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-preview {
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
border: 2px solid var(--color-border);
|
||||||
|
border-radius: $radius-md;
|
||||||
|
padding: $spacing-1;
|
||||||
|
background-color: var(--color-bg-input);
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Status flags fieldsets
|
||||||
|
fieldset {
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
border-radius: $radius-sm;
|
||||||
|
padding: $spacing-3;
|
||||||
|
margin: 0;
|
||||||
|
background-color: var(--color-bg-input);
|
||||||
|
|
||||||
|
legend {
|
||||||
|
font-size: $font-size-sm;
|
||||||
|
font-weight: $font-weight-semibold;
|
||||||
|
color: var(--color-accent-primary);
|
||||||
|
padding: 0 $spacing-2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flags category groupings
|
||||||
|
.flags-category {
|
||||||
|
margin-bottom: $spacing-3;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
margin: 0 0 $spacing-2 0;
|
||||||
|
font-size: $font-size-xs;
|
||||||
|
font-weight: $font-weight-semibold;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.03em;
|
||||||
|
border-bottom: 1px solid var(--color-border-light);
|
||||||
|
padding-bottom: $spacing-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flags grid for checkboxes
|
||||||
|
.flags-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
gap: $spacing-2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flag checkbox styling
|
||||||
|
.flag-checkbox {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: $spacing-2;
|
||||||
|
font-size: $font-size-sm;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
input[type="checkbox"] {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
margin: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
accent-color: var(--color-accent-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: var(--color-accent-primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Favor/Hinder section
|
||||||
|
.favor-hinder-section {
|
||||||
|
.favor-hinder-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: $spacing-4;
|
||||||
|
margin-bottom: $spacing-3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fh-category {
|
||||||
|
h4 {
|
||||||
|
margin: 0 0 $spacing-2 0;
|
||||||
|
font-size: $font-size-xs;
|
||||||
|
font-weight: $font-weight-semibold;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flags-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Section hints
|
||||||
|
.section-hint {
|
||||||
|
font-size: $font-size-xs;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
font-style: italic;
|
||||||
|
margin-bottom: $spacing-2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Included statuses list
|
||||||
|
.includes-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: $spacing-2;
|
||||||
|
|
||||||
|
.includes-entry {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: $spacing-2;
|
||||||
|
|
||||||
|
input {
|
||||||
|
flex: 1;
|
||||||
|
padding: $spacing-2;
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
border-radius: $radius-sm;
|
||||||
|
background-color: var(--color-bg-primary);
|
||||||
|
font-size: $font-size-sm;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete-entry {
|
||||||
|
@include button-icon;
|
||||||
|
color: var(--color-danger);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: rgba(201, 68, 68, 0.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-entry {
|
||||||
|
@include button-secondary;
|
||||||
|
align-self: flex-start;
|
||||||
|
font-size: $font-size-sm;
|
||||||
|
padding: $spacing-1 $spacing-3;
|
||||||
|
|
||||||
|
i {
|
||||||
|
margin-right: $spacing-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reference and full-width stat groups
|
||||||
|
.reference-section,
|
||||||
|
.stat-group.full-width {
|
||||||
|
margin-top: $spacing-2;
|
||||||
|
|
||||||
|
> label {
|
||||||
|
display: block;
|
||||||
|
font-size: $font-size-xs;
|
||||||
|
font-weight: $font-weight-semibold;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.03em;
|
||||||
|
margin-bottom: $spacing-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
width: 100%;
|
||||||
|
padding: $spacing-2;
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
border-radius: $radius-sm;
|
||||||
|
background-color: var(--color-bg-input);
|
||||||
|
font-size: $font-size-sm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
35
system.json
35
system.json
@ -104,13 +104,43 @@
|
|||||||
"PLAYER": "OBSERVER",
|
"PLAYER": "OBSERVER",
|
||||||
"ASSISTANT": "OWNER"
|
"ASSISTANT": "OWNER"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "statuses",
|
||||||
|
"label": "Statuses",
|
||||||
|
"path": "packs/statuses",
|
||||||
|
"type": "Item",
|
||||||
|
"ownership": {
|
||||||
|
"PLAYER": "OBSERVER",
|
||||||
|
"ASSISTANT": "OWNER"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "bestiary",
|
||||||
|
"label": "Bestiary",
|
||||||
|
"path": "packs/bestiary",
|
||||||
|
"type": "Actor",
|
||||||
|
"ownership": {
|
||||||
|
"PLAYER": "OBSERVER",
|
||||||
|
"ASSISTANT": "OWNER"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"packFolders": [
|
"packFolders": [
|
||||||
{
|
{
|
||||||
"name": "Vagabond RPG",
|
"name": "Vagabond RPG",
|
||||||
"sorting": "a",
|
"sorting": "a",
|
||||||
"packs": ["ancestries", "classes", "spells", "perks", "weapons", "armor", "equipment"]
|
"packs": [
|
||||||
|
"ancestries",
|
||||||
|
"classes",
|
||||||
|
"spells",
|
||||||
|
"perks",
|
||||||
|
"weapons",
|
||||||
|
"armor",
|
||||||
|
"equipment",
|
||||||
|
"statuses",
|
||||||
|
"bestiary"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"documentTypes": {
|
"documentTypes": {
|
||||||
@ -151,6 +181,9 @@
|
|||||||
},
|
},
|
||||||
"feature": {
|
"feature": {
|
||||||
"htmlFields": ["description"]
|
"htmlFields": ["description"]
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"htmlFields": ["description"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
{{!-- Character Sheet Header --}}
|
{{!-- Character Sheet Header --}}
|
||||||
|
<div class="header-wrapper">
|
||||||
<header class="sheet-header">
|
<header class="sheet-header">
|
||||||
<div class="header-left">
|
<div class="header-left">
|
||||||
<img class="profile-img" src="{{actor.img}}" alt="{{actor.name}}"
|
<img class="profile-img" src="{{actor.img}}" alt="{{actor.name}}"
|
||||||
@ -116,3 +117,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
{{!-- Status Bar (below header) --}}
|
||||||
|
{{> "systems/vagabond/templates/actor/parts/status-bar.hbs"}}
|
||||||
|
</div>
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
{{!-- NPC Sheet Header --}}
|
{{!-- NPC Sheet Header --}}
|
||||||
|
<div class="header-wrapper">
|
||||||
<header class="sheet-header npc-header">
|
<header class="sheet-header npc-header">
|
||||||
<div class="header-portrait">
|
<div class="header-portrait">
|
||||||
<img class="profile-img" src="{{actor.img}}" alt="{{actor.name}}"
|
<img class="profile-img" src="{{actor.img}}" alt="{{actor.name}}"
|
||||||
@ -59,3 +60,7 @@
|
|||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
{{!-- Status Bar (below header) --}}
|
||||||
|
{{> "systems/vagabond/templates/actor/parts/status-bar.hbs"}}
|
||||||
|
</div>
|
||||||
|
|||||||
18
templates/actor/parts/status-bar.hbs
Normal file
18
templates/actor/parts/status-bar.hbs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
{{!-- Status Bar - Displays active status conditions on the actor --}}
|
||||||
|
{{#if items.statuses.length}}
|
||||||
|
<div class="status-bar">
|
||||||
|
<div class="status-list">
|
||||||
|
{{#each items.statuses as |status|}}
|
||||||
|
<div class="status-chip" data-item-id="{{status.id}}" data-tooltip="{{status.name}}: {{{status.system.description}}}">
|
||||||
|
<img class="status-icon" src="{{status.img}}" alt="{{status.name}}" />
|
||||||
|
<span class="status-name">{{status.name}}</span>
|
||||||
|
{{#if ../editable}}
|
||||||
|
<button type="button" class="status-remove" data-action="removeStatus" data-tooltip="{{localize 'VAGABOND.RemoveStatus'}}">
|
||||||
|
<i class="fa-solid fa-xmark"></i>
|
||||||
|
</button>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
@ -64,7 +64,7 @@
|
|||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{!-- Damage Section (if hit) --}}
|
{{!-- Damage Section (if damage was rolled) --}}
|
||||||
{{#if hasDamage}}
|
{{#if hasDamage}}
|
||||||
<div class="damage-section {{#if isCrit}}critical{{/if}}">
|
<div class="damage-section {{#if isCrit}}critical{{/if}}">
|
||||||
<div class="damage-header">
|
<div class="damage-header">
|
||||||
@ -78,6 +78,13 @@
|
|||||||
<span class="damage-total">{{damageTotal}}</span>
|
<span class="damage-total">{{damageTotal}}</span>
|
||||||
<span class="damage-type">{{weapon.damageTypeLabel}}</span>
|
<span class="damage-type">{{weapon.damageTypeLabel}}</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="damage-breakdown">
|
||||||
|
{{#each damageDiceResults}}
|
||||||
|
<span class="damage-die" data-tooltip="d{{this.faces}}">
|
||||||
|
<i class="fa-solid fa-dice-d{{this.faces}}"></i> {{this.result}}
|
||||||
|
</span>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
<div class="damage-formula">
|
<div class="damage-formula">
|
||||||
{{damageFormula}}
|
{{damageFormula}}
|
||||||
{{#if twoHanded}}
|
{{#if twoHanded}}
|
||||||
@ -87,6 +94,20 @@
|
|||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
|
{{!-- Roll Damage Button (if hit but damage not yet rolled) --}}
|
||||||
|
{{#if showDamageButton}}
|
||||||
|
<div class="card-buttons">
|
||||||
|
<button type="button" class="roll-damage-btn {{#if isCrit}}critical{{/if}}">
|
||||||
|
<i class="fa-solid fa-burst"></i>
|
||||||
|
{{localize "VAGABOND.RollDamage"}}
|
||||||
|
{{#if isCrit}}
|
||||||
|
<span class="crit-label">({{localize "VAGABOND.Critical"}}!)</span>
|
||||||
|
{{/if}}
|
||||||
|
<span class="damage-preview">({{pendingDamageFormula}})</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
{{!-- Weapon Properties --}}
|
{{!-- Weapon Properties --}}
|
||||||
{{#if weapon.properties.length}}
|
{{#if weapon.properties.length}}
|
||||||
<div class="weapon-properties">
|
<div class="weapon-properties">
|
||||||
|
|||||||
@ -82,11 +82,11 @@
|
|||||||
<div class="favor-hinder-section">
|
<div class="favor-hinder-section">
|
||||||
<label>{{localize "VAGABOND.FavorHinder"}}</label>
|
<label>{{localize "VAGABOND.FavorHinder"}}</label>
|
||||||
<div class="favor-hinder-toggles">
|
<div class="favor-hinder-toggles">
|
||||||
<button type="button" class="favor-btn {{#if (eq config.favorHinder 1)}}active{{/if}}" data-favor="1">
|
<button type="button" class="favor-btn {{#if (eq config.favorHinder 1)}}active{{/if}}" data-action="toggle-favor">
|
||||||
<i class="fa-solid fa-arrow-up"></i>
|
<i class="fa-solid fa-arrow-up"></i>
|
||||||
{{localize "VAGABOND.Favor"}}
|
{{localize "VAGABOND.Favor"}}
|
||||||
</button>
|
</button>
|
||||||
<button type="button" class="hinder-btn {{#if (eq config.favorHinder -1)}}active{{/if}}" data-favor="-1">
|
<button type="button" class="hinder-btn {{#if (eq config.favorHinder -1)}}active{{/if}}" data-action="toggle-hinder">
|
||||||
<i class="fa-solid fa-arrow-down"></i>
|
<i class="fa-solid fa-arrow-down"></i>
|
||||||
{{localize "VAGABOND.Hinder"}}
|
{{localize "VAGABOND.Hinder"}}
|
||||||
</button>
|
</button>
|
||||||
@ -106,10 +106,10 @@
|
|||||||
<div class="modifier-section">
|
<div class="modifier-section">
|
||||||
<label>{{localize "VAGABOND.SituationalModifier"}}</label>
|
<label>{{localize "VAGABOND.SituationalModifier"}}</label>
|
||||||
<div class="modifier-presets">
|
<div class="modifier-presets">
|
||||||
<button type="button" class="modifier-preset" data-modifier="-5">-5</button>
|
<button type="button" class="modifier-preset" data-modifier-preset="-5">-5</button>
|
||||||
<button type="button" class="modifier-preset" data-modifier="-1">-1</button>
|
<button type="button" class="modifier-preset" data-modifier-preset="-1">-1</button>
|
||||||
<button type="button" class="modifier-preset" data-modifier="1">+1</button>
|
<button type="button" class="modifier-preset" data-modifier-preset="1">+1</button>
|
||||||
<button type="button" class="modifier-preset" data-modifier="5">+5</button>
|
<button type="button" class="modifier-preset" data-modifier-preset="5">+5</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modifier-input">
|
<div class="modifier-input">
|
||||||
<input type="number" name="modifier" value="{{config.modifier}}" placeholder="0">
|
<input type="number" name="modifier" value="{{config.modifier}}" placeholder="0">
|
||||||
|
|||||||
294
templates/item/types/status.hbs
Normal file
294
templates/item/types/status.hbs
Normal file
@ -0,0 +1,294 @@
|
|||||||
|
{{!-- Status Item Sheet Body --}}
|
||||||
|
<div class="item-content status-content">
|
||||||
|
{{!-- Status Icon --}}
|
||||||
|
<div class="status-icon-section">
|
||||||
|
<div class="stat-group">
|
||||||
|
<label>{{localize "VAGABOND.StatusIcon"}}</label>
|
||||||
|
<input type="text" name="system.icon" value="{{system.icon}}" placeholder="icons/svg/hazard.svg" {{#unless editable}}disabled{{/unless}} />
|
||||||
|
</div>
|
||||||
|
<div class="icon-preview">
|
||||||
|
<img src="{{system.icon}}" alt="Status Icon" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{!-- Core Status Flags --}}
|
||||||
|
<fieldset class="status-flags">
|
||||||
|
<legend>{{localize "VAGABOND.StatusRestrictions"}}</legend>
|
||||||
|
|
||||||
|
{{!-- Movement Restrictions --}}
|
||||||
|
<div class="flags-category">
|
||||||
|
<h4>{{localize "VAGABOND.MovementRestrictions"}}</h4>
|
||||||
|
<div class="flags-grid">
|
||||||
|
<label class="flag-checkbox">
|
||||||
|
<input type="checkbox" name="system.flags.cantMove" {{#if system.flags.cantMove}}checked{{/if}} {{#unless editable}}disabled{{/unless}} />
|
||||||
|
{{localize "VAGABOND.CantMove"}}
|
||||||
|
</label>
|
||||||
|
<label class="flag-checkbox">
|
||||||
|
<input type="checkbox" name="system.flags.cantRush" {{#if system.flags.cantRush}}checked{{/if}} {{#unless editable}}disabled{{/unless}} />
|
||||||
|
{{localize "VAGABOND.CantRush"}}
|
||||||
|
</label>
|
||||||
|
<label class="flag-checkbox">
|
||||||
|
<input type="checkbox" name="system.flags.speedZero" {{#if system.flags.speedZero}}checked{{/if}} {{#unless editable}}disabled{{/unless}} />
|
||||||
|
{{localize "VAGABOND.SpeedZero"}}
|
||||||
|
</label>
|
||||||
|
<label class="flag-checkbox">
|
||||||
|
<input type="checkbox" name="system.flags.crawlOnly" {{#if system.flags.crawlOnly}}checked{{/if}} {{#unless editable}}disabled{{/unless}} />
|
||||||
|
{{localize "VAGABOND.CrawlOnly"}}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{!-- Action Restrictions --}}
|
||||||
|
<div class="flags-category">
|
||||||
|
<h4>{{localize "VAGABOND.ActionRestrictions"}}</h4>
|
||||||
|
<div class="flags-grid">
|
||||||
|
<label class="flag-checkbox">
|
||||||
|
<input type="checkbox" name="system.flags.cantFocus" {{#if system.flags.cantFocus}}checked{{/if}} {{#unless editable}}disabled{{/unless}} />
|
||||||
|
{{localize "VAGABOND.CantFocus"}}
|
||||||
|
</label>
|
||||||
|
<label class="flag-checkbox">
|
||||||
|
<input type="checkbox" name="system.flags.cantUseActions" {{#if system.flags.cantUseActions}}checked{{/if}} {{#unless editable}}disabled{{/unless}} />
|
||||||
|
{{localize "VAGABOND.CantUseActions"}}
|
||||||
|
</label>
|
||||||
|
<label class="flag-checkbox">
|
||||||
|
<input type="checkbox" name="system.flags.onlyAttackMoveRush" {{#if system.flags.onlyAttackMoveRush}}checked{{/if}} {{#unless editable}}disabled{{/unless}} />
|
||||||
|
{{localize "VAGABOND.OnlyAttackMoveRush"}}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{!-- Sense Restrictions --}}
|
||||||
|
<div class="flags-category">
|
||||||
|
<h4>{{localize "VAGABOND.SenseRestrictions"}}</h4>
|
||||||
|
<div class="flags-grid">
|
||||||
|
<label class="flag-checkbox">
|
||||||
|
<input type="checkbox" name="system.flags.cantSee" {{#if system.flags.cantSee}}checked{{/if}} {{#unless editable}}disabled{{/unless}} />
|
||||||
|
{{localize "VAGABOND.CantSee"}}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{!-- Combat Modifiers --}}
|
||||||
|
<div class="flags-category">
|
||||||
|
<h4>{{localize "VAGABOND.CombatModifiers"}}</h4>
|
||||||
|
<div class="flags-grid">
|
||||||
|
<label class="flag-checkbox">
|
||||||
|
<input type="checkbox" name="system.flags.isVulnerable" {{#if system.flags.isVulnerable}}checked{{/if}} {{#unless editable}}disabled{{/unless}} />
|
||||||
|
{{localize "VAGABOND.IsVulnerable"}}
|
||||||
|
</label>
|
||||||
|
<label class="flag-checkbox">
|
||||||
|
<input type="checkbox" name="system.flags.closeAttacksAutoCrit" {{#if system.flags.closeAttacksAutoCrit}}checked{{/if}} {{#unless editable}}disabled{{/unless}} />
|
||||||
|
{{localize "VAGABOND.CloseAttacksAutoCrit"}}
|
||||||
|
</label>
|
||||||
|
<label class="flag-checkbox">
|
||||||
|
<input type="checkbox" name="system.flags.failsMightDexChecks" {{#if system.flags.failsMightDexChecks}}checked{{/if}} {{#unless editable}}disabled{{/unless}} />
|
||||||
|
{{localize "VAGABOND.FailsMightDexChecks"}}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{!-- Morale & Special --}}
|
||||||
|
<div class="flags-category">
|
||||||
|
<h4>{{localize "VAGABOND.MoraleSpecial"}}</h4>
|
||||||
|
<div class="flags-grid">
|
||||||
|
<label class="flag-checkbox">
|
||||||
|
<input type="checkbox" name="system.flags.noMoraleChecks" {{#if system.flags.noMoraleChecks}}checked{{/if}} {{#unless editable}}disabled{{/unless}} />
|
||||||
|
{{localize "VAGABOND.NoMoraleChecks"}}
|
||||||
|
</label>
|
||||||
|
<label class="flag-checkbox">
|
||||||
|
<input type="checkbox" name="system.flags.immuneToFrightened" {{#if system.flags.immuneToFrightened}}checked{{/if}} {{#unless editable}}disabled{{/unless}} />
|
||||||
|
{{localize "VAGABOND.ImmuneToFrightened"}}
|
||||||
|
</label>
|
||||||
|
<label class="flag-checkbox">
|
||||||
|
<input type="checkbox" name="system.flags.cantAttackCharmer" {{#if system.flags.cantAttackCharmer}}checked{{/if}} {{#unless editable}}disabled{{/unless}} />
|
||||||
|
{{localize "VAGABOND.CantAttackCharmer"}}
|
||||||
|
</label>
|
||||||
|
<label class="flag-checkbox">
|
||||||
|
<input type="checkbox" name="system.flags.reducesItemSlots" {{#if system.flags.reducesItemSlots}}checked{{/if}} {{#unless editable}}disabled{{/unless}} />
|
||||||
|
{{localize "VAGABOND.ReducesItemSlots"}}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
{{!-- Favor/Hinder Modifiers --}}
|
||||||
|
<fieldset class="favor-hinder-section">
|
||||||
|
<legend>{{localize "VAGABOND.FavorHinderModifiers"}}</legend>
|
||||||
|
|
||||||
|
<div class="favor-hinder-grid">
|
||||||
|
{{!-- Hinder on afflicted --}}
|
||||||
|
<div class="fh-category">
|
||||||
|
<h4>{{localize "VAGABOND.HinderOnAfflicted"}}</h4>
|
||||||
|
<div class="flags-grid">
|
||||||
|
<label class="flag-checkbox">
|
||||||
|
<input type="checkbox" name="system.favorHinder.hinderChecks" {{#if system.favorHinder.hinderChecks}}checked{{/if}} {{#unless editable}}disabled{{/unless}} />
|
||||||
|
{{localize "VAGABOND.Checks"}}
|
||||||
|
</label>
|
||||||
|
<label class="flag-checkbox">
|
||||||
|
<input type="checkbox" name="system.favorHinder.hinderSaves" {{#if system.favorHinder.hinderSaves}}checked{{/if}} {{#unless editable}}disabled{{/unless}} />
|
||||||
|
{{localize "VAGABOND.Saves"}}
|
||||||
|
</label>
|
||||||
|
<label class="flag-checkbox">
|
||||||
|
<input type="checkbox" name="system.favorHinder.hinderAttacks" {{#if system.favorHinder.hinderAttacks}}checked{{/if}} {{#unless editable}}disabled{{/unless}} />
|
||||||
|
{{localize "VAGABOND.Attacks"}}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{!-- Favor against afflicted --}}
|
||||||
|
<div class="fh-category">
|
||||||
|
<h4>{{localize "VAGABOND.FavorAgainstAfflicted"}}</h4>
|
||||||
|
<div class="flags-grid">
|
||||||
|
<label class="flag-checkbox">
|
||||||
|
<input type="checkbox" name="system.favorHinder.favorAgainstChecks" {{#if system.favorHinder.favorAgainstChecks}}checked{{/if}} {{#unless editable}}disabled{{/unless}} />
|
||||||
|
{{localize "VAGABOND.Checks"}}
|
||||||
|
</label>
|
||||||
|
<label class="flag-checkbox">
|
||||||
|
<input type="checkbox" name="system.favorHinder.favorAgainstSaves" {{#if system.favorHinder.favorAgainstSaves}}checked{{/if}} {{#unless editable}}disabled{{/unless}} />
|
||||||
|
{{localize "VAGABOND.Saves"}}
|
||||||
|
</label>
|
||||||
|
<label class="flag-checkbox">
|
||||||
|
<input type="checkbox" name="system.favorHinder.favorAgainstAttacks" {{#if system.favorHinder.favorAgainstAttacks}}checked{{/if}} {{#unless editable}}disabled{{/unless}} />
|
||||||
|
{{localize "VAGABOND.Attacks"}}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="stat-group">
|
||||||
|
<label>{{localize "VAGABOND.FavorHinderContext"}}</label>
|
||||||
|
<input type="text" name="system.favorHinder.context" value="{{system.favorHinder.context}}" placeholder="e.g. sight-based Detect checks" {{#unless editable}}disabled{{/unless}} />
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
{{!-- Damage/Healing Modifiers --}}
|
||||||
|
<fieldset class="modifiers-section">
|
||||||
|
<legend>{{localize "VAGABOND.DamageHealingModifiers"}}</legend>
|
||||||
|
<div class="item-stats-row">
|
||||||
|
<div class="stat-group">
|
||||||
|
<label>{{localize "VAGABOND.DamageDealtModifier"}}</label>
|
||||||
|
<input type="number" name="system.modifiers.damageDealt" value="{{system.modifiers.damageDealt}}" {{#unless editable}}disabled{{/unless}} />
|
||||||
|
</div>
|
||||||
|
<div class="stat-group">
|
||||||
|
<label>{{localize "VAGABOND.HealingReceivedModifier"}}</label>
|
||||||
|
<input type="number" name="system.modifiers.healingReceived" value="{{system.modifiers.healingReceived}}" {{#unless editable}}disabled{{/unless}} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
{{!-- Periodic Effects --}}
|
||||||
|
<fieldset class="periodic-section">
|
||||||
|
<legend>{{localize "VAGABOND.PeriodicEffects"}}</legend>
|
||||||
|
<div class="item-stats-row">
|
||||||
|
<div class="stat-group">
|
||||||
|
<label>{{localize "VAGABOND.Trigger"}}</label>
|
||||||
|
<select name="system.periodic.trigger" {{#unless editable}}disabled{{/unless}}>
|
||||||
|
<option value="" {{#unless system.periodic.trigger}}selected{{/unless}}>{{localize "VAGABOND.None"}}</option>
|
||||||
|
<option value="startOfTurn" {{#if (eq system.periodic.trigger "startOfTurn")}}selected{{/if}}>{{localize "VAGABOND.StartOfTurn"}}</option>
|
||||||
|
<option value="endOfTurn" {{#if (eq system.periodic.trigger "endOfTurn")}}selected{{/if}}>{{localize "VAGABOND.EndOfTurn"}}</option>
|
||||||
|
<option value="eachRound" {{#if (eq system.periodic.trigger "eachRound")}}selected{{/if}}>{{localize "VAGABOND.EachRound"}}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="stat-group">
|
||||||
|
<label>{{localize "VAGABOND.EffectType"}}</label>
|
||||||
|
<select name="system.periodic.type" {{#unless editable}}disabled{{/unless}}>
|
||||||
|
<option value="" {{#unless system.periodic.type}}selected{{/unless}}>{{localize "VAGABOND.None"}}</option>
|
||||||
|
<option value="damage" {{#if (eq system.periodic.type "damage")}}selected{{/if}}>{{localize "VAGABOND.Damage"}}</option>
|
||||||
|
<option value="fatigue" {{#if (eq system.periodic.type "fatigue")}}selected{{/if}}>{{localize "VAGABOND.Fatigue"}}</option>
|
||||||
|
<option value="healing" {{#if (eq system.periodic.type "healing")}}selected{{/if}}>{{localize "VAGABOND.Healing"}}</option>
|
||||||
|
<option value="check" {{#if (eq system.periodic.type "check")}}selected{{/if}}>{{localize "VAGABOND.Check"}}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="stat-group">
|
||||||
|
<label>{{localize "VAGABOND.Value"}}</label>
|
||||||
|
<input type="text" name="system.periodic.value" value="{{system.periodic.value}}" placeholder="e.g. 1d6" {{#unless editable}}disabled{{/unless}} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-group full-width">
|
||||||
|
<label>{{localize "VAGABOND.EffectDescription"}}</label>
|
||||||
|
<input type="text" name="system.periodic.effectDescription" value="{{system.periodic.effectDescription}}" placeholder="e.g. Takes damage at start of turn" {{#unless editable}}disabled{{/unless}} />
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
{{!-- Duration --}}
|
||||||
|
<fieldset class="duration-section">
|
||||||
|
<legend>{{localize "VAGABOND.Duration"}}</legend>
|
||||||
|
<div class="item-stats-row">
|
||||||
|
<div class="stat-group">
|
||||||
|
<label>{{localize "VAGABOND.DurationType"}}</label>
|
||||||
|
<select name="system.duration.type" {{#unless editable}}disabled{{/unless}}>
|
||||||
|
<option value="" {{#unless system.duration.type}}selected{{/unless}}>{{localize "VAGABOND.UntilRemoved"}}</option>
|
||||||
|
<option value="rounds" {{#if (eq system.duration.type "rounds")}}selected{{/if}}>{{localize "VAGABOND.Rounds"}}</option>
|
||||||
|
<option value="minutes" {{#if (eq system.duration.type "minutes")}}selected{{/if}}>{{localize "VAGABOND.Minutes"}}</option>
|
||||||
|
<option value="hours" {{#if (eq system.duration.type "hours")}}selected{{/if}}>{{localize "VAGABOND.Hours"}}</option>
|
||||||
|
<option value="untilRest" {{#if (eq system.duration.type "untilRest")}}selected{{/if}}>{{localize "VAGABOND.UntilRest"}}</option>
|
||||||
|
<option value="special" {{#if (eq system.duration.type "special")}}selected{{/if}}>{{localize "VAGABOND.Special"}}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="stat-group">
|
||||||
|
<label>{{localize "VAGABOND.DurationValue"}}</label>
|
||||||
|
<input type="number" name="system.duration.value" value="{{system.duration.value}}" min="0" {{#unless editable}}disabled{{/unless}} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
{{!-- Stacking --}}
|
||||||
|
<fieldset class="stacking-section">
|
||||||
|
<legend>{{localize "VAGABOND.Stacking"}}</legend>
|
||||||
|
<div class="item-stats-row">
|
||||||
|
<div class="stat-group">
|
||||||
|
<label class="flag-checkbox">
|
||||||
|
<input type="checkbox" name="system.stackable" {{#if system.stackable}}checked{{/if}} {{#unless editable}}disabled{{/unless}} />
|
||||||
|
{{localize "VAGABOND.Stackable"}}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
{{#if system.stackable}}
|
||||||
|
<div class="stat-group">
|
||||||
|
<label>{{localize "VAGABOND.MaxStacks"}}</label>
|
||||||
|
<input type="number" name="system.maxStacks" value="{{system.maxStacks}}" min="1" {{#unless editable}}disabled{{/unless}} />
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
{{!-- Included Statuses (for composites) --}}
|
||||||
|
<fieldset class="includes-section">
|
||||||
|
<legend>{{localize "VAGABOND.IncludedStatuses"}}</legend>
|
||||||
|
<p class="section-hint">{{localize "VAGABOND.IncludedStatusesHint"}}</p>
|
||||||
|
<div class="includes-list">
|
||||||
|
{{#each system.includesStatuses}}
|
||||||
|
<div class="includes-entry" data-index="{{@index}}">
|
||||||
|
<input type="text" name="system.includesStatuses.{{@index}}" value="{{this}}" placeholder="e.g. Blinded" {{#unless ../editable}}disabled{{/unless}} />
|
||||||
|
{{#if ../editable}}
|
||||||
|
<button type="button" class="delete-entry" data-action="deleteArrayEntry" data-field="system.includesStatuses" data-index="{{@index}}">
|
||||||
|
<i class="fas fa-trash"></i>
|
||||||
|
</button>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
{{#if editable}}
|
||||||
|
<button type="button" class="add-entry" data-action="addArrayEntry" data-field="system.includesStatuses">
|
||||||
|
<i class="fas fa-plus"></i> {{localize "VAGABOND.AddIncludedStatus"}}
|
||||||
|
</button>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
{{!-- Reference --}}
|
||||||
|
<div class="reference-section">
|
||||||
|
<label>{{localize "VAGABOND.Reference"}}</label>
|
||||||
|
<input type="text" name="system.reference" value="{{system.reference}}" placeholder="Core Rulebook p.36" {{#unless editable}}disabled{{/unless}} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{!-- Description --}}
|
||||||
|
<div class="item-description">
|
||||||
|
<label>{{localize "VAGABOND.Description"}}</label>
|
||||||
|
<div class="editor-wrapper">
|
||||||
|
{{#if editable}}
|
||||||
|
<prose-mirror name="system.description" toggled="false">{{{enrichedDescription}}}</prose-mirror>
|
||||||
|
{{else}}
|
||||||
|
<div class="editor-content">{{{enrichedDescription}}}</div>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
Loading…
Reference in New Issue
Block a user