Compare commits

...

104 Commits

Author SHA1 Message Date
Stefan Zermatten
8b3f11603a Update Meteor to 1.2
This requires local copies of packages that are broken or not Polymer 0.5
2015-10-03 22:38:25 +02:00
Stefan Zermatten
d05874ed13 Bumped version 2015-10-01 08:06:29 +02:00
Stefan Zermatten
df2521e69c Merge pull request #5 from ThaumRystra/bugfix-unprepared-spell-attacks
Spell child attacks now set their enabled state to match the parent spell prepared state
2015-10-01 08:03:30 +02:00
Stefan Zermatten
3c6a685fe8 Fixed reference to parentId which should be parent.id 2015-10-01 07:45:38 +02:00
Connor Petersen
a77e560284 Spell attacks correctly enable based on preparedness, Model correction with collection hooks 2015-09-30 13:30:59 -07:00
Stefan Zermatten
4cec83918f Updated README.md to remove out of date info 2015-09-28 07:35:10 +02:00
Stefan Zermatten
fec95c51c6 Rolled back changes to spells tab, It wasn't a column-layout 2015-09-25 13:03:14 +02:00
Stefan Zermatten
425c42d049 Bumped version 2015-09-25 12:52:28 +02:00
Stefan Zermatten
ab6f0c4f5b Merge branch 'fix-columns' 2015-09-25 12:51:04 +02:00
Stefan Zermatten
5d6e57b896 Wrap cards in padded divs to make columns behave 2015-09-25 12:49:48 +02:00
Stefan Zermatten
7c0a8125f2 Merge branch 'fix-carry-capacity-effectView' 2015-09-04 13:56:06 +02:00
Stefan Zermatten
7481ef08a8 Carry capacity effects no longer show up as "no stat" when viewed 2015-09-04 13:55:42 +02:00
Stefan Zermatten
b578dd5fb0 Merge branch 'feature-carry-capacity-modifier' 2015-09-03 14:09:51 +02:00
Stefan Zermatten
5d6f934d88 Bumped version 2015-09-03 14:09:23 +02:00
Stefan Zermatten
337f0bfa8a Made sure migration touches every character 2015-09-03 14:09:17 +02:00
Stefan Zermatten
c62784894b Made sure encumbered conditions respect carry capacity 2015-09-03 13:53:00 +02:00
Stefan Zermatten
75fff43d7d Gave an effect menu option for carry capacity 2015-09-03 13:52:40 +02:00
Stefan Zermatten
a9eeeac0df Fixed carry capacity bar 2015-09-03 13:52:22 +02:00
Stefan Zermatten
c8af0ff0a9 Fixed carry capacity table 2015-09-03 13:52:06 +02:00
Stefan Zermatten
9e200db7b9 Made carry capacity an attribute, migrations need testing 2015-08-31 15:51:52 +02:00
Stefan Zermatten
c08cf83096 Bumped version 2015-08-27 12:21:23 +02:00
Stefan Zermatten
d9368b06d0 Merge branch 'bugfix-0.6.8' 2015-08-27 12:07:42 +02:00
Stefan Zermatten
2703367681 Proficiencies now get disabled when their features are disabled 2015-08-27 12:05:56 +02:00
Stefan Zermatten
d419442549 Fixed share dialog not finding usernames or email addresses 2015-08-27 11:59:38 +02:00
Stefan Zermatten
99df01c950 Prevented negative temporary hitpoints being added 2015-08-27 11:43:34 +02:00
Stefan Zermatten
d76349b3bb Merge branch 'release-0.6.7a' 2015-07-29 09:57:06 +02:00
Stefan Zermatten
39c061f4e8 Fixed formatting of not found page, now has a toolbar and centered text 2015-07-29 09:55:22 +02:00
Stefan Zermatten
6d167ddb22 Fixed formatting of loading page, more padding 2015-07-29 09:55:01 +02:00
Stefan Zermatten
037acbd459 Added Starter Set Wizard to the front page 2015-07-29 09:54:43 +02:00
Stefan Zermatten
4d3fc3bb09 Fixed accidental back() requests when closing detail dialogs 2015-07-29 09:54:18 +02:00
Stefan Zermatten
4b984d4fac Made analytics show all characters as the same page 2015-07-29 09:53:46 +02:00
Stefan Zermatten
58843613ba Merge branch 'release-0.6.7' 2015-07-27 13:12:42 +02:00
Stefan Zermatten
39b549b24b Bumped version 2015-07-27 13:12:28 +02:00
Stefan Zermatten
c79177de72 Added Google Analytics 2015-07-27 13:10:33 +02:00
Stefan Zermatten
11d09b1487 Fixed effect values not being visible on mobile 2015-07-27 12:16:02 +02:00
Stefan Zermatten
0e4918d57d Merge branch 'hotfix-style' 2015-07-27 12:08:22 +02:00
Stefan Zermatten
949f313af2 removed 1st column of all tables being 100px 2015-07-27 12:08:15 +02:00
Stefan Zermatten
85b63f152f Merge branch 'release-0.6.6' into develop 2015-07-27 11:23:12 +02:00
Stefan Zermatten
2141d52a7a Merge branch 'release-0.6.6' 2015-07-27 11:22:41 +02:00
Stefan Zermatten
4c84235064 Bumped version 2015-07-27 11:22:26 +02:00
Stefan Zermatten
0e194a5408 Added markdown to text areas 2015-07-27 10:21:26 +02:00
Stefan Zermatten
4b60eac330 Fixed typo on change log 2015-07-24 11:52:46 +02:00
Stefan Zermatten
cb017c359d Merge branch 'release-0.6.5' into develop 2015-07-24 11:31:05 +02:00
Stefan Zermatten
15aaaa5c14 Merge branch 'release-0.6.5' 2015-07-24 11:29:50 +02:00
Stefan Zermatten
290bee83b4 Bumped version 2015-07-24 11:29:03 +02:00
Stefan Zermatten
fcd2461205 Merge branch 'master' into release-0.6.5 2015-07-24 11:26:46 +02:00
Stefan Zermatten
52198d0249 Disabled edit buttons for read-only viewers 2015-07-23 15:07:39 +02:00
Stefan Zermatten
ba7ccfdfa0 Added support for character profile pictures 2015-07-23 15:04:43 +02:00
Stefan Zermatten
92d3b086fa net worth calculations now take into account your containers' values 2015-07-23 09:14:55 +02:00
Stefan Zermatten
e180595dcd Merge branch 'release-0.6.4' 2015-07-06 13:37:02 +02:00
Stefan Zermatten
ed708bdde0 bumped version 2015-07-06 13:36:50 +02:00
Stefan Zermatten
d7852d640f Fixed Math using min and max incorrectly in skills 2015-07-03 13:21:26 +02:00
Stefan Zermatten
a2fdee88b6 Ordered Character lists 2015-06-29 14:00:55 +02:00
Stefan Zermatten
af070b1578 Attacks inherit spell names correctly 2015-06-29 13:55:27 +02:00
Stefan Zermatten
83a8eeef0f Fixed editing of multiple attacks 2015-06-29 13:55:15 +02:00
Stefan Zermatten
34f8e7402b Hit dice constitution now has a + sign when positive 2015-06-29 10:21:49 +02:00
Stefan Zermatten
1b7e2cd850 Merge branch 'hotfix-rounding' into develop 2015-06-29 10:04:45 +02:00
Stefan Zermatten
463b7f0fc9 Merge branch 'hotfix-rounding' 2015-06-29 09:45:38 +02:00
Stefan Zermatten
266495abc8 Bumped version 2015-06-29 09:44:57 +02:00
Stefan Zermatten
453d4365d3 Prevent memoized values being used in dependency loops 2015-06-29 09:41:01 +02:00
Stefan Zermatten
e0ce6275bf Floor character attribute values 2015-06-29 09:40:37 +02:00
Stefan Zermatten
16b16ce6c6 Merge branch 'hotfix-minmax' into develop 2015-06-26 10:49:10 +02:00
Stefan Zermatten
80c72a274e Merge branch 'hotfix-minmax' 2015-06-26 10:48:43 +02:00
Stefan Zermatten
91f0f7954c Bumped version 2015-06-26 10:48:33 +02:00
Stefan Zermatten
c74abcb608 Fixed min and max error 2015-06-26 10:48:04 +02:00
Stefan Zermatten
da8b91594e Removed reference to character helper 2015-06-25 14:22:07 +02:00
Stefan Zermatten
fc26f5a73e Merge branch 'hotfix-experience-inputs' into develop 2015-06-25 14:20:54 +02:00
Stefan Zermatten
4f60766d5d Merge branch 'hotfix-experience-edit-inputs' 2015-06-25 14:07:34 +02:00
Stefan Zermatten
e992aeebef Bumped version 2015-06-25 14:07:24 +02:00
Stefan Zermatten
4108346a98 Fixed experience inputs updating 2015-06-25 14:07:13 +02:00
Stefan Zermatten
946fadadc2 Merge branch 'release-0.6.0' 2015-06-25 13:49:25 +02:00
Stefan Zermatten
d2cc2833a9 Merge branch 'release-0.6.0' into develop 2015-06-25 13:48:32 +02:00
Stefan Zermatten
af57326194 Bumped version 2015-06-25 13:48:12 +02:00
Stefan Zermatten
98c69e9e17 Style tweaks 2015-06-25 13:38:33 +02:00
Stefan Zermatten
395edd0563 Character settings now formatted and has done button 2015-06-25 13:38:20 +02:00
Stefan Zermatten
43e87e7786 Container weight summaries now round off 2015-06-25 13:37:55 +02:00
Stefan Zermatten
ad347504c6 Fixed experienceDialog updating polymer inputs 2015-06-25 13:37:03 +02:00
Stefan Zermatten
4e6e99b695 Fixed spellDialog formatting 2015-06-25 13:36:42 +02:00
Stefan Zermatten
104624a322 Merge branch 'feature-soft-memoize' into develop 2015-06-25 13:35:19 +02:00
Stefan Zermatten
79d166e6af Removed references to old calculations 2015-06-25 13:34:44 +02:00
Stefan Zermatten
86c934e8ac Began replacing calls to helpers with calls to memoized functions 2015-06-18 15:14:37 +02:00
Stefan Zermatten
a034cbf30e Duplicate character helpers with memoized functions not attached to characters 2015-06-18 13:34:59 +02:00
Stefan Zermatten
d5680ebf8a Add memoize functionality 2015-06-18 13:33:54 +02:00
Stefan Zermatten
53f2fcc945 Merge branch 'release-0.5.7' into develop 2015-06-17 14:32:35 +02:00
Stefan Zermatten
612e127be4 Merge branch 'release-0.5.7' 2015-06-17 14:22:33 +02:00
Stefan Zermatten
2b0d975cee change logs 2015-06-17 14:22:12 +02:00
Stefan Zermatten
248ab9bb6b Added moving item dialog, that can't actually be triggered 2015-06-17 14:15:49 +02:00
Stefan Zermatten
314ce85410 Attacks can now be added to spells 2015-06-17 09:05:23 +02:00
Stefan Zermatten
9ff45dbcc2 backgrounds now have proficiencies 2015-06-17 08:49:26 +02:00
Stefan Zermatten
6caf19bc99 Merge branch 'release-0.5.6' into develop 2015-06-15 13:36:50 +02:00
Stefan Zermatten
c2b04d0977 Merge branch 'release-0.5.6' 2015-06-15 13:34:29 +02:00
Stefan Zermatten
9012c4a558 change logs 2015-06-15 13:34:10 +02:00
Stefan Zermatten
65a84937f2 Merge branch 'feature-share-publically' into develop 2015-06-15 13:30:42 +02:00
Stefan Zermatten
eebb88b6b1 New front page and darker style 2015-06-15 13:29:33 +02:00
Stefan Zermatten
06ab7c5116 Merge branch 'master' into feature-share-publically 2015-06-15 10:04:40 +02:00
Stefan Zermatten
89f03c7601 Merge branch 'hotfix-gmail-report' 2015-06-12 08:04:23 +02:00
Stefan Zermatten
9d2eb14c0c Change logs 2015-06-12 08:03:46 +02:00
Stefan Zermatten
7b3cb54983 Added gmail email address senders to the report emails 2015-06-12 08:02:33 +02:00
Stefan Zermatten
a09bad2fed Change logs 2015-06-10 11:13:58 +02:00
Stefan Zermatten
afd897edfe Merge branch 'Hotfix' 2015-06-10 11:05:01 +02:00
Stefan Zermatten
efc79cb6e7 Fixed net value calculation to avoid rounding errors 2015-06-10 11:00:42 +02:00
Stefan Zermatten
35efe39ea7 Made feedback reports send emails "from" their creator's address 2015-06-10 11:00:19 +02:00
Stefan Zermatten
034067bd6e Added link to example character 2015-06-10 10:58:47 +02:00
Stefan Zermatten
0d75cd5d15 Added sharing to anyone with link, changed home page 2015-06-09 17:06:51 +02:00
163 changed files with 2847 additions and 766 deletions

View File

@@ -1,58 +1,4 @@
TODO
====
RPG Docs
========
* Get Polymer installed using bower.
* Install Vulcanize package listed below
* Copy the differential polymer demo to get polymer implemented nicely
* Update Meteor
* Install and use LESS
Packages used
=============
* meteor-platform
* Base Meteor.
* [Docs](http://docs.meteor.com/#/full/)
* autopublish
* Publishes everything to the client.
* Must be removed before release
* insecure
* Allows the client the freedom to modify any colleciton.
* Must be removed before release
* iron:router
* Enables pagination and URL's to direct to specific templates.
* [Tutorial](http://www.manuel-schoebel.com/blog/iron-router-tutorial)
* accounts-password
* Lets users create accounts with a simple password
* accounts-ui
* Adds simple UI for logging in
* random
* Somewhat decent cryptographically strong psuedo random number generation.
* [readme](https://atmospherejs.com/meteor/random)
* dburles:collection-helpers
* Adds template-style helpers to collections. [github page](https://github.com/dburles/meteor-collection-helpers)
* reactive-var
* Friendly reactive variables
* [Meteor Docs](http://docs.meteor.com/#/full/reactivevar_pkg)
* cw4gn3r:jquery-event-drag
* Adds jquery drag events
* underscore
* Handy javascript utilities
* [Docs](http://underscorejs.org/)
* aldeed:collection2
* Extends collections with Schemas
* [(gitHub page)](https://github.com/aldeed/meteor-collection2)
* uses [SimpleSchema](https://github.com/aldeed/meteor-simple-schema)
* aldeed:autoform
* Automatically generates bootstrap forms for collection2 Schemas.
* [github](https://github.com/aldeed/meteor-autoform)
* differential:vulcanize
* Bakes all the polymer imports into one file
* [github](https://github.com/Differential/meteor-vulcanize)
************
Resources
=========
[differential's polymer demo](https://github.com/Differential/polymer-demo)
This is the repo for [DiceCloud](dicecloud.com). The currently deployed version should always be the head of the master branch.

1
rpg-docs/.gitignore vendored
View File

@@ -1,5 +1,6 @@
.meteor/local
.meteor/meteorite
settings.json
public/components
nohup.out
dump

View File

@@ -6,3 +6,7 @@ notices-for-0.9.0
notices-for-0.9.1
0.9.4-platform-file
notices-for-facebook-graph-api-2
1.2.0-standard-minifiers-package
1.2.0-meteor-platform-split
1.2.0-cordova-changes
1.2.0-breaking-changes

View File

@@ -1 +0,0 @@

View File

@@ -3,7 +3,6 @@
# 'meteor add' and 'meteor remove' will edit this file for you,
# but you can also edit it by hand.
meteor-platform
iron:router
accounts-password
accounts-ui
@@ -27,3 +26,19 @@ fourseven:scss@2.1.1
wolves:bourbon
meteorhacks:subs-manager
meteorhacks:kadira
chuangbo:marked
reywood:iron-router-ga
standard-minifiers
meteor-base
mobile-experience
mongo
blaze-html-templates
session
jquery
tracker
logging
reload
ejson
spacebars
check
useraccounts:iron-routing

View File

@@ -1 +1 @@
METEOR@1.1.0.2
METEOR@1.2.0.2

View File

@@ -1,94 +1,116 @@
accounts-base@1.2.0
accounts-google@1.0.4
accounts-oauth@1.1.5
accounts-password@1.1.1
accounts-ui@1.1.5
accounts-ui-unstyled@1.1.7
aldeed:collection2@2.3.3
accounts-base@1.2.1
accounts-google@1.0.6
accounts-oauth@1.1.7
accounts-password@1.1.3
accounts-ui@1.1.6
accounts-ui-unstyled@1.1.8
aldeed:collection2@2.5.0
aldeed:simple-schema@1.3.3
autoupdate@1.2.1
base64@1.0.3
binary-heap@1.0.3
blaze@2.1.2
blaze-tools@1.0.3
boilerplate-generator@1.0.3
callback-hook@1.0.3
check@1.0.5
coffeescript@1.0.6
autoupdate@1.2.3
babel-compiler@5.8.24_1
babel-runtime@0.1.4
base64@1.0.4
binary-heap@1.0.4
blaze@2.1.3
blaze-html-templates@1.0.1
blaze-tools@1.0.4
boilerplate-generator@1.0.4
caching-compiler@1.0.0
caching-html-compiler@1.0.2
callback-hook@1.0.4
check@1.0.6
chuangbo:marked@0.3.5_1
coffeescript@1.0.10
dburles:collection-helpers@1.0.3
dburles:mongo-collection-instances@0.3.3
ddp@1.1.0
deps@1.0.7
differential:vulcanize@0.0.5
dburles:mongo-collection-instances@0.3.4
ddp@1.2.2
ddp-client@1.2.1
ddp-common@1.2.1
ddp-rate-limiter@1.0.0
ddp-server@1.2.1
deps@1.0.9
diff-sequence@1.0.1
differential:vulcanize@2.0.1
ecmascript@0.1.5
ecmascript-collections@0.1.6
ecwyne:mathjs@0.25.0
ejson@1.0.6
email@1.0.6
fastclick@1.0.3
ejson@1.0.7
email@1.0.7
fastclick@1.0.7
fourseven:scss@2.1.1
geojson-utils@1.0.3
google@1.1.5
html-tools@1.0.4
htmljs@1.0.4
http@1.1.0
id-map@1.0.3
iron:controller@1.0.7
iron:core@1.0.7
iron:dynamic-template@1.0.7
iron:layout@1.0.7
iron:location@1.0.7
iron:middleware-stack@1.0.7
iron:router@1.0.7
iron:url@1.0.7
jquery@1.11.3_2
json@1.0.3
lai:collection-extensions@0.1.3
launch-screen@1.0.2
less@1.0.14
livedata@1.0.13
localstorage@1.0.3
logging@1.0.7
matb33:collection-hooks@0.7.13
meteor@1.1.6
meteor-platform@1.2.2
meteorhacks:kadira@2.21.0
geojson-utils@1.0.4
google@1.1.6
hot-code-push@1.0.0
html-tools@1.0.5
htmljs@1.0.5
http@1.1.1
id-map@1.0.4
iron:controller@1.0.8
iron:core@1.0.8
iron:dynamic-template@1.0.8
iron:layout@1.0.8
iron:location@1.0.9
iron:middleware-stack@1.0.9
iron:router@1.0.9
iron:url@1.0.9
jquery@1.11.4
lai:collection-extensions@0.1.4
launch-screen@1.0.4
less@2.5.0_3
livedata@1.0.15
localstorage@1.0.5
logging@1.0.8
matb33:collection-hooks@0.8.1
meteor@1.1.9
meteor-base@1.0.1
meteorhacks:kadira@2.23.4
meteorhacks:meteorx@1.3.1
meteorhacks:subs-manager@1.3.0
minifiers@1.1.5
minimongo@1.0.8
mobile-status-bar@1.0.3
momentjs:moment@2.10.3
mongo@1.1.0
mongo-livedata@1.0.8
meteorhacks:subs-manager@1.6.2
minifiers@1.1.7
minimongo@1.0.10
mobile-experience@1.0.1
mobile-status-bar@1.0.6
momentjs:moment@2.10.6
mongo@1.1.2
mongo-id@1.0.1
mongo-livedata@1.0.9
npm-bcrypt@0.7.8_2
oauth@1.1.4
oauth2@1.1.3
observe-sequence@1.0.6
ordered-dict@1.0.3
percolate:migrations@0.7.5
random@1.0.3
reactive-dict@1.1.0
reactive-var@1.0.5
reload@1.1.3
retry@1.0.3
routepolicy@1.0.5
service-configuration@1.0.4
session@1.1.0
sha@1.0.3
npm-mongo@1.4.39_1
oauth@1.1.6
oauth2@1.1.5
observe-sequence@1.0.7
ordered-dict@1.0.4
percolate:migrations@0.9.6
promise@0.5.0
random@1.0.4
rate-limit@1.0.0
reactive-dict@1.1.2
reactive-var@1.0.6
reload@1.1.4
retry@1.0.4
reywood:iron-router-ga@0.7.1
routepolicy@1.0.6
service-configuration@1.0.5
session@1.1.1
sha@1.0.4
softwarerero:accounts-t9n@1.0.9
spacebars@1.0.6
spacebars-compiler@1.0.6
spacebars@1.0.7
spacebars-compiler@1.0.7
splendido:accounts-emails-field@1.2.0
splendido:accounts-meld@1.3.0
srp@1.0.3
templating@1.1.1
tracker@1.0.7
ui@1.0.6
underscore@1.0.3
url@1.0.4
useraccounts:core@1.9.1
useraccounts:polymer@1.9.1
webapp@1.2.0
webapp-hashing@1.0.3
wolves:bourbon@1.0.0
zimme:collection-behaviours@1.0.4
splendido:accounts-meld@1.3.1
srp@1.0.4
standard-minifiers@1.0.1
templating@1.1.4
templating-tools@1.0.0
tracker@1.0.9
ui@1.0.8
underscore@1.0.4
url@1.0.5
useraccounts:core@1.12.3
useraccounts:iron-routing@1.12.3
useraccounts:polymer@1.12.3
webapp@1.2.2
webapp-hashing@1.0.5
wolves:bourbon@1.2.0
zimme:collection-behaviours@1.1.3
zimme:collection-softremovable@1.0.4

View File

@@ -69,5 +69,17 @@ Attacks.attachSchema(Schemas.Attack);
Attacks.attachBehaviour("softRemovable");
makeChild(Attacks, ["name", "enabled"]); //children of lots of things
Attacks.after.insert(function (userId, attack) {
//Check to see if this attack's parent is a spell, if so, mirror prepared state to enabled
if (attack.parent.collection === "Spells") {
var parentSpell = Spells.findOne(attack.parent.id);
if (parentSpell.prepared === "unprepared") {
Attacks.update(attack._id, {$set: {enabled: false}});
} else if (parentSpell.prepared === "prepared" || "always") {
Attacks.update(attack._id, {$set: {enabled: true}});
}
}
});
Attacks.allow(CHARACTER_SUBSCHEMA_ALLOW);
Attacks.deny(CHARACTER_SUBSCHEMA_DENY);

View File

@@ -3,16 +3,17 @@ Characters = new Mongo.Collection("characters");
Schemas.Character = new SimpleSchema({
//strings
name: {type: String, defaultValue: "", trim: false},
alignment: {type: String, defaultValue: "", trim: false},
gender: {type: String, defaultValue: "", trim: false},
race: {type: String, defaultValue: "", trim: false},
description: {type: String, defaultValue: "", trim: false},
personality: {type: String, defaultValue: "", trim: false},
ideals: {type: String, defaultValue: "", trim: false},
bonds: {type: String, defaultValue: "", trim: false},
flaws: {type: String, defaultValue: "", trim: false},
backstory: {type: String, defaultValue: "", trim: false},
name: {type: String, defaultValue: "", trim: false, optional: true},
alignment: {type: String, defaultValue: "", trim: false, optional: true},
gender: {type: String, defaultValue: "", trim: false, optional: true},
race: {type: String, defaultValue: "", trim: false, optional: true},
picture: {type: String, defaultValue: "", trim: true, optional: true},
description: {type: String, defaultValue: "", trim: false, optional: true},
personality: {type: String, defaultValue: "", trim: false, optional: true},
ideals: {type: String, defaultValue: "", trim: false, optional: true},
bonds: {type: String, defaultValue: "", trim: false, optional: true},
flaws: {type: String, defaultValue: "", trim: false, optional: true},
backstory: {type: String, defaultValue: "", trim: false, optional: true},
//attributes
//ability scores
@@ -32,6 +33,7 @@ Schemas.Character = new SimpleSchema({
age: {type: Schemas.Attribute},
ageRate: {type: Schemas.Attribute},
armor: {type: Schemas.Attribute},
carryMultiplier: {type: Schemas.Attribute},
//resources
level1SpellSlots: {type: Schemas.Attribute},
@@ -176,99 +178,115 @@ Schemas.Character = new SimpleSchema({
"settings.useStandardEncumbrance": {type: Boolean, defaultValue: true},
//hide spellcasting
"settings.hideSpellcasting": {type: Boolean, defaultValue: false},
//show to anyone with link
"settings.viewPermission": {
type: String,
defaultValue: "whitelist",
allowedValues: ["whitelist", "public"],
},
});
Characters.attachSchema(Schemas.Character);
var attributeBase = function(charId, statName){
var attributeBase = preventLoop(function(charId, statName){
check(statName, String);
//if it's a damage multiplier, we treat it specially
if (_.contains(DAMAGE_MULTIPLIERS, statName)){
var effects = Effects.find(
{charId: charId, stat: statName, enabled: true, operation: "mul"}
).fetch();
var resistCount = 0;
var vulnCount = 0;
var multiplierEvaluationFail = false;
_.each(effects, function(effect){
var val = evaluateEffect(charId, effect);
if (val === 0.5){ //resistance
resistCount += 1;
} else if (val === 2){ //vulnerability
vulnCount += 1;
} else if (val === 0){ //imunity
return 0; //imunity is absolute
} else {
multiplierEvaluationFail = true;
}
});
if (multiplierEvaluationFail){
//we can't work it out correctly, set the value to 1
//and try work it out using regular maths below
value = 1;
} else if (resistCount && !vulnCount){
var invulnerabilityCount = Effects.find({
charId: charId,
stat: statName,
enabled: true,
operation: "mul",
value: 0,
}).count();
if (invulnerabilityCount) return 0;
var resistCount = Effects.find({
charId: charId,
stat: statName,
enabled: true,
operation: "mul",
value: 0.5,
}).count();
var vulnCount = Effects.find({
charId: charId,
stat: statName,
enabled: true,
operation: "mul",
value: 2,
}).count();
if (!resistCount && !vulnCount){
return 1;
} else if (resistCount && !vulnCount){
return 0.5;
} else if (!resistCount && vulnCount){
} else if (!resistCount && vulnCount){
return 2;
} else {
return 1;
}
}
var value;
var base = 0;
var add = 0;
var mul = 1;
var min = Number.NEGATIVE_INFINITY;
var max = Number.POSITIVE_INFINITY;
var value = 0;
//start with the highest base value
Effects.find(
{charId: charId, stat: statName, enabled: true, operation: "base"}
).forEach(function(effect){
var efv = evaluateEffect(charId, effect);
if (efv > value){
value = efv;
Effects.find({
charId: charId,
stat: statName,
enabled: true,
operation: {$in: ["base", "add", "mul", "min", "max"]},
}).forEach(function(effect) {
value = evaluateEffect(charId, effect);
if (effect.operation === "base"){
if (value > base) base = value;
} else if (effect.operation === "add"){
add += value;
} else if (effect.operation === "mul"){
mul *= value;
} else if (effect.operation === "min"){
if (value > min) min = value;
} else if (effect.operation === "max"){
if (value < max) max = value;
}
});
//add all the add values
Effects.find(
{charId: charId, stat: statName, enabled: true, operation: "add"}
).forEach(function(effect){
value += evaluateEffect(charId, effect);
});
var result = (base + add) * mul;
if (result < min) result = min;
if (result > max) result = max;
//multiply all the mul values
Effects.find(
{charId: charId, stat: statName, enabled: true, operation: "mul"}
).forEach(function(effect){
value *= evaluateEffect(charId, effect);
});
return Math.floor(result);
});
//ensure value is >= all mins
Effects.find(
{charId: charId, stat: statName, enabled: true, operation: "min"}
).forEach(function(effect){
var min = evaluateEffect(charId, effect);
value = value > min ? value : min;
if (Meteor.isClient) {
Template.registerHelper("characterCalculate", function(func, charId, input) {
try {
return Characters.calculate[func](charId, input);
} catch (e){
if (!Characters.calculate[func]){
throw new Error(func + "is not a function name");
} else {
throw e;
}
}
});
}
//ensure value is <= all maxes
Effects.find(
{charId: charId, stat: statName, enabled: true, operation: "max"}
).forEach(function(effect){
var max = evaluateEffect(charId, effect);
value = value < max ? value : max;
//create a local memoize with a argument concatenating hash function
var memoize = function(f) {
return Tracker.memoize(f, function() {
return _.reduce(arguments, function(memo, arg) {
return memo + arg;
}, "");
});
return value;
};
//functions and calculated values.
//These functions can only rely on this._id since no other
//field is likely to be attached to all returned characters
Characters.helpers({
//returns the value stored in the field requested
//will set up dependencies on just that field
getField : function(fieldName){
//memoize funcitons that have finds and slow loops
Characters.calculate = {
getField: function(charId, fieldName) {
var fieldSelector = {};
fieldSelector[fieldName] = 1;
var char = Characters.findOne(this._id, {fields: fieldSelector});
var char = Characters.findOne(charId, {fields: fieldSelector});
var field = char[fieldName];
if (field === undefined){
throw new Meteor.Error(
@@ -281,8 +299,7 @@ Characters.helpers({
}
return field;
},
//returns the value of a field
fieldValue : function(fieldName){
fieldValue: function(charId, fieldName) {
if (!Schemas.Character.schema(fieldName)){
throw new Meteor.Error(
"Field not found",
@@ -292,102 +309,92 @@ Characters.helpers({
//duck typing to get the right value function
//.ability implies skill
if (Schemas.Character.schema(fieldName + ".ability")){
return this.skillMod(fieldName);
return Characters.calculate.skillMod(charId, fieldName);
}
//adjustment implies attribute
if (Schemas.Character.schema(fieldName + ".adjustment")){
return this.attributeValue(fieldName);
return Characters.calculate.attributeValue(charId, fieldName);
}
//fall back to just returning the field itself
return this.getField(fieldName);
return Characters.calculate.getField(charId, fieldName);
},
attributeValue: function(attributeName){
var charId = this._id;
var attribute = this.getField(attributeName);
attributeValue: memoize(function(charId, attributeName){
var attribute = Characters.calculate.getField(charId, attributeName);
//base value
var value = this.attributeBase(attributeName);
var value = Characters.calculate.attributeBase(charId, attributeName);
//plus adjustment
value += attribute.adjustment;
return value;
},
attributeBase: preventLoop(function(attributeName){
var charId = this._id;
//base value
}),
attributeBase: memoize(function(charId, attributeName){
return attributeBase(charId, attributeName);
}),
skillMod: preventLoop(function(skillName){
var charId = this._id;
var skill = this.getField(skillName);
skillMod: memoize(preventLoop(function(charId, skillName){
var skill = Characters.calculate.getField(charId, skillName);
//get the final value of the ability score
var ability = this.attributeValue(skill.ability);
var ability = Characters.calculate.attributeValue(charId, skill.ability);
//base modifier
var mod = +getMod(ability);
//multiply proficiency bonus by largest value in proficiency array
var prof = this.proficiency(skillName);
var prof = Characters.calculate.proficiency(charId, skillName);
//add multiplied proficiency bonus to modifier
mod += prof * this.attributeValue("proficiencyBonus");
mod += prof * Characters.calculate.attributeValue(charId, "proficiencyBonus");
//apply all effects
var rawEffects = Effects.find(
{charId: charId, stat: skillName, enabled: true}
).fetch();
var effects = _.groupBy(rawEffects, "operation");
_.forEach(effects.add, function(effect){
mod += evaluateEffect(charId, effect);
});
_.forEach(effects.mul, function(effect){
mod *= evaluateEffect(charId, effect);
});
_.forEach(effects.min, function(effect){
var min = evaluateEffect(charId, effect);
mod = mod > min ? mod : min;
});
_.forEach(effects.max, function(effect){
var max = evaluateEffect(charId, effect);
mod = mod < max ? mod : max;
});
return signedString(mod);
}),
var value;
var add = 0;
var mul = 1;
var min = Number.NEGATIVE_INFINITY;
var max = Number.POSITIVE_INFINITY;
proficiency: function(skillName){
var charId = this._id;
//return largest value in proficiency array
var prof = 0;
Proficiencies.find(
{charId: charId, name: skillName, enabled: true}
).forEach(function(proficiency){
var newProf = proficiency.value;
if (newProf > prof){
prof = newProf;
Effects.find({
charId: charId,
stat: skillName,
enabled: true,
operation: {$in: ["base", "add", "mul", "min", "max"]},
}).forEach(function(effect) {
value = evaluateEffect(charId, effect);
if (effect.operation === "add"){
add += value;
} else if (effect.operation === "mul"){
mul *= value;
} else if (effect.operation === "min"){
if (value > min) min = value;
} else if (effect.operation === "max"){
if (value < max) max = value;
}
});
return prof;
},
var result = (mod + add) * mul;
if (result < min) result = min;
if (result > max) result = max;
passiveSkill: function(skillName){
if (_.isString(skillName)){
var skill = this.getField(skillName);
}
var charId = this._id;
var mod = +this.skillMod(skillName);
return Math.floor(result);
})),
proficiency: memoize(function(charId, skillName){
//return largest value in proficiency array
var prof = Proficiencies.findOne(
{charId: charId, name: skillName, enabled: true},
{sort: {value: -1}}
);
return prof && prof.value || 0;
}),
passiveSkill: memoize(function(charId, skillName){
var skill = Characters.calculate.getField(charId, skillName);
var mod = +Characters.calculate.skillMod(charId, skillName);
var value = 10 + mod;
Effects.find(
{charId: charId, stat: skillName, enabled: true, operation: "passiveAdd"}
).forEach(function(effect){
value += evaluateEffect(charId, effect);
});
return value;
//TODO decide whether (dis)advantage gives (-)+5 to passive checks
},
advantage: function(skillName){
var charId = this._id;
var advantage = Characters.calculate.advantage(charId, skillName);
value += 5 * advantage;
return Math.floor(value);
}),
advantage: memoize(function(charId, skillName){
var advantage = Effects.find(
{charId: charId, stat: skillName, enabled: true, operation: "advantage"}
).count();
@@ -397,19 +404,18 @@ Characters.helpers({
if (advantage && !disadvantage) return 1;
if (disadvantage && !advantage) return -1;
return 0;
}),
abilityMod: function(charId, attribute){
return getMod(
Characters.calculate.attributeValue(charId, attribute)
);
},
abilityMod: function(attribute){
return signedString(getMod(this.attributeValue(attribute)));
},
passiveAbility: function(attribute){
var mod = +getMod(this.attributeValue(attribute));
passiveAbility: function(charId, attribute){
var mod = +getMod(Characters.calculate.attributeValue(charId, attribute));
return 10 + mod;
},
xpLevel: function(){
var xp = this.experience();
xpLevel: function(charId){
var xp = Characters.calculate.experience(charId);
for (var i = 0; i < 19; i++){
if (xp < XP_TABLE[i]){
return i;
@@ -418,30 +424,103 @@ Characters.helpers({
if (xp > 355000) return 20;
return 0;
},
level: function(){
level: memoize(function(charId){
var level = 0;
Classes.find({charId: this._id}).forEach(function(cls){
Classes.find({charId: charId}).forEach(function(cls){
level += cls.level;
});
return level;
},
experience: function(){
}),
experience: memoize(function(charId){
var xp = 0;
Experiences.find(
{charId: this._id},
{charId: charId},
{fields: {value: 1}}
).forEach(function(e){
xp += e.value;
});
return xp;
}),
};
var depreciated = function() {
//var err = new Error("this function has been depreciated");
var name = "";
if (Template.instance()){
name = Template.instance().view.name;
}
var logString = "this function has been depreciated \n";
if (name){
logString += "View: " + name + "\n\n";
}
//logString += err.stack + "\n\n---------------------\n\n";
console.log(logString);
};
//functions and calculated values.
//These functions can only rely on this._id since no other
//field is likely to be attached to all returned characters
Characters.helpers({
//returns the value stored in the field requested
//will set up dependencies on just that field
getField : function(fieldName){
depreciated();
return Characters.calculate.getField(this._id, fieldName);
},
//returns the value of a field
fieldValue : function(fieldName){
depreciated();
return Characters.calculate.fieldValue(this._id, fieldName);
},
attributeValue: function(attributeName){
depreciated();
return Characters.calculate.attributeValue(this._id, attributeName);
},
attributeBase: function(attributeName){
depreciated();
return Characters.calculate.attributeBase(this._id, attributeName);
},
skillMod: function(skillName){
depreciated();
return Characters.calculate.skillMod(this._id, skillName);
},
proficiency: function(skillName){
depreciated();
return Characters.calculate.proficiency(this._id, skillName);
},
passiveSkill: function(skillName){
depreciated();
return Characters.calculate.passiveSkill(this._id, skillName);
},
advantage: function(skillName){
depreciated();
return Characters.calculate.advantage(this._id, skillName);
},
abilityMod: function(attribute){
depreciated();
return Characters.calculate.abilityMod(this._id, attribute);
},
passiveAbility: function(attribute){
depreciated();
return Characters.calculate.passiveAbility(this._id, attribute);
},
xpLevel: function(){
depreciated();
return Characters.calculate.xpLevel(this._id);
},
level: function(){
depreciated();
return Characters.calculate.level(this._id);
},
experience: function(){
depreciated();
return Characters.calculate.experience(this._id);
},
});
//clean up all data related to that character before removing it
Characters.after.remove(function(userId, character) {
if (Meteor.isServer){
if (Meteor.isServer){
Characters.after.remove(function(userId, character) {
Actions .remove({charId: character._id});
Attacks .remove({charId: character._id});
Buffs .remove({charId: character._id});
@@ -454,8 +533,8 @@ Characters.after.remove(function(userId, character) {
SpellLists .remove({charId: character._id});
Items .remove({charId: character._id});
Containers .remove({charId: character._id});
}
});
});
}
Characters.allow({
insert: function(userId, doc) {

View File

@@ -107,6 +107,18 @@ if (Meteor.isServer) Characters.after.insert(function(userId, char) {
group: "Inate",
},
});
Effects.insert({
charId: char._id,
name: "Natural Carrying Capacity",
stat: "carryMultiplier",
operation: "base",
value: "1",
parent: {
id: char._id,
collection: "Characters",
group: "Inate",
},
});
});
Effects.attachBehaviour("softRemovable");

View File

@@ -30,7 +30,7 @@ Schemas.Proficiency = new SimpleSchema({
Proficiencies.attachSchema(Schemas.Proficiency);
Proficiencies.attachBehaviour("softRemovable");
makeChild(Proficiencies);
makeChild(Proficiencies, ["enabled"]);
Proficiencies.allow(CHARACTER_SUBSCHEMA_ALLOW);
Proficiencies.deny(CHARACTER_SUBSCHEMA_DENY);

View File

@@ -62,6 +62,23 @@ Spells.attachSchema(Schemas.Spell);
Spells.attachBehaviour("softRemovable");
makeChild(Spells); //children of spell lists
makeParent(Spells, ["name", "enabled"]); //parents of attacks
Spells.after.update(function (userId, spell, fieldNames) {
//Update prepared state of spell and child attacks to be enabled or not
if (_.contains(fieldNames, "prepared")) {
var childAttacks = Attacks.find({"parent.id": spell._id}).fetch();
if (spell.prepared === "unprepared") {
_.each(childAttacks, function(attack){
Attacks.update(attack._id, {$set: {enabled: false}});
});
} else if (spell.prepared === "prepared" || "always") {
_.each(childAttacks, function(attack){
Attacks.update(attack._id, {$set: {enabled: true}});
});
}
}
});
Spells.allow(CHARACTER_SUBSCHEMA_ALLOW);
Spells.deny(CHARACTER_SUBSCHEMA_DENY);

View File

@@ -3,10 +3,6 @@
* Damage, healing and resource cost/recovery are all adjustments
*/
Schemas.Adjustment = new SimpleSchema({
name: {
type: String,
optional: true,
},
//which stat the adjustment is applied to
stat: {
type: String,

View File

@@ -3,9 +3,9 @@ TemporaryHitPoints = new Mongo.Collection("temporaryHitPoints");
Schemas.TemporaryHitPoints = new SimpleSchema({
charId: {type: String, regEx: SimpleSchema.RegEx.Id},
name: {type: String, optional: true},
maximum: {type: Number, defaultValue: 0},
used: {type: Number, defaultValue: 0},
deleteOnZero:{type: Boolean, defaultValue: true},
maximum: {type: Number, defaultValue: 0, min: 0, max: 500},
used: {type: Number, defaultValue: 0, min: 0, max: 500},
deleteOnZero:{type: Boolean, defaultValue: false},
dateAdded: {
type: Date,
autoValue: function() {

View File

@@ -45,12 +45,25 @@ Meteor.methods({
metaData: Object,
});
report.owner = this.userId;
Reports.insert(report);
var id = Reports.insert(report);
var user = Meteor.users.findOne(this.userId);
var sender = user &&
user.emails &&
user.emails[0] &&
user.emails[0].address ||
user.services &&
user.services.google &&
user.services.google.email ||
"reports@dicecloud.com";
var bodyText = "Report ID: " + id +
"\nSeverity: " + report.severity +
"\nType: " + report.type +
"\n\n" + report.description;
Email.send({
from: "reports@dicecloud.com",
from: sender,
to: "stefan.zermatten@gmail.com",
subject: "DiceCloud feedback - " + report.title,
text: JSON.stringify(_.omit(report, "metaData"), null, '\t'),
text: bodyText,
});
},
deleteReport: function(id) {

View File

@@ -1,20 +1,13 @@
Router.configure({
loadingTemplate: "loading",
layoutTemplate: "layout",
trackPageView: true,
});
Router.plugin("ensureSignedIn", {
except: [
"home",
"atSignIn",
"atSignUp",
"atForgotPassword",
"atResetPwd",
"atEnrollAccount",
"atVerifyEmail",
"atResendVerificationEmail",
"loginButtons",
"notFound",
only: [
"profile",
"characterList",
]
});
@@ -35,7 +28,7 @@ Router.map(function() {
},
data: {
characters: function(){
return Characters.find({}, {fields: {_id: 1}});
return Characters.find({}, {fields: {_id: 1}, sort: {name: 1}});
}
},
onAfterAction: function() {
@@ -64,6 +57,12 @@ Router.map(function() {
document.title = name;
}
},
//analytics
trackPageView: false,
onRun: function() {
window.ga && window.ga("send", "pageview", "/character");
this.next();
},
});
this.route("loading", {
@@ -93,4 +92,11 @@ Router.map(function() {
document.title = appName;
},
});
this.route("/guide", {
name: "guide",
onAfterAction: function() {
document.title = appName;
},
});
});

View File

@@ -77,10 +77,10 @@ this.GlobalUI = (function() {
var throttleBack = _.throttle(function() {
history.back();
}, 800, {trailing: false});
}, 100, {trailing: false});
GlobalUI.closeDetail = function() {
if (!!(window.history && window.history.pushState)) {
if (window.history && history.pushState && history.state.detail === "opened") {
throttleBack();
} else {
Session.set("global.ui.detailShow", false);

View File

@@ -1,6 +1,10 @@
Template.registerHelper("canEditCharacter", function(charId) {
return canEditCharacter(charId);
});
canEditCharacter = function(charId) {
var char = Characters.findOne(charId)
var userId = Meteor.userId();
return char.owner === userId ||
_.contains(char.writers, userId);
});
};

View File

@@ -20,6 +20,11 @@ openParentDialog = function(parent, charId, heroId) {
template: "itemDialog",
data: {itemId: parent.id},
};
} else if (parent.collection === "Spells") {
detail = {
template: "spellDialog",
data: {spellId: parent.id},
};
}
detail.heroId = heroId;
detail.charId = charId;

View File

@@ -1,25 +1,27 @@
Template.registerHelper("valueString", function(value) {
var intValue = Math.round(value * 100);
var cp = intValue % 10;
intValue -= cp;
cp = Math.round(cp);
sp = intValue % 100;
intValue -= sp;
sp = Math.round(sp / 10)
gp = Math.floor(value);
var resultArray = [];
//sp
var gp = Math.floor(value);
if (gp > 0) {
resultArray.push(gp + "gp");
}
//sp
var sp = Math.floor(10 * (value % 1));
if (sp > 0) {
resultArray.push(sp + "sp");
}
//cp
var cp = 10 * ((value * 10) % 1);
cp = Math.round(cp * 1000) / 1000;
if (cp > 0) {
resultArray.push(cp + "cp");
}
//build string with correct spacing
var result = "";
for (var i = 0; i < resultArray.length; i++) {
for (var i = 0, l = resultArray.length; i < l; i++) {
//add a space between values
if (i !== 0) {
result += " ";

View File

@@ -3,17 +3,24 @@
$thickColumnWidth: 304px;
$thinColumnWidth: 240px;
//Column layouts of cards
//Column layout
.column-container {
@include column-fill(balance);
@include column-gap(8px);
@include column-gap(0px);
@include column-width($thickColumnWidth);
padding: 8px;
padding: 4px;
&.thin-columns {
@include column-count(4);
@include column-width($thinColumnWidth);
}
& > div {
padding: 4px;
//stop divs breaking over multiple columns
-webkit-column-break-inside: avoid;
page-break-inside: avoid;
break-inside: avoid;
}
}
//Cards
@@ -21,20 +28,6 @@ $thinColumnWidth: 240px;
background: white;
border-radius: 2px;
.column-container & {
margin-bottom: 8px;
width: 100%;
//hack to stop flickering
-webkit-backface-visibility: hidden;
-webkit-transform: translateX(0);
//stop breaking over column divide
-webkit-column-break-inside: avoid;
page-break-inside: avoid;
break-inside: avoid;
//Fixes extra margin at top of columns
display: inline-block;
}
.top {
cursor: pointer;
padding: 16px;
@@ -91,6 +84,6 @@ $thinColumnWidth: 240px;
}
/* undo pointer cursor on detail box heading */
#globalDetail .card .top {
#globalDetail.card .top {
cursor: auto;
}

View File

@@ -70,8 +70,8 @@
background-color: #9E9E9E;
}
.blue-grey {
background-color: #607D8B;
.app-grey {
background-color: #424242;
}
.white {

View File

@@ -19,6 +19,21 @@ body {
background-color: #E0E0E0;
}
//fix tabs and core-toolbar having box shadow
core-toolbar {
box-shadow: none;
}
//give drawer panel a shadow always
core-header-panel[drawer] {
box-shadow: 2px 0px 5px 0px rgba(0,0,0,0.2);
}
//Paragraphs
p {
margin-bottom: 8px;
}
//Horizontal rule
hr {
background-color: #444;
@@ -27,7 +42,7 @@ hr {
color: #444;
height: 1px;
line-height: 0;
margin: 16px -16px;
margin: 16px 0;
text-align: center;
}

View File

@@ -1,8 +1,5 @@
td {
padding: 8px;
&:nth-child(1) {
min-width: 100px;
}
}
.strengthTable{
@@ -15,4 +12,10 @@ td {
width: 250px;
}
}
}
}
.summaryTable {
&:nth-child(3){
text-align: right;
}
}

View File

@@ -3,26 +3,26 @@
<div layout vertical flex>
<div layout horizontal>
<!--attackBonus-->
<paper-input id="attackBonusInput"
<paper-input class="attackBonusInput"
label="Attack Bonus"
floatinglabel
value={{attackBonus}}
flex></paper-input>
<!--details-->
<paper-input id="detailInput"
<paper-input class="detailInput"
label="Details"
floatinglabel
value={{details}}></paper-input>
</div>
<div layout horizontal>
<!--damageBonus-->
<paper-input id="damageInput"
<paper-input class="damageInput"
label="Damage"
floatinglabel
value={{damage}}
flex></paper-input>
<!--DamageType-->
<paper-dropdown-menu id="damageTypeDropdown" label="Damage Type">
<paper-dropdown-menu class="damageTypeDropdown" label="Damage Type">
<paper-dropdown layered class="dropdown">
<core-menu class="menu" selected={{damageType}}>
{{#each damageTypes}}
@@ -34,6 +34,6 @@
</div>
</div>
<!--Delete Button-->
<paper-icon-button id="deleteAttack" role="button" tabindex="0" icon="delete" aria-label="Delete"></paper-icon-button>
<paper-icon-button class="deleteAttack" role="button" tabindex="0" icon="delete" aria-label="Delete"></paper-icon-button>
</div>
</template>

View File

@@ -15,23 +15,23 @@ var damageTypes = [
];
Template.attackEdit.events({
"tap #deleteAttack": function(event, instance) {
"tap .deleteAttack": function(event, instance) {
Attacks.softRemoveNode(this._id);
GlobalUI.deletedToast(this._id, "Attacks", "Attack");
},
"change #attackBonusInput": function(event) {
"change .attackBonusInput": function(event) {
var value = event.currentTarget.value;
Attacks.update(this._id, {$set: {attackBonus: value}});
},
"change #damageInput": function(event) {
"change .damageInput": function(event) {
var value = event.currentTarget.value;
Attacks.update(this._id, {$set: {damage: value}});
},
"change #detailInput": function(event) {
"change .detailInput": function(event) {
var value = event.currentTarget.value;
Attacks.update(this._id, {$set: {details: value}});
},
"core-select #damageTypeDropdown": function(event) {
"core-select .damageTypeDropdown": function(event) {
var detail = event.originalEvent.detail;
if (!detail.isSelected) return;
var value = detail.item.getAttribute("name");

View File

@@ -1,7 +1,7 @@
<template name="characterSettings">
{{#with character}}
<div>
<table>
<div style="height: 100px;">
<table style="width: 100%;">
<tr>
<td>Hide Spells tab</td>
<td>
@@ -23,4 +23,5 @@
</table>
</div>
{{/with}}
<paper-button id="doneButton" affirmative> Done </paper-button>
</template>

View File

@@ -1,5 +1,17 @@
<template name="shareDialog">
<div style="width: 360px;">
<div layout horizontal center>
<div>Who can view this character: </div>
<paper-dropdown-menu class="visibilityDropdown"
label="Visibility">
<paper-dropdown layered class="dropdown">
<core-menu class="menu visibilityMenu" selected={{viewPermission}}>
<paper-item name="whitelist">Only people I share with</paper-item>
<paper-item name="public">Anyone with link</paper-item>
</core-menu>
</paper-dropdown>
</paper-dropdown-menu>
</div>
<div>
{{#if readers.count}}
<div style="font-weight: 500;">
@@ -7,7 +19,7 @@
</div>
{{#each readers}}
<div layout horizontal center>
<div flex>{{username}}</div>
<div flex>{{getUserName}}</div>
<paper-icon-button class="deleteShare" icon="delete"></paper-icon-button>
</div>
{{/each}}

View File

@@ -3,6 +3,10 @@ Template.shareDialog.onCreated(function(){
});
Template.shareDialog.helpers({
viewPermission: function() {
var char = Characters.findOne(this._id, {fields: {settings: 1}});
return char.settings.viewPermission || "whitelist";
},
readers: function(){
var char = Characters.findOne(this._id, {fields: {readers: 1}});
return Meteor.users.find({_id: {$in: char.readers}});
@@ -19,9 +23,20 @@ Template.shareDialog.helpers({
return "User not found";
}
},
getUserName: function() {
return this.username || "user: " + this._id;
}
});
Template.shareDialog.events({
"core-select .visibilityDropdown": function(event){
var detail = event.originalEvent.detail;
if (!detail.isSelected) return;
var value = detail.item.getAttribute("name");
var char = Characters.findOne(this._id, {fields: {settings: 1}});
if (value == char.settings.viewPermission) return;
Characters.update(this._id, {$set: {"settings.viewPermission": value}});
},
"input #userNameOrEmailInput":
function(event, instance){
var userName = instance.find("#userNameOrEmailInput").value;

View File

@@ -20,7 +20,7 @@ Template.characterSheet.helpers({
hideSpellcasting: function() {
var char = Characters.findOne(this._id);
return char && char.settings.hideSpellcasting;
}
},
});
Template.characterSheet.events({

View File

@@ -44,7 +44,8 @@
label="Value"
floatinglabel
value={{effectValue}}
flex>
flex
style="flex-basis: 100px;">
</paper-input>
</template>

View File

@@ -42,6 +42,7 @@ var stats = [
{stat: "rageDamage", name: "Rage Damage", group: "Stats"},
{stat: "expertiseDice", name: "Expertise Dice", group: "Stats"},
{stat: "superiorityDice", name: "Superiority Dice", group: "Stats"},
{stat: "carryMultiplier", name: "Carry Capacity Multiplier", group: "Stats"},
{stat: "level1SpellSlots", name: "level 1", group: "Spell Slots"},
{stat: "level2SpellSlots", name: "level 2", group: "Spell Slots"},
{stat: "level3SpellSlots", name: "level 3", group: "Spell Slots"},

View File

@@ -42,6 +42,7 @@ var stats = {
"rageDamage":{"name":"Rage Damage"},
"expertiseDice":{"name":"Expertise Dice"},
"superiorityDice":{"name":"Superiority Dice"},
"carryMultiplier": {"name": "Carry Capacity Multiplier"},
"level1SpellSlots":{"name":"level 1 Spell Slots"},
"level2SpellSlots":{"name":"level 2 Spell Slots"},
"level3SpellSlots":{"name":"level 3 Spell Slots"},

View File

@@ -32,7 +32,7 @@
{{/if}}
{{#if description}}
<div class="pre-wrap">{{evaluateString charId description}}</div>
<div>{{#markdown}}{{evaluateString charId description}}{{/markdown}}</div>
{{/if}}
{{> effectsViewList charId=charId parentId=_id}}

View File

@@ -12,8 +12,9 @@
{{>resource name="sorceryPoints" title="Sorcery Points" color="teal" char=this}}
<!--superiorityDice-->
{{>resource name="superiorityDice" title="Superiority Dice" color="teal" char=this}}
<!--Attacks-->
<div>
<paper-shadow class="card">
<div class="top white">
Attacks
@@ -48,8 +49,10 @@
{{/each}}
</div>
</paper-shadow>
</div>
<!--Proficiencies-->
<div>
<paper-shadow class="card">
<div class="white top">
Proficiencies
@@ -75,13 +78,15 @@
{{/each}}
</div>
</paper-shadow>
</div>
<!--features-->
{{#each features}}
<div>
<paper-shadow class="card featureCard"
hero-id="main" {{detailHero}}>
<div class="top {{colorClass}} subhead"
layout horizontal
<div class="top {{colorClass}} subhead"
layout horizontal
hero-id="toolbar" {{detailHero}}>
<div flex hero-id="title" {{detailHero}}>
{{name}}
@@ -94,57 +99,61 @@
{{#if canEnable}}
<core-tooltip label="Feature enabled"
position="left">
<paper-checkbox class="enabledCheckbox"
checked={{enabled}}>
<paper-checkbox class="enabledCheckbox"
checked={{enabled}}
disabled={{#unless canEditCharacter charId}}true{{/unless}}>
</paper-checkbox>
</core-tooltip>
{{/if}}
</div>
{{#if description}}
<div flex class="bottom text"
>{{evaluateString charId description}}</div>
<div flex class="bottom">
{{#markdown}}{{evaluateString charId shortDescription}}{{/markdown}}
</div>
{{/if}}
{{#if hasUses}}
<div layout horizontal center end-justified>
<paper-button class="useFeature"
<paper-button class="useFeature"
disabled={{noUsesLeft}}>
Use
</paper-button>
<paper-button class="resetFeature"
<paper-button class="resetFeature"
disabled={{usesFull}}>
Reset
</paper-button>
</div>
{{/if}}
</paper-shadow>
</div>
{{/each}}
</div>
<div class="fab-buffer"></div>
</div>
{{#if canEditCharacter _id}}
<paper-fab id="addFeature"
class="floatyButton"
icon="add"
title="Add"
role="button"
tabindex="0"
aria-label="Add"
<paper-fab id="addFeature"
class="floatyButton"
icon="add"
title="Add"
role="button"
tabindex="0"
aria-label="Add"
hero-id="main"></paper-fab>
{{/if}}
</div>
</template>
<template name="resource">
{{#if char.attributeBase name}}
<paper-shadow class="card"
{{#if characterCalculate "attributeBase" char._id name}}
<div>
<paper-shadow class="card"
hero-id="main" {{detailHero name char._id}}
layout horizontal>
<div class="left {{getColor}} display1 white-text"
<div class="left {{getColor}} display1 white-text"
hero-id="toolbar" {{detailHero name char._id}}
layout horizontal center>
<div style="margin-right: 8px;">
<paper-icon-button class="resourceUp"
icon="arrow-drop-up"
<paper-icon-button class="resourceUp"
icon="arrow-drop-up"
disabled={{cantIncrement}}>
</paper-icon-button>
<paper-icon-button class="resourceDown"
@@ -152,13 +161,14 @@
disabled={{cantDecrement}}>
</paper-icon-button>
</div>
<div>{{char.attributeValue name}}</div>
<div>{{characterCalculate "attributeValue" char._id name}}</div>
<!--<div>/{{char.attributeBase name}}</div>-->
</div>
<div class="right clickable"
<div class="right clickable"
flex layout horizontal center>
{{title}}
</div>
</paper-shadow>
</div>
{{/if}}
</template>

View File

@@ -3,14 +3,19 @@ Template.features.helpers({
var features = Features.find({charId: this._id}, {sort: {color: 1, name: 1}});
return features;
},
shortDescription: function() {
if (_.isString(this.description)){
return this.description.split(/^( *[-*_]){3,} *(?:\n+|$)/m)[0];
}
},
hasUses: function(){
return this.usesValue() > 0;
},
noUsesLeft: function(){
return this.usesLeft() <= 0;
return this.usesLeft() <= 0 || !canEditCharacter(this.charId);
},
usesFull: function(){
return this.usesLeft() >= this.usesValue();
return this.usesLeft() >= this.usesValue() || !canEditCharacter(this.charId);
},
colorClass: function(){
return getColorClass(this.color);
@@ -96,16 +101,19 @@ Template.features.events({
Template.resource.helpers({
cantIncrement: function(){
var baseBigger = this.char.attributeValue(this.name) <
this.char.attributeBase(this.name);
return !baseBigger;
var value = Characters.calculate.attributeValue(this.char._id, this.name);
var base = Characters.calculate.attributeBase(this.char._id, this.name);
var baseBigger = value < base;
return !baseBigger || !canEditCharacter(this.char._id);
},
cantDecrement: function(){
var valuePositive = this.char.attributeValue(this.name) > 0;
return !valuePositive;
var value = Characters.calculate.attributeValue(this.char._id, this.name);
var valuePositive = value > 0;
return !valuePositive || !canEditCharacter(this.char._id);
},
getColor: function(){
if (this.char.attributeValue(this.name) > 0){
var value = Characters.calculate.attributeValue(this.char._id, this.name);
if (value > 0){
return this.color;
} else {
return "grey";
@@ -115,14 +123,17 @@ Template.resource.helpers({
Template.resource.events({
"tap .resourceUp": function(event){
if (this.char.attributeValue(this.name) < this.char.attributeBase(this.name)){
var value = Characters.calculate.attributeValue(this.char._id, this.name);
var base = Characters.calculate.attributeBase(this.char._id, this.name);
if (value < base){
var modifier = {$inc: {}};
modifier.$inc[this.name + ".adjustment"] = 1;
Characters.update(this.char._id, modifier, {validate: false});
}
},
"tap .resourceDown": function(event){
if (this.char.attributeValue(this.name) > 0){
var value = Characters.calculate.attributeValue(this.char._id, this.name);
if (value > 0){
var modifier = {$inc: {}};
modifier.$inc[this.name + ".adjustment"] = -1;
Characters.update(this.char._id, modifier, {validate: false});

View File

@@ -13,8 +13,10 @@ var getFractionCarried = function(char) {
weight += item.totalWeight();
});
//get strength
var strength = char.attributeValue("strength");
var capacity = strength * 15;
var strength = Characters.calculate.attributeValue(char._id, "strength");
var carryMultiplier = Characters.calculate
.attributeValue(char._id, "carryMultiplier");
var capacity = strength * 15 * carryMultiplier;
return weight / capacity;
};

View File

@@ -34,13 +34,13 @@
<template name="containerView">
<div layout horizontal wrap center justified>
<table class="summaryTable fullwidth">
<tr><td>Container</td><td>{{weight}}lbs</td><td>{{longValueString value}}</td></tr>
<tr><td>Contents</td><td>{{contentsWeight}}lbs</td><td>{{longValueString contentsValue}}</td></tr>
<tr class="body2"><td>Total</td><td>{{totalWeight}}lbs</td><td>{{longValueString totalValue}}</td></tr>
<tr><td>Container</td><td>{{round weight}}lbs</td><td>{{longValueString value}}</td></tr>
<tr><td>Contents</td><td>{{round contentsWeight}}lbs</td><td>{{longValueString contentsValue}}</td></tr>
<tr class="body2"><td>Total</td><td>{{round totalWeight}}lbs</td><td>{{longValueString totalValue}}</td></tr>
</table>
</div>
{{#if description}}
<hr class="vertMargin">
<div class="pre-wrap">{{evaluateString charId description}}</div>
<div>{{#markdown}}{{evaluateString charId description}}{{/markdown}}</div>
{{/if}}
</template>

View File

@@ -3,6 +3,7 @@
<div id="inventory" class="scroll-y" fit>
<div class="column-container">
<!--Net Worth-->
<div>
<paper-shadow class="card">
<div class="white top" layout horizontal center>
<div class="subhead" flex>
@@ -13,7 +14,9 @@
</div>
</div>
</paper-shadow>
</div>
<!--Weight Carried-->
<div>
<paper-shadow class="card"
hero-id="main" {{detailHero "weightCarried" _id}}>
<div class="top green white-text weightCarried"
@@ -35,8 +38,7 @@
<div class="item-slot">
<div class="item buff"
hero-id="main" {{detailHero}}
layout horizontal center
draggable="true">
layout horizontal center>
<div flex>
<core-icon icon="work"
style="margin-right: 16px">
@@ -49,7 +51,9 @@
</div>
{{/if}}
</paper-shadow>
</div>
<!--Equipment-->
<div>
<paper-shadow class="card equipmentContainer">
<div class="white top" layout horizontal center>
<div class="subhead" flex>
@@ -77,7 +81,9 @@
{{/each}}
</div>
</paper-shadow>
</div>
<!--Carried Items-->
<div>
<paper-shadow class="card carriedContainer">
<div class="white top" layout horizontal center>
<div class="subhead" flex>
@@ -96,8 +102,10 @@
{{/each}}
</div>
</paper-shadow>
</div>
{{#each containers}}
<paper-shadow class="card itemContainer"
<div>
<paper-shadow class="card itemContainer"
hero-id="main" {{detailHero}}>
<div class="top {{colorClass}}"
hero-id="toolbar" {{detailHero}}
@@ -114,6 +122,7 @@
</div>
<core-tooltip label="Container carried" position="left">
<paper-checkbox class="carriedCheckbox"
disabled={{#unless canEditCharacter charId}}true{{/unless}}
checked={{isCarried}}>
</paper-checkbox>
</core-tooltip>
@@ -124,6 +133,7 @@
{{/each}}
</div>
</paper-shadow>
</div>
{{/each}}
</div>
<div class="fab-buffer"></div>
@@ -152,11 +162,11 @@
<div class="item {{hidden}} inventoryItem"
hero-id="main" {{detailHero}}
layout horizontal center
draggable="true">
draggable={{canEditCharacter charId}}>
<div flex class="itemName">
{{#if ne1 quantity}}{{quantity}}&nbsp;{{/if}}{{pluralName}}
</div>
{{#if settings.showIncrement}}
{{#if settings.showIncrement}}{{#if canEditCharacter charId}}
<div class="incrementButtons">
<paper-icon-button class="addItemQuantity"
icon="add"
@@ -166,7 +176,7 @@
icon="remove"
style="margin-right: -8px"></paper-icon-button>
</div>
{{/if}}
{{/if}}{{/if}}
</div>
</div>
</template>

View File

@@ -44,6 +44,12 @@ Template.inventory.helpers({
).forEach(function(item){
worth += item.totalValue();
});
Containers.find(
{charId: this._id},
{fields: {value : 1}}
).forEach(function(container) {
if (container.value) worth += container.value;
});
return worth;
},
weightCarried: function(){
@@ -174,6 +180,20 @@ Template.inventory.events({
heroId: itemId,
});
},
"hold .inventoryItem": function(event, instance) {
var itemId = this._id;
var charId = Template.parentData()._id;
var containerId = this.parent.id;
GlobalUI.showDialog({
template: "moveItemDialog",
data: {
charId: charId,
itemId: itemId,
containerId: containerId,
},
heading: "Move " + this.pluralName(),
});
},
"tap .incrementButtons": function(event) {
event.stopPropagation();
},

View File

@@ -18,8 +18,8 @@
{{#if requiresAttunement}}<div class="vertMargin">Requires Attunement</div>{{/if}}
</div>
{{#if description}}
<hr class="vertMargin">
<div class="pre-wrap">{{evaluateString charId description}}</div>
<hr style="margin: 16px 0 16px 0;">
<div>{{#markdown}}{{evaluateString charId description}}{{/markdown}}</div>
{{/if}}
{{> effectsViewList charId=charId parentId=_id}}
{{> attacksViewList charId=charId parentId=_id}}

View File

@@ -0,0 +1,7 @@
html /deep/ .moveItemDialog paper-tabs::shadow #selectionBar {
background-color: #D50000;
}
html /deep/ .moveItemDialog paper-tab::shadow #ink {
color: #D50000;
}

View File

@@ -0,0 +1,49 @@
<template name="moveItemDialog">
<div class="moveItemDialog">
<paper-tabs selected="{{selectedTab}}">
<paper-tab name="containers"
class="clickable">
Containers
</paper-tab>
<paper-tab name="characters"
class="clickable">
Characters
</paper-tab>
</paper-tabs>
<core-animated-pages selected="{{selectedTab}}"
transitions="slide-from-right"
style="width: 250px;
height: 200px;
overflow-y: auto;
overflow-x: hidden;">
<section name="containers">
<core-menu id="containerMenu" style="margin: 0;">
{{#each containers}}
<paper-item name={{_id}}
layout horizontal center>
<core-icon icon="image:brightness-1"
style="color: {{hexColor color}};
margin-right: 16px;">
</core-icon>
<div>{{name}}</div>
</paper-item>
{{/each}}
</core-menu>
</section>
<section name="characters">
<core-menu id="characterMenu" style="margin: 0;">
{{#each characters}}
<paper-item name={{_id}}
layout horizontal center>
<div class="item small">
{{name}}
</div>
</paper-item>
{{/each}}
</core-menu>
</section>
</core-animated-pages>
</div>
<paper-button id="cancelButton" affirmative> Cancel </paper-button>
<paper-button id="moveButton" affirmative> Move </paper-button>
</template>

View File

@@ -0,0 +1,56 @@
Template.moveItemDialog.onCreated(function() {
Session.setDefault("moveItemDialogTab", "containers");
});
Template.moveItemDialog.helpers({
selectedTab: function() {
return Session.get("moveItemDialogTab");
},
characters: function() {
var userId = Meteor.userId();
return Characters.find(
{
$or: [
{readers: userId},
{writers: userId},
{owner: userId},
],
_id: {$ne: this.charId},
},
{fields: {name: 1}}
);
},
containers: function(){
return Containers.find(
{
charId: this.charId,
_id: {$ne: this.containerId},
},
{
fields: {color: 1, name: 1},
sort: {color: 1, name: 1},
}
);
},
});
Template.moveItemDialog.events({
"tap paper-tab": function(event) {
Session.set("moveItemDialogTab", event.currentTarget.getAttribute("name"));
},
"tap #moveButton": function(event, instance) {
var tab = Session.get("moveItemDialogTab");
if (tab === "containers"){
var containerId = instance.find("#containerMenu").selected;
if (!containerId) throw "no menu selection";
Meteor.call("moveItemToContainer", this.itemId, containerId);
} else if (tab === "characters"){
var characterId = instance.find("#characterMenu").selected;
if (!characterId) throw "no menu selection";
Meteor.call("moveItemToCharacter", this.itemId, characterId);
} else {
throw "Move item dialog tab is not set to containers or character," +
" it is set to " + tab;
}
},
});

View File

@@ -6,23 +6,27 @@
</div>
{{#if description}}
<hr class="vertMargin">
<div class="pre-wrap">{{description}}</div>
<div>{{#markdown}}{{description}}{{/markdown}}</div>
{{/if}}
{{else}}
<div horizontal layout>
<!--Name-->
<paper-input id="experienceNameInput" label="Name" floatinglabel value={{name}} flex></paper-input>
<!--Value-->
<paper-input-decorator label="Value" floatinglabel>
<input id="valueInput" type="number" value={{value}}>
</paper-input-decorator>
</div>
<!--Description-->
<paper-input-decorator label="Description" floatinglabel layout vertical>
<paper-autogrow-textarea>
<textarea id="experienceDescriptionInput" placeholder value={{description}}></textarea>
</paper-autogrow-textarea>
</paper-input-decorator>
{{> experienceEdit}}
{{/baseDialog}}
{{/with}}
</template>
</template>
<template name="experienceEdit">
<div horizontal layout>
<!--Name-->
<paper-input id="experienceNameInput" label="Name" floatinglabel value={{name}} flex></paper-input>
<!--Value-->
<paper-input-decorator label="Value" floatinglabel>
<input id="valueInput" type="number" value={{value}}>
</paper-input-decorator>
</div>
<!--Description-->
<paper-input-decorator label="Description" floatinglabel layout vertical>
<paper-autogrow-textarea>
<textarea id="experienceDescriptionInput" placeholder value={{description}}></textarea>
</paper-autogrow-textarea>
</paper-input-decorator>
</template>

View File

@@ -1,3 +1,7 @@
Template.experienceEdit.onRendered(function(){
updatePolymerInputs(this);
});
Template.experienceDialog.helpers({
experience: function(){
Experiences.findOne(this.experienceId);
@@ -18,8 +22,10 @@ Template.experienceDialog.events({
);
GlobalUI.closeDetail();
},
//TODO validate input (integer, non-negative, etc) for these inputs and give validation errors
"change #experienceNameInput, input #experienceNameInput": function(event){
});
Template.experienceEdit.events({
"change #experienceNameInput": function(event){
var value = event.currentTarget.value;
Experiences.update(this._id, {$set: {name: value}});
},

View File

@@ -3,14 +3,15 @@
<div id="journal" class="scroll-y" fit>
<div class="column-container">
<!--Experience Table-->
<paper-shadow class="card experiencesCard"
<div><paper-shadow class="card experiencesCard"
hero-id="main" {{detailHero}}>
<div class="top white subhead"
hero-id="toolbar" {{detailHero}}
layout horizontal center>
<div flex>Experience</div>
<div >{{experience}} XP</div>
<paper-icon-button class="black54" id="addXP" icon="add"></paper-icon-button>
<div >{{characterCalculate "experience" _id}} XP</div>
<paper-icon-button class="black54" id="addXP" icon="add"
disabled={{#unless canEditCharacter _id}}true{{/unless}}></paper-icon-button>
</div>
<div class="bottom list">
{{#each experiences}}
@@ -36,16 +37,16 @@
</paper-button>
</div>
{{/if}}
</paper-shadow>
</paper-shadow></div>
<!--Class Table-->
<paper-shadow class="card"
<div><paper-shadow class="card"
hero-id="main" {{detailHero}}>
<div class="white top"
hero-id="toolbar" {{detailHero}}
layout horizontal center>
<div flex>
<div class="containerName subhead">
Level {{level}}
Level {{characterCalculate "level" _id}}
</div>
{{#if nextLevelXP}}
<div class="caption">
@@ -55,7 +56,8 @@
</div>
<paper-icon-button class="black54"
id="addClassButton"
icon="add">
icon="add"
disabled={{#unless canEditCharacter _id}}true{{/unless}}>
</paper-icon-button>
</div>
<div class="bottom list">
@@ -76,29 +78,31 @@
</div>
{{/each}}
</div>
</paper-shadow>
</paper-shadow></div>
<!--Notes-->
{{#each notes}}
<div>
<paper-shadow class="card" hero-id="main" {{detailHero}}>
<div class="top {{colorClass}} noteTop subhead"
hero-id="toolbar" {{detailHero}}
layout horizontal center>
{{name}}
</div>
<div class="bottom text">{{description}}</div>
<div class="bottom">{{#markdown}}{{description}}{{/markdown}}</div>
</paper-shadow>
</div>
{{/each}}
</div>
<div class="fab-buffer"></div>
</div>
</div>
{{#if canEditCharacter _id}}
<paper-fab id="addNote"
class="floatyButton"
icon="add"
title="Add"
role="button"
tabindex="0"
<paper-fab id="addNote"
class="floatyButton"
icon="add"
title="Add"
role="button"
tabindex="0"
hero-id="main"></paper-fab>
{{/if}}
</template>
</template>

View File

@@ -41,7 +41,7 @@ Template.journal.helpers({
return Levels.find({charId: charId, classId: this._id}, {sort: {value: 1}});
},
nextLevelXP: function(){
var currentLevel = this.level();
var currentLevel = Characters.calculate.level(this._id);
if (currentLevel < 20){
return XP_TABLE[currentLevel];
}

View File

@@ -1,7 +1,7 @@
<template name="noteDialog">
{{#with note}}
{{#baseDialog title=name class=colorClass startEditing=../startEditing}}
<div class="pre-wrap">{{description}}</div>
<div>{{#markdown}}{{description}}{{/markdown}}</div>
{{else}}
{{> noteDialogEdit}}
{{/baseDialog}}

View File

@@ -0,0 +1,9 @@
<template name="backgroundDialog">
{{#baseDialog title=title class=colorClass hideColor="true" hideDelete="true"}}
<div>{{#markdown}}{{evaluateString charId value}}{{/markdown}}</div>
{{> proficiencyViewList charId=charId parentId=charId parentGroup="background"}}
{{else}}
{{> textDialogEdit}}
{{> proficiencyEditList parentId=charId parentCollection="Characters" charId=charId parentGroup="background"}}
{{/baseDialog}}
</template>

View File

@@ -0,0 +1,8 @@
Template.backgroundDialog.helpers({
value: function(){
var fieldSelector = {fields: {}};
fieldSelector.fields[this.field] = 1;
var char = Characters.findOne(this.charId, fieldSelector);
return char[this.field];
}
});

View File

@@ -1,18 +1,36 @@
<template name="personaDetailsDialog">
{{#baseDialog title=name class="deep-purple white-text" hideColor="true" hideDelete="true" startEditing=startEditing}}
{{alignment}} {{gender}} {{race}}
{{#with char}}
<div>{{alignment}} {{gender}} {{race}}</div>
<core-image style="width: 350px; height: 350px; margin-top: 8px;"
sizing="cover"
hero-id="image" hero
src={{picture}}></core-image>
{{/with}}
{{else}}
{{> personaDetailsEdit}}
{{#with char}}
{{> personaDetailsEdit}}
{{/with}}
{{/baseDialog}}
</template>
<template name="personaDetailsEdit">
<!--Name-->
<paper-input id="nameInput" label="Name" floatinglabel value={{name}}></paper-input><br>
<!--Alignment-->
<paper-input id="alignmentInput" label="Alignment" floatinglabel value={{alignment}}></paper-input><br>
<!--Gender-->
<paper-input id="genderInput" label="Gender" floatinglabel value={{gender}}></paper-input><br>
<!--Race-->
<paper-input id="raceInput" label="Race" floatinglabel value={{race}}></paper-input><br>
<div layout horizontal center-justified>
<div flex style="max-width: 350px;" layout vertical>
<!--Name-->
<paper-input id="nameInput" label="Name" floatinglabel value={{name}}></paper-input>
<!--Alignment-->
<paper-input id="alignmentInput" label="Alignment" floatinglabel value={{alignment}}></paper-input>
<!--Gender-->
<paper-input id="genderInput" label="Gender" floatinglabel value={{gender}}></paper-input>
<!--Race-->
<paper-input id="raceInput" label="Race" floatinglabel value={{race}}></paper-input>
<!--Picture-->
<paper-input id="pictureInput" label="Picture URL" floatinglabel value={{picture}}></paper-input>
<core-image style="height:350px; width: 100%; margin-top: 8px;"
sizing="cover"
hero-id="image" hero
src={{picture}}></core-image>
</div>
</div>
</template>

View File

@@ -2,21 +2,34 @@ Template.personaDetailsEdit.onRendered(function(){
updatePolymerInputs(this);
});
Template.personaDetailsDialog.helpers({
char: function() {
return Characters.findOne(
this._id,
{fields: {name: 1, alignment: 1, gender: 1, race: 1, picture: 1}}
);
}
});
Template.personaDetailsEdit.events({
"change #nameInput": function(event){
var input = event.currentTarget.value;
Characters.update(this.charId, {$set: {name: input}});
Characters.update(this._id, {$set: {name: input}});
},
"change #alignmentInput": function(event){
var input = event.currentTarget.value;
Characters.update(this.charId, {$set: {alignment: input}});
Characters.update(this._id, {$set: {alignment: input}});
},
"change #genderInput": function(event){
var input = event.currentTarget.value;
Characters.update(this.charId, {$set: {gender: input}});
Characters.update(this._id, {$set: {gender: input}});
},
"change #raceInput": function(event){
var input = event.currentTarget.value;
Characters.update(this.charId, {$set: {race: input}});
Characters.update(this._id, {$set: {race: input}});
},
"change #pictureInput": function(event){
var input = event.currentTarget.value;
Characters.update(this._id, {$set: {picture: input}});
},
});

View File

@@ -3,14 +3,45 @@
<div id="persona" class="scroll-y" fit>
<div class="column-container">
{{#with characterDetails}}
{{#containerCardHelper this}}{{alignment}} {{gender}} {{race}}{{/containerCardHelper}}
<div>
<paper-shadow class="card"
hero-id="main" {{detailHero "details" _id}}>
{{#unless picture}}
<div class="top subhead characterField {{colorClass}}"
hero-id="toolbar" {{detailHero "details" _id}}>
<div class="subhead" flex
hero-id="title" {{detailHero "details" _id}}>
{{name}}
</div>
</div>
{{else}}
<core-image class="characterField clickable"
style="height:350px; width: 100%;
background-color: #e8e8e8;"
sizing="cover"
hero-id="image" {{detailHero "details" _id}}
src={{picture}}></core-image>
{{/unless}}
<div class="bottom">
{{#if picture}}
<div class="title" hero-id="title" {{detailHero "details" _id}}>
{{name}}
</div>
{{/if}}
<div class="subhead">
{{alignment}} {{gender}} {{race}}
</div>
</div>
</paper-shadow>
</div>
{{/with}}
{{> containerCard characterField "description" "Description"}}
{{> containerCard characterField "personality" "Personality Traits"}}
{{> containerCard characterField "ideals" "Ideals"}}
{{> containerCard characterField "bonds" "Bonds"}}
{{> containerCard characterField "flaws" "Flaws"}}
{{> containerCard characterField "backstory" "Background"}}
<div>{{> containerCard characterField "description" "Description"}}</div>
<div>{{> containerCard characterField "personality" "Personality Traits"}}</div>
<div>{{> containerCard characterField "ideals" "Ideals"}}</div>
<div>{{> containerCard characterField "bonds" "Bonds"}}</div>
<div>{{> containerCard characterField "flaws" "Flaws"}}</div>
<div>{{> containerCard characterField "backstory" "Background"}}</div>
<div>
<paper-shadow class="card">
<div class="white top subhead">
Languages
@@ -21,6 +52,7 @@
{{/each}}
</div>
</paper-shadow>
</div>
</div>
</div>
</div>
@@ -40,6 +72,6 @@
{{title}}
</div>
</div>
<div class="bottom text">{{> UI.contentBlock}}</div>
<div class="bottom">{{#markdown}}{{> UI.contentBlock}}{{/markdown}}</div>
</paper-shadow>
</template>
</template>

View File

@@ -11,12 +11,12 @@ Template.persona.helpers({
characterDetails: function(){
var char = Characters.findOne(
this._id,
{fields: {name: 1, gender: 1, alignment: 1, race:1}}
{fields: {name: 1, gender: 1, alignment: 1, race:1, picture: 1}}
);
char.field = "details";
char.title = char.name;
char.color = "d";
char.topClass = "characterField";
char.startEditing = true;
return char;
},
characterField: function(field, title){
@@ -40,25 +40,28 @@ Template.persona.helpers({
Template.persona.events({
"tap .characterField": function(event){
if (this.field !== "details"){
var charId = Template.parentData()._id;
GlobalUI.setDetail({
template: "textDialog",
data: {
charId: charId,
field: this.field,
title: this.title,
color: this.color,
},
heroId: this._id + this.field,
});
} else {
if (this.field == "details"){
this.charId = Template.parentData()._id;
GlobalUI.setDetail({
template: "personaDetailsDialog",
data: this,
heroId: this._id + this.field,
});
} else {
var template = "textDialog";
if (this.field === "backstory") template = "backgroundDialog";
var charId = Template.parentData()._id;
GlobalUI.setDetail({
template: template,
data: {
charId: charId,
field: this.field,
title: this.title,
color: this.color,
startEditing: true,
},
heroId: this._id + this.field,
});
}
}
});

View File

@@ -1,6 +1,6 @@
<template name="textDialog">
{{#baseDialog title=title class=colorClass hideColor="true" hideDelete="true" startEditing=startEditing}}
<div class="pre-wrap">{{evaluateString charId value}}</div>
<div>{{#markdown}}{{evaluateString charId value}}{{/markdown}}</div>
{{else}}
{{> textDialogEdit}}
{{/baseDialog}}

View File

@@ -1,6 +1,10 @@
<template name="proficiencyView">
<div class="proficiencyView" layout horizontal center>
<core-icon icon="{{profIcon}}"></core-icon>
<div class="sideMargin">{{getName}}</div>
<div class="proficiencyView item small"
style="padding: 0;"
layout horizontal center>
<core-icon icon="{{profIcon}}" style="margin-right: 16px;"></core-icon>
<div>{{getName}}</div>
</div>
</template>

View File

@@ -2,7 +2,7 @@
{{#if proficiencies.count}}
<hr class="vertMargin">
<div class="proficiencies">
<h2 class="spaceAfter">Proficiencies</h2>
<h2 style="margin-bottom: 8px;">Proficiencies</h2>
{{#each proficiencies}}
{{> proficiencyView}}
{{/each}}

View File

@@ -9,24 +9,33 @@
</template>
<template name="spellDetails">
<div class="caption">
<div class="body2">
Level {{level}} {{school}}, {{preparedString}}
</div>
<div class="vertMargin">
<div style="margin: 16px 0 16px 0;">
{{#if castingTime}}
<div>
<span class="body2">Casting Time: </span><span>{{castingTime}}</span>
</div>
{{/if}}
{{#if range}}
<div>
<span class="body2">Range: </span><span>{{range}}</span>
</div>
{{/if}}
{{#if getComponents}}
<div>
<span class="body2">Components: </span><span>{{getComponents}}</span>
</div>
{{/if}}
{{#if duration}}
<div>
<span class="body2">Duration: </span><span>{{duration}}</span>
</div>
{{/if}}
</div>
<div class="pre-wrap">{{evaluateString charId description}}</div>
<div>{{#markdown}}{{evaluateString charId description}}{{/markdown}}</div>
{{> attacksViewList charId=charId parentId=_id}}
</template>
<template name="spellEdit">
@@ -126,4 +135,5 @@
<textarea id="descriptionInput" placeholder value={{description}}></textarea>
</paper-autogrow-textarea>
</paper-input-decorator>
{{> attackEditList parentId=_id parentCollection="Spells" charId=charId enabled=true name=name}}
</template>

View File

@@ -20,7 +20,7 @@
{{/if}}
</div>
<hr class="vertMargin">
<div class="pre-wrap">{{evaluateString charId description}}</div>
<div>{{#markdown}}{{evaluateString charId description}}{{/markdown}}</div>
</div>
{{else}}
<!--Name-->

View File

@@ -1,7 +1,7 @@
<template name="spells">
<div fit>
<div id="spells" class="scroll-y" fit>
<div style="padding: 4px;"
<div style="padding: 4px;"
layout horizontal start wrap>
{{#if hasSlots}}
<paper-shadow class="card"
@@ -72,6 +72,7 @@
<core-tooltip label="Change prepared spells"
position="left">
<paper-icon-button class="prepSpells"
disabled={{#unless canEditCharacter charId}}true{{/unless}}
icon="book">
</paper-icon-button>
</core-tooltip>
@@ -91,7 +92,7 @@
<div class="tall spell item"
hero-id="main" {{detailHero}}
layout horizontal center>
<core-icon icon="social:whatshot"
<core-icon icon="social:whatshot"
style="color: {{hexColor color}};
margin-right: 16px;"
></core-icon>
@@ -143,4 +144,4 @@
</core-tooltip>
{{/fabMenu}}
{{/if}}
</template>
</template>

View File

@@ -84,39 +84,35 @@ Template.spells.helpers({
},
cantCast: function(level, char){
for (var i = level; i <= 9; i++){
if (char.attributeValue("level" + i + "SpellSlots") > 0){
if (Characters.calculate.attributeValue(char._id, "level" + i + "SpellSlots") > 0){
return false;
}
}
return true;
},
baseSlots: function(char){
return char.attributeBase("level" + this.level + "SpellSlots");
},
slots: function(char){
return char.attributeValue("level" + this.level + "SpellSlots");
},
showSlots: function(char){
return this.level && char.attributeBase("level" + this.level + "SpellSlots");
return this.level && Characters.calculate.attributeBase(
char._id, "level" + this.level + "SpellSlots"
);
},
hasSlots: function(){
for (var i = 1; i <= 9; i += 1){
if (this.attributeBase("level" + i + "SpellSlots")){
if (Characters.calculate.attributeBase(this._id, "level" + i + "SpellSlots")){
return true;
}
}
return false;
},
slotBubbles: function(char){
var baseSlots = char.attributeBase("level" + this.level + "SpellSlots");
var currentSlots = char.attributeValue("level" + this.level + "SpellSlots");
var baseSlots = Characters.calculate.attributeBase(char._id, "level" + this.level + "SpellSlots");
var currentSlots = Characters.calculate.attributeValue(char._id, "level" + this.level + "SpellSlots");
var slotsUsed = baseSlots - currentSlots;
var bubbles = [];
var i;
for (i = 0; i < currentSlots; i++){
bubbles.push({
icon: "radio-button-on",
disabled: i !== currentSlots - 1, //last full slot not disabled
disabled: i !== currentSlots - 1 || !canEditCharacter(char._id), //last full slot not disabled
attribute: "level" + this.level + "SpellSlots",
charId: char._id,
});
@@ -124,7 +120,7 @@ Template.spells.helpers({
for (i = 0; i < slotsUsed; i++){
bubbles.push({
icon: "radio-button-off",
disabled: i !== 0, //first empty slot not disabled
disabled: i !== 0 || !canEditCharacter(char._id), //first empty slot not disabled
attribute: "level" + this.level + "SpellSlots",
charId: char._id,
});
@@ -143,15 +139,15 @@ Template.spells.events({
var char = Characters.findOne(this.charId);
if (event.currentTarget.icon === "radio-button-off"){
if (
char.attributeValue(this.attribute) <
char.attributeBase(this.attribute)
Characters.calculate.attributeValue(char._id, this.attribute) <
Characters.calculate.attributeBase(char._id, this.attribute)
){
modifier = {$inc: {}};
modifier.$inc[this.attribute + ".adjustment"] = 1;
Characters.update(this.charId, modifier, {validate: false});
}
} else {
if (char.attributeValue(this.attribute) > 0){
if (Characters.calculate.attributeValue(char._id, this.attribute) > 0){
modifier = {$inc: {}};
modifier.$inc[this.attribute + ".adjustment"] = -1;
Characters.update(this.charId, modifier, {validate: false});

View File

@@ -1,14 +1,16 @@
<template name="abilityMiniCard">
<paper-shadow class="card abilityMiniCard clickable"
<div>
<paper-shadow class="card abilityMiniCard clickable"
hero-id="main" {{detailHero ability ../_id}}
layout horizontal>
<div class="left white-text {{color}}"
hero-id="toolbar" {{detailHero ability ../_id}}>
<div class="display1">{{../attributeValue ability}}</div>
<div class="title">{{../abilityMod ability}}</div>
<div class="display1">{{characterCalculate "attributeValue" ../_id ability}}</div>
<div class="title">{{abilityMod}}</div>
</div>
<div class="right subhead" layout horizontal center>
{{title}}
</div>
</paper-shadow>
</div>
</template>

View File

@@ -0,0 +1,9 @@
Template.abilityMiniCard.helpers({
abilityMod: function() {
return signedString(
Characters.calculate.abilityMod(
Template.parentData()._id, this.ability
)
);
}
});

View File

@@ -1,9 +1,11 @@
Template.addTHPDialog.events({
"tap #addButton": function(event, instance){
var max = +instance.find("#quantityInput").value;
if (!max || max < 0) max = 0;
TemporaryHitPoints.insert({
charId: this.charId,
name: instance.find("#nameInput").value,
maximum: +instance.find("#quantityInput").value,
maximum: max,
deleteOnZero: !!instance.find("#deleteWhenZeroCheckbox").checked,
});
}

View File

@@ -106,10 +106,8 @@ Template.attributeDialogView.helpers({
return a || b || c;
},
adjustment: function(){
var char = Characters.findOne(this.charId);
if (!char) return;
var value = char.attributeValue(this.statName);
var base = char.attributeBase(this.statName);
var value = Characters.calculate.attributeValue(this.charId, this.statName);
var base = Characters.calculate.attributeBase(this.charId, this.statName);
return value - base;
},
baseEffects: function(){
@@ -138,14 +136,10 @@ Template.attributeDialogView.helpers({
);
},
attributeBase: function(){
var char = Characters.findOne(this.charId);
if (!char) throw "character is " + char;
return char.attributeBase(this.statName);
return Characters.calculate.attributeBase(this.charId, this.statName);
},
attributeValue: function() {
var char = Characters.findOne(this.charId);
if (!char) throw "character is " + char;
return char.attributeValue(this.statName);
return Characters.calculate.attributeValue(this.charId, this.statName);
},
sourceName: function(){
if (this.parent.group === "racial"){

View File

@@ -2,27 +2,27 @@
<table class="carryCapacityTable strengthTable">
<tr>
<td>Encumbered</td>
<td>&gt;{{evaluate charId "strength * 5"}}lbs</td>
<td>&gt;{{evaluate charId "strength * 5 * carryMultiplier"}}lbs</td>
<td class="caption">Variant rule, encumbered characters move 10 feet slower</td>
</tr>
<tr>
<td>Heavily encumbered</td>
<td>&gt;{{evaluate charId "strength * 10"}}lbs</td>
<td>&gt;{{evaluate charId "strength * 10 * carryMultiplier"}}lbs</td>
<td class="caption">
Variant rule, heavily encumbered characters move 20 feet slower and have disadvantage on ability checks, attack rolls, and saving thows that use Strength, Dexterity, or Constitution
</td>
</tr>
<tr>
<td>Over Encumbered</td>
<td>&gt;{{evaluate charId "strength * 15"}}lbs</td>
<td>&gt;{{evaluate charId "strength * 15 * carryMultiplier"}}lbs</td>
<td class="caption">
Characters that can only just lift, push or drag their current load can only move at 5 feet.
</td>
</tr>
<tr>
<td>Push, drag or lift maximum</td>
<td>{{evaluate charId "strength * 30"}}lbs</td>
<td>{{evaluate charId "strength * 30 * carryMultiplier"}}lbs</td>
<td class="caption"></td>
</tr>
</table>
</template>
</template>

View File

@@ -1,4 +1,4 @@
.healthCard paper-slider{
.healthCard paper-diff-slider{
width: 100%;
margin-right: 8px;
}

View File

@@ -1,43 +1,60 @@
<template name="healthCard">
<paper-shadow class="card container healthCard"
hero-id="main" {{detailHero "hitPoints" _id}}
<paper-shadow class="card container healthCard"
hero-id="main" {{detailHero "hitPoints" _id}}
layout horizontal wrap>
<div class="green white-text subhead left"
<div class="green white-text subhead left"
hero-id="toolbar" {{detailHero "hitPoints" _id}}
layout vertical center center-justified>
<div class="hitPointTitle clickable">Hit Points</div>
<paper-icon-button class="white54" id="addTempHP" icon="add"></paper-icon-button>
<paper-icon-button class="white54"
id="addTempHP"
icon="add"
disabled={{#unless canEditCharacter _id}}true{{/unless}}>
</paper-icon-button>
</div>
<div class="right" flex layout vertical center-justified style="min-width: 180px;">
<div layout horizontal>
<paper-slider id="hitPointSlider"
value={{attributeValue "hitPoints"}}
max={{attributeBase "hitPoints"}}
editable pin
role="slider"
></paper-slider>
<paper-diff-slider id="hitPointSlider"
value={{characterCalculate "attributeValue" _id "hitPoints"}}
max={{characterCalculate "attributeBase" _id "hitPoints"}}
editable pin
disabled={{#unless canEditCharacter _id}}true{{/unless}}
role="slider">
</paper-diff-slider>
</div>
{{#each tempHitPoints}}
<div>
{{name}}
<div layout horizontal>
<paper-slider class="tempHitPointSlider"
<paper-diff-slider class="tempHitPointSlider"
value={{left}}
max={{maximum}}
editable pin
role="slider"
flex
></paper-slider>
{{#unless left}}{{#unless deleteOnZero}}
></paper-diff-slider>
{{#unless left}}
<paper-icon-button class="deleteTHP" icon="delete"></paper-icon-button>
{{/unless}}{{/unless}}
{{/unless}}
</div>
</div>
{{/each}}
<div class="caption">
{{#if multipliers.immunities.length}} <div>Immune: {{#each multipliers.immunities}} {{name}} {{/each}}</div>{{/if}}
{{#if multipliers.resistances.length}}<div>Resistance: {{#each multipliers.resistances}} {{name}} {{/each}}</div>{{/if}}
{{#if multipliers.weaknesses.length}} <div>Weakness: {{#each multipliers.weaknesses}} {{name}} {{/each}}</div>{{/if}}
{{#if multipliers.immunities.length}}
<div>
Immune: {{#each multipliers.immunities}} {{name}} {{/each}}
</div>
{{/if}}
{{#if multipliers.resistances.length}}
<div>
Resistance: {{#each multipliers.resistances}} {{name}} {{/each}}
</div>
{{/if}}
{{#if multipliers.weaknesses.length}}
<div>
Weakness: {{#each multipliers.weaknesses}} {{name}} {{/each}}
</div>
{{/if}}
</div>
{{#if showDeathSave}}
{{#with deathSaveObject}}

View File

@@ -3,7 +3,7 @@ Template.healthCard.helpers({
return TemporaryHitPoints.find({charId: this._id});
},
showDeathSave: function(){
return this.attributeValue("hitPoints") <= 0;
return Characters.calculate.attributeValue(this._id, "hitPoints") <= 0;
},
deathSaveObject: function(){
var char = Characters.findOne(this._id, {fields: {deathSave: 1}});
@@ -27,21 +27,20 @@ Template.healthCard.helpers({
return this.fail >= 3;
},
multipliers: function(){
var char = Characters.findOne(this._id, {fields: {_id: 1}});
var multipliers = [
{name: "Acid", value: char.attributeValue("acidMultiplier", 1)},
{name: "Bludgeoning", value: char.attributeValue("bludgeoningMultiplier", 1)},
{name: "Cold", value: char.attributeValue("coldMultiplier", 1)},
{name: "Fire", value: char.attributeValue("fireMultiplier", 1)},
{name: "Force", value: char.attributeValue("forceMultiplier", 1)},
{name: "Lightning", value: char.attributeValue("lightningMultiplier", 1)},
{name: "Necrotic", value: char.attributeValue("necroticMultiplier", 1)},
{name: "Piercing", value: char.attributeValue("piercingMultiplier", 1)},
{name: "Poison", value: char.attributeValue("poisonMultiplier", 1)},
{name: "Psychic", value: char.attributeValue("psychicMultiplier", 1)},
{name: "Radiant", value: char.attributeValue("radiantMultiplier", 1)},
{name: "Slashing", value: char.attributeValue("slashingMultiplier", 1)},
{name: "Thunder", value: char.attributeValue("thunderMultiplier", 1)},
{name: "Acid", value: Characters.calculate.attributeValue(this._id, "acidMultiplier")},
{name: "Bludgeoning", value: Characters.calculate.attributeValue(this._id, "bludgeoningMultiplier")},
{name: "Cold", value: Characters.calculate.attributeValue(this._id, "coldMultiplier")},
{name: "Fire", value: Characters.calculate.attributeValue(this._id, "fireMultiplier")},
{name: "Force", value: Characters.calculate.attributeValue(this._id, "forceMultiplier")},
{name: "Lightning", value: Characters.calculate.attributeValue(this._id, "lightningMultiplier")},
{name: "Necrotic", value: Characters.calculate.attributeValue(this._id, "necroticMultiplier")},
{name: "Piercing", value: Characters.calculate.attributeValue(this._id, "piercingMultiplier")},
{name: "Poison", value: Characters.calculate.attributeValue(this._id, "poisonMultiplier")},
{name: "Psychic", value: Characters.calculate.attributeValue(this._id, "psychicMultiplier")},
{name: "Radiant", value: Characters.calculate.attributeValue(this._id, "radiantMultiplier")},
{name: "Slashing", value: Characters.calculate.attributeValue(this._id, "slashingMultiplier")},
{name: "Thunder", value: Characters.calculate.attributeValue(this._id, "thunderMultiplier")},
];
multipliers = _.groupBy(multipliers, "value");
return {
@@ -55,7 +54,8 @@ Template.healthCard.helpers({
Template.healthCard.events({
"change #hitPointSlider": function(event){
var value = event.currentTarget.value;
var adjustment = value - this.attributeBase("hitPoints");
var base = Characters.calculate.attributeBase(this._id, "hitPoints")
var adjustment = value - base;
Characters.update(this._id, {$set: {"hitPoints.adjustment": adjustment}});
//reset the death saves if we are gaining HP
if (value > 0)

View File

@@ -1,14 +1,15 @@
<template name="hitDice">
{{#if ../attributeBase name}}
<paper-shadow class="card hit-dice" hero-id="main"
{{detailHero name ../_id}}
{{#if characterCalculate "attributeBase" ../_id name}}
<div>
<paper-shadow class="card hit-dice" hero-id="main"
{{detailHero name ../_id}}
layout horizontal>
<div class="left green display1 white-text"
<div class="left green display1 white-text"
hero-id="toolbar" {{detailHero name ../_id}}
layout horizontal>
<div>
<paper-icon-button class="resourceUp"
icon="arrow-drop-up"
<paper-icon-button class="resourceUp"
icon="arrow-drop-up"
disabled={{cantIncrement}}>
</paper-icon-button>
<paper-icon-button class="resourceDown"
@@ -18,10 +19,10 @@
</div>
<div class="resourceValue" layout vertical center>
<div>
{{../attributeValue name}}
{{characterCalculate "attributeValue" ../_id name}}
</div>
<div class="title white-text">
d{{diceNum}} {{../abilityMod "constitution"}}
d{{diceNum}} {{conMod}}
</div>
</div>
</div>
@@ -29,5 +30,6 @@
Hit Dice
</div>
</paper-shadow>
</div>
{{/if}}
</template>

View File

@@ -1,25 +1,33 @@
Template.hitDice.helpers({
cantIncrement: function(){
var valueSmallerThanBase = this.char.attributeValue(this.name) <
this.char.attributeBase(this.name);
return !valueSmallerThanBase;
var value = Characters.calculate.attributeValue(this.char._id, this.name);
var base = Characters.calculate.attributeBase(this.char._id, this.name);
return value >= base || !canEditCharacter(this.char._id);
},
cantDecrement: function(){
var valuePositive = this.char.attributeValue(this.name) > 0;
return !valuePositive;
var value = Characters.calculate.attributeValue(this.char._id, this.name);
return value <= 0 || !canEditCharacter(this.char._id);
},
conMod: function(){
return signedString(
Characters.calculate.abilityMod(this.char._id, "constitution")
);
},
});
Template.hitDice.events({
"tap .resourceUp": function(event){
if (this.char.attributeValue(this.name) < this.char.attributeBase(this.name)){
var value = Characters.calculate.attributeValue(this.char._id, this.name);
var base = Characters.calculate.attributeBase(this.char._id, this.name);
if (value < base){
var modifier = {$inc: {}};
modifier.$inc[this.name + ".adjustment"] = 1;
Characters.update(this.char._id, modifier, {validate: false});
}
},
"tap .resourceDown": function(event){
if (this.char.attributeValue(this.name) > 0){
var value = Characters.calculate.attributeValue(this.char._id, this.name);
if (value > 0){
var modifier = {$inc: {}};
modifier.$inc[this.name + ".adjustment"] = -1;
Characters.update(this.char._id, modifier, {validate: false});

View File

@@ -1,4 +1,4 @@
<!-- needs name, char, and skillName -->
<!-- needs name, charId, and skillName -->
<template name="skillDialog">
{{#baseDialog title=name class=color hideEdit=true}}
{{> skillDialogView}}
@@ -8,7 +8,7 @@
<template name="skillDialogView">
<div layout vertical center>
<div class="display2">
{{char.skillMod skillName}}
{{characterCalculate "skillMod" charId skillName}}
</div>
<div class="subhead">
<core-icon icon="{{profIcon}}" class="black54"></core-icon>
@@ -25,9 +25,9 @@
<table class="summaryTable">
<tr>
<td>{{abilityName}}</td>
<td>{{char.abilityMod ability}}</td>
<td>{{characterCalculate "abilityMod" charId ability}}</td>
</tr>
{{#if char.proficiency skillName}}
{{#if characterCalculate "proficiency" charId skillName}}
<tr>
<td>{{proficiencyValue}}</td>
<td>{{signedString profBonus}}</td>
@@ -59,7 +59,7 @@
{{/each}}
<tr class="body2">
<td>Total</td>
<td>{{char.skillMod skillName}}</td>
<td>{{characterCalculate "skillMod" charId skillName}}</td>
</tr>
</table>

View File

@@ -106,9 +106,7 @@ Template.skillDialogView.helpers({
return a || b || c;
},
profIcon: function(){
var char = Characters.findOne(this.charId);
if (!char) return;
var prof = char.proficiency(this.skillName);
var prof = Characters.calculate.proficiency(this.charId, this.skillName);
if (prof > 0 && prof < 1) return "image:brightness-2";
if (prof === 1) return "image:brightness-1";
if (prof > 1) return "av:album";
@@ -123,13 +121,13 @@ Template.skillDialogView.helpers({
profBonus: function(){
var char = Characters.findOne(this.charId);
if (!char) return;
return char.proficiency(this.skillName) *
char.attributeValue("proficiencyBonus");
var prof = Characters.calculate.proficiency(this.charId, this.skillName);
var proficiencyBonus =
Characters.calculate.attributeValue(this.charId, "proficiencyBonus");
return prof * proficiencyBonus;
},
proficiencyValue: function(){
var char = Characters.findOne(this.charId);
if (!char) return;
var prof = char.proficiency(this.skillName);
var prof = Characters.calculate.proficiency(this.charId, this.skillName);
if (prof == 0.5) return "Half Proficiency";
if (prof == 1) return "Proficient";
if (prof == 2) return "Double Proficiency";
@@ -199,20 +197,21 @@ Template.skillDialogView.helpers({
return skill.ability;
},
abilityName: function(){
var opts = {fields: {}};
opts.fields[this.skillName] = 1;
var char = Characters.findOne(this.charId, opts);
if (!char) return;
var skill = char[this.skillName];
var skill = Characters.calculate.getField(this.charId, this.skillName);
if (!skill) return;
var ability = skill.ability;
return abilities[ability] && abilities[ability].name;
},
char: function(){
return Characters.findOne(this.charId, {fields:{_id: 1}});
},
sourceName: function(){
if (this.parent.collection === "Characters") return "inate";
if (this.parent.collection === "Characters"){
if (this.parent.group === "racial"){
return Characters.calculate.getField(this.charId, "race") || "Race";
}
if (this.parent.group === "background"){
return "Background";
}
return "Innate";
}
return this.getParent().name;
},
operationName: function(){

View File

@@ -8,7 +8,9 @@
{{#if failSkill}}
<div class="fail skill-mod">fail</div>
{{else}}
<div class="{{advantage}} skill-mod">{{../skillMod skill}}</div>
<div class="{{advantage}} skill-mod">
{{skillMod}}
</div>
{{/if}}
<div flex>
{{name}}
@@ -16,7 +18,7 @@
*
{{/if}}
{{#if showPassive}}
({{../passiveSkill skill}})
({{characterCalculate "passiveSkill" ../_id skill}})
{{/if}}
</div>
</div>

View File

@@ -1,13 +1,21 @@
Template.skillRow.helpers({
skillMod: function() {
return signedString(
Characters.calculate.skillMod(
Template.parentData()._id, this.skill
)
);
},
profIcon: function(){
var prof = Template.parentData(1).proficiency(this.skill);
var charId = Template.parentData()._id;
var prof = Characters.calculate.proficiency(charId, this.skill);
if (prof > 0 && prof < 1) return "image:brightness-2";
if (prof === 1) return "image:brightness-1";
if (prof > 1) return "av:album";
return "radio-button-off";
},
failSkill: function(){
var charId = Template.parentData(1)._id;
var charId = Template.parentData()._id;
return Effects.find({
charId: charId,
stat: this.skill,
@@ -16,12 +24,13 @@ Template.skillRow.helpers({
}).count();
},
advantage: function(){
var advantage = Template.parentData(1).advantage(this.skill);
var charId = Template.parentData()._id;
var advantage = Characters.calculate.advantage(charId, this.skill);
if (advantage > 0) return "advantage";
if (advantage < 0) return "disadvantage";
},
conditionalCount: function(){
var charId = Template.parentData(1)._id;
var charId = Template.parentData()._id;
return Effects.find({
charId: charId,
stat: this.skill,

View File

@@ -27,6 +27,7 @@
{{>hitDice name="d10HitDice" diceNum="10" char=this}}
{{>hitDice name="d12HitDice" diceNum="12" char=this}}
<!--Saving Throws-->
<div>
<paper-shadow class="card">
<div class="top white subhead">
Saving Throws
@@ -40,7 +41,9 @@
{{> skillRow name="Charisma" skill="charismaSave"}}
</div>
</paper-shadow>
</div>
<!--Skills-->
<div>
<paper-shadow class="card">
<div class="top white subhead">
Skills
@@ -66,22 +69,25 @@
{{> skillRow name="Survival" skill="survival"}}
</div>
</paper-shadow>
</div>
</div>
</div>
</template>
<template name="statCard">
<div>
<paper-shadow class="card statCard clickable" hero-id="main" {{detailHero stat ../_id}} layout horizontal>
<div class="left display1 white-text {{color}}"
hero-id="toolbar" {{detailHero stat ../_id}}>
{{#if isSkill}}
{{../skillMod stat}}
{{prefix}}{{skillMod}}
{{else}}
{{prefix}}{{../attributeValue stat}}
{{prefix}}{{characterCalculate "attributeValue" ../_id stat}}
{{/if}}
</div>
<div class="right subhead" flex horizontal layout center>
{{name}}
</div>
</paper-shadow>
</div>
</template>

View File

@@ -67,6 +67,12 @@ Template.stats.events({
},
});
Template.stats.helpers({
Template.statCard.helpers({
skillMod: function() {
return signedString(
Characters.calculate.skillMod(
Template.parentData()._id, this.stat
)
);
},
});

View File

@@ -1,5 +1,5 @@
<template name="characterList">
<core-toolbar class="blue-grey white-text">
<core-toolbar class="app-grey white-text">
<core-icon-button icon="menu" core-drawer-toggle></core-icon-button>
<div flex>
Characters

View File

@@ -13,7 +13,10 @@ Template.characterSideList.helpers({
{owner: userId},
]
},
{fields: {name: 1}}
{
fields: {name: 1},
sort: {name: 1},
}
);
}
});

View File

@@ -1,11 +1,10 @@
<template name="guide">
<core-toolbar class="app-grey white-text">
<core-icon-button icon="menu" core-drawer-toggle></core-icon-button>
<div flex>Guide</div>
</core-toolbar>
<div layout vertical center>
<paper-shadow class="wallOfText card" style="padding: 32px; max-width: 800px;">
<h1>Dicecloud Beta</h1>
<p>Welcome to the Dicecloud beta.</p>
<p>The beta is going to start with just the character sheet. You can play D&amp;D without minis and maps, without a pre-written adventure, you can play without a lot of things, but the character sheet is necessary. So I'm starting here and working my way outwards.</p>
<p>Leave any comments, feedback and suggestions on <a href="http://reddit.com/r/dicecloud">this subreddit</a>. If you've never used reddit before, all you need is a username and password to sign up. So it should be pretty accessible.</p>
<p>If you'd like to see a list of known issues and upcoming features, check out the <a href="https://trello.com/b/94M0SCnq/dicecloud-roadmap">DiceCloud Roadmap</a>.</p>
<h2>Character Sheet Philosophy</h2>
<p>Setting up your character on Dicecloud is going to take you a little longer than just filling it in on a paper character sheet would have. The goal of using an online sheet is to make actually playing the game more streamlined, and ultimately more fun. So putting a little extra effort into setting up your character now will pay off over and over again once you're playing.</p>
<p>The idea is to track where each number comes from, and allow you to easily make changes on the fly.</p>

View File

@@ -1,11 +1,9 @@
<template name="home">
<core-toolbar class="blue-grey white-text">
<core-toolbar class="app-grey white-text">
<core-icon-button icon="menu" core-drawer-toggle></core-icon-button>
<div flex>
DiceCloud
Home
</div>
</core-toolbar>
<div class="scroll-y" style="padding: 16px" fit>
{{> guide}}
</div>
{{> intro}}
</template>

View File

@@ -1,25 +1,15 @@
Template.home.helpers({
characterDetails: function(){
var char = Characters.findOne(
this._id,
{fields: {name: 1, gender: 1, alignment: 1, race:1}}
);
char.title = char.name;
char.field = "base";
char.color = "d";
char.class = "characterCard";
return char;
}
selectedTab: function(){
return Session.get("homePage.selectedTab");
},
});
Template.home.events({
"tap .characterCard": function(event, instance){
Router.go("characterSheet", {_id: this._id});
"core-animated-pages-transition-end .tabPages": function(event) {
event.stopPropagation();
},
"tap #addCharacter": function(event, template) {
Characters.insert({owner: Meteor.userId()});
},
"tap #deleteChar": function(event, template){
Characters.remove(this._id);
"tap .homeTabs paper-tab": function(event, instance){
Session.set("homePage.selectedTab",
event.currentTarget.getAttribute("name"));
},
});

View File

@@ -0,0 +1,98 @@
<template name="intro">
<div class="intro">
<div class="section white-text" style="background: #282828">
<div class="display2">
Dice Cloud
</div>
<img style="width:130px; height:130px; background-color: #282828;"
src="/crown-dice-logo-cropped-transparent.png">
<div class="display1">
Unofficial Online Realtime D&amp;D 5e App
</div>
<h2>
Spend less time shuffling paper and more time playing the game
</h2>
{{#unless currentUser}}
<div layout horizontal around-justified wrap>
<paper-button class="red white-text signInButton"
style="margin: 16px;"
raised>
Sign In
</paper-button>
<paper-button class="red white-text signUpButton"
style="margin: 16px;"
raised>
Sign Up
</paper-button>
</div>
{{else}}
<div style="padding-bottom: 0;"></div>
{{/unless}}
</div>
<div class="section" style="background-color: #e9e9e9;">
<div>
<div class="display1">Character Sheet Open Beta</div>
<h2 style="margin-bottom: 16px;">
Check out the example characters
</h2>
<div layout horizontal around-justified wrap>
<paper-shadow class="card characterCard ssArcher clickable"
z="2">
<div class="top subhead green white-text">
<div class="subhead" flex>
Starter Set Archer
</div>
</div>
<div class="bottom text">Lawful Good Human</div>
</paper-shadow>
<paper-shadow class="card characterCard ssWizard clickable"
z="2">
<div class="top subhead deep-purple white-text">
<div class="subhead" flex>
Starter Set Wizard
</div>
</div>
<div class="bottom text">Chaotic Good High Elf</div>
</paper-shadow>
</div>
</div>
</div>
<div class="section white-text" style="background: #282828">
<div class="columns" layout horizontal around-justified wrap>
<div>
<h1>Check out the guide</h1>
<p>
Learn how your class gives you features, those features have effects,
and those effects determine your stats.
<paper-button class="guideButton">View Guide</paper-button>
</p>
</div>
<div>
<h1>
Discuss
</h1>
<p>
On the official subreddit
<paper-button class="redditButton">
<a href="http://www.reddit.com/r/dicecloud/">
/r/dicecloud
</a>
</paper-button>
</p>
</div>
<div>
<h1>
Get involved
</h1>
<p>Shape upcoming features and track bugs on the Dice Cloud Trello board
<paper-button class="trelloButton">
<a href="https://trello.com/b/94M0SCnq/dicecloud-roadmap">
Trello Roadmap
</a>
</paper-button>
</p>
</div>
</div>
</div>
</div>
</template>

View File

@@ -0,0 +1,17 @@
Template.intro.events({
"tap .signInButton": function() {
Router.go("/sign-in");
},
"tap .signUpButton": function() {
Router.go("/sign-up");
},
"tap .ssArcher": function() {
Router.go("/character/yBWwt5XQTTHZiRQxq");
},
"tap .ssWizard": function() {
Router.go("/character/KxHKskm22fS2Xogah");
},
"tap .guideButton": function() {
Router.go("/guide");
},
});

View File

@@ -0,0 +1,33 @@
.intro {
.section {
width: 100%;
min-height: 200px;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
padding-top: 24px;
padding-bottom: 24px;
& > div, & > h2 {
padding: 32px;
.display1 {
margin-bottom: 16px;
}
}
.columns > div{
max-width: 300px;
padding: 16px;
text-align: center;
paper-button {
color: #FF5252;
}
}
}
paper-button {
min-width: 200px;
a {
color: inherit;
text-decoration: inherit;
}
}
}

View File

@@ -1,42 +0,0 @@
<!--core components-->
<link rel="import" href="/components/core-animated-pages/core-animated-pages.html">
<link rel="import" href="/components/core-animated-pages/transitions/cross-fade.html">
<link rel="import" href="/components/core-animated-pages/transitions/hero-transition.html">
<link rel="import" href="/components/core-animated-pages/transitions/slide-from-right.html">
<link rel="import" href="/components/core-icons/av-icons.html">
<link rel="import" href="/components/core-icons/core-icons.html">
<link rel="import" href="/components/core-icons/editor-icons.html">
<link rel="import" href="/components/core-icons/image-icons.html">
<link rel="import" href="/components/core-icons/social-icons.html">
<link rel="import" href="/components/core-item/core-item.html">
<link rel="import" href="/components/core-menu/core-menu.html">
<link rel="import" href="/components/core-scaffold/core-scaffold.html">
<link rel="import" href="/components/core-transition/core-transition.html">
<!--paper components-->
<link rel="import" href="/components/paper-button/paper-button.html">
<link rel="import" href="/components/paper-checkbox/paper-checkbox.html">
<link rel="import" href="/components/paper-dialog/paper-action-dialog.html">
<link rel="import" href="/components/paper-dialog/paper-dialog.html">
<link rel="import" href="/components/paper-dialog/paper-dialog-transition.html">
<link rel="import" href="/components/paper-dropdown/paper-dropdown.html">
<link rel="import" href="/components/paper-fab/paper-fab.html">
<link rel="import" href="/components/paper-fab-menu/paper-fab-menu.html">
<link rel="import" href="/components/paper-icon-button/paper-icon-button.html">
<link rel="import" href="/components/paper-input/paper-autogrow-textarea.html">
<link rel="import" href="/components/paper-input/paper-input.html">
<link rel="import" href="/components/paper-input/paper-input-decorator.html">
<link rel="import" href="/components/paper-item/paper-item.html">
<link rel="import" href="/components/paper-menu-button/paper-menu-button.html">
<link rel="import" href="/components/paper-radio-button/paper-radio-button.html">
<link rel="import" href="/components/paper-radio-group/paper-radio-group.html">
<link rel="import" href="/components/paper-shadow/paper-shadow.html">
<link rel="import" href="/components/paper-spinner/paper-spinner.html">
<link rel="import" href="/components/paper-tabs/paper-tabs.html">
<link rel="import" href="/components/paper-toast/paper-toast.html">
<link rel="import" href="/components/paper-toggle-button/paper-toggle-button.html">
<!--custom components-->
<link rel="import" href="/custom_components/paper-dropdown-menu/paper-dropdown-menu.html">
<link rel="import" href="/custom_components/paper-slider-diff/paper-slider.html">
<link rel="import" href="/custom_components/swipe-detect/swipe-detect.html">

View File

@@ -3,7 +3,8 @@
<core-header-panel drawer navigation flex mode="seamed" class="white">
<div id="accountSummary">
{{#if currentUser}}
<div id="profileLink" style="text-decoration: underline; cursor: pointer;">
<div id="profileLink"
style="text-decoration: underline; cursor: pointer; font-size: 16px;">
{{profileLink}}
</div>
{{else}}
@@ -13,6 +14,7 @@
<div id="navPanel">
<core-item id="homeNav" icon="home" label="Home"></core-item>
{{> characterSideList}}
<core-item id="guide" icon="social:school" label="Guide"></core-item>
<core-item id="feedback" icon="bug-report" label="Send Feedback"></core-item>
<core-item id="changeLog" icon="list" label="Change Log"></core-item>
</div>
@@ -23,7 +25,7 @@
transitions="hero-transition cross-fade"
selected={{globalDetailSelected}}>
<section id="mainContentSection" class={{notSelected}}>
<core-header-panel fit mode="seamed">
<core-header-panel fit mode="standard">
{{> yield}}
</core-header-panel>
<div>

View File

@@ -41,4 +41,8 @@ Template.layout.events({
Router.go("changeLog");
instance.find("core-drawer-panel").closeDrawer();
},
"tap #guide": function(event, instance) {
Router.go("guide");
instance.find("core-drawer-panel").closeDrawer();
},
});

View File

@@ -1,4 +1,5 @@
.bigSpinner {
width: 100px;
height: 100px;
margin-bottom: 16px;
}

View File

@@ -1,9 +1,12 @@
<template name="loading">
<core-toolbar class="blue-grey white-text">
<core-toolbar class="app-grey white-text">
<core-icon-button icon="menu" core-drawer-toggle></core-icon-button>
</core-toolbar>
<div fit layout vertical center center-justified>
<paper-spinner class="bigSpinner" active></paper-spinner>
<div class="subhead">{{randomHint}}</div>
<div class="subhead"
style="margin-left: 16px;
margin-right: 16px;
text-align: center;">{{randomHint}}</div>
</div>
</template>

View File

@@ -1,5 +1,5 @@
<template name="changeLog">
<core-toolbar class="blue-grey white-text">
<core-toolbar class="app-grey white-text">
<core-icon-button icon="menu" core-drawer-toggle></core-icon-button>
<div flex>
Change Log

View File

@@ -1,10 +1,14 @@
<template name="notFound">
<div layout vertical center center-justified fit>
<h2>The data for the page you requested could not be found.</h2>
<core-toolbar class="app-grey white-text">
<core-icon-button icon="menu" core-drawer-toggle></core-icon-button>
</core-toolbar>
<div layout vertical center center-justified fit
style="padding: 16px; text-align: center;">
<h2 style="margin-bottom: 12px;">The data for the page you requested could not be found.</h2>
{{#if currentUser}}
<h2>It might not exist, or you might not have permission to view it.</h2>
<h3>It might not exist, or you might not have permission to view it.</h3>
{{else}}
<h2>Perhaps you need to sign in first:</h2>
<h3>Perhaps you need to sign in first:</h3>
{{atForm}}
{{/if}}
</div>

View File

@@ -13,22 +13,22 @@
role="button"
tabindex="0"
icon="delete"
aria-label="Delete Feature"
noink></paper-icon-button>
aria-label="Delete Feature">
</paper-icon-button>
{{/unless}}
{{#unless hideColor}}
{{> colorDropdown}}
{{/unless}}
<paper-icon-button id="doneEditingButton"
icon="done"
aria-label="Delete Feature"
noink></paper-icon-button>
aria-label="Delete Feature">
</paper-icon-button>
{{else}}
{{#if showEdit}}
<paper-icon-button id="editButton"
icon="create"
aria-label="Delete Feature"
noink></paper-icon-button>
aria-label="Delete Feature">
</paper-icon-button>
{{/if}}
{{/if}}
</div>

View File

@@ -9,19 +9,11 @@ Template.baseDialog.onRendered(function(){
Template.baseDialog.helpers({
editing: function(){
return Template.instance().editing.get();
return Template.instance().editing.get() && canEditCharacter(Template.parentData().charId);
},
showEdit: function() {
if (this.hideEdit) return false;
var charId = Template.parentData().charId;
if (charId){
var char = Characters.findOne(charId);
var userId = Meteor.userId();
if (char && userId)
return char.owner === userId ||
_.contains(char.writers, userId);
}
return true;
return canEditCharacter(Template.parentData().charId);
},
});

View File

@@ -1,5 +1,5 @@
<template name="titledAtForm">
<core-toolbar class="blue-grey white-text">
<core-toolbar class="app-grey white-text">
<core-icon-button icon="menu" core-drawer-toggle></core-icon-button>
<div flex>

45
rpg-docs/config.vulcanize Normal file
View File

@@ -0,0 +1,45 @@
{
"imports": [
"/components/core-animated-pages/core-animated-pages.html",
"/components/core-animated-pages/transitions/cross-fade.html",
"/components/core-animated-pages/transitions/hero-transition.html",
"/components/core-animated-pages/transitions/slide-from-right.html",
"/components/core-icons/av-icons.html",
"/components/core-icons/core-icons.html",
"/components/core-icons/editor-icons.html",
"/components/core-icons/image-icons.html",
"/components/core-icons/social-icons.html",
"/components/core-image/core-image.html",
"/components/core-item/core-item.html",
"/components/core-menu/core-menu.html",
"/components/core-scaffold/core-scaffold.html",
"/components/core-transition/core-transition.html",
"/components/paper-button/paper-button.html",
"/components/paper-checkbox/paper-checkbox.html",
"/components/paper-dialog/paper-action-dialog.html",
"/components/paper-dialog/paper-dialog.html",
"/components/paper-dialog/paper-dialog-transition.html",
"/components/paper-dropdown/paper-dropdown.html",
"/components/paper-fab/paper-fab.html",
"/components/paper-fab-menu/paper-fab-menu.html",
"/components/paper-icon-button/paper-icon-button.html",
"/components/paper-input/paper-autogrow-textarea.html",
"/components/paper-input/paper-input.html",
"/components/paper-input/paper-input-decorator.html",
"/components/paper-item/paper-item.html",
"/components/paper-menu-button/paper-menu-button.html",
"/components/paper-radio-button/paper-radio-button.html",
"/components/paper-radio-group/paper-radio-group.html",
"/components/paper-shadow/paper-shadow.html",
"/components/paper-spinner/paper-spinner.html",
"/components/paper-slider/paper-slider.html",
"/components/paper-tabs/paper-tabs.html",
"/components/paper-toast/paper-toast.html",
"/components/paper-toggle-button/paper-toggle-button.html",
"/custom_components/paper-dropdown-menu/paper-dropdown-menu.html",
"/custom_components/paper-diff-slider/paper-diff-slider.html",
"/custom_components/swipe-detect/swipe-detect.html"
]
}

View File

@@ -1,11 +1,10 @@
//evaluates a calculation string
evaluate = function(charId, string){
if (!string) return string;
var char = Characters.findOne(charId, {fields: {_id: 1}});
string = string.replace(/\b[a-z]+\b/gi, function(sub){
//fields
if (Schemas.Character.schema(sub)){
return char.fieldValue(sub);
return Characters.calculate.fieldValue(charId, sub);
}
//ability modifiers
var abilityMods = [
@@ -19,7 +18,7 @@ evaluate = function(charId, string){
if (_.contains(abilityMods, sub)){
var slice = sub.slice(0, -3);
try {
return char.abilityMod(slice);
return Characters.calculate.abilityMod(charId, slice);
} catch (e){
return sub;
}
@@ -33,7 +32,7 @@ evaluate = function(charId, string){
}
//character level
if (sub.toUpperCase() === "LEVEL"){
return char.level();
return Characters.calculate.level(charId);
}
return sub;
});
@@ -41,7 +40,6 @@ evaluate = function(charId, string){
var result = math.eval(string);
return result;
} catch (e){
console.log("Failed to evaluate ", string);
return string;
}
};

View File

@@ -1,4 +1,5 @@
preventLoop = function(inputFunction){
var self = this;
if (!_.isFunction(inputFunction)){
throw new Meteor.Error(
"Not a function",
@@ -9,23 +10,26 @@ preventLoop = function(inputFunction){
//if we try to visit the same argument twice before resolving its value
//we are in a dependency loop and need to GTFO
var visitedArgs = [];
return function(argument){
var value;
return function(){
var result;
var hash = _.reduce(arguments, function(memo, arg) {
return memo + arg;
}, "");
//we're still evaluating this attribute, must be in a loop
if (_.contains(visitedArgs, argument)) {
if (_.contains(visitedArgs, hash)) {
console.warn("dependency loop detected");
return NaN;
} else {
//push this skill to the list of visited skills
//push this hash to the list of visited hashes
//we can't visit it again unless it returns first
visitedArgs.push(argument);
visitedArgs.push(hash);
}
try {
value = inputFunction.call(this, argument);
result = inputFunction.apply(this, arguments);
} finally{
//this argument returns or fails, pull it from the array
visitedArgs = _.without(visitedArgs, argument);
//this hash returns or fails, pull it from the array
visitedArgs = _.without(visitedArgs, hash);
}
return value;
return result;
};
};

View File

@@ -1,8 +1,13 @@
Meteor.methods({
"getUserId": function(username){
if (!username) return;
regex = new RegExp("^" + username + "$", "i")
var user = Meteor.users.findOne(
{$or: [{username: username}, {"emails.address": username}]}
{$or: [
{username: username},
{"emails.address": regex},
{"services.google.email": regex},
]}
);
return user && user._id;
}

Some files were not shown because too many files have changed in this diff Show More