-
Notifications
You must be signed in to change notification settings - Fork 324
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Allow
SpecialStatistic
to create item-spellcasting abilities
- Loading branch information
Showing
9 changed files
with
219 additions
and
43 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
134 changes: 134 additions & 0 deletions
134
src/module/item/spellcasting-entry/items-spellcasting.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
import type { CreaturePF2e } from "@actor"; | ||
import { AttributeString } from "@actor/types.ts"; | ||
import type { PhysicalItemPF2e, SpellPF2e } from "@item"; | ||
import type { PredicatePF2e } from "@system/predication.ts"; | ||
import type { Statistic } from "@system/statistic/statistic.ts"; | ||
import * as R from "remeda"; | ||
import { SpellCollection } from "./collection.ts"; | ||
import type { CastOptions, SpellcastingEntry, SpellcastingSheetData } from "./types.ts"; | ||
|
||
/** An in-memory spellcasting entry for items-only spellcasting */ | ||
class ItemsSpellcasting<TActor extends CreaturePF2e = CreaturePF2e> implements SpellcastingEntry<TActor> { | ||
id: string; | ||
|
||
name: string; | ||
|
||
actor: TActor; | ||
|
||
statistic: Statistic; | ||
|
||
/** A predicate to test against a physical item to determine whether its contained spell can be cast */ | ||
castPredicate: PredicatePF2e; | ||
|
||
constructor({ id, name, actor, statistic, castPredicate }: ItemsSpellcastingConstructorParams<TActor>) { | ||
this.id = id; | ||
this.name = name; | ||
this.actor = actor; | ||
this.statistic = statistic; | ||
this.castPredicate = castPredicate; | ||
} | ||
|
||
get attribute(): AttributeString { | ||
return this.statistic.attribute ?? "cha"; | ||
} | ||
|
||
get category(): "items" { | ||
return "items"; | ||
} | ||
|
||
get tradition(): null { | ||
return null; | ||
} | ||
|
||
get sort(): number { | ||
return Math.max(0, ...this.actor.itemTypes.spellcastingEntry.map((e) => e.sort)) + 10; | ||
} | ||
|
||
get spells(): SpellCollection<TActor, this> { | ||
return new SpellCollection(this); | ||
} | ||
|
||
get isFlexible(): false { | ||
return false; | ||
} | ||
|
||
get isFocusPool(): false { | ||
return false; | ||
} | ||
|
||
get isInnate(): false { | ||
return false; | ||
} | ||
|
||
get isPrepared(): false { | ||
return false; | ||
} | ||
|
||
get isSpontaneous(): false { | ||
return false; | ||
} | ||
|
||
get isRitual(): false { | ||
return false; | ||
} | ||
|
||
get isEphemeral(): true { | ||
return true; | ||
} | ||
|
||
canCast(spell: SpellPF2e, { origin }: { origin?: PhysicalItemPF2e } = {}): boolean { | ||
if (!origin || !spell.actor?.isOfType("creature")) return false; | ||
const rollOptions = new Set( | ||
R.compact([ | ||
...this.actor.getRollOptions(), | ||
...spell.getRollOptions("spell"), | ||
...origin.getRollOptions("activatable"), | ||
]), | ||
); | ||
return this.castPredicate.test(rollOptions); | ||
} | ||
|
||
async cast(spell: SpellPF2e, options: CastOptions = {}): Promise<void> { | ||
const consume = options.consume ?? true; | ||
const message = options.message ?? true; | ||
const valid = !consume || spell.atWill; | ||
if (message && valid) { | ||
spell.system.location.value = this.id; | ||
await spell.toMessage(null, { rollMode: options.rollMode, data: { castRank: spell.rank } }); | ||
} | ||
} | ||
|
||
async getSheetData(): Promise<SpellcastingSheetData> { | ||
return { | ||
...R.pick(this, [ | ||
"id", | ||
"name", | ||
"category", | ||
"tradition", | ||
"sort", | ||
"isFlexible", | ||
"isFocusPool", | ||
"isInnate", | ||
"isPrepared", | ||
"isRitual", | ||
"isSpontaneous", | ||
"isEphemeral", | ||
]), | ||
statistic: this.statistic.getChatData(), | ||
hasCollection: false, | ||
usesSpellProficiency: false, | ||
groups: [], | ||
prepList: R.mapToObj(Array.fromRange(10, 1), (n) => [n, []]), | ||
}; | ||
} | ||
} | ||
|
||
interface ItemsSpellcastingConstructorParams<TActor extends CreaturePF2e> { | ||
id: string; | ||
name: string; | ||
actor: TActor; | ||
statistic: Statistic; | ||
castPredicate: PredicatePF2e; | ||
} | ||
|
||
export { ItemsSpellcasting }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.