Skip to content

Instantly share code, notes, and snippets.

@moshmage
Last active January 15, 2017 02:36
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save moshmage/5a895d86a7a6dd16444eb5025576106e to your computer and use it in GitHub Desktop.
Character Sheet for a RPG looselly based on FUDGE system
"use strict";
import {DiceTransformations} from './roll-transforms.js';
const Dice = new require('roll')();
const BASE_HEALTH = 10;
const BASE_SKILL_MODIFIER = 1.25;
const MINIMUM_SKILL_MODIFIER = 0.1;
const BASE_CRITICAL_FAILURE = -3;
const CRITICAL_DICES = 2;
const SERIOUS_FAILURE_DICES = 3;
const INITIAL_SKILL_POINTS = 3;
export function roll(dices = 0, transformations = []) {
return Dice.roll({
quantity: dices || 4,
sides: 6,
transformations: [ DiceTransformations.FUDGE, ...transformations, 'sum' ]
});
}
export class Sheet {
constructor() {
this.skills = { Fighting: 0, Physique: 0, Investigate: 0, Athletics: 0 };
this.points = { skill: INITIAL_SKILL_POINTS, fame: 0, karma: 0 };
this._health = { max: BASE_HEALTH, actual: BASE_HEALTH };
}
_skillExists(skill) {
return Object.keys(this.skills).indexOf(skill) > -1;
}
_modifySkill(skill = "", input = +1) {
if (!skill || !this._skillExists(skill)) throw Error('Skill does not exist');
if (typeof input !== "number") throw Error("input must be number");
if (this.points.skill < input || !this.points.skill) return this.skills[skill];
this.points.skill -= input;
return this.skills[skill] += input;
}
_rollAthletics() {
// 4df + Athletics
return roll(4, [['add', this.Athletics]]);
}
_rollStrength(dice, critical) {
// 4df + Fighting + 2df?
return roll(4, [['add', this.skills.Fighting], critical]);
}
_roll(attack = false) {
let dice = {roll: roll().result, strength: 0, selfDamage: 0, movement: 0};
let critical = ['add', 0];
dice.movement = this._rollAthletics().result;
if (dice.roll === 4) critical = ['add', roll(CRITICAL_DICES, [DiceTransformations.OnlyPositiveNumbers]).result];
if (!attack) {
dice.strength = this._rollStrength(critical).result;
} else {
if (dice.roll > BASE_CRITICAL_FAILURE) {
dice.strength = this._rollStrength(dice, critical).result;
} else {
let criticalFailureDices = (dice.roll === -4) ? SERIOUS_FAILURE_DICES : CRITICAL_DICES;
dice.selfDamage = roll(criticalFailureDices, [DiceTransformations.OnlyPositiveNumbers]).result;
}
}
return dice;
}
decreaseSkillLevel(skill = "", modifier) { return this._modifySkill(skill, modifier || -1); }
icreaseSkillLevel(skill = "", modifier) { return this._modifySkill(skill, modifier || +1); }
rollAttack() { return this._roll(true); }
rollDefense() { return this._roll(false); }
changeHealth(modifier = +0) { return this._health.actual += modifier; }
setMaxHealth() {
// ( ( ( ((Fighting+0.1) * 1.25) * ((Athletics+0.1) * 1.25) ) + 10 ) * Physique )
return this._health.max = Math.floor((((((this.skills.Fighting + MINIMUM_SKILL_MODIFIER) * BASE_SKILL_MODIFIER) * ((this.skills.Athletics + MINIMUM_SKILL_MODIFIER) * BASE_SKILL_MODIFIER)) + BASE_HEALTH) * this.skills.Physique));
}
resetSkills() {
let totalSkillPoints = Object.values(this.skills).reduce((a, b) => a + b);
this.points += totalSkillPoints;
this.skills = { Fighting: 0, Physique: 1, Investigate: 0, Athletics: 0 };
this._health.actual = this.setMaxHealth();
}
get health() {
return Math.floor((this._health.actual / this._health.max) * 100);
}
}
export const DiceTransformations = {
FUDGE(results) {
return results.map(result => {
if (result === 1 || result === 2) return -1;
if (result === 3 || result === 4) return 0;
if (result === 5 || result === 6) return 1;
});
},
OnlyPositiveNumbers(results) {
return results.filter(result => result > 0);
}
};

Character Sheet for a RPG looselly based on FUDGE system

Usage

let player = new Sheet();
player.increaseSkillLevel('Fighting'); // value of player.skills.Fighting is now 1
player._modifySkill('Physique', +3); // player.skills.Physique = 3
player.setHealth(); // set max health after changing Physique
console.log(player.rollAttack()); // {4df, movement, strength, selfDamage?}
console.log(player.rollDefense()); // {4df, movement, strength}
player.changeHealth(-1);

What dis?

This Sheet class is a helper for character sheets. It tracks, and changes, health and skills as well as giving you the ability to make (heavily opionated) attack and defense rolls for the player.

It's made public purely because there's so little of these examples around.

Notes:

Investigation is not implemented as it's a skill that interacts with "the game" and not "the player"
As per FUDGE system, character leveling experience does not exist - skills are awarded levels based on stuff (books, training, etc)
Health does not follow FUDGE standarts (it can*), instead it uses a formula with each skill (focusing on Physique, ignoring Investigation)
Attacking and Defending is not implemented, though the results of the rollAttack and rollDefense are pretty close.

formulas:

  • Health: ( ( ( ((Fighting+0.1) * 1.25) * ((Athletics+0.1) * 1.25) ) + 10 ) * Physique )
  • Strength: 4df + Fighting + 2df?
  • Movement/Agility: 4df + Athletics

The Works

Attacking

(Sheet.rollAttack()) Roll 4dF to hit/miss/critical/crit-fail. Results:

  • -4 = crit-fail (self damage with the positive results of 3dF)
  • -3 = fail (self damage with the positive results of 2dF)
  • -3 = might hit, depending on the defense roll

  • 4 = critical hit, check the ahead (but you can go ahead and roll 2dF)

Roll for 4dF + Athletics to match agains the Athletic roll of target (> -3 condition)

Roll 4dF, add Fighting skill and add the positive result of the critical hit roll

Defending

(Sheet.rollDefense()) Roll for movement (Athletics)
Roll for Strength

Results

Results:

  • if Attacker rolled a critical-/fail apply dice.selfDamage to player;
  • if Attacker dice.movement is bigger than defender dice.movement, then the defender takes attacker.dice.strength - defender.dice.strength
  • Otherwise a miss happens

FUDGE Health*

You can use fudge health by calling Sheet.health as it will return the current player health in percentage form; Just correlate that with a "100 = Healthy", "90 = Hurt", etc..

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment