Skip to content

Commit

Permalink
Add creature-size rule element, start tracking natural reach
Browse files Browse the repository at this point in the history
  • Loading branch information
stwlam committed Aug 9, 2021
1 parent c2ba51d commit 57a8f85
Show file tree
Hide file tree
Showing 14 changed files with 128 additions and 11 deletions.
3 changes: 3 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@ module.exports = {
modulePaths: ["<rootDir>", "<rootDir>/src", "<rootDir>/dist", "<rootDir>/types/foundry-pc-types"],
moduleNameMapper: {
"^@actor/(.*)$": "<rootDir>/src/module/actor/$1",
"^@actor$": "<rootDir>/src/module/actor",
"^@item/(.*)$": "<rootDir>/src/module/item/$1",
"^@item$": "<rootDir>/src/module/item",
"^@scene/(.*)$": "<rootDir>/src/module/scene/$1",
"^@scene$": "<rootDir>/src/module/scene",
"^@module/(.*)$": "<rootDir>/src/module/$1",
"^@scripts/(.*)$": "<rootDir>/src/scripts/$1",
"^@system/(.*)$": "<rootDir>/src/module/system/$1",
Expand Down
21 changes: 18 additions & 3 deletions packs/data/feat-effects.db/effect-giants-stature.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,23 @@
},
"rules": [
{
"key": "PF2E.RuleElement.TokenSize",
"key": "CreatureSize",
"value": "large"
},
{
"key": "PF2E.RuleElement.FlatModifier",
"key": "ActiveEffectLike",
"mode": "add",
"path": "data.attributes.reach.value",
"value": 5
},
{
"key": "ActiveEffectLike",
"mode": "add",
"path": "data.attributes.reach.manipulate",
"value": 5
},
{
"key": "FlatModifier",
"label": "Giant's Stature",
"selector": "dex-based",
"type": "status",
Expand All @@ -34,6 +46,9 @@
"value": 0
},
"target": null,
"tokenIcon": {
"show": false
},
"traits": {
"custom": "",
"rarity": {
Expand All @@ -44,7 +59,7 @@
},
"effects": [],
"flags": {},
"img": "systems/pf2e/icons/spells/summon-giant.webp",
"img": "systems/pf2e/icons/features/feats/giants-stature.webp",
"name": "Effect: Giant's Stature",
"type": "effect"
}
4 changes: 2 additions & 2 deletions src/module/actor/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { DamageDicePF2e, ModifierPF2e, ModifierPredicate, ProficiencyModifier, R
import { isCycle } from "@item/container/helpers";
import { DicePF2e } from "@scripts/dice";
import { ItemPF2e, SpellcastingEntryPF2e, PhysicalItemPF2e, ContainerPF2e } from "@item";
import type { ConditionPF2e, ArmorPF2e } from "@item/index";
import type { ConditionPF2e, ArmorPF2e } from "@item";
import { ConditionData, WeaponData, ItemSourcePF2e, ItemType } from "@item/data";
import { ErrorPF2e, objectHasKey } from "@module/utils";
import type { ActiveEffectPF2e } from "@module/active-effect";
Expand All @@ -16,7 +16,7 @@ import { SUPPORTED_ROLL_OPTIONS } from "./data/values";
import { SaveData, SkillAbbreviation, SkillData, VisionLevel, VisionLevels } from "./creature/data";
import { AbilityString, BaseActorDataPF2e } from "./data/base";
import { ActorDataPF2e, ActorSourcePF2e, ModeOfBeing, SaveType } from "./data";
import { TokenDocumentPF2e } from "@module/scene/token-document";
import { TokenDocumentPF2e } from "@scene";
import { UserPF2e } from "@module/user";
import { isCreatureData } from "./data/helpers";
import { ConditionType } from "@item/condition/data";
Expand Down
7 changes: 7 additions & 0 deletions src/module/actor/character/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,13 @@ export interface CharacterAttributes extends BaseCreatureAttributes {
/** The number of familiar abilities this character's familiar has access to. */
familiarAbilities: StatisticModifier;

/** The character's natural reach */
reach: {
value: number;
/** Its reach for the purpose of manipulate actions */
manipulate: number | null;
};

/** Data related to character hitpoints. */
hp: HitPointsData;

Expand Down
2 changes: 2 additions & 0 deletions src/module/actor/character/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,11 @@ export class CharacterPF2e extends CreaturePF2e {
attributes.classDC = { rank: 0 };
attributes.dexCap = [{ value: Infinity, source: "" }];
attributes.perception = { ability: "wis", rank: 0 };
attributes.reach = { value: 5, manipulate: 5 };
attributes.doomed = { value: 0, max: 3 };
attributes.dying = { value: 0, max: 4 };
attributes.wounded = { value: 0, max: 3 };

// Hit points from Ancestry and Class
attributes.ancestryhp = 0;
attributes.classhp = 0;
Expand Down
9 changes: 7 additions & 2 deletions src/module/item/ancestry/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ export class AncestryPF2e extends ABCItemPF2e {
return this.data.data.size;
}

get reach(): number {
return this.data.data.reach;
}

/** Prepare a character's data derived from their ancestry */
prepareActorData(this: Embedded<AncestryPF2e>): void {
if (!(this.actor instanceof CharacterPF2e)) {
Expand All @@ -30,9 +34,10 @@ export class AncestryPF2e extends ABCItemPF2e {

const actorData = this.actor.data;
const systemData = actorData.data;
systemData.attributes.ancestryhp = this.hitPoints;
systemData.attributes.speed.value = String(this.speed);
systemData.attributes.reach = { value: this.reach, manipulate: this.reach };
systemData.traits.size.value = this.size;
systemData.attributes.ancestryhp = this.hitPoints;

// Add traits from ancestry and heritage
const ancestryTraits: Set<string> = this?.traits ?? new Set();
Expand All @@ -44,7 +49,7 @@ export class AncestryPF2e extends ABCItemPF2e {
)
)
).sort();
actorData.data.traits.traits.value.push(...traits);
systemData.traits.traits.value.push(...traits);
}
}

Expand Down
58 changes: 58 additions & 0 deletions src/module/rules/elements/creature-size.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { CreaturePF2e } from "@actor";
import { ItemPF2e } from "@item";
import { Size, SIZES } from "@module/data";
import { tupleHasValue } from "@module/utils";
import { RuleElementPF2e } from "../rule-element";
import { RuleElementSource } from "../rules-data-definitions";

/**
* @category RuleElement
* Increase the creature's size'
*/
export class CreatureSizeRuleElement extends RuleElementPF2e {
constructor(data: RuleElementSource, item: Embedded<ItemPF2e>) {
super(data, item);
if (!(this.actor instanceof CreaturePF2e)) {
console.warn(
`PF2E System | CreatureSize Rule Element on actor ${this.actor.id} (${this.actor.name}) must be used on a creature`
);
this.ignored = true;
}
}

private static wordToAbbreviation: Record<string, Size | undefined> = {
tiny: "tiny",
small: "sm",
medium: "med",
large: "lg",
huge: "huge",
gargantuan: "grg",
};

override onAfterPrepareData() {
if (this.ignored) return;

const value = this.resolveValue();
if (typeof value !== "string") {
console.warn(
`PF2E System | CreatureSize Rule Element on actor ${this.actor.id} (${this.actor.name})`,
"has a non-string value"
);
return;
}

const size = CreatureSizeRuleElement.wordToAbbreviation[value] ?? value;
if (!tupleHasValue(SIZES, size)) {
const validValues = Array.from(
new Set(Object.entries(CreatureSizeRuleElement.wordToAbbreviation).flat())
).join(", ");
console.warn(
`PF2E System | CreatureSize Rule Element on actor ${this.actor.id} (${this.actor.name})`,
`has an invalid value: must be one of ${validValues}`
);
return;
}

this.actor.data.data.traits.size.value = size;
}
}
2 changes: 1 addition & 1 deletion src/module/rules/rule-element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ export abstract class RuleElementPF2e {
(Number(defaultValue) || 0);
}

if (typeof value === "string") {
if (typeof value === "string" && value.includes("@")) {
value = Roll.safeEval(Roll.replaceFormulaData(value, { ...actor.data.data, item: this.item.data.data }));
}

Expand Down
2 changes: 2 additions & 0 deletions src/module/rules/rules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { PF2RecoveryCheckDCRuleElement } from "@module/rules/feats/recovery-chec
import { PF2AdjustDegreeOfSuccessRuleElement } from "./elements/adjust-degree-of-success";
import { AELikeRuleElement } from "./elements/ae-like";
import { LoseHitPointsRuleElement } from "./elements/lose-hit-points";
import { CreatureSizeRuleElement } from "./elements/creature-size";

/**
* @category RuleElement
Expand All @@ -39,6 +40,7 @@ export class RuleElements {
TempHP: PF2TempHPRuleElement,
DamageDice: PF2DamageDiceRuleElement,
ToggleProperty: PF2TogglePropertyRuleElement,
CreatureSize: CreatureSizeRuleElement,
TokenEffectIcon: PF2TokenEffectIconRuleElement,
TokenImage: PF2TokenImageRuleElement,
TokenSize: PF2TokenSizeRuleElement,
Expand Down
23 changes: 22 additions & 1 deletion src/module/scene/token-document.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ export class TokenDocumentPF2e extends TokenDocument<ActorPF2e> {
super.prepareDerivedData();
if (!(this.initialized && this.actor && canvas.scene)) return;

mergeObject(this.data, this.actor.overrides.token ?? {}, { insertKeys: false });
this.prepareSize();

if (!canvas.sight.rulesBasedVision) return;

const lightLevel = canvas.scene.lightLevel;
Expand All @@ -75,6 +76,26 @@ export class TokenDocumentPF2e extends TokenDocument<ActorPF2e> {
this.data.brightSight = perceivedBrightness > lightLevel || hasDarkvision ? 1000 : 0;
}

/** Set this token's dimensions from actor data */
private prepareSize(): void {
if (!(this.actor instanceof CreaturePF2e)) return;
const { width, height } = this.data;
mergeObject(this.data, this.actor.overrides.token ?? {}, { insertKeys: false });

// If not overridden by an actor override, set according to creature size (skipping gargantuan)
if (this.data.width == width && this.data.height === height && this.actor.size !== "grg") {
const size = {
tiny: 0.5,
sm: 1,
med: 1,
lg: 2,
huge: 3,
grg: 4,
}[this.actor.size];
if (size !== width) this.data.width = this.data.height = size;
}
}

/**
* Foundry (at least as of 0.8.8) has a security exploit allowing any user, regardless of permissions, to update
* scene embedded documents. This is a client-side check providing some minimal protection against unauthorized
Expand Down
Binary file added static/icons/features/feats/giants-stature.webp
Binary file not shown.
1 change: 1 addition & 0 deletions static/lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1522,6 +1522,7 @@
"ActorTraits": "Actor Traits",
"AdjustDegreeOfSuccess": "Adjust Degree of Success",
"BaseSpeed": "Base Speed",
"CreatureSize": "Creature Size",
"DamageDice": "Damage Dice",
"DexterityModifierCap": "Dexterity Modifier Cap",
"FlatModifier": "Flat Modifier",
Expand Down
6 changes: 4 additions & 2 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,12 @@
"removeComments": false,
"resolveJsonModule": true,
"paths": {
"@actor": ["src/module/actor/index"],
"@actor": ["src/module/actor"],
"@actor/*": ["src/module/actor/*"],
"@item": ["src/module/item/index"],
"@item": ["src/module/item"],
"@item/*": ["src/module/item/*"],
"@scene": ["src/module/scene"],
"@scene/*": ["src/module/scene/*"],
"@system/*": ["src/module/system/*"],
"@module/*": ["src/module/*"],
"@scripts/*": ["src/scripts/*"],
Expand Down
1 change: 1 addition & 0 deletions webpack.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ const config: Configuration = {
"@actor": path.resolve(__dirname, "src/module/actor"),
"@item": path.resolve(__dirname, "src/module/item"),
"@module": path.resolve(__dirname, "src/module"),
"@scene": path.resolve(__dirname, "src/module/scene"),
"@scripts": path.resolve(__dirname, "src/scripts"),
"@system": path.resolve(__dirname, "src/module/system"),
},
Expand Down

0 comments on commit 57a8f85

Please sign in to comment.