Skip to content

About

Rolemaster Standard System for FoundryVTT

Resources

Stars

2 stars

Watchers

2 watching

Forks

Latest commit

 

History

808 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Rolemaster Standard System (RMSS) for Foundry VTT

System for playing Rolemaster Standard System in Foundry Virtual Tabletop. Based on the original repository by Cynicide.

Requirements

  • Foundry VTT v13+
  • socketlib (required module)

Installation

  1. Install socketlib from the module directory.
  2. Install RMSS as a system from the manifest URL or by copying the folder to Data/systems/rmss.

Features

Characters and actors

  • Character sheet (PC): stats, armor, weapons, skills, spells, inventory, experience.
  • NPC sheet and creature sheet with attacks and attack tables.
  • Races and professions as draggable items.
  • Level-up system with skill development.

Skills

  • Skill categories with configurable progression.
  • Skills with ranks, category bonus, and designations (Occupational, Everyman, Restricted).
  • Skill maneuvers with Static Maneuver table and unified penalties (hits taken, bleeding, stunned, wounds).

Spells

  • Spell lists (open, closed, base) organized by realm (Essence, Channeling, Mentalism and Arcane).
  • Force (F): Basic Spell Attack Table, RR per target, chat with targets and RR to beat.
  • Base Elemental (BE): attack tables (bola, fire_ball, fire_bolt, etc.), attack confirmation to GM.
  • Directed Elemental (DE): bolt tables, directed spell skill, flow similar to BE.
  • Static Maneuver (E, P, U, I): static maneuver table.
  • Casting options (hands, voice, preparation) and automatic penalties.
  • Spell failure table on fumbles.
  • Manual fumbles: the RMSS Effects popup (token HUD skull button) has a Fumble tab, open to every user, to roll a weapon fumble (pick one of the character's weapons or a weapon type) or a spell failure (spell family, severity, casting modifiers) on purpose, rolling the dice or typing the result. The card goes to the chat.
  • Per-spell macros with access to spellContext (RR and targets) for Force spells.

Combat

  • Attack tables by weapon (melee, missile, bolt, ball).
  • Critical resolution (slash, krush, puncture, heat, cold, electricity, etc.).
  • Weapon Slaying property (multi-tag, e.g. "orc slayer"): when a weapon's Slaying tag(s) match a target npc/creature's Creature tags, the critical confirmation dialog auto-selects the Superlarge critical table and the Slaying column — regardless of the target's own Critical Table setting (Normal/Large/Superlarge).
  • Automatic effects: Stunned, Bleeding, Penalty.
  • Attack confirmation to GM (socket) for player attacks.
  • Parry: a combatant reserves part of their OB to parry (combat tracker button, or game.rmss.openParryDialog(actor)), always 1 OB = 1 DB. One-handed weapons can reserve up to 100 % of the OB; two-handed and pole weapons up to 50 %; creature attacks have their own limit (100 or 50 %); being Stunned caps it at 50 % too (the caps don't stack). The reserved OB comes off the combatant's attacks, and the defense is added automatically to the one frontal melee attack they suffer next (never missiles, thrown weapons or spells). The reservation is a standing stance: it keeps costing that OB every round and is re-armed when the combatant's turn starts, until they change or release it (a player can't lower or release it until they have attacked once with it on; the GM always can). So nobody forgets it, the owner gets a whispered card with a "Change or release" button when their turn starts, and the token carries a "Parry +N" shield icon (dimmed once the defense is spent). A "must parry" critical (P with rounds and an optional value) creates its own "Parry" effect: while any is active the victim must keep at least half their OB reserved (house rule: the manual only asks for 1 point, which makes the effect meaningless; it can't be released), and the values add up as a penalty on all their attacks; each effect expires on its own.
  • Parry safety switch (system setting "Parry rules"): Automatic (default), Manual (the reservation, tracker badge, token icon and cards work as a record, but the attack dialog is not pre-filled and "must parry" criticals force nothing and add no penalty) or Off (no parry features, and shields count regardless of facing, as before).
  • Shield: its DB bonus only counts against frontal attacks; the attack confirmation takes it out of the defender's DB for flank and rear attacks (and follows the facing selector live).
  • Initiative and combat tracker.
  • Movement in combat: each combatant spends their remaining Movement Rate as the token moves, using the route cost Foundry measures. Draw a Region with the Increase Movement Cost behavior (set the multiplier for walking) over rough terrain and only the stretches that cross it cost more: 15 ft of open ground plus 10 ft at x2 spends 35 ft. A move that costs more than what is left is refused; pushes, teleports and undoing a move cost nothing.

Items

  • Weapons, armor, transport, herbs/poisons.
  • Special ammunition (items tagged arrow/bolt/bullet): besides the attack bonus, ammo can carry an extra critical (e.g. fire arrows), Increased Critical, bleeding, and the magical/holy/unholy/slaying properties, applied to the shot made with it. If the ammo has a macro it replaces the bow's macro for that shot; either macro now runs once the shot is confirmed (and receives weapon, ammo, target and targets besides the usual variables).
  • Containers with capacity.
  • Currency system (mithril, platinum, gold, silver, etc.).

Other

  • Languages: English and Spanish.
  • Unit tests (Jest) with GitHub Actions pipeline.
  • Embedded macros in items with integrated editor.

Scripting API

game.rmss exposes a small API for macros and scene triggers to talk to the system without reaching into internal classes.

Traps and hazards

For traps and hazards driven by scene triggers (native Region Behavior "Execute Script", Monk's Active Tiles, a macro...), game.rmss exposes two functions that reuse the normal combat resolution (GM confirmation, chat cards, etc.) instead of duplicating it:

  • game.rmss.triggerTrapAttack(trapActorId, target, weaponItemId?) — full attack: rolls on the attack table and resolves the critical as usual (Slaying included). trapActorId is a hidden npc/creature actor representing the trap; its attack is whatever it has equipped (a weapon item) or, for a creature actor, its natural creature_attack (no equipped flag needed). target is the token that triggered the trap (a Token/TokenDocument, or its id as a string). Pass weaponItemId to pick a specific attack when the trap actor has more than one.

    // Region Behavior "Execute Script" (or Monk's Active Tiles), token = the token that entered
    await game.rmss.triggerTrapAttack("<trapActorId>", token);
  • game.rmss.triggerTrapCritical(target, { severity, critType, damage, modifier, trapActorId }) — fires a critical directly, with no attack roll: rolls 1d100 on the given critical table and applies it (hit points, chat card, effects), the same as the GM's manual "Effects" button on the token HUD. severity is a letter A–E, critType any code from CONFIG.rmss.criticalDictionary (S, K, P, U, G, T, heat, cold, ...). Does not support the large-creature subtypes (magic/mithril/holy/slaying) — use triggerTrapAttack for those.

    await game.rmss.triggerTrapCritical(token, { severity: "C", critType: "P", damage: 15 });

Both resolve the triggering token's actor and skip already-defeated targets; look up the token variable your trigger module provides (e.g. Monk's Active Tiles exposes it as token and inside args[0].token).

Macro helpers

General-purpose helpers meant for macros (hotbar buttons, item macros, etc.):

  • game.rmss.getActorSex(actor) — normalized sex ("male"/"female"/"other") for any actor type (character, npc, creature).

  • game.rmss.castSpellFromHotbar(actorId, itemId) — cast a spell from a hotbar macro (routes to the Force/BE/DE/instant service based on the spell, same as casting it from the character sheet). Use this instead of calling spell.use() directly so targeting context is set up correctly for Force spells.

    await game.rmss.castSpellFromHotbar(actor.id, "<spellItemId>");
  • game.rmss.createProfession(professionKey, options?) — create a profession item from the built-in profession data (options.openSheet to open its sheet after creating it). Returns the created Item, or null if professionKey isn't recognized.

    await game.rmss.createProfession("Cleric");
  • game.rmss.createProfessionDialog() — same as above, but shows a dialog to pick the profession first.

  • game.rmss.applySpellHealHits(options) — heal hit points on 1–maxTargets targeted tokens as GM (for healing-spell macros).

    await game.rmss.applySpellHealHits({ amountPerTarget: 20, maxTargets: 1 });
  • game.rmss.findAmmoStacksOnActor(actorId, ammoTag) — ammo item stacks on an actor matching a tag from CONFIG.rmss.ammunition_types (e.g. "arrow") with quantity > 0.

  • game.rmss.findAmmoStacksForWeapon(actorId, weaponItemId) — same, but resolved from a specific missile weapon's own system.ammoType instead of a tag you pick yourself.

  • game.rmss.rollResistance({ target, attackerLevel, defenderLevel?, modifier? }) — rolls a Resistance Roll against target (a Token/TokenDocument, or its id) and returns { success, finalRoll, rrTarget } immediately, so a spell/item macro can branch on the outcome. defenderLevel defaults to the target's own actor level if omitted. Posts the same RR result card to chat as the Token HUD's Effects popup.

    for (const target of Array.from(game.user.targets)) {
      const { success } = await game.rmss.rollResistance({
        target,
        attackerLevel: actor.system.attributes.level.value
      });
      if (success) { /* target resisted */ } else { /* effect takes hold */ }
    }
  • game.rmss.scheduleDelayedAction({ combat?, roundsFromNow?, atRound?, command, context? }) — schedules command (a JS code string, same as an item macro) to run automatically once combat reaches a future round — for spells with a casting delay (e.g. a 2-round summon: place a marker on round 1, the creature appears on its own when round 2 begins). Stored on the Combat document, so it survives a reload/disconnect and is cleaned up when the encounter ends. context is a plain-data object passed into command as the context argument; game/canvas/ui/etc. are available as usual globals. Returns the pending action's id — pass it to game.rmss.cancelDelayedAction(id) if the caster gets interrupted first.

    await game.rmss.scheduleDelayedAction({
      roundsFromNow: 1,
      context: { x: token.x, y: token.y, elementalActorId: "<id>" },
      command: `
        const elemental = game.actors.get(context.elementalActorId);
        const tokenDoc = await elemental.getTokenDocument({ x: context.x, y: context.y });
        await canvas.scene.createEmbeddedDocuments("Token", [tokenDoc.toObject()]);
      `
    });

Macros on combat events

The system can run a world macro when something happens in combat, without knowing anything about animations or modules. Set the macro's UUID (right-click the macro > Copy UUID) in the system settings; empty means nothing runs.

Event Setting When
Missed melee attack macroOnMeleeMiss A melee attack (not missile) deals no damage and no critical

The macro runs on the GM's client with actor, token (attacker), target (defender), targets, weapon and event. These names are function parameters, so don't redeclare them with const/let (use typeof target !== "undefined" to fall back to game.user.targets when the macro is also run by hand).

Development

npm install
npm test          # Run tests
npm run test:watch

Credits

About

Rolemaster Standard System for FoundryVTT

Resources

Stars

2 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages