18 Commits

Author SHA1 Message Date
aad90144fe Better import and various stuff 2024-08-10 09:48:43 +02:00
2b1da44f3a Gestion de l'import skill/categories 2024-08-10 00:26:22 +02:00
420f912c8c Gestion de l'import skill/categories 2024-08-10 00:26:05 +02:00
6cfedca162 Gestion de l'import skill/categories 2024-08-10 00:24:15 +02:00
de884cbd22 Gestion de l'import skill/categories 2024-08-10 00:15:44 +02:00
8b37e16915 Gestion de l'import skill/categories 2024-08-09 23:58:38 +02:00
46d991fb65 Fix compendiums 2024-08-09 08:47:23 +02:00
5ca0362773 Fix compendiums 2024-08-09 08:44:14 +02:00
f777131374 Fix compendiums 2024-08-08 23:16:50 +02:00
c11f7d23a8 Add game system for skills 2024-08-08 05:04:53 +02:00
98e6b70b1b Add game system for skills 2024-08-07 23:08:58 +02:00
6597334682 Add game system for skills 2024-08-07 23:08:46 +02:00
534fcb04fb Manage game systems 2024-08-07 17:27:08 +02:00
8be95c20bd Add new rank option 2024-08-04 20:44:34 +02:00
cba4394a37 Rework skill/skill categ links 2024-08-03 16:41:04 +02:00
1f2558b680 Skills below Skills categories + skills rollable 2024-08-02 17:07:02 +02:00
e25c51a570 Rework roll window 2024-07-29 09:28:42 +02:00
3ba8fdd641 Actualiser README.md 2024-07-27 18:20:30 +02:00
57 changed files with 945 additions and 531 deletions

View File

@ -1,16 +1,15 @@
# Rolemaster Standard System for Foundry VTT
## Introduction
This is an in-development implementation of the Rolemaster Standard System for FoundryVTT. All rights to the system remain property of Iron Crown Enterprises (http://ironcrown.com/). This system will not include any of the book content and aims to provide only what is on the character sheet.
If you need access to the Rolemaster Standard System you may be out of luck as the system has been out of print for some time. However it's successor Rolemaster Fantasy Roleplaying is broadly compatible and can be purchased as a PDF via Drive Thru RPG here: https://www.drivethrurpg.com/product/91995/Rolemaster-Fantasy-Role-Playing?cPath=1361_6495
This repo is an independant fork from https://github.com/Cynicide/RMSS-FoundryVTT from Cynicide, in order to implement a fully playable Rolemaster FRP system in FoundryVTT.
All rights to the system remain property of Iron Crown Enterprises (http://ironcrown.com/). This system will not include any of the book content and aims to provide only what is on the character sheet.
## How to Use
Download the latest release from this repository and then extract the rmss folder. Drag it into the systems folder of your FoundryVTT Data Directory. More detailed instructions can be found [here](docs/INSTALL.md) in the docs directory.
Download the latest release from this repository and then extract the rmss folder. Drag it into the systems folder of your FoundryVTT Data Directory. More detailed instructions can be found [here](docs/INSTALL.md) in the docs directory (to be updated).
If you are using this system I highly recommend the "Simple Dice Roller" module which will allow you to roll dice easily while this feature is in development. You can install it in the Foundry Modules section or you can visit the following link for more instructions: https://foundryvtt.com/packages/simple-dice-roller/
Further information on how the system works can be found [here](docs/USAGE.md)
Further information on how the system works can be found [here](docs/USAGE.md) (to be updated)
## Goals/ToDo
Project goals include:
@ -20,13 +19,11 @@ Project goals include:
I maintain a public Trello board here where I log my work items: https://trello.com/b/JkXd5EGx/rmss-for-foundryvtt-features
## About Me
My name is Anthony, I'm a DevOps Engineer who has been playing Roleplaying Games since the mid 80's. I've been involved in numerous small programming projects. This system is by far the largest thing I've done. If the code here is awful it's because I'm learning CSS/Javascript as I go.
## Credits
This system is based on:
- The Foundry VTT Boilerplate system by Asacolips. (https://gitlab.com/asacolips-projects/foundry-mods/boilerplate)
- The video tutorials by Cédric Hauteville you can watch them here: https://www.youtube.com/playlist?list=PLFV9z59nkHDccUbRXVt623UdloPTclIrz
- The Rolemaster FRP is derivated from the RMSS system from Cynicide, available here https://github.com/Cynicide/RMSS-FoundryVTT
Icons used in this system have been sourced from https://game-icons.net

View File

@ -1,4 +1,5 @@
{
"rmss": {
"player_character": {
"name": "Name:",
@ -43,7 +44,8 @@
"equipment": "Equipment",
"spells": "Spells",
"status_record": "Status Record",
"experience_points": "Experience Points"
"experience_points": "Experience Points",
"background": "Background"
},
"pc_sheet_fixed_info": {
"race": "Race:",

View File

@ -47,3 +47,7 @@
border-bottom: 1px solid;
background-image: linear-gradient(rgba(0, 0, 0, 0.1) 0 0);
}
.skill-box {
margin-left: 1.2rem;
background-color: lightgrey;
}

View File

@ -12,7 +12,7 @@
padding-bottom: 3px;
display: flex;
justify-content: flex-end;
flex-direction: column;
//flex-direction: column;
justify-content: center;
}
@ -36,7 +36,7 @@
padding-bottom: 3px;
display: flex;
justify-content: flex-end;
flex-direction: column;
//flex-direction: column;
justify-content: center;
background-image: linear-gradient(rgba(0, 0, 0, 0.1) 0 0);
}
@ -46,3 +46,8 @@
border-bottom: 1px solid;
background-image: linear-gradient(rgba(0, 0, 0, 0.1) 0 0);
}
.skills-name-left-align {
text-align: left;
padding-left: 2px;
}

View File

@ -28,3 +28,6 @@
font-size: 12px;
text-align: center;
}
.select-fixed-width {
width: 100px;
}

View File

@ -15,6 +15,11 @@
.roll-button-container {
display: flex;
flex-direction: column;
justify-content: flex-end;
flex-direction: row;
justify-content: flex-start;
}
.roll-button {
margin-top: 2px;
width: 96px;
max-width: 96px;
}

View File

@ -1,6 +1,6 @@
export const rmss = {};
rmss.curreny_type = {
rmss.currency_type = {
mp: "rmss.curreny_type.mp",
pp: "rmss.curreny_type.pp",
gp: "rmss.curreny_type.gp",
@ -9,6 +9,66 @@ rmss.curreny_type = {
cp: "rmss.curreny_type.cp"
};
rmss.difficulties = {
routine: {key: "routine", label:"Routine (+30)", value: 30},
easy: {key: "easy", label:"Easy (+20)", value: 20},
light: {key: "light", label:"Light (+10)", value: 10},
medium: {key: "medium", label:"Medium (0)", value: 0},
hard: {key: "hard", label:"Hard (-10)", value: -10},
very_hard: {key: "very_hard", label:"Very Hard (-20)", value: -20},
extremely_hard: {key: "extremely_hard", label:"Extremely Hard (-30)", value: -30},
sheer_folly: {key: "sheer_folly", label:"Sheer Folly (-50)", value: -50},
absurd: {key: "absurd", label:"Absurd (-70)", value: -70},
};
rmss.gameSystems = [
{key: "common", label:"Common"},
{key: "merp", label:"Middle Earth Role Playing (MERP)"},
{key: "rmfrp", label:"Rolemaster Fantasy Role Playing (RMFRP)"},
];
rmss.combatSituations = [
{key: "none", label:"None (0)", modifier: 0},
{key: "melee", label:"Melee environment (-20)", modifier: -20},
{key: "missile", label:"Under missile fire (-10)", modifier: -10},
];
rmss.rankBonusProgressionList = [
{key: "standard", label:"Standard"},
{key: "limited", label:"Limited"},
{key: "combined", label:"Combined"},
{key: "race", label:"Linked to Race"},
]
rmss.lightOrDarknessModifiers = [
{key: "none", label:"None", modifierLight: 0, modifierDark: 0},
{key: "noshadows", label:"No shadows", modifierLight: 10, modifierDark: -30},
{key: "lightshadows", label:"Light shadows", modifierLight: 5, modifierDark: -20},
{key: "mediumshadows", label:"Medium shadows", modifierLight: 0, modifierDark: 0},
{key: "heavyshadows", label:"Heavy shadows", modifierLight: -10, modifierDark: 10},
{key: "dark", label:"Darkness", modifierLight: -25, modifierDark: 30},
{key: "pitchblack", label:"Pitch black", modifierLight: -40, modifierDark: 40},
]
rmss.hitsPerRound = [
{key: "none", label:"None", modifier: 0},
{key: "one", label:"One", modifier: -5},
{key: "two", label:"Two", modifier: -10},
{key: "three", label:"Three", modifier: -20},
{key: "four", label:"Four", modifier: -25},
{key: "five", label:"Five", modifier: -30},
{key: "six", label:"Six", modifier: -35},
{key: "seven", label:"Seven", modifier: -40},
{key: "eight", label:"Eight", modifier: -45},
{key: "nine", label:"Nine", modifier: -50},
{key: "ten", label:"Ten", modifier: -55},
{key: "eleven", label:"Eleven", modifier: -60},
{key: "twelve", label:"Twelve", modifier: -65},
{key: "thirteen", label:"Thirteen", modifier: -70},
{key: "fourteen", label:"Fourteen", modifier: -75},
{key: "fifteen", label:"Fifteen", modifier: -80}
];
rmss.stats = {
agility: {
fullname: "Agility",

View File

@ -27,6 +27,12 @@ export class RMSSActor extends Actor {
_prepareCharacterData(actorData) {
if (actorData.type !== "character") return;
console.log("*****Flag", this.getFlag("world", "importing"));
if (this.getFlag("world", "importing")) {
return; // Don't calculate skill bonuses if we are importing
}
this.calculateBasicStatBonus(actorData);
// Calculate Stat Bonuses for the Actor
@ -40,6 +46,31 @@ export class RMSSActor extends Actor {
// Iterate through and apply Skill Category Bonuses for Skill items
this.calculateSkillBonuses();
this.computeWoundsMalus();
}
getStunnedModifier() {
if (this.system.state.stunned) {
return Math.min(-50 + (3*this.system.stats.self_discipline.stat_bonus), 0)
} else {
return 0;
}
}
computeWoundsMalus() {
// Compute % of wounds
let percent = 100 - (this.system.attributes.hits.current*100/this.system.attributes.hits.max);
let modifier = 0;
if (percent > 25 && percent < 50) {
modifier = -10;
} else if (percent >= 51 && percent < 75) {
modifier = -20;
} else if (percent >= 76) {
modifier = -30;
}
this.system.modifiers.woundsModifier = modifier;
console.log(`rmss | actor.js | Wounds Malus: ${this.system.modifiers.woundsModifier} ${percent}`);
}
/**
@ -208,9 +239,7 @@ export class RMSSActor extends Actor {
for (const item of this.items) {
if (item.type === "skill") {
console.log(`rmss | actor.js | Calculating skill bonus for Skill: ${item.name}`);
console.log(`rmss | actor.js | Updating Skill Category Bonus for Skill: ${item.name}`);
item.calculateSelectedSkillCategoryBonus(item);
console.log(`rmss | actor.js | Updating Skill Total Bonus for Skill: ${item.name}`);
item.calculateSkillTotalBonus(item);
}
}
@ -233,52 +262,36 @@ export class RMSSActor extends Actor {
}
else
{
let applicable_stat_bonus = 0;
let app_stat_1_found = false;
let app_stat_2_found = false;
let app_stat_3_found = false;
let applicable_stat_bonuses = [];
// Iterate through the applicable stats and find their full names
for (const stat in CONFIG.rmss.stats) {
// If the configured App Stat matches the one of the stats in config
if (app_stat_1 === CONFIG.rmss.stats[stat].shortname) {
app_stat_1_found = true;
// Get the Stat Bonus
applicable_stat_bonus = applicable_stat_bonus + this.system.stats[stat].stat_bonus;
// Add the Stat Bonus to the array
applicable_stat_bonuses.push(this.system.stats[stat].stat_bonus);
}
if (app_stat_2 === CONFIG.rmss.stats[stat].shortname) {
app_stat_2_found = true;
applicable_stat_bonus = applicable_stat_bonus + this.system.stats[stat].stat_bonus;
// Add the Stat Bonus to the array
applicable_stat_bonuses.push(this.system.stats[stat].stat_bonus);
}
if (app_stat_3 === CONFIG.rmss.stats[stat].shortname) {
app_stat_3_found = true;
applicable_stat_bonus = applicable_stat_bonus + this.system.stats[stat].stat_bonus;
// Add the Stat Bonus to the array
applicable_stat_bonuses.push(this.system.stats[stat].stat_bonus);
}
}
if (app_stat_1_found === true && app_stat_2_found === true && app_stat_3_found === true) {
// Compute the total bonus for the applicable stats
let applicable_stat_bonus = 0;
for (const bonus of applicable_stat_bonuses) {
applicable_stat_bonus += bonus;
}
// Apply the update if we found stat bonuses for every applicable stat
if ( item.system.stat_bonus != applicable_stat_bonus ) {
item.system.stat_bonus = applicable_stat_bonus;
}
// Update the total in the Item
item.calculateSkillCategoryTotalBonus(item);
}
else if (app_stat_1_found === true && app_stat_2_found === true && app_stat_3_found === false) {
// Apply the update if we found stat bonuses for the first two applicable stats
item.system.stat_bonus = applicable_stat_bonus;
// Update the total in the Item
item.calculateSkillCategoryTotalBonus(item);
}
else if (app_stat_1_found === true && app_stat_2_found === false && app_stat_3_found === false) {
// Apply the update if we found stat bonuses for the first applicable stat
item.system.stat_bonus = applicable_stat_bonus;
// Update the total in the Item
item.calculateSkillCategoryTotalBonus(item);
}
}
}
}
}

View File

@ -1,3 +1,5 @@
import { RFRPUtility } from "../rfrp-utility.js";
export class RMSSItem extends Item {
/** @override */
@ -44,10 +46,11 @@ export class RMSSItem extends Item {
prepareDerivedData() {
const itemData = this;
const systemData = itemData.system;
const flags = itemData.flags.rmss || {};
if (this.parent?.getFlag("world", "importing")) {
return; // Don't calculate skill bonuses if we are importing
}
// Make separate methods for each item type to keep things organized.
if (itemData.type === "skill") {
this._prepareSkillCategoryData(itemData);
}
@ -66,6 +69,7 @@ export class RMSSItem extends Item {
_prepareSkillData(itemData) {
if (itemData.type !== "skill") return;
console.log(`rmss | item.js | Preparing Skill Data for: ${itemData.name}`);
// Make modifications to data here. For example:
// const systemData = itemData.system;
@ -100,21 +104,19 @@ export class RMSSItem extends Item {
}
calculateSelectedSkillCategoryBonus(itemData) {
if (this.isEmbedded === null) {
console.log(`rmss | item.js | Skill ${this.name} has no owner. Not calculating Skill Category bonus`);
}
else
{
const items = this.parent?.items;
console.log(`rmss | item.js | Skill ${this.name} has owner, calculating skill category bonus.`);
if (items) {
for (const item of items) {
if (item.type === "skill_category" && item._id === itemData.system.category) {
console.log(`rmss | item.js | Calculating Skill Category bonus for skill: ${this.name}`);
// Find the relevant skill category
if (!this.parent) { return; } // Only if attached to an actor
let skillC = this.parent?.items || RFRPUtility.getSkillCategories();
if (skillC) {
let item = skillC.find(it => it.type == "skill_category" && it.name.toLowerCase() == itemData.system.category.toLowerCase());
if (item) {
this.system.category_bonus = item.system.total_bonus;
}
}
}
} else {
ui.notifications.warn(`Skill Category ${itemData.system.category} not found for Skill ${itemData.name}`);
}
} else {
ui.notifications.info("No Skill Categories found. Please create a Skill Category.");
}
}
}

201
module/rfrp-utility.js Normal file
View File

@ -0,0 +1,201 @@
/* -------------------------------------------- */
export class RFRPUtility {
/* -------------------------------------------- */
static async init() {
}
/* -------------------------------------------- */
static async ready() {
this.registerSettings();
this.gameSystem = game.settings.get("fvtt-rolemaster-frp", "game_system");
const skillCategories = await RFRPUtility.loadCompendium("fvtt-rolemaster-frp.skill_categories")
this.skillCategories = skillCategories.map(i => i.toObject()).filter( i => i.system.game_system == "common" || i.system.game_system == this.gameSystem);
// Sort skill categories by name
this.skillCategories.sort((a, b) => a.name.localeCompare(b.name));
}
static getGameSystem() {
return this.gameSystem;
}
/* -------------------------------------------- */
static getSkillCategories() {
return this.skillCategories
}
/* -------------------------------------------- */
static registerSettings() {
game.settings.register("fvtt-rolemaster-frp", "game_system", {
name: "Game System",
hint: "List of Game Systems",
scope: "world",
default: "rmfrp",
requiresReload: true,
type: String,
config: true,
choices: {
rmfrp: "Rolemaster Fantasy Role Playing (RMFRP)",
merp: "Middle Earth Role Playing (MERP)"
}
});
}
/* -------------------------------------------- */
static async loadCompendiumData(compendium) {
const pack = game.packs.get(compendium);
return await pack?.getDocuments() ?? [];
}
/* -------------------------------------------- */
static async loadCompendium(compendium, filter = item => true) {
let compendiumData = await RFRPUtility.loadCompendiumData(compendium);
return compendiumData.filter(filter);
}
/* -------------------------------------------- */
static removeChatMessageId(messageId) {
if (messageId) {
game.messages.get(messageId)?.delete();
}
}
static findChatMessageId(current) {
return RFRPUtility.getChatMessageId(HeritiersUtility.findChatMessage(current));
}
static getChatMessageId(node) {
return node?.attributes.getNamedItem('data-message-id')?.value;
}
static findChatMessage(current) {
return RFRPUtility.findNodeMatching(current, it => it.classList.contains('chat-message') && it.attributes.getNamedItem('data-message-id'))
}
static findNodeMatching(current, predicate) {
if (current) {
if (predicate(current)) {
return current;
}
return RFRPUtility.findNodeMatching(current.parentElement, predicate);
}
return undefined;
}
/* -------------------------------------------- */
static getUsers(filter) {
return game.users.filter(filter).map(user => user._id);
}
/* -------------------------------------------- */
static getWhisperRecipients(rollMode, name) {
switch (rollMode) {
case "blindroll": return this.getUsers(user => user.isGM);
case "gmroll": return this.getWhisperRecipientsAndGMs(name);
case "selfroll": return [game.user.id];
}
return undefined;
}
/* -------------------------------------------- */
static getWhisperRecipientsAndGMs(name) {
let recep1 = ChatMessage.getWhisperRecipients(name) || [];
return recep1.concat(ChatMessage.getWhisperRecipients('GM'));
}
/* -------------------------------------------- */
static blindMessageToGM(chatOptions) {
let chatGM = foundry.utils.duplicate(chatOptions);
chatGM.whisper = this.getUsers(user => user.isGM);
chatGM.content = "Blinde message of " + game.user.name + "<br>" + chatOptions.content;
console.log("blindMessageToGM", chatGM);
game.socket.emit("system.fvtt-rolemaster-frp", { msg: "msg_gm_chat_message", data: chatGM });
}
/* -------------------------------------------- */
static async searchItem(dataItem) {
let item
if (dataItem.pack) {
let id = dataItem.id || dataItem._id
let items = await this.loadCompendium(dataItem.pack, item => item.id == id)
item = items[0] || undefined
} else {
item = game.items.get(dataItem.id)
}
return item
}
/* -------------------------------------------- */
static loadHandlebarsTemplates() {
const templatePaths = [
"systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-stats.html",
"systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-fixed-info.html",
"systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-armor-info.html",
"systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-resistance.html",
"systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-race-stat-fixed-info.html",
"systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-role-traits.html",
"systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-background-info.html",
"systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-skill-categories.html",
"systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-skills.html",
"systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-fav-skills.html",
"systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-items.html",
"systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-weapons.html",
"systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-money.html",
"systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-skill-categories.html",
"systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-skills.html",
"systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-armor.html",
"systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-herbs.html",
"systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-spells.html",
"systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-fav-spells.html",
"systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-fav-items.html",
"systems/fvtt-rolemaster-frp/templates/sheets/apps/app_skill_category_importer.html"
];
return loadTemplates(templatePaths);
}
/* -------------------------------------------- */
static loadHandlebarsHelpers() {
// Handlebars Helpers
Handlebars.registerHelper('count', function (list) {
return list.length;
})
Handlebars.registerHelper('includes', function (array, val) {
return array.includes(val);
})
Handlebars.registerHelper('upper', function (text) {
return text.toUpperCase();
})
Handlebars.registerHelper('lower', function (text) {
return text.toLowerCase()
})
Handlebars.registerHelper('upperFirst', function (text) {
if (typeof text !== 'string') return text
return text.charAt(0).toUpperCase() + text.slice(1)
})
Handlebars.registerHelper('notEmpty', function (list) {
return list.length > 0;
})
Handlebars.registerHelper('mul', function (a, b) {
return parseInt(a) * parseInt(b);
})
Handlebars.registerHelper("switch", function (value, options) {
this.switch_value = value;
return options.fn(this);
});
Handlebars.registerHelper("case", function (value, options) {
if (value === this.switch_value) {
return options.fn(this);
}
});
// Handle v12 removal of this helper
Handlebars.registerHelper('select', function (selected, options) {
const escapedValue = RegExp.escape(Handlebars.escapeExpression(selected));
const rgx = new RegExp(' value=[\"\']' + escapedValue + '[\"\']');
const html = options.fn(this);
return html.replace(rgx, "$& selected");
});
}
}

View File

@ -90,11 +90,11 @@ export default class RMSSPlayerSheet extends ActorSheet {
context.system.attributes.power_points.modifier = "PP Exhaustion Penalty: -20 ";
break;
case (powerpointPercentage < 75):
console.log("Less than 75");
//console.log("Less than 75");
context.system.attributes.power_points.modifier = "PP Exhaustion Penalty: -10 ";
break;
default:
console.log("Setting Default");
//console.log("Setting Default");
context.system.attributes.power_points.modifier = "PP Exhaustion Penalty: 0 ";
}
@ -117,11 +117,11 @@ export default class RMSSPlayerSheet extends ActorSheet {
context.system.attributes.exhaustion_points.modifier = "Exhaustion Penalty: -15 ";
break;
case (exhaustionPercentage < 75):
console.log("Less than 75");
//console.log("Less than 75");
context.system.attributes.exhaustion_points.modifier = "Exhaustion Penalty: -5 ";
break;
default:
console.log("Setting Default");
//console.log("Setting Default");
context.system.attributes.exhaustion_points.modifier = "Exhaustion Penalty: 0 ";
}
@ -167,28 +167,25 @@ export default class RMSSPlayerSheet extends ActorSheet {
spells.push(i);
}
}
// Parse skill categories and re+levant skills
for (let s of skillcat) {
s.skills = [];
for (let sk of playerskill) {
if (sk.system.category.toLowerCase() === s.name.toLowerCase()) {
s.skills.push(sk);
}
}
// Sort skills with localcompare
s.skills.sort((a, b) => a.name.localeCompare(b.name));
}
// Sort Skill/Skillcat Arrays
skillcat.sort(function(a, b) {
if (a.name < b.name) {
return -1;
}
if (a.name > b.name) {
return 1;
}
return 0;
});
playerskill.sort(function(a, b) {
if (a.name < b.name) {
return -1;
}
if (a.name > b.name) {
return 1;
}
return 0;
});
// Sort all items
skillcat.sort((a, b) => a.name.localeCompare(b.name));
gear.sort((a, b) => a.name.localeCompare(b.name));
weapons.sort((a, b) => a.name.localeCompare(b.name));
armor.sort((a, b) => a.name.localeCompare(b.name));
herbs.sort((a, b) => a.name.localeCompare(b.name));
spells.sort((a, b) => a.name.localeCompare(b.name));
// Assign and return
context.gear = gear;
@ -198,6 +195,10 @@ export default class RMSSPlayerSheet extends ActorSheet {
context.armor = armor;
context.herbs = herbs;
context.spells = spells;
// Dump context to console
console.log("ACTOR CONTEXT", context);
}
async renderCharacterSettings(data) {
@ -217,7 +218,7 @@ export default class RMSSPlayerSheet extends ActorSheet {
html.find(".item-roll").click(ev => {
const item = this.actor.items.get(ev.currentTarget.getAttribute("data-item-id"));
new game.rmss.applications.RMSSToolsDiceRoller(item.name, item.system.total_bonus).render(true);
new game.rmss.applications.RMSSToolsDiceRoller(item, this.actor).render(true);
});
// -------------------------------------------------------------
@ -239,8 +240,10 @@ export default class RMSSPlayerSheet extends ActorSheet {
let selectOptions = {};
for (const pack of game.packs) {
if (pack.metadata.type === "Item") {
selectOptions[pack.metadata.id] = pack.metadata.label;
}
}
new game.rmss.applications.RMSSToolsSCImporter(selectOptions, this.actor).render(true);
});

View File

@ -1,22 +1,12 @@
import {
roll_one_to_onehundred,
roll_low_open_ended,
roll_high_open_ended,
roll_open_ended
} from "./rmss_dice_roller_rolls.js";
import {
getOpenEndedRollModifier,
processOpenEndedSixtySixRoll,
processOpenEndedRoll,
processHighOpenEndedRoll,
processLowOpenEndedRoll
} from "./rmss_dice_roller_processing.js";
export default class RMSSToolsDiceRoller extends FormApplication {
constructor(itemName, characterBonus) {
constructor(item, actor) {
super();
this.itemName = itemName;
this.characterBonus = characterBonus;
this.item = foundry.utils.duplicate(item);
this.actor = actor;
this.itemName = item.name;
this.characterBonus = Number(item.system.total_bonus);
this.stunnedModifier = actor.getStunnedModifier()
this.rollType = [
{ value: "one_to_onehundred", text: "1-100", selected: false },
{ value: "open_ended", text: "Open-Ended", selected: true },
@ -30,8 +20,8 @@ export default class RMSSToolsDiceRoller extends FormApplication {
classes: ["form"],
title: "Rolemaster Dice Roller",
popOut: true,
width: 380,
height: 210,
width: 480,
height: 440,
template: "systems/fvtt-rolemaster-frp/templates/sheets/apps/app_dice_roller.html"
});
}
@ -42,6 +32,15 @@ export default class RMSSToolsDiceRoller extends FormApplication {
itemName: this.itemName,
characterBonus: this.characterBonus,
selectOptions: this.rollType,
woundsModifier: this.actor.system.modifiers.woundsModifier,
config: CONFIG.rmss,
difficulty: 0,
combatSituation: 0,
lightningModifier: 0,
darknessModifier: 0,
hitsPerRound: 0,
isStunned: this.actor.system.state.stunned,
stunnedModifier: this.stunnedModifier
};
}
@ -53,33 +52,112 @@ export default class RMSSToolsDiceRoller extends FormApplication {
console.log("Rolling Dice");
console.log(formData);
console.log(event);
switch (formData.rollType) {
case "one_to_onehundred":
this.roll_one_to_onehundred();
this.roll(event.submitter?.dataset?.value, formData);
}
/* -------------------------------------------- */
async showDiceSoNice(roll, rollMode) {
if (game.modules.get("dice-so-nice")?.active) {
if (game.dice3d) {
let whisper = null;
let blind = false;
rollMode = rollMode ?? game.settings.get("core", "rollMode");
switch (rollMode) {
case "blindroll": //GM only
blind = true;
case "gmroll": //GM + rolling player
whisper = this.getUsers(user => user.isGM);
break;
case "open_ended":
this.roll_open_ended();
case "roll": //everybody
whisper = this.getUsers(user => user.active);
break;
case "high_open_ended":
this.roll_high_open_ended();
break;
case "low_open_ended":
this.roll_low_open_ended();
case "selfroll":
whisper = [game.user.id];
break;
}
await game.dice3d.showForRoll(roll, game.user, true, whisper, blind);
}
}
}
RMSSToolsDiceRoller.prototype.roll_one_to_onehundred = roll_one_to_onehundred;
RMSSToolsDiceRoller.prototype.roll_low_open_ended = roll_low_open_ended;
RMSSToolsDiceRoller.prototype.roll_high_open_ended = roll_high_open_ended;
RMSSToolsDiceRoller.prototype.roll_open_ended = roll_open_ended;
/* -------------------------------------------- */
async roll(rollKey, formData) {
let baseRoll = await new Roll("1d100").roll();
await this.showDiceSoNice(baseRoll, game.settings.get("core", "rollMode"))
let rollType = this.rollType.find(r => r.value == rollKey)?.text;
let rollData = {
name: this.itemName,
rollKey: rollKey,
rollType: rollType,
difficulty: Number(formData.difficulty),
combatSituation: Number(formData?.combatSituation || 0),
lightningModifier: Number(formData?.lightningModifier || 0),
darknessModifier: Number(formData?.darknessModifier || 0),
characterBonus: Number(this.characterBonus),
woundsModifier: Number(this.actor.system.modifiers.woundsModifier),
hitsPerRound: Number(formData.hitsPerRound),
isStunned: this.actor.system.state.stunned,
stunnedModifier: this.stunnedModifier,
rolls: [baseRoll],
}
if (baseRoll.result == 66) {
rollData.content = "You rolled a 66!";
}
// Process the for low open ended rolls
if (rollKey === "open_ended" || rollKey === "low_open_ended") {
if (baseRoll.result < 6) {
rollData.lowopen = true
let newRoll = await new Roll("-1d100").roll();
await this.showDiceSoNice(newRoll, game.settings.get("core", "rollMode"))
rollData.rolls.push(newRoll);
while (newRoll.result > 95) {
newRoll = await new Roll("-1d100").roll();
await this.showDiceSoNice(newRoll, game.settings.get("core", "rollMode"))
rollData.rolls.push(newRoll);
}
}
}
// Process the for high open ended rolls
if (rollKey === "open_ended" || rollKey === "high_open_ended") {
if (baseRoll.result > 95) {
rollData.highopen = true
let newRoll = await new Roll("1d100").roll();
await this.showDiceSoNice(newRoll, game.settings.get("core", "rollMode"))
rollData.rolls.push(newRoll);
while (newRoll.result > 95) {
newRoll = await new Roll("1d100").roll();
await this.showDiceSoNice(newRoll, game.settings.get("core", "rollMode"))
rollData.rolls.push(newRoll);
}
}
}
// Compute total of rolls
rollData.totalRolls = rollData.rolls.reduce((acc, roll) => Number(acc) + Number(roll.result), 0);
rollData.totalFinal = rollData.totalRolls + Number(rollData.combatSituation) +
Number(rollData.lightningModifier) +
Number(rollData.darknessModifier) +
Number(this.actor.system.modifiers.woundsModifier) +
Number(formData.difficulty) +
Number(rollData.hitsPerRound) +
Number(rollData.stunnedModifier) +
Number(this.characterBonus);
console.log(">>> Roll Data: ", rollData);
RMSSToolsDiceRoller.prototype.getOpenEndedRollModifier =
getOpenEndedRollModifier;
RMSSToolsDiceRoller.prototype.processOpenEndedSixtySixRoll =
processOpenEndedSixtySixRoll;
RMSSToolsDiceRoller.prototype.processOpenEndedRoll = processOpenEndedRoll;
RMSSToolsDiceRoller.prototype.processHighOpenEndedRoll =
processHighOpenEndedRoll;
RMSSToolsDiceRoller.prototype.processLowOpenEndedRoll = processLowOpenEndedRoll;
// Define the Chat Message Template
let chatTemplate = "systems/fvtt-rolemaster-frp/templates/chat/chat_dice_roll.html";
// Pass the Data through to be used in the Chat Message
let chatData = rollData
// Render the Rolls to the Chat Window
renderTemplate(chatTemplate, chatData).then((html) => {
let chatOptions = {
style: CONST.CHAT_MESSAGE_STYLES.ROLL,
flavor: rollType,
rollMode: game.settings.get("core", "rollMode"),
content: html,
};
ChatMessage.create(chatOptions);
});
}
}

View File

@ -1,131 +0,0 @@
export async function getOpenEndedRollModifier() {
return await new Roll("1d100x>95").roll();
}
export function processOpenEndedSixtySixRoll(baseroll, rolltype) {
// Log the Roll to Chat
let chatOptions = {
type: CONST.CHAT_MESSAGE_TYPES.ROLL,
rolls: [baseroll],
flavor: rolltype,
rollMode: game.settings.get("core", "rollMode"),
content: "You rolled a 66!",
};
ChatMessage.create(chatOptions);
}
export function processOpenEndedRoll(baseroll, rolltype) {
// Define the Chat Message Template
let chatTemplate = "systems/fvtt-rolemaster-frp/templates/chat/chat_dice_roll.html";
// Pass the Data through to be used in the Chat Message
let chatData = {
baseroll: baseroll,
total: baseroll.result,
highopen: false,
lowopen: false,
};
// Render the Rolls to the Chat Window
renderTemplate(chatTemplate, chatData).then((html) => {
let chatOptions = {
type: CONST.CHAT_MESSAGE_TYPES.ROLL,
rolls: [baseroll],
flavor: rolltype,
rollMode: game.settings.get("core", "rollMode"),
content: html,
};
ChatMessage.create(chatOptions);
});
}
export async function processHighOpenEndedRoll(baseroll, rolltype) {
// Get the Base Roll followed by the High Open Ended Roll
let originalRoll = baseroll;
let openendedRoll = await this.getOpenEndedRollModifier();
// Create a rolls array for Dice So Nice integration.
let rolls = [originalRoll, openendedRoll];
// Create an Array to hold the High Open Ended Roll Results and set the total to base roll
let openendedResults = [];
let total = Number(originalRoll.result);
// Each time the High Open Ended Roll is triggered add the result to an array and add it to the total.
for (const rollResult of openendedRoll.dice[0].results) {
openendedResults.push(rollResult.result);
total = total + Number(rollResult.result);
}
// Define the Chat Message Template
let chatTemplate = "systems/fvtt-rolemaster-frp/templates/chat/chat_dice_roll.html";
// Pass the Data through to be used in the Chat Message
let chatData = {
baseroll: baseroll,
opeendedresults: [openendedResults],
highopen: true,
lowopen: false,
total: total,
};
// Render the Rolls to the Chat Window
renderTemplate(chatTemplate, chatData).then((html) => {
let chatOptions = {
style: CONST.CHAT_MESSAGE_STYLES.ROLL,
rolls: rolls,
flavor: rolltype,
rollMode: game.settings.get("core", "rollMode"),
content: html,
};
ChatMessage.create(chatOptions);
});
}
export async function processLowOpenEndedRoll(baseroll, rolltype) {
// Get the Base Roll followed by the Low Open Ended Roll
let originalRoll = baseroll;
let openendedRoll = await this.getOpenEndedRollModifier();
// Create a rolls array for Dice So Nice integration.
let rolls = [originalRoll, openendedRoll];
// Create an Array to hold the Low Open Ended Roll Results and set the total to base roll
let openendedResults = [];
let total = Number(originalRoll.result);
// Each time the Low Open Ended Roll is triggered add the result to an array and subtract it from the total.
for (const rollResult of openendedRoll.dice[0].results) {
openendedResults.push(rollResult.result);
total = total - Number(rollResult.result);
}
// Define the Chat Message Template
let chatTemplate = "systems/fvtt-rolemaster-frp/templates/chat/chat_dice_roll.html";
// Pass the Data through to be used in the Chat Message
let chatData = {
baseroll: baseroll,
rolls: rolls,
opeendedresults: [openendedResults],
highopen: false,
lowopen: true,
total: total,
};
// Render the Rolls to the Chat Window
renderTemplate(chatTemplate, chatData).then((html) => {
let chatOptions = {
style: CONST.CHAT_MESSAGE_STYLES.ROLL,
rolls: rolls,
flavor: rolltype,
rollMode: game.settings.get("core", "rollMode"),
content: html,
};
ChatMessage.create(chatOptions);
});
}

View File

@ -1,71 +0,0 @@
export async function roll_one_to_onehundred() {
// Construct the Roll instance
let baseroll = await new Roll("1d100 + @characterBonus", {characterBonus: this.characterBonus}).roll({async: true});
let rolltype = "Roll Type: 1-100";
// Log the Roll to Chat
let chatOptions = {
type: CONST.CHAT_MESSAGE_TYPES.ROLL,
rolls: [baseroll],
flavor: rolltype,
rollMode: game.settings.get("core", "rollMode")
};
ChatMessage.create(chatOptions);
this.close();
};
export async function roll_low_open_ended() {
// Construct the Roll instance
let baseroll = await new Roll("1d100").roll({async: true});
console.log(baseroll.result);
let rolltype = "Roll Type: Low Open-Ended";
switch (true) {
case (baseroll.result < 6):
this.processLowOpenEndedRoll(baseroll, rolltype);
break;
case (baseroll.result === 66):
this.processOpenEndedSixtySixRoll(baseroll, rolltype);
break;
default:
this.processOpenEndedRoll(baseroll, rolltype);
}
}
export async function roll_high_open_ended() {
// Construct the Roll instance
let baseroll = await new Roll("1d100").roll({async: true});
console.log(baseroll.result);
let rolltype = "Roll Type: High Open-Ended";
switch (true) {
case (baseroll.result === 66):
this.processOpenEndedSixtySixRoll(baseroll, rolltype);
break;
case (baseroll.result > 95):
this.processHighOpenEndedRoll(baseroll, rolltype);
break;
default:
this.processOpenEndedRoll(baseroll, rolltype);
}
}
export async function roll_open_ended() {
// Construct the Roll instance
let baseroll = await new Roll("1d100").roll({async: true});
console.log(baseroll.result);
let rolltype = "Roll Type: Open-Ended";
switch (true) {
case (baseroll.result < 6):
this.processLowOpenEndedRoll(baseroll, rolltype);
break;
case (baseroll.result === 66):
this.processOpenEndedSixtySixRoll(baseroll, rolltype);
break;
case (baseroll.result > 95):
this.processHighOpenEndedRoll(baseroll, rolltype);
break;
default:
this.processOpenEndedRoll(baseroll, rolltype);
}
}

View File

@ -1,3 +1,5 @@
import { RFRPUtility } from "../../rfrp-utility.js";
export default class RMSSToolsSCImporter extends FormApplication {
constructor(selectOptions, character) {
@ -9,6 +11,7 @@ export default class RMSSToolsSCImporter extends FormApplication {
static get defaultOptions() {
return foundry.utils.mergeObject(super.defaultOptions, {
classes: ["form"],
width: 520,
popOut: true,
title: "Import Skill Categories",
template: "systems/fvtt-rolemaster-frp/templates/sheets/apps/app_skill_category_importer.html"
@ -27,30 +30,38 @@ export default class RMSSToolsSCImporter extends FormApplication {
}
async _updateObject(event, formData) {
console.log("Deleting Old Skill Categories.");
for (const item of this.character.items) {
if (item.type === "skill_category") {
item.delete();
}
}
await this.character.setFlag("world", "importing", true);
const pack = game.packs.get(formData.selectOptions);
let itemType = event.submitter.value;
let toDelete = [];
for (const item of this.character.items) {
if (item.type === itemType) {
toDelete.push(item.id);
}
if (itemType == "skill_category" && item.type === "skill") {
toDelete.push(item.id); // Delete also skill when re-importing skill categories.
}
}
await this.character.deleteEmbeddedDocuments("Item", toDelete);
let comp = (itemType == "skill") ? formData.selectOptionsSkills : formData.selectOptionsCategories;
const pack = game.packs.get(comp);
const skillCategoryData = await pack.getIndex();
console.log("Importing New Skill Categories.");
console.log("Importing New Skills/Skill Categories.");
let newDocuments = [];
let gameSystem = RFRPUtility.getGameSystem();
for (const sc of skillCategoryData) {
const newitem = await pack.getDocument(sc._id);
let newDocuments = [];
if (newitem.type === "skill_category") {
console.log(newitem);
if (newitem.type === itemType && (newitem.system.game_system === "common" || newitem.system.game_system === gameSystem)) {
newDocuments.push(newitem);
}
}
if (newDocuments.length > 0) {
await Item.createDocuments(newDocuments, {parent: this.character});
}
}
await this.character.setFlag("world", "importing", false);
}
}

View File

@ -1,3 +1,5 @@
import { RFRPUtility } from "../../rfrp-utility.js";
// Our Item Sheet extends the default
export default class RMSSSkillSheet extends ItemSheet {
@ -70,21 +72,20 @@ export default class RMSSSkillSheet extends ItemSheet {
// If this Skill is owned then we will return a list of Skill Categories and allow them to choose
// Otherwise we'll just return 'Skill has no owner'
prepareSkillCategoryValues() {
let skillNoOwner = { None: "Skill Has No Owner" };
if (!this.item.isEmbedded) {
return (skillNoOwner);
} else {
const skillCategories = this.item.parent.getOwnedItemsByType("skill_category");
return (skillCategories);
let skillCategories = RFRPUtility.getSkillCategories();
if (this.item.isEmbedded) {
skillCategories = this.item.parent.items.filter(it => it.type == "skill_category");
}
//console.log("CATEG", skillCategories);
return (skillCategories);
}
// Determine which Skill Category is selected and test that it is in the current list of categories.
// If it isn't set it to None.
prepareSelectedSkillCategory(ownedSkillCategories, selectedSkillCategory) {
let defaultSelectedCategory = "None";
if (Object.keys(ownedSkillCategories).includes(selectedSkillCategory)) {
let skillC = ownedSkillCategories.find(it => it.name.toLowerCase() == selectedSkillCategory.toLowerCase());
if (skillC) {
return (selectedSkillCategory);
} else {
return (defaultSelectedCategory);
@ -95,18 +96,14 @@ export default class RMSSSkillSheet extends ItemSheet {
// Iterate through the owned skill categories and if one of them matches the item id of currently
// selected skill category then set the Skill Category Bonus field to the Total Bonus field of the Skill Category
prepareSelectedSkillCategoryBonus(selected_skillcat) {
if (this.item.isEmbedded === null) {
console.log("Skill has no owner");
}
else {
const items = this.object.parent.items;
for (const item of items) {
if (item.type === "skill_category" && item._id === selected_skillcat) {
console.log(`rmss | rmss_skill_sheet | Calculating Skill Category bonus for skill: ${this.object.name}`);
this.object.system.category_bonus = item.system.total_bonus;
}
let skillC = this.parent?.items || RFRPUtility.getSkillCategories();
if (skillC) {
let item = skillC.find(it => it.type == "skill_category" && it.name.toLowerCase() == itemData.system.category.toLowerCase());
if (item) {
this.system.category_bonus = item.system.total_bonus;
return
}
}
ui.notifications.warn("No Skill Categories found for " + this.name + ". Please create and link a Skill Category.");
}
}

Binary file not shown.

Binary file not shown.

View File

@ -1 +1 @@
MANIFEST-000010
MANIFEST-000137

View File

@ -1,8 +1,15 @@
2024/07/26-14:23:44.308792 7f70f96006c0 Recovering log #8
2024/07/26-14:23:44.319859 7f70f96006c0 Delete type=3 #6
2024/07/26-14:23:44.320012 7f70f96006c0 Delete type=0 #8
2024/07/26-18:27:58.297420 7f70f3e006c0 Level-0 table #13: started
2024/07/26-18:27:58.297474 7f70f3e006c0 Level-0 table #13: 0 bytes OK
2024/07/26-18:27:58.371139 7f70f3e006c0 Delete type=0 #11
2024/07/26-18:27:58.497430 7f70f3e006c0 Manual compaction at level-0 from '!items!1HevhbCbvMonyQXe' @ 72057594037927935 : 1 .. '!items!yRIFroc5VC9Oj3qY' @ 0 : 0; will stop at (end)
2024/07/26-18:27:58.497486 7f70f3e006c0 Manual compaction at level-1 from '!items!1HevhbCbvMonyQXe' @ 72057594037927935 : 1 .. '!items!yRIFroc5VC9Oj3qY' @ 0 : 0; will stop at (end)
2024/08/10-08:47:18.899008 7f9286a006c0 Recovering log #135
2024/08/10-08:47:18.967334 7f9286a006c0 Delete type=3 #133
2024/08/10-08:47:18.967424 7f9286a006c0 Delete type=0 #135
2024/08/10-09:47:32.985517 7f9285a006c0 Level-0 table #140: started
2024/08/10-09:47:32.989699 7f9285a006c0 Level-0 table #140: 25092 bytes OK
2024/08/10-09:47:32.997934 7f9285a006c0 Delete type=0 #138
2024/08/10-09:47:33.008747 7f9285a006c0 Manual compaction at level-0 from '!items!1HevhbCbvMonyQXe' @ 72057594037927935 : 1 .. '!items!yRIFroc5VC9Oj3qY' @ 0 : 0; will stop at (end)
2024/08/10-09:47:33.020954 7f9285a006c0 Manual compaction at level-1 from '!items!1HevhbCbvMonyQXe' @ 72057594037927935 : 1 .. '!items!yRIFroc5VC9Oj3qY' @ 0 : 0; will stop at '!items!yRIFroc5VC9Oj3qY' @ 192 : 1
2024/08/10-09:47:33.020989 7f9285a006c0 Compacting 1@1 + 1@2 files
2024/08/10-09:47:33.025637 7f9285a006c0 Generated table #141@1: 57 keys, 26383 bytes
2024/08/10-09:47:33.025675 7f9285a006c0 Compacted 1@1 + 1@2 files => 26383 bytes
2024/08/10-09:47:33.032592 7f9285a006c0 compacted to: files[ 0 0 1 0 0 0 0 ]
2024/08/10-09:47:33.032827 7f9285a006c0 Delete type=2 #80
2024/08/10-09:47:33.033191 7f9285a006c0 Delete type=2 #140
2024/08/10-09:47:33.050945 7f9285a006c0 Manual compaction at level-1 from '!items!yRIFroc5VC9Oj3qY' @ 192 : 1 .. '!items!yRIFroc5VC9Oj3qY' @ 0 : 0; will stop at (end)

View File

@ -1,8 +1,8 @@
2024/07/26-13:01:33.184951 7f70fa0006c0 Recovering log #4
2024/07/26-13:01:33.276590 7f70fa0006c0 Delete type=0 #4
2024/07/26-13:01:33.276711 7f70fa0006c0 Delete type=3 #2
2024/07/26-14:15:40.712242 7f70f3e006c0 Level-0 table #9: started
2024/07/26-14:15:40.712297 7f70f3e006c0 Level-0 table #9: 0 bytes OK
2024/07/26-14:15:40.750893 7f70f3e006c0 Delete type=0 #7
2024/07/26-14:15:40.806643 7f70f3e006c0 Manual compaction at level-0 from '!items!1HevhbCbvMonyQXe' @ 72057594037927935 : 1 .. '!items!yRIFroc5VC9Oj3qY' @ 0 : 0; will stop at (end)
2024/07/26-14:15:40.863267 7f70f3e006c0 Manual compaction at level-1 from '!items!1HevhbCbvMonyQXe' @ 72057594037927935 : 1 .. '!items!yRIFroc5VC9Oj3qY' @ 0 : 0; will stop at (end)
2024/08/10-00:31:40.615380 7f9287e006c0 Recovering log #131
2024/08/10-00:31:40.668948 7f9287e006c0 Delete type=3 #129
2024/08/10-00:31:40.669000 7f9287e006c0 Delete type=0 #131
2024/08/10-08:46:35.462850 7f9285a006c0 Level-0 table #136: started
2024/08/10-08:46:35.462903 7f9285a006c0 Level-0 table #136: 0 bytes OK
2024/08/10-08:46:35.469319 7f9285a006c0 Delete type=0 #134
2024/08/10-08:46:35.492643 7f9285a006c0 Manual compaction at level-0 from '!items!1HevhbCbvMonyQXe' @ 72057594037927935 : 1 .. '!items!yRIFroc5VC9Oj3qY' @ 0 : 0; will stop at (end)
2024/08/10-08:46:35.510777 7f9285a006c0 Manual compaction at level-1 from '!items!1HevhbCbvMonyQXe' @ 72057594037927935 : 1 .. '!items!yRIFroc5VC9Oj3qY' @ 0 : 0; will stop at (end)

Binary file not shown.

Binary file not shown.

View File

View File

@ -0,0 +1 @@
MANIFEST-000010

0
packs/skills-merp/LOCK Normal file
View File

8
packs/skills-merp/LOG Normal file
View File

@ -0,0 +1,8 @@
2024/08/10-00:18:04.261355 7f92874006c0 Recovering log #8
2024/08/10-00:18:04.271365 7f92874006c0 Delete type=3 #6
2024/08/10-00:18:04.271415 7f92874006c0 Delete type=0 #8
2024/08/10-00:18:22.906854 7f9285a006c0 Level-0 table #13: started
2024/08/10-00:18:22.906926 7f9285a006c0 Level-0 table #13: 0 bytes OK
2024/08/10-00:18:22.913782 7f9285a006c0 Delete type=0 #11
2024/08/10-00:18:22.934544 7f9285a006c0 Manual compaction at level-0 from '!items!5Sg9t8YQubtRoghF' @ 72057594037927935 : 1 .. '!items!zvdsAxlRZnL6gqms' @ 0 : 0; will stop at (end)
2024/08/10-00:18:22.934626 7f9285a006c0 Manual compaction at level-1 from '!items!5Sg9t8YQubtRoghF' @ 72057594037927935 : 1 .. '!items!zvdsAxlRZnL6gqms' @ 0 : 0; will stop at (end)

View File

@ -0,0 +1,8 @@
2024/08/10-00:16:16.693967 7f92874006c0 Recovering log #4
2024/08/10-00:16:16.704014 7f92874006c0 Delete type=3 #2
2024/08/10-00:16:16.704134 7f92874006c0 Delete type=0 #4
2024/08/10-00:17:37.874387 7f9285a006c0 Level-0 table #9: started
2024/08/10-00:17:37.874475 7f9285a006c0 Level-0 table #9: 0 bytes OK
2024/08/10-00:17:37.881498 7f9285a006c0 Delete type=0 #7
2024/08/10-00:17:37.894547 7f9285a006c0 Manual compaction at level-0 from '!items!5Sg9t8YQubtRoghF' @ 72057594037927935 : 1 .. '!items!zvdsAxlRZnL6gqms' @ 0 : 0; will stop at (end)
2024/08/10-00:17:37.894586 7f9285a006c0 Manual compaction at level-1 from '!items!5Sg9t8YQubtRoghF' @ 72057594037927935 : 1 .. '!items!zvdsAxlRZnL6gqms' @ 0 : 0; will stop at (end)

Binary file not shown.

Binary file not shown.

View File

View File

@ -0,0 +1 @@
MANIFEST-000010

0
packs/skills-rmfrp/LOCK Normal file
View File

8
packs/skills-rmfrp/LOG Normal file
View File

@ -0,0 +1,8 @@
2024/08/10-00:18:04.273721 7f928cc006c0 Recovering log #8
2024/08/10-00:18:04.284604 7f928cc006c0 Delete type=3 #6
2024/08/10-00:18:04.284657 7f928cc006c0 Delete type=0 #8
2024/08/10-00:18:22.934766 7f9285a006c0 Level-0 table #13: started
2024/08/10-00:18:22.934803 7f9285a006c0 Level-0 table #13: 0 bytes OK
2024/08/10-00:18:22.944819 7f9285a006c0 Delete type=0 #11
2024/08/10-00:18:22.973938 7f9285a006c0 Manual compaction at level-0 from '!items!03BgTdeYE7TYk9LN' @ 72057594037927935 : 1 .. '!items!zYdJP3YQjsK9c3kh' @ 0 : 0; will stop at (end)
2024/08/10-00:18:22.973982 7f9285a006c0 Manual compaction at level-1 from '!items!03BgTdeYE7TYk9LN' @ 72057594037927935 : 1 .. '!items!zYdJP3YQjsK9c3kh' @ 0 : 0; will stop at (end)

View File

@ -0,0 +1,8 @@
2024/08/10-00:16:16.707097 7f9287e006c0 Recovering log #4
2024/08/10-00:16:16.718136 7f9287e006c0 Delete type=3 #2
2024/08/10-00:16:16.718187 7f9287e006c0 Delete type=0 #4
2024/08/10-00:17:37.881615 7f9285a006c0 Level-0 table #9: started
2024/08/10-00:17:37.881641 7f9285a006c0 Level-0 table #9: 0 bytes OK
2024/08/10-00:17:37.888187 7f9285a006c0 Delete type=0 #7
2024/08/10-00:17:37.894563 7f9285a006c0 Manual compaction at level-0 from '!items!03BgTdeYE7TYk9LN' @ 72057594037927935 : 1 .. '!items!zYdJP3YQjsK9c3kh' @ 0 : 0; will stop at (end)
2024/08/10-00:17:37.894604 7f9285a006c0 Manual compaction at level-1 from '!items!03BgTdeYE7TYk9LN' @ 72057594037927935 : 1 .. '!items!zYdJP3YQjsK9c3kh' @ 0 : 0; will stop at (end)

Binary file not shown.

0
packs/skills/000045.log Normal file
View File

BIN
packs/skills/000047.ldb Normal file

Binary file not shown.

1
packs/skills/CURRENT Normal file
View File

@ -0,0 +1 @@
MANIFEST-000043

0
packs/skills/LOCK Normal file
View File

15
packs/skills/LOG Normal file
View File

@ -0,0 +1,15 @@
2024/08/10-08:47:18.971370 7f928cc006c0 Recovering log #41
2024/08/10-08:47:19.065211 7f928cc006c0 Delete type=3 #39
2024/08/10-08:47:19.065338 7f928cc006c0 Delete type=0 #41
2024/08/10-09:47:33.068934 7f9285a006c0 Level-0 table #46: started
2024/08/10-09:47:33.075322 7f9285a006c0 Level-0 table #46: 140828 bytes OK
2024/08/10-09:47:33.081650 7f9285a006c0 Delete type=0 #44
2024/08/10-09:47:33.090270 7f9285a006c0 Manual compaction at level-0 from '!folders!Lr9SCthdWWHecwEI' @ 72057594037927935 : 1 .. '!items!zvdsAxlRZnL6gqms' @ 0 : 0; will stop at (end)
2024/08/10-09:47:33.097522 7f9285a006c0 Manual compaction at level-1 from '!folders!Lr9SCthdWWHecwEI' @ 72057594037927935 : 1 .. '!items!zvdsAxlRZnL6gqms' @ 0 : 0; will stop at '!items!zYdJP3YQjsK9c3kh' @ 574 : 1
2024/08/10-09:47:33.097537 7f9285a006c0 Compacting 1@1 + 1@2 files
2024/08/10-09:47:33.105028 7f9285a006c0 Generated table #47@1: 260 keys, 146683 bytes
2024/08/10-09:47:33.105065 7f9285a006c0 Compacted 1@1 + 1@2 files => 146683 bytes
2024/08/10-09:47:33.111688 7f9285a006c0 compacted to: files[ 0 0 1 0 0 0 0 ]
2024/08/10-09:47:33.111910 7f9285a006c0 Delete type=2 #10
2024/08/10-09:47:33.112302 7f9285a006c0 Delete type=2 #46
2024/08/10-09:47:33.126561 7f9285a006c0 Manual compaction at level-1 from '!items!zYdJP3YQjsK9c3kh' @ 574 : 1 .. '!items!zvdsAxlRZnL6gqms' @ 0 : 0; will stop at (end)

8
packs/skills/LOG.old Normal file
View File

@ -0,0 +1,8 @@
2024/08/10-00:31:40.672178 7f9286a006c0 Recovering log #37
2024/08/10-00:31:40.729626 7f9286a006c0 Delete type=3 #35
2024/08/10-00:31:40.729689 7f9286a006c0 Delete type=0 #37
2024/08/10-08:46:35.486154 7f9285a006c0 Level-0 table #42: started
2024/08/10-08:46:35.486208 7f9285a006c0 Level-0 table #42: 0 bytes OK
2024/08/10-08:46:35.492434 7f9285a006c0 Delete type=0 #40
2024/08/10-08:46:35.510744 7f9285a006c0 Manual compaction at level-0 from '!folders!Lr9SCthdWWHecwEI' @ 72057594037927935 : 1 .. '!items!zvdsAxlRZnL6gqms' @ 0 : 0; will stop at (end)
2024/08/10-08:46:35.510832 7f9285a006c0 Manual compaction at level-1 from '!folders!Lr9SCthdWWHecwEI' @ 72057594037927935 : 1 .. '!items!zvdsAxlRZnL6gqms' @ 0 : 0; will stop at (end)

Binary file not shown.

View File

@ -41,6 +41,10 @@
border-bottom: 1px solid;
background-image: linear-gradient(rgba(0, 0, 0, 0.1) 0 0);
}
.skill-box {
margin-left: 1.2rem;
background-color: lightgrey;
}
.container {
display: flex;
}
@ -199,7 +203,6 @@
padding-bottom: 3px;
display: flex;
justify-content: flex-end;
flex-direction: column;
justify-content: center;
}
.skills-grid-container > div:nth-child(22n+1),
@ -221,7 +224,6 @@
padding-bottom: 3px;
display: flex;
justify-content: flex-end;
flex-direction: column;
justify-content: center;
background-image: linear-gradient(rgba(0, 0, 0, 0.1) 0 0);
}
@ -230,6 +232,10 @@
border-bottom: 1px solid;
background-image: linear-gradient(rgba(0, 0, 0, 0.1) 0 0);
}
.skills-name-left-align {
text-align: left;
padding-left: 2px;
}
.money-column {
flex-direction: column;
}
@ -492,6 +498,9 @@
font-size: 12px;
text-align: center;
}
.select-fixed-width {
width: 100px;
}
.applicable-stats-grid-container {
display: grid;
grid-template-columns: [app-stat-1] 33% [app-stat-2] 33% [app-stat-3] 33%;
@ -522,8 +531,13 @@
}
.roll-button-container {
display: flex;
flex-direction: column;
justify-content: flex-end;
flex-direction: row;
justify-content: flex-start;
}
.roll-button {
margin-top: 2px;
width: 96px;
max-width: 96px;
}
.sheet form {
display: flex;

50
rmss.js
View File

@ -19,34 +19,7 @@ import RMSSSkillSheet from "./module/sheets/skills/rmss_skill_sheet.js";
import RMSSPlayerSheet from "./module/sheets/actors/rmss_player_sheet.js";
import RMSSToolsSCImporter from "./module/sheets/apps/rmss_import_skill_categories.js";
import RMSSToolsDiceRoller from "./module/sheets/apps/rmss_dice_roller.js";
/** Preload handlebars templates for character sheets */
async function preloadHandlebarsTemplates() {
const templatePaths = [
"systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-stats.html",
"systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-fixed-info.html",
"systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-armor-info.html",
"systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-resistance.html",
"systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-race-stat-fixed-info.html",
"systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-role-traits.html",
"systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-background-info.html",
"systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-skill-categories.html",
"systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-skills.html",
"systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-fav-skills.html",
"systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-items.html",
"systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-weapons.html",
"systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-money.html",
"systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-skill-categories.html",
"systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-skills.html",
"systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-armor.html",
"systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-herbs.html",
"systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-spells.html",
"systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-fav-spells.html",
"systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-fav-items.html",
"systems/fvtt-rolemaster-frp/templates/sheets/apps/app_skill_category_importer.html"
];
return loadTemplates(templatePaths);
}
import { RFRPUtility } from "./module/rfrp-utility.js";
// Register Scene Controls
// registerGetSceneControlButtonsHook();
@ -107,19 +80,14 @@ Hooks.once("init", function() {
// Actors
Actors.registerSheet("fvtt-rolemaster-frp", RMSSPlayerSheet, { makeDefault: true, label: "rmss.entity_sheet.player_characrer", types: ["character"] });
// Preload Handlebars Templates
console.log("rmss | Preloading Handlebars Templates");
preloadHandlebarsTemplates();
RFRPUtility.loadHandlebarsTemplates();
RFRPUtility.loadHandlebarsHelpers();
// Handlebars Helpers
Handlebars.registerHelper("switch", function(value, options) {
this.switch_value = value;
return options.fn(this);
});
Handlebars.registerHelper("case", function(value, options) {
if (value === this.switch_value) {
return options.fn(this);
}
});
});
Hooks.once("ready", async function () {
console.log("rmss | Ready");
// Load Utility
await RFRPUtility.ready();
})

View File

@ -3,7 +3,7 @@
"title": "Rolemaster FRP System",
"description": "The Rolemaster FRP system for FoundryVTT.",
"manifest": "https://www.uberwald.me/gitea/public/fvtt-rolemaster-frp/raw/branch/develop/system.json",
"download": "https://www.uberwald.me/gitea/public/fvtt-rolemaster-frp/archive/v12.0.1.zip",
"download": "https://www.uberwald.me/gitea/public/fvtt-rolemaster-frp/archive/v12.0.16.zip",
"authors": [
{
"name": "Cynicide",
@ -14,7 +14,7 @@
"email": ""
}
],
"version": "12.0.1",
"version": "12.0.16",
"compatibility": {
"minimum": "12",
"verified": "12"
@ -27,7 +27,14 @@
"name": "skill_categories",
"label": "Skill Categories",
"system": "fvtt-rolemaster-frp",
"path": "./packs/skill_categories.db",
"path": "./packs/skill_categories",
"type": "Item"
},
{
"name": "skill",
"label": "Skills",
"system": "fvtt-rolemaster-frp",
"path": "./packs/skills",
"type": "Item"
}
],

View File

@ -222,6 +222,14 @@
},
"character": {
"templates": ["background", "stats", "resistance_rolls", "armor_info", "fixed_info", "race_stat_fixed_info", "role_traits", "money", "description"],
"modifiers": {
"woundsModifier": 0
},
"state": {
"stunned": false,
"prone": false,
"noparry": false
},
"attributes": {
"level": {
"value": 1
@ -305,6 +313,7 @@
"skill": {
"templates": ["base"],
"category" : "",
"game_system": "common",
"ranks": 0,
"new_ranks": {
"value": 0,
@ -318,11 +327,13 @@
"special_bonus_2": 0,
"total_bonus": 0,
"favorite": false,
"bonus_progression": "standard",
"designation": "None"
},
"skill_category": {
"templates": ["base"],
"applicable_stats": "None",
"game_system": "common",
"app_stat_1": "None",
"app_stat_2": "None",
"app_stat_3": "None",
@ -339,6 +350,7 @@
"special_bonus_1": 0,
"special_bonus_2": 0,
"total_bonus": 0,
"bonus_progression": "standard",
"favorite": false
},
"spell": {

View File

@ -1,28 +1,70 @@
<div class="dice-roll">
<div class="dice-result">
Original Roll:
<h4 class="dice-total" >{{ baseroll.result }}</h4>
Rolling for : {{name}}
</div>
{{#if highopen }}
<div class=dice-result>
Rolled over 95 - High Open-Ended!
{{#each opeendedresults as |rollresult|}}
<h4 class="dice-total" >{{ rollresult }}</h4>
{{/each}}
</div>
{{/if}}
{{#if lowopen }}
<div class=dice-result>
Rolled under 6 - Low Open-Ended!
{{#each opeendedresults as |rollresult|}}
<h4 class="dice-total" >{{ rollresult }}</h4>
{{/each}}
</div>
{{/if}}
{{#if difficulty}}
<div class=dice-result>
Difficulty : {{difficulty}}
</div>
{{/if}}
{{#if combatSituation}}
<div class=dice-result>
Combat situation : {{combatSituation}}
</div>
{{/if}}
{{#if stunnedModifier}}
<div class=dice-result>
Stunned : {{stunnedModifier}}
</div>
{{/if}}
{{#if hitsPerRound}}
<div class=dice-result>
Hits/round malus : {{hitsPerRound}}
</div>
{{/if}}
{{#if lightningModifier}}
<div class=dice-result>
Lightning modifierLight : {{lightningModifier}}
</div>
{{/if}}
{{#if darknessModifier}}
<div class=dice-result>
Darkness modifierDark : {{darknessModifier}}
</div>
{{/if}}
{{#if woundsModifier}}
<div class="dice-result">
<div>% of hits malus : {{woundsModifier}}</div>
</div>
{{/if}}
<div class="dice-result">
Total of d100 rolls:
<h4 class="dice-total">{{totalRolls}}<br>
({{#each rolls as |roll|}}{{roll.total}}{{#unless @last}}, {{/unless}}{{/each}})</h4>
</div>
<div class=dice-result>
Character Bonus : {{characterBonus}}
</div>
<div class="dice-result">
Total :
<h4 class="dice-total" >{{ total }}</h4>
<h4 class="dice-total">{{totalFinal}}</h4>
</div>
</div>

View File

@ -15,8 +15,11 @@
<button type="button" class="import-skillcats" title="Import" acotr_id="">{{ localize "rmss.pc_sheet.import_skillcat" }}</button>
</div>
</div>
</div>
{{#each skillcat as |skill_category id|}}
<div>{{skill_category.name}}</div>
<div class="skillcat-grid-container">
<div><a class="item-roll" title="Roll Check" data-item-id="{{skill_category._id}}">{{skill_category.name}}</a> <i class="fas fa-dice"></i></div>
<div>{{skill_category.system.applicable_stats}}</div>
<div>{{skill_category.system.development_cost}}</div>
<div>{{skill_category.system.ranks}}</div>
@ -37,7 +40,13 @@
<div class="skillcat-icons">
<a class="item-edit" title="Edit Category" data-item-id="{{skill_category._id}}"><i class="fas fa-edit"></i></a>
<a class="item-delete item" title="Delete Category" data-item-id="{{skill_category._id}}"><i class="fas fa-trash"></i></a>
<a class="item-roll" title="Roll Check" data-item-id="{{skill_category._id}}"><i class="fas fa-dice"></i></a>
</div>
</div>
{{#if (count skill_category.skills)}}
<div class="skill-box">
{{> "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-skills.html" }}
</div>
{{/if}}
{{/each}}
</div>

View File

@ -10,16 +10,19 @@
<div class="skills-grid-heading">{{ localize "rmss.pc_sheet_skills.special_bonus" }}</div>
<div class="skills-grid-heading">{{ localize "rmss.pc_sheet_skills.total_bonus" }}</div>
<div class="skills-grid-heading">
<!--<a class="item-create" title="Create Skill" data-type="skill"><i class="fas fa-plus"></i>{{ localize "rmss.pc_sheet_skills.add_skill" }}</a>-->
<a class="item-create" title="Create Skill" data-type="skill"><i class="fas fa-plus"></i>{{ localize "rmss.pc_sheet_skills.add_skill" }}</a>
</div>
{{#each playerskill as |skill id|}}
</div>
{{#each skills as |skill id|}}
<div class="skills-grid-container">
{{#if skill.system.favorite}}
<div><a class="skill-favorite" data-item-id="{{skill._id}}"><i class="fa-regular fa-square-check"></i></a></div>
{{else}}
<div><a class="skill-favorite" data-item-id="{{skill._id}}"><i class="fa-regular fa-square"></i></a></div>
{{/if}}
<!--<div><input type="checkbox" name="system.favorite" {{checked skill.system.favorite}}/></div>-->
<div>{{skill.name}}</div>
<div class="skills-name-left-align"><a class="item-roll" title="Roll Check" data-item-id="{{skill._id}}">{{skill.name}}<i class="fas fa-dice"></i></a></div>
<div>{{skill.system.ranks}}</div>
<div>
{{#switch skill.system.new_ranks.value}}
@ -39,5 +42,6 @@
<a class="item-edit" title="Edit Skill" data-item-id="{{skill._id}}"><i class="fas fa-edit"></i></a>
<a class="item-delete" title="Delete Skill" data-item-id="{{skill._id}}"><i class="fas fa-trash"></i></a>
</div>
{{/each}}
</div>
{{/each}}

View File

@ -19,6 +19,7 @@
<div class="resource-entry">
{{ localize "rmss.player_character.resources.hits" }}
<h4><input name="system.attributes.hits.current" type="Number" value="{{system.attributes.hits.current}}"/>/<input name="system.attributes.hits.max" type="Number" value="{{system.attributes.hits.max}}"/></h4>
<div>Wounds Modifier : {{system.modifiers.woundsModifier}}</div>
</div>
<div class="resource-entry">
@ -70,9 +71,9 @@
{{!-- Default tab is specified in actor-sheet.mjs --}}
<a class="item" data-tab="Record">{{ localize "rmss.pc_sheet_tabs.record" }}</a>
<a class="item" data-tab="SkillCategory">{{ localize "rmss.pc_sheet_tabs.skill_categories" }}</a>
<a class="item" data-tab="Skills">{{ localize "rmss.pc_sheet_tabs.skills" }}</a>
<a class="item" data-tab="Equipment">{{ localize "rmss.pc_sheet_tabs.equipment" }}</a>
<a class="item" data-tab="Spells">{{ localize "rmss.pc_sheet_tabs.spells" }}</a>
<a class="item" data-tab="Background">{{ localize "rmss.pc_sheet_tabs.background" }}</a>
<a class="item" data-tab="StatusRecord">{{ localize "rmss.pc_sheet_tabs.status_record" }}</a>
<a class="item" data-tab="ExperiencePoints">{{ localize "rmss.pc_sheet_tabs.experience_points" }}</a>
</nav>
@ -84,14 +85,16 @@
{{> "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-fixed-info.html" }}
{{> "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-armor-info.html" }}
{{> "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-resistance.html" }}
{{> "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-race-stat-fixed-info.html" }}
{{> "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-role-traits.html" }}
{{> "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-background-info.html" }}
</div>
<div class="stat-container">
{{> "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-stats.html" }}
<div class="favorite-container">
<span class="label-name">Stunned : </span><input type="checkbox" name="system.state.stunned" {{checked system.state.stunned}}/>
<span class="label-name">Prone : </span><input type="checkbox" name="system.state.prone" {{checked system.state.prone}}/>
</div>
<div class="favorite-container">
<h2>Favorite Skills</h2>
{{> "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-fav-skills.html" }}
@ -103,8 +106,6 @@
{{editor enrichedDescription target="system.description" button=true owner=owner editable=editable}}
</div>
</div>
</div>
</div>
@ -112,10 +113,6 @@
{{> "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-skill-categories.html" }}
</div>
<div class="tab skills" data-group="primary" data-tab="Skills">
{{> "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-skills.html" }}
</div>
<div class="tab equipment" data-group="primary" data-tab="Equipment">
<div class="container">
<div class="equipment-container">
@ -140,6 +137,19 @@
{{> "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-spells.html" }}
</div>
</div>
<div class="tab background" data-group="primary" data-tab="Background">
<div class="container">
<div class="fixed-info-container">
{{> "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-race-stat-fixed-info.html" }}
</div>
<div class="fixed-info-container">
{{> "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-role-traits.html" }}
{{> "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-background-info.html" }}
</div>
</div>
</div>
</section>
</form>

View File

@ -2,26 +2,95 @@
<div class="dice-roller-container">
<div class="dice-roller-options">
<div class="dice-roller-item">
<div>Rolling for:</div><div>{{itemName}}</div>
<div>Rolling for:</div>
<div>{{itemName}}</div>
</div>
<div class="dice-roller-item">
<div>Character Bonus:</div><div>{{characterBonus}}</div>
<div>Character Bonus:</div>
<div>{{characterBonus}}</div>
</div>
<div class="dice-roller-item">
<div>Misc Bonus:</div><div><input name="miscBonus" value="0" /></div>
</div>
<div class="dice-roller-item">
<div>Select Roll Type:</div>
<div>Difficulty:</div>
<div>
<select name="rollType" value="None" itemid="blah">
{{#each selectOptions as |option|}}
<option value="{{option.value}}" {{#if option.selected}}selected{{/if}}>{{option.text}}</option>
{{/each}}
<select name="difficulty">
{{selectOptions config.difficulties selected="0" valueKey="value" labelKey="label"}}
</select>
</div>
</div>
<div class="dice-roller-item">
<div>% of hits taken malus:</div>
<div>{{woundsModifier}}</div>
</div>
{{#if isStunned}}
<div class="dice-roller-item">
<div>Stunned:</div>
<div>{{stunnedModifier}}</div>
</div>
{{/if}}
<div class="dice-roller-item">
<div>Combat situations:</div>
<div>
<select name="combatSituation">
{{#select combatSituation}}
{{#each config.combatSituations as |situation|}}
<option value="{{situation.modifier}}">{{situation.label}}</option>
{{/each}}
{{/select}}
</select>
</div>
</div>
<div class="dice-roller-item">
<div>Hits/round taken:</div>
<div>
<select name="hitsPerRound">
{{#select hitsPerRound}}
{{#each config.hitsPerRound as |hit|}}
<option value="{{hit.modifier}}">{{hit.label}}</option>
{{/each}}
{{/select}}
</select>
</div>
</div>
<div class="dice-roller-item">
<div>Lightning, if required:</div>
<div>
<select name="lightningModifier">
{{#select lightningModifier}}
{{#each config.lightOrDarknessModifiers as |lightning|}}
<option value="{{lightning.modifierLight}}">{{lightning.label}}</option>
{{/each}}
{{/select}}
</select>
</div>
</div>
<div class="dice-roller-item">
<div>Darkness, if advantageous:</div>
<div>
<select name="darknessModifier">
{{#select lightningModifier}}
{{#each config.lightOrDarknessModifiers as |darkness|}}
<option value="{{darkness.modifierDark}}">{{darkness.label}}</option>
{{/each}}
{{/select}}
</select>
</div>
</div>
<div class="dice-roller-item">
<div>Misc Bonus:</div>
<div><input name="miscBonus" value="0" /></div>
</div>
<div class="roll-button-container">
<button type="submit">Roll</button>
{{#each selectOptions as |option|}}
<button type="submit" class="roll-button" data-value="{{option.value}}">{{option.text}}</button>
{{/each}}
</div>
</div>
</div>
</form>

View File

@ -1,16 +1,27 @@
<form>
<div>
<h3>Import Skill Categories</h3>
<h3>Import Skill Categories/Skills</h3>
<div>
WARNING: This will erase your existing Skill Categories and import all Skill Categories from the selected Compendium.
<span>
WARNING: This will erase your existing Skill Categories or Skills and import all Skill Categories/Skills from the selected Compendium.
Note that the import will select only skills and categories matching the "Common" items and the selected game system.
</span>
</div>
<div>
Select Compendium:
<select name="selectOptions" class="compendium-selector" value="None" itemid="blah">
<div class="flexrow">
<span >Select Skill Categories Compendium:</span>
<select name="selectOptionsCategories" class="compendium-selector" value="None" itemid="blah">
{{selectOptions selectOptions}}
</select></div>
<div>
<button class="import-skillcats" title="Import">Import</button>
</select>
<button class="import-skillcats" value="skill_category" name="skill_category" title="Import">Import Skill Categories</button>
</div>
<div class="flexrow">
<span>Select Skills Compendium:</span>
<select name="selectOptionsSkills" class="compendium-selector" value="None" itemid="blah">
{{selectOptions selectOptions}}
</select>
<button class="import-skills" value="skill" name="skill" title="Import">Import Skills</button>
</div>
</div>

View File

@ -4,6 +4,18 @@
<h1><input name="name" type="text" value="{{item.name}}" placeholder="{{ localize 'Name' }}"/></h1>
</header>
<div class="sheet-content">
<div class="flexrow">
<div>Rank Bonus Progression
<select class="select-fixed-width" name="system.bonus_progression" value="{{system.bonus_progression}}" itemid="{{ item._id }}">
{{selectOptions config.rankBonusProgressionList selected=system.bonus_progression valueAttr="key" labelAttr="label"}}
</select>
</div>
<div>Game system
<select class="select-fixed-width" name="system.game_system" value="{{system.game_system}}" itemid="{{ item._id }}">
{{selectOptions config.gameSystems selected=system.game_system valueAttr="key" labelAttr="label"}}
</select>
</div>
</div>
<div class="applicable-stats-grid-container">
<div>
Applicable Stat 1

View File

@ -4,10 +4,22 @@
<h1><input name="name" type="text" value="{{item.name}}" placeholder="{{ localize 'Name' }}"/></h1>
</header>
<div class="sheet-content">
<div class="flexrow">
<div>Rank Bonus Progression
<select class="select-fixed-width" name="system.bonus_progression" value="{{system.bonus_progression}}" itemid="{{ item._id }}">
{{selectOptions config.rankBonusProgressionList selected=system.bonus_progression valueAttr="key" labelAttr="label"}}
</select>
</div>
<div>Game system
<select class="select-fixed-width" name="system.game_system" value="{{system.game_system}}" itemid="{{ item._id }}">
{{selectOptions config.gameSystems selected=system.game_system valueAttr="key" labelAttr="label"}}
</select>
</div>
</div>
<div>
Skill Category
<select name="system.category" class="app-stat-selector" value="{{system.category}}" itemid="{{ item._id }}">
{{selectOptions owned_skillcats selected=selected_skillcat }}
<select name="system.category" class="app-stat-selector" value="{{system.category}}">
{{selectOptions owned_skillcats selected=selected_skillcat nameAttr="name" valueAttr="name" labelAttr="name"}}
</select>
</div>
<div>