Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Basic Fantasy RPG for FoundryVTT

This is the [Basic Fantasy RPG](https://www.basicfantasy.org/) system for FoundryVTT. Please also see the [companion compendium module](https://github.com/Stew-rt/basicfantasyrpg-corerules-en), which contains items, spells, monsters etc. for easy use with the system.
This is the [Basic Fantasy RPG](https://www.basicfantasy.org/) system for FoundryVTT. Please also see the [companion compendium module](https://github.com/DC23/basicfantasyrpg-corerules-en), which contains items, spells, monsters etc. for easy use with the system.

## Installation

Expand Down
38 changes: 22 additions & 16 deletions module/basicfantasyrpg.mjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Import document classes.
import { BasicFantasyRPGActor } from './documents/actor.mjs';
import { BasicFantasyRPGItem } from './documents/item.mjs';
import { ACTOR_DATA_MODELS, ITEM_DATA_MODELS } from './documents/data-models.mjs';
// Import sheet classes.
import { BasicFantasyRPGActorSheet } from './sheets/actor-sheet.mjs';
import { BasicFantasyRPGItemSheet } from './sheets/item-sheet.mjs';
Expand All @@ -25,6 +26,11 @@ Hooks.once('init', async function() {
// Add custom constants for configuration.
CONFIG.BASICFANTASYRPG = BASICFANTASYRPG;

CONFIG.Actor.dataModels ??= {};
CONFIG.Item.dataModels ??= {};
Object.assign(CONFIG.Actor.dataModels, ACTOR_DATA_MODELS);
Object.assign(CONFIG.Item.dataModels, ITEM_DATA_MODELS);

/**
* Set an initiative formula for the system
* @type {String}
Expand Down Expand Up @@ -127,14 +133,14 @@ Hooks.on("renderDialog", (dialog, html) => {

Hooks.on('createActor', async function(actor) {
if (actor.type === 'character') {
actor.updateSource({
await actor.update({
prototypeToken: {
actorLink: true,
disposition: CONST.TOKEN_DISPOSITIONS.FRIENDLY
}
});
} else if (actor.type === 'monster') {
actor.updateSource({
await actor.update({
prototypeToken: {
appendNumber: true,
displayName: CONST.TOKEN_DISPLAY_MODES.OWNER
Expand All @@ -154,11 +160,13 @@ Hooks.on('createActor', async function(actor) {
/* -------------------------------------------- */

Hooks.on('createToken', async function(token, options, id) {
if (token.actor.type === 'monster') {
if (token.actor?.type === 'monster') {
let newHitPoints = new Roll(`${token.actor.system.hitDice.number}${token.actor.system.hitDice.size}+${token.actor.system.hitDice.mod}`);
await newHitPoints.evaluate({ async: true });
token.actor.system.hitPoints.value = Math.max(1, newHitPoints.total);
token.actor.system.hitPoints.max = Math.max(1, newHitPoints.total);
await token.actor.update({
'system.hitPoints.value': Math.max(1, newHitPoints.total),
'system.hitPoints.max': Math.max(1, newHitPoints.total)
});
}
});

Expand All @@ -175,11 +183,11 @@ Hooks.on('createToken', async function(token, options, id) {
*/
async function createItemMacro(data, slot) {
if (data.type !== 'Item') return;
if (!('data' in data)) return ui.notifications.warn('You can only create macro buttons for owned Items');
const item = data.data;
const item = await Item.implementation.fromDropData(data);
if (!item?.actor) return ui.notifications.warn('You can only create macro buttons for owned Items');

// Create the macro command
const command = `game.basicfantasyrpg.rollItemMacro('${item.name}');`;
const command = `game.basicfantasyrpg.rollItemMacro('${item.uuid}');`;
let macro = game.macros.find(m => (m.name === item.name) && (m.command === command));
if (!macro) {
macro = await Macro.create({
Expand All @@ -197,16 +205,14 @@ async function createItemMacro(data, slot) {
/**
* Create a Macro from an Item drop.
* Get an existing item macro if one exists, otherwise create a new one.
* @param {string} itemName
* @param {string} itemUuid
* @return {Promise}
*/
function rollItemMacro(itemName) {
const speaker = ChatMessage.getSpeaker();
let actor;
if (speaker.token) actor = game.actors.tokens[speaker.token];
if (!actor) actor = game.actors.get(speaker.actor);
const item = actor ? actor.items.find(i => i.name === itemName) : null;
if (!item) return ui.notifications.warn(`Your controlled Actor does not have an item named ${itemName}`);
async function rollItemMacro(itemUuid) {
const item = await fromUuid(itemUuid);
if (!(item instanceof Item) || !item.actor) {
return ui.notifications.warn('This item macro is no longer valid. Please drag the item to your hotbar again.');
}

// Trigger the item roll
return item.roll();
Expand Down
5 changes: 1 addition & 4 deletions module/documents/actor.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export class BasicFantasyRPGActor extends Actor {
* @override
* Augment the basic actor data with additional dynamic data. Typically,
* you'll want to handle most of your calculated/derived data in this step.
* Data calculated in this step should generally not exist in template.json
* Data calculated in this step should generally not exist in the system data model
* (such as ability modifiers rather than ability scores) and should be
* available both inside and outside of character sheets (such as if an actor
* is queried and has a roll executed directly from it).
Expand Down Expand Up @@ -101,9 +101,6 @@ export class BasicFantasyRPGActor extends Actor {

const data = actorData.system;

// Handle changed label for monster special ability XP bonus -- this will be handled in the system data model when it's implemented
data.specialAbility.label = 'BASICFANTASYRPG.SpecialAbilityXPBonus';

data.xp.value = this._calculateMonsterXPValue();
data.attackBonus.value = this._calculateMonsterAttackBonus();
}
Expand Down
Loading