init
This commit is contained in:
16
.codio
Normal file
16
.codio
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
// Configure your Run and Preview buttons here.
|
||||
|
||||
// Run button configuration
|
||||
"commands": {
|
||||
"Node version": "node --version"
|
||||
},
|
||||
|
||||
// Preview button configuration
|
||||
"preview": {
|
||||
"Project Index (static)": "https://{{domain}}/{{index}}",
|
||||
"Current File (static)": "https://{{domain}}/{{filepath}}",
|
||||
"Box URL": "http://{{domain}}:3000/",
|
||||
"Box URL SSL": "https://{{domain}}:9500/"
|
||||
}
|
||||
}
|
||||
26
.guides/sections.md
Normal file
26
.guides/sections.md
Normal file
@@ -0,0 +1,26 @@
|
||||
---
|
||||
title: Example section
|
||||
files: []
|
||||
editable: true
|
||||
layout: 2-panels-tree
|
||||
|
||||
---
|
||||
Some **awesome** content 1
|
||||
|
||||
---
|
||||
title: Example section 3
|
||||
files: []
|
||||
editable: true
|
||||
layout: ""
|
||||
|
||||
---
|
||||
Some **awesome** content 3
|
||||
|
||||
---
|
||||
title: Example section 4
|
||||
files: []
|
||||
editable: true
|
||||
layout: ""
|
||||
|
||||
---
|
||||
Some **awesome** content 4
|
||||
1
.guides/styles.css
Normal file
1
.guides/styles.css
Normal file
@@ -0,0 +1 @@
|
||||
/* Place you styles here */
|
||||
37
TODO.md
Normal file
37
TODO.md
Normal file
@@ -0,0 +1,37 @@
|
||||
Character.js is under construction... expect broken character sheets
|
||||
|
||||
issues
|
||||
------
|
||||
|
||||
* hot code pushes don't apply transforms correctly
|
||||
|
||||
Characters attributes and buffs
|
||||
-------------------------------
|
||||
|
||||
Characters currently have attributes and skills that can take bonuses and multipliers.
|
||||
When a feature is activated or enabled on a characer or a piece of equipment is equipped
|
||||
the buffs and effects should be applied to the correct attribute or skill. When the
|
||||
equipment or feature is removed or deactivated, the effects should be removed as well.
|
||||
|
||||
Effects need the following data as a bare minimum:
|
||||
|
||||
* attribute or skill to effect
|
||||
* name
|
||||
* value
|
||||
|
||||
For example, plate would be an object like this:
|
||||
|
||||
{
|
||||
name: "Plate Armor" ,
|
||||
effects: [
|
||||
{stat: "skills.dexArmor.min", value: 0},
|
||||
{stat: "skills.dexArmor.max", value: 0},
|
||||
{stat: "attributes.armor.min", value: 18},
|
||||
{stat: "skills.stealth.disadvantage", value 1} //disadvantage doesn't need a value
|
||||
]
|
||||
}
|
||||
|
||||
See Conditions for this implemented.
|
||||
|
||||
The effects ultimately need to be pushed to the correct array when applied: `attributes.armor.min.push({name: "Plate Armor", type: "Equpiment", value: 18})`
|
||||
They will also need to be removed correctly by the thing that applied them, or after some time.
|
||||
6
rpg-docs/.meteor/.finished-upgraders
Normal file
6
rpg-docs/.meteor/.finished-upgraders
Normal file
@@ -0,0 +1,6 @@
|
||||
# This file contains information which helps Meteor properly upgrade your
|
||||
# app when you run 'meteor update'. You should check it into version control
|
||||
# with your project.
|
||||
|
||||
notices-for-0.9.0
|
||||
notices-for-0.9.1
|
||||
1
rpg-docs/.meteor/.gitignore
vendored
Normal file
1
rpg-docs/.meteor/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
local
|
||||
7
rpg-docs/.meteor/.id
Normal file
7
rpg-docs/.meteor/.id
Normal file
@@ -0,0 +1,7 @@
|
||||
# This file contains a token that is unique to your project.
|
||||
# Check it into your repository along with the rest of this directory.
|
||||
# It can be used for purposes such as:
|
||||
# - ensuring you don't accidentally deploy one app on top of another
|
||||
# - providing package authors with aggregated statistics
|
||||
|
||||
1xg0ir21aq4e081rfkzg3
|
||||
1
rpg-docs/.meteor/cordova-plugins
Normal file
1
rpg-docs/.meteor/cordova-plugins
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
13
rpg-docs/.meteor/packages
Normal file
13
rpg-docs/.meteor/packages
Normal file
@@ -0,0 +1,13 @@
|
||||
# Meteor packages used by this project, one per line.
|
||||
#
|
||||
# 'meteor add' and 'meteor remove' will edit this file for you,
|
||||
# but you can also edit it by hand.
|
||||
|
||||
meteor-platform
|
||||
autopublish
|
||||
insecure
|
||||
iron:router
|
||||
accounts-password
|
||||
accounts-ui
|
||||
random
|
||||
|
||||
1
rpg-docs/.meteor/release
Normal file
1
rpg-docs/.meteor/release
Normal file
@@ -0,0 +1 @@
|
||||
METEOR@0.9.2.2
|
||||
66
rpg-docs/.meteor/versions
Normal file
66
rpg-docs/.meteor/versions
Normal file
@@ -0,0 +1,66 @@
|
||||
accounts-base@1.1.0
|
||||
accounts-password@1.0.1
|
||||
accounts-ui-unstyled@1.1.1
|
||||
accounts-ui@1.1.0
|
||||
application-configuration@1.0.2
|
||||
autopublish@1.0.0
|
||||
autoupdate@1.1.0
|
||||
base64@1.0.0
|
||||
binary-heap@1.0.0
|
||||
blaze-tools@1.0.0
|
||||
blaze@2.0.0
|
||||
boilerplate-generator@1.0.0
|
||||
callback-hook@1.0.0
|
||||
check@1.0.0
|
||||
ctl-helper@1.0.3
|
||||
ctl@1.0.1
|
||||
ddp@1.0.8
|
||||
deps@1.0.3
|
||||
ejson@1.0.2
|
||||
email@1.0.2
|
||||
fastclick@1.0.0
|
||||
follower-livedata@1.0.1
|
||||
geojson-utils@1.0.0
|
||||
html-tools@1.0.0
|
||||
htmljs@1.0.1
|
||||
http@1.0.5
|
||||
id-map@1.0.0
|
||||
insecure@1.0.0
|
||||
iron:core@0.3.4
|
||||
iron:dynamic-template@0.4.1
|
||||
iron:layout@0.4.1
|
||||
iron:router@0.9.4
|
||||
jquery@1.0.0
|
||||
json@1.0.0
|
||||
less@1.0.8
|
||||
livedata@1.0.9
|
||||
localstorage@1.0.0
|
||||
logging@1.0.3
|
||||
meteor-platform@1.1.0
|
||||
meteor@1.1.0
|
||||
minifiers@1.1.0
|
||||
minimongo@1.0.3
|
||||
mobile-status-bar@1.0.0
|
||||
mongo@1.0.5
|
||||
npm-bcrypt@0.7.7
|
||||
observe-sequence@1.0.2
|
||||
ordered-dict@1.0.0
|
||||
random@1.0.0
|
||||
reactive-dict@1.0.2
|
||||
reactive-var@1.0.1
|
||||
reload@1.1.0
|
||||
retry@1.0.0
|
||||
routepolicy@1.0.1
|
||||
service-configuration@1.0.1
|
||||
session@1.0.1
|
||||
sha@1.0.0
|
||||
spacebars-compiler@1.0.2
|
||||
spacebars@1.0.1
|
||||
srp@1.0.0
|
||||
templating@1.0.6
|
||||
tracker@1.0.2
|
||||
ui@1.0.2
|
||||
underscore@1.0.0
|
||||
url@1.0.0
|
||||
webapp-hashing@1.0.0
|
||||
webapp@1.1.1
|
||||
9
rpg-docs/Model/Character/Armor.js
Normal file
9
rpg-docs/Model/Character/Armor.js
Normal file
@@ -0,0 +1,9 @@
|
||||
Armor = function(name, value){
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
this.equipped = true;
|
||||
this.dexModMax = 20;
|
||||
this.dexModMin = -20;
|
||||
this.strengthNeeded = 0;
|
||||
this.stealthDisadvantage = false;
|
||||
}
|
||||
324
rpg-docs/Model/Character/Characters.js
Normal file
324
rpg-docs/Model/Character/Characters.js
Normal file
@@ -0,0 +1,324 @@
|
||||
//set up the collection for characters
|
||||
Characters = new Meteor.Collection("characters", {
|
||||
//transform function alters the object returned by the database
|
||||
transform: function (doc) {
|
||||
//extend character with its protoypal functions
|
||||
var newInstance = Object.create(protoCharacter);
|
||||
doc = _.extend(newInstance, doc);
|
||||
|
||||
return doc;
|
||||
}
|
||||
});
|
||||
|
||||
//Attributes are numerical values
|
||||
Attribute = function(base){
|
||||
this.base = base; //the unmodified value of the attribute
|
||||
//effects of the form {name: "Ring of Protection", value: 1}
|
||||
this.add = []; //bonuses added to the attribute
|
||||
this.mul = []; //multipliers to the attribute (after adding bonuses)
|
||||
this.min = []; //effects setting the minimum value of the attribute
|
||||
this.max = []; //effects setting the maximum value of the attribute
|
||||
this.conditional = []; //conditional modifiers
|
||||
}
|
||||
|
||||
var attributes = [
|
||||
"strength",
|
||||
"dexterity",
|
||||
"constitution",
|
||||
"intelligence",
|
||||
"wisdom",
|
||||
"charisma",
|
||||
"hitPoints",
|
||||
"proficiencyBonus",
|
||||
"speed",
|
||||
"armor",
|
||||
"weight",
|
||||
"weightCarried",
|
||||
"age",
|
||||
"ageRate",
|
||||
"level1SpellSlots",
|
||||
"level2SpellSlots",
|
||||
"level3SpellSlots",
|
||||
"level4SpellSlots",
|
||||
"level5SpellSlots",
|
||||
"level6SpellSlots",
|
||||
"level7SpellSlots",
|
||||
"level8SpellSlots",
|
||||
"level9SpellSlots",
|
||||
"ki",
|
||||
"sorceryPoints",
|
||||
"rages"
|
||||
];
|
||||
|
||||
//Skills are bonuses to rolls: "+2" etc.
|
||||
//They are based off of some ability
|
||||
Skill = function(ability){
|
||||
//proficiencies of the form {name: "Jack of all Trades", value: 0.5}
|
||||
//only the highest is used
|
||||
this.proficiency = [];
|
||||
//ability name that this skill uses as base for roll
|
||||
this.ability = ability;
|
||||
this.add = [];
|
||||
this.mul = [];
|
||||
this.min = [];
|
||||
this.max = [];
|
||||
this.advantage = []; //effects granting advantage
|
||||
this.disadvantage = [];
|
||||
this.passiveAdd = []; //only added to passive checks
|
||||
this.fail = []; //all checks are failed
|
||||
this.conditional = []; //conditional modifiers
|
||||
}
|
||||
|
||||
var skills = [
|
||||
{skill: "strengthSave", ability: "strength"},
|
||||
{skill: "dexteritySave", ability: "dexterity"},
|
||||
{skill: "constitutionSave", ability: "constitution"},
|
||||
{skill: "intelligenceSave", ability: "intelligence"},
|
||||
{skill: "wisdomSave", ability: "wisdom"},
|
||||
{skill: "charismaSave", ability: "charisma"},
|
||||
|
||||
{skill: "acrobatics", ability: "dexterity"},
|
||||
{skill: "animalHandling", ability: "wisdom"},
|
||||
{skill: "arcana",ability: "intelligence"},
|
||||
{skill: "athletics", ability: "strength"},
|
||||
{skill: "deception", ability: "charisma"},
|
||||
{skill: "history", ability: "intelligence"},
|
||||
{skill: "insight", ability: "wisdom"},
|
||||
{skill: "intimidation", ability: "charisma"},
|
||||
{skill: "investigation", ability: "intelligence"},
|
||||
{skill: "medicine", ability: "wisdom"},
|
||||
{skill: "nature", ability: "intelligence"},
|
||||
{skill: "perception", ability: "wisdom"},
|
||||
{skill: "performance", ability: "charisma"},
|
||||
{skill: "persuasion", ability: "charisma"},
|
||||
{skill: "religion", ability: "intelligence"},
|
||||
{skill: "sleightOfHand", ability: "dexterity"},
|
||||
{skill: "stealth", ability: "dexterity"},
|
||||
{skill: "survival", ability: "wisdom"},
|
||||
|
||||
{skill: "initiative", ability: "dexterity"},
|
||||
{skill: "strengthAttack", ability: "strength"},
|
||||
{skill: "dexterityAttack", ability: "dexterity"},
|
||||
{skill: "rangedAttack", ability: "dexterity"},
|
||||
{skill: "dexterityArmor", ability: "dexterity"}
|
||||
|
||||
];
|
||||
|
||||
//Plain text fields for the character
|
||||
var strings = [
|
||||
"name",
|
||||
"alignment",
|
||||
"gender",
|
||||
"race",
|
||||
"description",
|
||||
"personality",
|
||||
"ideals",
|
||||
"bonds",
|
||||
"flaws"
|
||||
];
|
||||
|
||||
//Data structure for the character
|
||||
//no functions can be added to this constructor
|
||||
Character = function(owner){
|
||||
//attributes
|
||||
this.attributes = {};
|
||||
for(var i = 0, l = attributes.length; i < l; i++){
|
||||
this.attributes[attributes[i]] = new Attribute(0);
|
||||
}
|
||||
|
||||
//add 10 and dex bonus to armor
|
||||
this.attributes.armor.add.push({name: "Base Armor Class", value: 10});
|
||||
this.attributes.armor.add.push({name: "Dexterity Modifier", value: "skillMod skills.dexterityArmor"});
|
||||
|
||||
//skills
|
||||
this.skills = {};
|
||||
for(var i = 0, l = skills.length; i < l; i++){
|
||||
this.skills[skills[i].skill] = new Skill(skills[i].ability);
|
||||
}
|
||||
|
||||
this.deathSave = {
|
||||
success : 0,
|
||||
fail: 0
|
||||
};
|
||||
|
||||
this.hitDice = [];
|
||||
|
||||
this.weaponProficiencies = [];
|
||||
this.toolProficiencies = [];
|
||||
this.languages = [];
|
||||
|
||||
this.features = [];
|
||||
|
||||
this.spells = [];
|
||||
|
||||
this.classes = [];
|
||||
|
||||
this.experience = new Experience();
|
||||
|
||||
this.vulnerability = {};
|
||||
for(var i = 0, l = DamageTypes.length; i < l; i++){
|
||||
this.vulnerability[DamageTypes[i]] = new Attribute(1);
|
||||
this.vulnerability[DamageTypes[i]].min.push({name: "Resistance doesn't stack", value: 0.5});
|
||||
this.vulnerability[DamageTypes[i]].max.push({name: "Vulnerability doesn't stack", value: 2});
|
||||
}
|
||||
|
||||
//admin
|
||||
this.owner = owner;
|
||||
this.readers = [];
|
||||
this.writers = [];
|
||||
}
|
||||
|
||||
//functions and calculated values go here
|
||||
var protoCharacter = {
|
||||
attributeValue: function(attribute){
|
||||
if (attribute === undefined) return;
|
||||
//base value
|
||||
var value = attribute.base;
|
||||
|
||||
//add all values in add array
|
||||
for(var i = 0, l = attribute.add.length; i < l; i++){
|
||||
var add = pop(attribute.add[i].value, this);
|
||||
value += add ;
|
||||
}
|
||||
|
||||
//multiply all values in mul array
|
||||
for(var i = 0, l = attribute.mul.length; i < l; i++){
|
||||
var mul = pop(attribute.mul[i], this);
|
||||
value *= mul;
|
||||
}
|
||||
|
||||
//largest min
|
||||
for(var i = 0, l = attribute.min.length; i < l; i++){
|
||||
var min = pop(attribute.min[i], this);
|
||||
value = value > min? value : min;
|
||||
}
|
||||
|
||||
//smallest max
|
||||
for(var i = 0, l = attribute.max.length; i < l; i++){
|
||||
var max = pop(attribute.max[i], this);
|
||||
value = value < max? value : max;
|
||||
}
|
||||
|
||||
return value;
|
||||
},
|
||||
|
||||
skillMod: function(skill){
|
||||
//get the final value of the ability score
|
||||
var ability = this.attributeValue(this.attributes[skill.ability]);
|
||||
|
||||
//base modifier
|
||||
var mod = +getMod(ability)
|
||||
|
||||
//multiply proficiency bonus by largest value in proficiency array
|
||||
var prof = 0;
|
||||
for(var i = 0, l = skill.proficiency.length; i < l; i++){
|
||||
var newProf = pop(skill.proficiency[i].value, this);
|
||||
if (newProf > prof){
|
||||
prof = newProf;
|
||||
}
|
||||
}
|
||||
//add multiplied proficiency bonus to modifier
|
||||
mod += prof * this.attributeValue(this.attributes.proficiencyBonus);
|
||||
|
||||
//add all values in add array
|
||||
for(var i = 0, l = skill.add.length; i < l; i++){
|
||||
mod += pop(skill.add[i].value, this);
|
||||
}
|
||||
|
||||
//multiply all values in mul array
|
||||
for(var i = 0, l = skill.mul.length; i < l; i++){
|
||||
mod *= pop(skill.mul[i].value, this);
|
||||
}
|
||||
|
||||
//largest min
|
||||
for(var i = 0, l = skill.min.length; i < l; i++){
|
||||
var min = pop(skill.min[i], this);
|
||||
mod = mod > min? mod : min;
|
||||
}
|
||||
|
||||
//smallest max
|
||||
for(var i = 0, l = skill.max.length; i < l; i++){
|
||||
var max = pop(skill.max[i], this);
|
||||
mod = mod < max? mod : max;
|
||||
}
|
||||
|
||||
return signedString(mod);
|
||||
},
|
||||
|
||||
passiveSkill: function(skill){
|
||||
var mod = +this.skillMod(skill);
|
||||
var value = 10 + mod;
|
||||
for(var i = 0, l = skill.passiveAdd.length; i < l; i++){
|
||||
value += pop(skill.passiveAdd[i].value, this);
|
||||
}
|
||||
return value;
|
||||
//TODO decide whether (dis)advantage gives (-)+5 to passive checks
|
||||
},
|
||||
|
||||
abilityMod: function(attribute){
|
||||
return signedString(getMod(this.attributeValue(attribute)));
|
||||
},
|
||||
|
||||
passiveAbility: function(attribute){
|
||||
var mod = +getMod(this.attributeValue(attribute));
|
||||
return 10 + mod;
|
||||
}
|
||||
}
|
||||
|
||||
getMod = function(score){
|
||||
return Math.floor((score-10)/2);
|
||||
}
|
||||
|
||||
signedString = function(number){
|
||||
return number > 0? "+" + number : "" + number;
|
||||
}
|
||||
|
||||
// turns dot notation strings into keys of root
|
||||
// argument formats:
|
||||
// 157, anything -> 157
|
||||
// "some.number", object -> object.some.number
|
||||
// "some.function", object -> object.some.function()
|
||||
// "some.function arg1 arg2", object -> object.some.function(arg1, arg2)
|
||||
pop = function(input, root){
|
||||
|
||||
if(typeof(input) === "string"){
|
||||
//we need root for this part
|
||||
if(root === undefined) return;
|
||||
|
||||
//this is a likely to fail if the string is malformed
|
||||
try{
|
||||
//split over spaces
|
||||
var parts = input.split(" ");
|
||||
|
||||
//for each word
|
||||
for (var i = 0; i < parts.length; i++){
|
||||
//split over dots
|
||||
var str = parts[i].split(".");
|
||||
|
||||
//start at root
|
||||
parts[i] = root;
|
||||
|
||||
//for each word between dots
|
||||
for (var j = 0; j < str.length; j++){
|
||||
parts[i] = parts[i][str[j]];
|
||||
}
|
||||
}
|
||||
|
||||
//pull the first word out, might be a function
|
||||
var func = parts.splice(0, 1)[0];
|
||||
|
||||
//if it's a function, apply the arguments to it
|
||||
if(_.isFunction(func)) return +func.apply(root, parts);
|
||||
|
||||
//if it's a number, return it
|
||||
if(!isNaN(func)) return +func;
|
||||
} catch (err) {
|
||||
//TODO pokemon catch statement is bad
|
||||
//"gotta catch em all"
|
||||
console.log(err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return +input;
|
||||
}
|
||||
118
rpg-docs/Model/Character/Conditions.js
Normal file
118
rpg-docs/Model/Character/Conditions.js
Normal file
@@ -0,0 +1,118 @@
|
||||
DamageTypes = [
|
||||
"acid", "bludgeoning", "cold", "fire", "force",
|
||||
"lightning", "necrotic", "piercing", "poison", "psychic",
|
||||
"radiant", "slashing", "thunder"
|
||||
]
|
||||
Conditions = {};
|
||||
|
||||
Conditions.Blinded = {
|
||||
description: ["a blinded creature can't see and automatically fails any ability check that requires sight.",
|
||||
"Attack rolls against the creature have advantage, and the creature's attack rolls have disadvantage."]
|
||||
}
|
||||
|
||||
Conditions.Charmed = {
|
||||
description: ["A charmed creature can't attack the charmer or target the charmer with harmful abilities or magical effects",
|
||||
"The charmer has advantage on any ability check to interact socially with the creature."]
|
||||
}
|
||||
|
||||
Conditions.Deafened = {
|
||||
description: ["A deafened creature can't hear and automatically fails any ability check that requires hearing"]
|
||||
}
|
||||
|
||||
Conditions.Frightened = {
|
||||
description: []
|
||||
}
|
||||
|
||||
Conditions.Grappled = {
|
||||
description: [
|
||||
"A grappled creature's speed becomes 0, and it can't benefit from any bonuses to its speed",
|
||||
"The condition ends if the grappler is incapacitated",
|
||||
"The conditions also ends if if an effect removes the\
|
||||
grappled creature from the reach of the grappler or grappling\
|
||||
effect, such as when a creature is hurled\
|
||||
away by the thunderwave spell."
|
||||
],
|
||||
effects: [
|
||||
{stat: "attributes.speed.maximum", value: 0}
|
||||
]
|
||||
}
|
||||
|
||||
Conditions.Incapacitated = {
|
||||
effects: [
|
||||
{stat: "attributes.actions.maximum", value: 0},
|
||||
{stat: "attributes.reactions.maximum", value: 0},
|
||||
{stat: "attributes.bonusActions.maximum", value: 0}
|
||||
]
|
||||
}
|
||||
|
||||
Conditions.Invisible = {
|
||||
|
||||
}
|
||||
|
||||
Conditions.Paralyzed = {
|
||||
//implies incapacitated
|
||||
effects: [
|
||||
{stat: "skills.strengthSave.fail", value: 1},
|
||||
{stat: "skills.dexteritySave.fail", value: 1},
|
||||
{stat: "attributes.speed.maximum", value: 0}
|
||||
]
|
||||
}
|
||||
_.extend(Conditions.Paralyzed, Conditions.Incapacitated);
|
||||
|
||||
Conditions.Petrified = {
|
||||
|
||||
effects: [
|
||||
{stat: "attributes.weight.mul", value: 10},
|
||||
{stat: "attributes.ageRate.max", value: 0},
|
||||
{stat: "attributes.ageRate.min", value: 0},
|
||||
{stat: "skills.strengthSave.fail", value: 1},
|
||||
{stat: "skills.dexteritySave.fail", value: 1},
|
||||
{stat: "attributes.speed.maximum", value: 0}
|
||||
]
|
||||
}
|
||||
for(var i = 0, l = DamageTypes.length; i < l; i++){
|
||||
var str = "vulnerability." + DamageTypes[i] + ".mul"
|
||||
Conditions.Petrified.effects.push({stat: str, value: 0.5});
|
||||
}
|
||||
_.extend(Conditions.Petrified, Conditions.Incapacitated);
|
||||
|
||||
Conditions.Poisoned = {
|
||||
description: []
|
||||
}
|
||||
|
||||
Conditions.Prone = {
|
||||
description: [],
|
||||
effects: [
|
||||
{stat: "skills.strengthAttack.disadvantage", value: 1},
|
||||
{stat: "skills.dexterityAttack.disadvantage", value: 1},
|
||||
{stat: "skills.rangedAttack.disadvantage", value: 1}
|
||||
]
|
||||
}
|
||||
|
||||
Conditions.Restrained = {
|
||||
effects: [
|
||||
{stat: "attributes.speed.maximum", value: 0}
|
||||
]
|
||||
}
|
||||
|
||||
Conditions.Stunned = {
|
||||
//implies incapacitated
|
||||
effects: [
|
||||
{stat: "attributes.speed.maximum", value: 0},
|
||||
{stat: "skills.strengthSave.fail", value: 1},
|
||||
{stat: "skills.dexteritySave.fail", value: 1}
|
||||
]
|
||||
}
|
||||
_.extend(Conditions.Stunned, Conditions.Incapacitated);
|
||||
|
||||
Conditions.Unconscious = {
|
||||
//implies incapacitated
|
||||
//implies prone
|
||||
effects: [
|
||||
{stat: "attributes.speed.maximum", value: 0},
|
||||
{stat: "skills.strengthSave.fail", value: 1},
|
||||
{stat: "skills.dexteritySave.fail", value: 1}
|
||||
]
|
||||
}
|
||||
_.extend(Conditions.Unconscious, Conditions.Incapacitated);
|
||||
_.extend(Conditions.Unconscious, Conditions.Prone);
|
||||
52
rpg-docs/Model/Character/Experience.js
Normal file
52
rpg-docs/Model/Character/Experience.js
Normal file
@@ -0,0 +1,52 @@
|
||||
Experience = function(){
|
||||
this.total = 0;
|
||||
this.events = [];
|
||||
this.level = 0;
|
||||
}
|
||||
|
||||
Experience.prototype.addEvent = function(description, value){
|
||||
this.events.push({
|
||||
"description": description,
|
||||
"value": value
|
||||
})
|
||||
this.total += value;
|
||||
this.level = this.getLevel();
|
||||
}
|
||||
|
||||
Experience.prototype.removeEvent = function(index){
|
||||
this.total -= this.events[index].value;
|
||||
this.events.splice(index,1);
|
||||
this.level = this.getLevel();
|
||||
}
|
||||
|
||||
Experience.prototype.refreshTotal = function(){
|
||||
this.total = 0;
|
||||
for(var i = 0, length = this.events.length; i < length; i++){
|
||||
this.total += this.events[i].value;
|
||||
}
|
||||
this.level = this.getLevel();
|
||||
}
|
||||
|
||||
Experience.prototype.getLevel = function(){
|
||||
var xp = this.total;
|
||||
if(xp > 355000) return 20;
|
||||
if(xp > 305000) return 19;
|
||||
if(xp > 265000) return 18;
|
||||
if(xp > 225000) return 17;
|
||||
if(xp > 195000) return 16;
|
||||
if(xp > 165000) return 15;
|
||||
if(xp > 140000) return 14;
|
||||
if(xp > 120000) return 13;
|
||||
if(xp > 100000) return 12;
|
||||
if(xp > 85000) return 11;
|
||||
if(xp > 64000) return 10;
|
||||
if(xp > 48000) return 9;
|
||||
if(xp > 34000) return 8;
|
||||
if(xp > 23000) return 7;
|
||||
if(xp > 14000) return 6;
|
||||
if(xp > 6500) return 5;
|
||||
if(xp > 2700) return 4;
|
||||
if(xp > 900) return 3;
|
||||
if(xp > 300) return 2;
|
||||
return 1;
|
||||
}
|
||||
4
rpg-docs/Model/Character/Feature.js
Normal file
4
rpg-docs/Model/Character/Feature.js
Normal file
@@ -0,0 +1,4 @@
|
||||
Feature = function(name){
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
}
|
||||
6
rpg-docs/Model/Character/HitDice.js
Normal file
6
rpg-docs/Model/Character/HitDice.js
Normal file
@@ -0,0 +1,6 @@
|
||||
HitDice = function(sides){
|
||||
this.sides = sides;
|
||||
this.bonus = 0;
|
||||
this.number = 0;
|
||||
this.max = 0;
|
||||
}
|
||||
11
rpg-docs/Model/Character/Spell.js
Normal file
11
rpg-docs/Model/Character/Spell.js
Normal file
@@ -0,0 +1,11 @@
|
||||
Spell = function(name){
|
||||
this.name = name;
|
||||
this.level = 0;
|
||||
this.school = "";
|
||||
this.range = "";
|
||||
this.verbal = false;
|
||||
this.somatic = false;
|
||||
this.material = false;
|
||||
this.duration = "";
|
||||
this.description = "";
|
||||
}
|
||||
7
rpg-docs/Model/Inventory/Containers.js
Normal file
7
rpg-docs/Model/Inventory/Containers.js
Normal file
@@ -0,0 +1,7 @@
|
||||
Containers = new Meteor.Collection('containers');
|
||||
|
||||
Container = function(name, owner){
|
||||
this.name = name;
|
||||
this.owner = owner;
|
||||
this.isCarried = true;
|
||||
}
|
||||
10
rpg-docs/Model/Inventory/Items.js
Normal file
10
rpg-docs/Model/Inventory/Items.js
Normal file
@@ -0,0 +1,10 @@
|
||||
Items = new Meteor.Collection('items');
|
||||
|
||||
Item = function(name, container){
|
||||
this.name = name;
|
||||
this.container = container;
|
||||
this.quantity = 1;
|
||||
this.weight = 0.0;
|
||||
this.value = 0;//value in gold pieces
|
||||
this.description = "";
|
||||
}
|
||||
44
rpg-docs/Model/Utility/dice.js
Normal file
44
rpg-docs/Model/Utility/dice.js
Normal file
@@ -0,0 +1,44 @@
|
||||
roll = function (n, d){
|
||||
if(!isNaN(n)){
|
||||
//first digit is a number
|
||||
if(d === undefined){
|
||||
d = n;
|
||||
n = 1;
|
||||
}
|
||||
if(n > 500){
|
||||
console.log(n + " > 500, cannot lift that many dice to roll them");
|
||||
return;
|
||||
}
|
||||
var result = {sum: 0, rolls: []};
|
||||
for (var i = 0; i < n; i++){
|
||||
var roll = Math.floor(Random.fraction() * d + 1)
|
||||
result.sum += roll;
|
||||
result.rolls.push(roll);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
console.log("rolling dice failed for inputs: ", n, d);
|
||||
return {sum: 0, rolls: []};
|
||||
}
|
||||
|
||||
rollDropLow = function(n, d, drop){
|
||||
var r = roll(n,d)
|
||||
r.rolls.sort(function(a, b){return a-b}); //sort ascending
|
||||
r.rolls.splice(0, drop); //remove the lowest elements
|
||||
r.sum = 0;
|
||||
for (var i = 0, l = r.rolls.length; i , l ; i++){
|
||||
sum += r.rolls[i];
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
rollDropHigh = function(n, d, drop){
|
||||
var r = roll(n,d)
|
||||
r.rolls.sort(function(a, b){return b-a}); //sort descending
|
||||
r.rolls.splice(0, drop); //remove the highest elements
|
||||
r.sum = 0;
|
||||
for (var i = 0, l = r.rolls.length; i , l ; i++){
|
||||
sum += r.rolls[i];
|
||||
}
|
||||
return r;
|
||||
}
|
||||
20
rpg-docs/Routes/Routes.js
Normal file
20
rpg-docs/Routes/Routes.js
Normal file
@@ -0,0 +1,20 @@
|
||||
Router.map( function () {
|
||||
this.route('home', {
|
||||
path: '/',
|
||||
data: { characters: function(){
|
||||
console.log('id ' + Meteor.userId());
|
||||
return Characters.find({owner: Meteor.userId()})
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.route('character', {
|
||||
path: '/character/:_id',
|
||||
notFoundTemplate: 'characterNotFound',
|
||||
data: function() {
|
||||
character = Characters.findOne({_id: this.params._id});
|
||||
if (character) character.items = Items.find({owner: this.params._id});
|
||||
return character;
|
||||
}
|
||||
});
|
||||
});
|
||||
81
rpg-docs/client/css/character.css
Normal file
81
rpg-docs/client/css/character.css
Normal file
@@ -0,0 +1,81 @@
|
||||
.flexContainer {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
#abilityScores {
|
||||
text-align: center;
|
||||
flex-basis: 120px;
|
||||
flex-grow: 1;
|
||||
max-width: 340px;
|
||||
}
|
||||
|
||||
/*Float boxes are indivisble, have shadows*/
|
||||
.floatBox{
|
||||
border: 2px solid black;
|
||||
border-radius: 0px 0px 10px 10px;
|
||||
padding: 5px;
|
||||
margin: 5px;
|
||||
background: white;
|
||||
}
|
||||
|
||||
/* headings in floatboxes */
|
||||
.floatBox h2{
|
||||
background: black;
|
||||
color: white;
|
||||
font-size: 1em;
|
||||
margin: 0px -5px 0px -5px;
|
||||
padding: 2px 15px;
|
||||
}
|
||||
|
||||
.floatBox h2:first-child{
|
||||
margin: -5px -5px 0px -5px;
|
||||
}
|
||||
|
||||
.floatBox.rounded {
|
||||
border-radius: 10px;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Ability scores */
|
||||
.floatBox.ability {
|
||||
border-radius: 10px;
|
||||
width: 85px;
|
||||
text-align: center;
|
||||
margin: 5px 5px 20px 5px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.abilityName {
|
||||
|
||||
}
|
||||
|
||||
.abilityScore {
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
.abilityMod {
|
||||
margin: 0 auto -15px;
|
||||
padding: 2px;
|
||||
border: 2px solid black;
|
||||
border-radius: 5px;
|
||||
background: white;
|
||||
width: 40px;
|
||||
}
|
||||
|
||||
/* Stats */
|
||||
#armorClassBox {
|
||||
width: 90px;
|
||||
height: 100px;
|
||||
background-image: url('/svg/ac.svg');
|
||||
background-repeat: no-repeat;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.statValue {
|
||||
font-size: 2em;
|
||||
}
|
||||
7
rpg-docs/client/css/general.css
Normal file
7
rpg-docs/client/css/general.css
Normal file
@@ -0,0 +1,7 @@
|
||||
root {
|
||||
display: block;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
}
|
||||
68
rpg-docs/client/views/character/abilities.html
Normal file
68
rpg-docs/client/views/character/abilities.html
Normal file
@@ -0,0 +1,68 @@
|
||||
<template name = "abilities">
|
||||
<div class="ability floatBox">
|
||||
<div class ="abilityName">
|
||||
Strength
|
||||
</div>
|
||||
<div class="abilityScore">
|
||||
{{attributeValue attributes.strength}}
|
||||
</div>
|
||||
<div class="abilityMod">
|
||||
{{abilityMod attributes.strength}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="ability floatBox">
|
||||
<div class ="abilityName">
|
||||
Dexterity
|
||||
</div>
|
||||
<div class="abilityScore">
|
||||
{{attributeValue attributes.dexterity}}
|
||||
</div>
|
||||
<div class="abilityMod">
|
||||
{{abilityMod attributes.dexterity}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="ability floatBox">
|
||||
<div class ="abilityName">
|
||||
Constitution
|
||||
</div>
|
||||
<div class="abilityScore">
|
||||
{{attributeValue attributes.constitution}}
|
||||
</div>
|
||||
<div class="abilityMod">
|
||||
{{abilityMod attributes.constitution}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="ability floatBox">
|
||||
<div class ="abilityName">
|
||||
Intelligence
|
||||
</div>
|
||||
<div class="abilityScore">
|
||||
{{attributeValue attributes.intelligence}}
|
||||
</div>
|
||||
<div class="abilityMod">
|
||||
{{abilityMod attributes.intelligence}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="ability floatBox">
|
||||
<div class ="abilityName">
|
||||
Wisdom
|
||||
</div>
|
||||
<div class="abilityScore">
|
||||
{{attributeValue attributes.wisdom}}
|
||||
</div>
|
||||
<div class="abilityMod">
|
||||
{{abilityMod attributes.wisdom}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="ability floatBox">
|
||||
<div class ="abilityName">
|
||||
Charisma
|
||||
</div>
|
||||
<div class="abilityScore">
|
||||
{{attributeValue attributes.charisma}}
|
||||
</div>
|
||||
<div class="abilityMod">
|
||||
{{abilityMod attributes.charisma}}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
21
rpg-docs/client/views/character/character.html
Normal file
21
rpg-docs/client/views/character/character.html
Normal file
@@ -0,0 +1,21 @@
|
||||
<template name="character">
|
||||
<div>
|
||||
{{> characterName}}
|
||||
</div>
|
||||
<div class="flexContainer">
|
||||
<div id="abilityScores" class="flexItem">
|
||||
{{> abilities}}
|
||||
</div>
|
||||
<div class="flexItem">
|
||||
<div>
|
||||
Proficiency Bonus {{proficiencyBonus}}
|
||||
</div>
|
||||
<div id="savesAndSkills" class="floatBox">
|
||||
{{> savesAndSkills}}
|
||||
</div>
|
||||
</div>
|
||||
<div id="stats" class="flexItem">
|
||||
{{> characterStats}}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
11
rpg-docs/client/views/character/characterName.html
Normal file
11
rpg-docs/client/views/character/characterName.html
Normal file
@@ -0,0 +1,11 @@
|
||||
<template name="characterName">
|
||||
<div id="level">
|
||||
{{experience.level}}
|
||||
</div>
|
||||
<div id="name">
|
||||
{{name}}
|
||||
</div>
|
||||
<div id="role">
|
||||
{{alignment}} {{gender}} {{race}} {{#each class}} {{this}} {{/each}}
|
||||
</div>
|
||||
</template>
|
||||
50
rpg-docs/client/views/character/characterStats.html
Normal file
50
rpg-docs/client/views/character/characterStats.html
Normal file
@@ -0,0 +1,50 @@
|
||||
<template name="characterStats">
|
||||
<div id="hitPointBox">
|
||||
Hit Points
|
||||
<div id="hitPoints">
|
||||
<input type="number" value={{attributeValue attributes.hitPoints}}>
|
||||
</div>
|
||||
<div id="maxHitPoints">
|
||||
{{attributeValue attributes.maxHitPoints}}
|
||||
</div>
|
||||
</div>
|
||||
<div id="armorClassBox">
|
||||
<div id="armorClass">
|
||||
<div id="armorClassValue" class="statValue">
|
||||
{{attributeValue attributes.armor}}
|
||||
</div>
|
||||
<div id="armorClassLabel">
|
||||
Armor<br>Class
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="amorBox">
|
||||
</div>
|
||||
<div id="initiativeBox" class="floatBox rounded">
|
||||
<div class="statValue">
|
||||
{{skillMod skills.initiative}}
|
||||
</div>
|
||||
Initiative
|
||||
</div>
|
||||
<div id="speedBox" class="floatBox rounded">
|
||||
<div class="statValue">
|
||||
{{attributeValue attributes.speed}}
|
||||
</div>
|
||||
Speed
|
||||
</div>
|
||||
<div id="passivePerceptionBox" class="floatBox rounded">
|
||||
<div class="statValue">
|
||||
{{passiveSkill skills.perception}}
|
||||
</div>
|
||||
Passive Perception
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
Death Saves
|
||||
</div><div>
|
||||
Successes {{deathSaveSuccess}}
|
||||
</div><div>
|
||||
Failures {{deathSaveFail}}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
52
rpg-docs/client/views/character/savesAndSkills.html
Normal file
52
rpg-docs/client/views/character/savesAndSkills.html
Normal file
@@ -0,0 +1,52 @@
|
||||
<template name="savesAndSkills">
|
||||
<h2>Saving Throws</h2>
|
||||
<div>
|
||||
Strength Save {{skillMod skills.strengthSave}}
|
||||
</div><div>
|
||||
Dexterity Save {{skillMod skills.dexteritySave}}
|
||||
</div><div>
|
||||
Constitution Save {{skillMod skills.constitutionSave}}
|
||||
</div><div>
|
||||
Intelligence Save {{skillMod skills.intelligenceSave}}
|
||||
</div><div>
|
||||
Wisdom Save {{skillMod skills.wisdomSave}}
|
||||
</div><div>
|
||||
Charisma Save {{skillMod skills.charismaSave}}
|
||||
</div>
|
||||
<h2>Skills</h2>
|
||||
<div>
|
||||
Acrobatics {{skillMod skills.acrobatics}}
|
||||
</div><div>
|
||||
Animal Handling {{skillMod skills.animalHandling}}
|
||||
</div><div>
|
||||
Arcana {{skillMod skills.arcana}}
|
||||
</div><div>
|
||||
Athletics {{skillMod skills.athletics}}
|
||||
</div><div>
|
||||
Deception {{skillMod skills.deception}}
|
||||
</div><div>
|
||||
History {{skillMod skills.history}}
|
||||
</div><div>
|
||||
Insight {{skillMod skills.insight}}
|
||||
</div><div>
|
||||
Intimidation {{skillMod skills.intimidation}}
|
||||
</div><div>
|
||||
Investigation {{skillMod skills.investigation}}
|
||||
</div><div>
|
||||
Medicine {{skillMod skills.medicine}}
|
||||
</div><div>
|
||||
Nature {{skillMod skills.nature}}
|
||||
</div><div>
|
||||
Perception {{skillMod skills.perception}}
|
||||
</div><div>
|
||||
Persuasion {{skillMod skills.persuasion}}
|
||||
</div><div>
|
||||
Religion {{skillMod skills.religion}}
|
||||
</div><div>
|
||||
Sleight of Hand {{skillMod skills.sleightOfHand}}
|
||||
</div><div>
|
||||
Stealth {{skillMod skills.stealth}}
|
||||
</div><div>
|
||||
Survival {{skillMod skills.survival}}
|
||||
</div>
|
||||
</template>
|
||||
10
rpg-docs/client/views/home/home.html
Normal file
10
rpg-docs/client/views/home/home.html
Normal file
@@ -0,0 +1,10 @@
|
||||
<template name="home">
|
||||
{{>loginButtons}}
|
||||
<div>
|
||||
{{# each characters}}
|
||||
<li><a href="{{ pathFor 'character' }} ">{{_id}}</a></li>
|
||||
{{/each}}
|
||||
</div>
|
||||
<input id="addCharacter" type="button" value="Add Character">
|
||||
<input id="nukeCharacters" type="button" value="Clear all characters">
|
||||
</template>
|
||||
11
rpg-docs/client/views/home/home.js
Normal file
11
rpg-docs/client/views/home/home.js
Normal file
@@ -0,0 +1,11 @@
|
||||
Template.home.events({
|
||||
"click #addCharacter": function (event, template) {
|
||||
Characters.insert(new Character(Meteor.userId()));
|
||||
},
|
||||
"click #nukeCharacters": function(event, template){
|
||||
while(true){
|
||||
if(!Characters.findOne()) break;
|
||||
Characters.remove(Characters.findOne()._id);
|
||||
}
|
||||
}
|
||||
});
|
||||
4
rpg-docs/client/views/index.html
Normal file
4
rpg-docs/client/views/index.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<head>
|
||||
<title>RPG Docs</title>
|
||||
<meta name="viewport" content="width=device-width">
|
||||
</head>
|
||||
36
rpg-docs/public/svg/ac.svg
Normal file
36
rpg-docs/public/svg/ac.svg
Normal file
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
version="1.1"
|
||||
width="90"
|
||||
height="100"
|
||||
id="svg2">
|
||||
<defs
|
||||
id="defs4" />
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
transform="translate(0,-952.36218)"
|
||||
id="layer1">
|
||||
<path
|
||||
d="m 15,962.36218 c -0.870551,10.48175 -8.4321358,17.45735 -13,18 l 0,23.00002 c 5.0277793,16.7056 22.831231,42.1683 43,47 19.444592,-3.432 35.858861,-26.1733 43,-47 l 0,-23.00002 c -7.815979,-1.16093 -10.356092,-11.69154 -12,-18 l -31,-8 z"
|
||||
id="path2985"
|
||||
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
2
startup.sh
Normal file
2
startup.sh
Normal file
@@ -0,0 +1,2 @@
|
||||
cd rpg-docs
|
||||
export MONGO_URL=mongodb://thaum:pandas@linus.mongohq.com:10050/green_meteor
|
||||
Reference in New Issue
Block a user