Skip to content

Commit

Permalink
Merge pull request #450 from Wasteland-Ventures-Group/feature/charact…
Browse files Browse the repository at this point in the history
…er-sheet-magic

Feature/character sheet magic
  • Loading branch information
kmoschcau authored Aug 27, 2022
2 parents b099405 + db57d09 commit 79027c3
Show file tree
Hide file tree
Showing 13 changed files with 193 additions and 6 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
},
"scripts": {
"lint": "eslint --ext .d.ts,.ts,.test-d.ts,.cjs . && prettier --check ./src/main/compendiums/**/*.json ./src/main/lang/*.json",
"lint-fix": "eslint --ext .d.ts,.ts,.test-d.ts,.cjs . --fix && prettier --check ./src/main/compendiums/**/*.json ./src/main/lang/*.json",
"prepare": "husky install",
"test": "mocha && cd ./src/main/typescript && tsd",
"typecheck": "tsc --project ./src/main/typescript/tsconfig.json --noEmit"
Expand Down
36 changes: 36 additions & 0 deletions src/main/handlebars/actors/parts/magic.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,39 @@
{{selectOptions sheet.magic.thaumSpecials selected=data.data.magic.thaumSpecial}}
</select>
</label>
<button type="button" class="control item-control fas fa-plus" data-action="create" data-type="magic" title="{{localize 'wv.system.actions.create'}}"></button>
<table class="fvtt-item-table">
<thead>
<tr>
<th scope="col" class="align-left"></th>
<th scope="col" class="align-left">{{localize "wv.system.misc.name"}}</th>
<th scope="col" class="align-left">{{localize "wv.rules.magic.school.singular"}}</th>
<th scope="col" class="align-left">{{localize "wv.rules.magic.potency"}}</th>
<th scope="col" class="align-left">{{localize "wv.rules.actionPoints.use"}}</th>
<th scope="col" class="align-left">{{localize "wv.rules.magic.strainUse"}}</th>
<th scope="col" class="align-right"></th>
</tr>
</thead>
<tbody>
{{#each sheet.magic.spells as |spell|~}}
<tr data-item-id="{{spell.id}}">
<td class="align-left">
{{#if spell.img}}
<img src="{{spell.img}}" />
{{/if}}
</td>
<td class="align-left">{{spell.name}}</td>
<td class="align-left">{{spell.school}}</td>
<td class="align-left">{{spell.potency}}</td>
<td class="align-left">{{spell.apCost}}</td>
<td class="align-left">{{spell.strainCost}}</td>
<td class="align-right no-wrap">
<button type="button" class="control small item-control fas fa-pen" data-action="edit"
title="{{localize 'wv.system.actions.edit'}}"></button><button type="button"
class="control small item-control fas fa-minus" data-action="delete"
title="{{localize 'wv.system.actions.delete'}}"></button>
</td>
</tr>
{{/each}}
</tbody>
</table>
5 changes: 5 additions & 0 deletions src/main/lang/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@
"experience": "Erfahrung"
},
"magic": {
"potency": "Potenz",
"magic": "Magie",
"strain": "Anstrengung",
"strainUse": "Anstrengungskosten",
Expand Down Expand Up @@ -578,6 +579,10 @@
"weaponSheet": "Waffenbogen"
}
},
"spell": {
"singular": "Beschwörung",
"plural": "Beschwörungen"
},
"thaumSpecial": "SPECIA für Thaumaturgie",
"values": {
"amount": "Menge",
Expand Down
5 changes: 5 additions & 0 deletions src/main/lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@
"magic": "Magic",
"strain": "Strain",
"strainUse": "Strain use",
"potency": "Potency",
"type": {
"singular": "Magic Type",
"plural": "Magic Types",
Expand Down Expand Up @@ -578,6 +579,10 @@
"weaponSheet": "Weapon Sheet"
}
},
"spell": {
"singular": "Spell",
"plural": "Spells"
},
"thaumSpecial": "SPECIA for Thaumaturgy",
"values": {
"amount": "Amount",
Expand Down
43 changes: 42 additions & 1 deletion src/main/typescript/applications/actor/wvActorSheet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
import { getGame } from "../../foundryHelpers.js";
import * as helpers from "../../helpers.js";
import Apparel from "../../item/apparel.js";
import type Magic from "../../item/magic.js";
import Weapon from "../../item/weapon.js";
import WvItem from "../../item/wvItem.js";
import { WvItemProxy } from "../../item/wvItemProxy.js";
Expand Down Expand Up @@ -207,6 +208,27 @@ export default class WvActorSheet extends ActorSheet {
};
});

// filter, sort, and transform items into sheet data
const spells = this.actor.items
.filter(
(item): item is StoredDocument<Magic> =>
typeof item.id === "string" && item.type === TYPES.ITEM.MAGIC
)
.sort((a, b) => (a.data.sort ?? 0) - (b.data.sort ?? 0))
.map((spell) => {
const spellData = spell.data.data;
const schoolI18n = WvI18n.magicSchools[spellData.school];
return {
id: spell.id,
img: spell.img,
name: spell.name,
school: schoolI18n,
potency: spellData.potency.total,
apCost: spellData.apCost.total,
strainCost: spellData.strainCost.total
};
});

const sheetData: SheetData = {
...(await super.getData()),
sheet: {
Expand Down Expand Up @@ -290,7 +312,8 @@ export default class WvActorSheet extends ActorSheet {
return thaumSpecials;
},
{} as Record<ThaumaturgySpecial, string>
)
),
spells
},
effects: this.actor.items
.filter(
Expand Down Expand Up @@ -637,6 +660,13 @@ export default class WvActorSheet extends ActorSheet {
}),
type: event.target.dataset.type
};
} else if (event.target.dataset.type === TYPES.ITEM.MAGIC) {
data = {
name: getGame().i18n.format("wv.system.misc.newName", {
what: getGame().i18n.localize("wv.system.spell.singular")
}),
type: event.target.dataset.type
};
} else return;

const item = await Item.create(data, { parent: this.actor });
Expand Down Expand Up @@ -947,8 +977,19 @@ interface SheetLeveling {

interface SheetMagic {
thaumSpecials: Record<ThaumaturgySpecial, string>;
spells: SheetSpell[];
}

type SheetSpell = {
id: string;
apCost: number;
strainCost: number;
potency: number;
school: string;
img: string | null;
name: string | null;
};

interface SheetSpecial extends I18nSpecial {
points: number;
permTotal: number;
Expand Down
2 changes: 1 addition & 1 deletion src/main/typescript/applications/item/magicSheet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export default class MagicSheet extends WvItemSheet {
static override get defaultOptions(): ItemSheet.Options {
const defaultOptions = super.defaultOptions;
defaultOptions.classes.push("magic-sheet");
defaultOptions.height = 480;
defaultOptions.height = 700;
defaultOptions.width = 670;
return defaultOptions;
}
Expand Down
37 changes: 35 additions & 2 deletions src/main/typescript/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ export function getMagicType(school: GeneralMagicSchool): MagicType {
}

export type GeneralMagicSchool = typeof GeneralMagicSchools[number];
export const MagicSpecials = {
export const MagicSpecials: Record<GeneralMagicSchool, SpecialName[]> = {
agility: ["agility"],
endurance: ["endurance"],
wonderboltAndTalon: ["agility", "endurance", "charisma"],
Expand All @@ -156,6 +156,7 @@ export const MagicSpecials = {
illusion: ["charisma"],
medical: ["intelligence"],
perception: ["perception"],
protective: ["endurance"],
transmutation: ["endurance"],
incantations: [
"strength",
Expand All @@ -174,8 +175,40 @@ export const MagicSpecials = {
streams: ["endurance"],
trust: ["charisma"],
whispers: ["charisma"]
} as Record<GeneralMagicSchool, SpecialName[]>;
};

/**
* Get the first element of all arrays present in `MagicSpecials`
* @returns A record mapping a magic school to its default SPECIAL
*/
export function defaultMagicSpecial(): Record<GeneralMagicSchool, SpecialName> {
return GeneralMagicSchools.reduce((acc, magicSchool) => {
const magicSpecial = MagicSpecials[magicSchool][0];
if (magicSpecial !== undefined) {
acc[magicSchool] = magicSpecial;
} else {
throw Error(`School ${magicSchool} has no special attached to it`);
}
return acc;
}, {} as Record<GeneralMagicSchool, SpecialName>);
}

/**
* Computes the bonus to potency based on the value of the relevant SPECIAL
* @param special - the value of the relevant SPECIAL
* @returns the extra potency
*/
export function extraPotency(special: number): number {
if (special >= 8) {
return 3;
} else if (special >= 4) {
return 2;
} else if (special >= 1) {
return 1;
} else {
return 0;
}
}
export const SpellRanges = [
"none",
"self",
Expand Down
28 changes: 28 additions & 0 deletions src/main/typescript/data/actor/character/magic/properties.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import {
defaultMagicSpecial,
GeneralMagicSchool,
GeneralMagicSchools,
SpecialName
} from "../../../../constants";
import MagicSource from "./source";

export default class MagicProperties extends MagicSource {
constructor(source: MagicSource) {
super();
foundry.utils.mergeObject(this, source);

this.magicSpecials = defaultMagicSpecial();
GeneralMagicSchools.forEach((school) => {
const specialOverride = source.magicSpecials[school];
if (specialOverride !== undefined) {
this.magicSpecials[school] = specialOverride;
}
});
}

/**
* The record of which special a character uses to compute
* potency for a given school of magic
*/
magicSpecials: Record<GeneralMagicSchool, SpecialName>;
}
14 changes: 13 additions & 1 deletion src/main/typescript/data/actor/character/magic/source.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import type { JSONSchemaType } from "ajv";
import {
SpecialName,
SpecialNames,
ThaumaturgySpecial,
ThaumaturgySpecials
} from "../../../../constants.js";

type CharacterMagicSpecials = Partial<Record<string, SpecialName>>;
export default class MagicSource {
/** The SPECIAL of the character associated with the Thaumaturgy skill */
thaumSpecial: ThaumaturgySpecial = "intelligence";

magicSpecials: CharacterMagicSpecials = {};
}

export const MAGIC_JSON_SCHEMA: JSONSchemaType<MagicSource> = {
Expand All @@ -17,9 +22,16 @@ export const MAGIC_JSON_SCHEMA: JSONSchemaType<MagicSource> = {
description: "The selected Thaumaturgy SPECIAL of the character",
type: "string",
enum: ThaumaturgySpecials
},
magicSpecials: {
type: "object",
additionalProperties: {
type: "string",
enum: SpecialNames
}
}
},
required: ["thaumSpecial"],
required: ["thaumSpecial", "magicSpecials"],
additionalProperties: false,
default: {
thaumSpecial: "intelligence"
Expand Down
4 changes: 4 additions & 0 deletions src/main/typescript/data/actor/character/properties.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { CompositeNumber } from "../../common.js";
import BackgroundProperties from "./background/properties.js";
import EquipmentProperties from "./equipment/properties.js";
import LevelingProperties from "./leveling/properties.js";
import MagicProperties from "./magic/properties.js";
import SkillsProperties from "./skills/properties.js";
import { CharacterDataSourceData } from "./source.js";
import SpecialsProperties, { Special } from "./specials/properties.js";
Expand Down Expand Up @@ -86,6 +87,7 @@ export class CharacterDataPropertiesData extends CharacterDataSourceData {
this.background = new BackgroundProperties(source.background);
this.equipment = new EquipmentProperties(source.equipment);
this.vitals = new VitalsProperties(source.vitals);
this.magic = new MagicProperties(source.magic);
}

override background: BackgroundProperties;
Expand All @@ -96,6 +98,8 @@ export class CharacterDataPropertiesData extends CharacterDataSourceData {

override vitals: VitalsProperties;

override magic: MagicProperties;

/** The secondary statistics of the character */
secondary = new SecondaryStatisticsProperties();

Expand Down
2 changes: 2 additions & 0 deletions src/main/typescript/data/item/magic/properties.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,7 @@ export class MagicDataPropertiesData

override target: TargetProperties;

potency: CompositeNumber = new CompositeNumber();

type: MagicType;
}
19 changes: 18 additions & 1 deletion src/main/typescript/item/magic.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { TYPES } from "../constants.js";
import { extraPotency, TYPES } from "../constants.js";
import { MagicDataPropertiesData } from "../data/item/magic/properties.js";
import { LOG } from "../systemLogger.js";
import WvItem from "./wvItem";

/** An Item that can represent a spell of any school and type. */
Expand All @@ -18,6 +19,22 @@ export default class Magic extends WvItem {
override prepareBaseData(): void {
this.data.data = new MagicDataPropertiesData(this.data.data, this);
}

override finalizeData(): void {
if (!this.actor) {
LOG.warn(
`Trying to finalise a magic item without a parent actor. ${this.ident}`
);
return;
}
const actorData = this.actor.data.data;
const relevantSpecialName =
actorData.magic.magicSpecials[this.data.data.school];
const relevantSpecialValue =
actorData.specials[relevantSpecialName].tempTotal;
this.data.data.potency.source =
actorData.leveling.level + extraPotency(relevantSpecialValue);
}
}

export default interface Magic {
Expand Down
3 changes: 3 additions & 0 deletions src/main/typescript/lang.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,8 @@ export interface LangSchema {
};
/** Labels related to magic */
magic: {
/** The label for potency */
potency: string;
/** The name of "Magic" */
magic: string;
/** The label for the strain */
Expand Down Expand Up @@ -741,6 +743,7 @@ export interface LangSchema {
weaponSheet: string;
};
};
spell: QuantityNames;
/** The label for the Thaumaturgy special select */
thaumSpecial: string;
/** Labels for describing different values */
Expand Down

0 comments on commit 79027c3

Please sign in to comment.