Merge pull request 'Custom stock files and data' (#11) from custom-stocks into main

Reviewed-on: #11
pull/17/head
commit 32c91f437d
  1. 12
      CHANGELOG.md
  2. 1
      Gemfile
  3. 2
      Gemfile.lock
  4. 16
      src/app.rb
  5. 1
      src/data/custom/.gitignore
  6. 551
      src/data/dark_elf/lifepaths.json
  7. 231
      src/data/dark_elf/resources.json
  8. 3837
      src/data/gold/lifepaths/dwarf.json
  9. 3969
      src/data/gold/lifepaths/elf.json
  10. 23373
      src/data/gold/lifepaths/man.json
  11. 3061
      src/data/gold/lifepaths/orc.json
  12. 3325
      src/data/gold/lifepaths/roden.json
  13. 1835
      src/data/gold/lifepaths/wolf.json
  14. 307
      src/data/gold/resources/dwarf.json
  15. 355
      src/data/gold/resources/elf.json
  16. 871
      src/data/gold/resources/man.json
  17. 425
      src/data/gold/resources/orc.json
  18. 281
      src/data/gold/resources/roden.json
  19. 87
      src/data/gold/resources/wolf.json
  20. 114
      src/data/gold/starting_stat_pts/dwarf.json
  21. 146
      src/data/gold/starting_stat_pts/elf.json
  22. 90
      src/data/gold/starting_stat_pts/man.json
  23. 98
      src/data/gold/starting_stat_pts/orc.json
  24. 74
      src/data/gold/starting_stat_pts/roden.json
  25. 58
      src/data/gold/starting_stat_pts/wolf.json
  26. 130
      src/data/gold/stocks/dwarf.json
  27. 161
      src/data/gold/stocks/elf.json
  28. 99
      src/data/gold/stocks/man.json
  29. 114
      src/data/gold/stocks/orc.json
  30. 90
      src/data/gold/stocks/roden.json
  31. 75
      src/data/gold/stocks/wolf.json
  32. 1151
      src/data/troll/lifepaths.json
  33. 117
      src/data/troll/resources.json
  34. 82
      src/data/troll/starting_stat_pts.json
  35. 100
      src/data/troll/stock.json
  36. 2330
      src/data/wizard/lifepaths.json
  37. 15
      src/lib/data.rb
  38. 27
      src/lib/data/custom.rb
  39. 8
      src/lib/data/dark_elf.rb
  40. 22
      src/lib/data/gold.rb
  41. 17
      src/lib/data/troll.rb
  42. 5
      src/lib/data/wizard.rb
  43. 34
      src/lib/stock.rb
  44. 47
      src/public/js/burning-serialize.js
  45. 205
      src/public/js/burning-service.js
  46. 452
      src/public/js/burning.js
  47. 4
      src/public/js/server_settings.js
  48. 9
      src/views/partials/main.erb
  49. 133
      tests/data/custom/test.lifepaths
  50. 25
      tests/data/custom/test.resources
  51. 39
      tests/data/custom/test.skills
  52. 95
      tests/data/custom/test.stock
  53. 55
      tests/data/custom/test.traits

@ -11,6 +11,16 @@ and this project adheres to [Semantic Versioning](semver).
- Custom upload for your own data files - Custom upload for your own data files
- Updates to Roden and Great Wolves files (currently the data comes from Monster Burner and not Codex) - Updates to Roden and Great Wolves files (currently the data comes from Monster Burner and not Codex)
## [3.0.0] - 2023-09-03
### Added
- Custom stocks can now be added to a server
- Stock data moved from code to dedicated data file
- Data files split into stock, lifepath, skills, and traits files, with designated extensions
- "Born" lifepaths with arbitrary names
### Fixed
- Spite shade calculation
## [2.3.0] - 2019-07-28 ## [2.3.0] - 2019-07-28
### Added ### Added
- Display emotional attribute traits on PDF - Display emotional attribute traits on PDF
@ -59,4 +69,4 @@ and this project adheres to [Semantic Versioning](semver).
[changelog]: https://keepachangelog.com/en/1.0.0/ [changelog]: https://keepachangelog.com/en/1.0.0/
[semver]: https://semver.org/spec/v2.0.0.html [semver]: https://semver.org/spec/v2.0.0.html

@ -5,6 +5,7 @@ gem 'sinatra'
gem 'sinatra-contrib' gem 'sinatra-contrib'
gem 'prawn' gem 'prawn'
gem 'prawn-templates' gem 'prawn-templates'
gem 'deep_merge', '~> 1.2', '>= 1.2.1'
group :development do group :development do
gem 'rerun' gem 'rerun'

@ -4,6 +4,7 @@ GEM
Ascii85 (1.1.0) Ascii85 (1.1.0)
afm (0.2.2) afm (0.2.2)
daemons (1.4.1) daemons (1.4.1)
deep_merge (1.2.2)
eventmachine (1.2.7) eventmachine (1.2.7)
ffi (1.15.5) ffi (1.15.5)
hashery (2.1.2) hashery (2.1.2)
@ -58,6 +59,7 @@ PLATFORMS
x86_64-linux x86_64-linux
DEPENDENCIES DEPENDENCIES
deep_merge (~> 1.2, >= 1.2.1)
prawn prawn
prawn-templates prawn-templates
rerun rerun

@ -49,24 +49,20 @@ get '/traits' do
json DATA[:traits] json DATA[:traits]
end end
get '/lifepaths/:stock' do get '/stocks' do
if DATA[:stocks].include? params['stock'] json DATA[:stocks]
json DATA[:lifepaths][params['stock']]
else
404
end
end end
get '/starting_stat_pts/:stock' do get '/lifepaths/:stock' do
if DATA[:stocks].include? params['stock'] if DATA[:stocks].keys.include? params['stock']
json DATA[:stat_pts][params['stock']] json DATA[:lifepaths][params['stock']]
else else
404 404
end end
end end
get '/resources/:stock' do get '/resources/:stock' do
if DATA[:stocks].include? params['stock'] if DATA[:stocks].keys.include? params['stock']
json DATA[:resources][params['stock']] json DATA[:resources][params['stock']]
else else
404 404

@ -1,296 +1,299 @@
{ {
"Path Of Spite Subsetting": { "stock": "elf",
"Griever": { "settings": {
"time": 3, "Path Of Spite Subsetting": {
"res": 0, "Griever": {
"skills": [ "time": 3,
[ "res": 0,
3, "skills": [
"Sorrow Of Truth", [
"Dark Elf-wise" 3,
] "Sorrow Of Truth",
], "Dark Elf-wise"
"traits": [ ]
1, ],
"Spite" "traits": [
]
},
"Wastrel": {
"time": 25,
"res": 3,
"skills": [
[
6,
"Scavenging",
"Brawling",
"Forest-wise",
"Wasteland-wise",
"Animal-wise"
]
],
"traits": [
2,
"Filthy",
"Feral Elf"
],
"requires": "Griever",
"requires_expr": [
"griever"
]
},
"Thief": {
"time": 18,
"res": 6,
"stat": [
[
1, 1,
"pm" "Spite"
] ]
], },
"skills": [ "Wastrel": {
[ "time": 25,
6, "res": 3,
"Lock Pick", "skills": [
"Stealthy", [
"Climbing", 6,
"Sleight Of Hand", "Scavenging",
"Dirge Of Night" "Brawling",
"Forest-wise",
"Wasteland-wise",
"Animal-wise"
]
],
"traits": [
2,
"Filthy",
"Feral Elf"
],
"requires": "Griever",
"requires_expr": [
"griever"
] ]
], },
"traits": [ "Thief": {
1, "time": 18,
"Thief" "res": 6,
], "stat": [
"requires": "Griever", [
"requires_expr": [ 1,
"griever" "pm"
] ]
}, ],
"Assassin": { "skills": [
"time": 15, [
"res": 6, 6,
"stat": [ "Lock Pick",
[ "Stealthy",
"Climbing",
"Sleight Of Hand",
"Dirge Of Night"
]
],
"traits": [
1, 1,
"p" "Thief"
] ],
], "requires": "Griever",
"skills": [ "requires_expr": [
[ "griever"
7,
"Intimidation",
"Poisons",
"Escape Artist",
"Knives",
"Garotte",
"Keen Of Terror"
]
],
"traits": [
1,
"Murderous",
"Callous",
"Cold Blooded"
],
"requires": "Griever",
"requires_expr": [
"griever"
]
},
"Stalker": {
"time": 20,
"res": 8,
"skills": [
[
8,
"Hunting",
"Elf-wise",
"Tracking",
"Trapper",
"Observation",
"Stealthy",
"Throwing",
"Javelin",
"Supplication To Shadows"
] ]
], },
"traits": [ "Assassin": {
1, "time": 15,
"Saturnine" "res": 6,
], "stat": [
"requires": "Griever", [
"requires_expr": [ 1,
"griever" "p"
] ]
}, ],
"Deceiver": { "skills": [
"time": 35, [
"res": 10, 7,
"stat": [ "Intimidation",
[ "Poisons",
"Escape Artist",
"Knives",
"Garotte",
"Keen Of Terror"
]
],
"traits": [
1, 1,
"m" "Murderous",
] "Callous",
], "Cold Blooded"
"skills": [ ],
[ "requires": "Griever",
7, "requires_expr": [
"Sleight Of Hand", "griever"
"Disguise",
"Inconspicuous",
"Rhyme Of The Unraveller"
] ]
], },
"traits": [ "Stalker": {
1, "time": 20,
"Deceptive" "res": 8,
], "skills": [
"requires": "Griever", [
"requires_expr": [ 8,
"griever" "Hunting",
] "Elf-wise",
}, "Tracking",
"Liar": { "Trapper",
"time": 25, "Observation",
"res": 8, "Stealthy",
"stat": [ "Throwing",
[ "Javelin",
"Supplication To Shadows"
]
],
"traits": [
1, 1,
"m" "Saturnine"
] ],
], "requires": "Griever",
"skills": [ "requires_expr": [
[ "griever"
6,
"Falsehood",
"Soothing Platitudes",
"Persuasion",
"Twisted Tongue"
] ]
], },
"traits": [ "Deceiver": {
1, "time": 35,
"Compulsive Liar" "res": 10,
], "stat": [
"requires": "Griever", [
"requires_expr": [ 1,
"griever" "m"
] ]
}, ],
"Siren": { "skills": [
"time": 55, [
"res": 20, 7,
"stat": [ "Sleight Of Hand",
[ "Disguise",
"Inconspicuous",
"Rhyme Of The Unraveller"
]
],
"traits": [
1, 1,
"pm" "Deceptive"
] ],
], "requires": "Griever",
"skills": [ "requires_expr": [
[ "griever"
9,
"Seduction",
"Etiquette",
"Persuasion",
"Soothing Platitudes",
"Gossip-wise",
"Fugue Of Discord",
"Litany Of Fools"
] ]
], },
"traits": [ "Liar": {
2, "time": 25,
"Charismatic", "res": 8,
"Femme Fatale/Homme Fatale" "stat": [
], [
"requires": "Assassin, Deceiver or Liar", 1,
"requires_expr": [ "m"
"assassin", ]
"deceiver", ],
"liar" "skills": [
] [
}, 6,
"Eremite": { "Falsehood",
"time": 150, "Soothing Platitudes",
"res": 15, "Persuasion",
"stat": [ "Twisted Tongue"
[ ]
],
"traits": [
1, 1,
"m" "Compulsive Liar"
] ],
], "requires": "Griever",
"skills": [ "requires_expr": [
[ "griever"
12,
"Philosophy",
"Ugly Truth",
"Obscure History",
"Symbology",
"Strategy",
"Elf-wise",
"Orc-wise",
"Dwarf-wise",
"Man-wise",
"Paean To The Dark Fire"
] ]
], },
"traits": [ "Siren": {
2, "time": 55,
"Remote", "res": 20,
"Cold" "stat": [
], [
"requires": "Siren, Wastrel or Stalker", 1,
"requires_expr": [ "pm"
"siren", ]
"wastrel", ],
"stalker" "skills": [
] [
}, 9,
"Recluse": { "Seduction",
"time": 225, "Etiquette",
"res": 25, "Persuasion",
"stat": [ "Soothing Platitudes",
[ "Gossip-wise",
1, "Fugue Of Discord",
"p" "Litany Of Fools"
]
],
"traits": [
2,
"Charismatic",
"Femme Fatale/Homme Fatale"
],
"requires": "Assassin, Deceiver or Liar",
"requires_expr": [
"assassin",
"deceiver",
"liar"
] ]
], },
"skills": [ "Eremite": {
[ "time": 150,
"res": 15,
"stat": [
[
1,
"m"
]
],
"skills": [
[
12,
"Philosophy",
"Ugly Truth",
"Obscure History",
"Symbology",
"Strategy",
"Elf-wise",
"Orc-wise",
"Dwarf-wise",
"Man-wise",
"Paean To The Dark Fire"
]
],
"traits": [
2, 2,
"Ancient History", "Remote",
"Dwarf-wise", "Cold"
"Elven Politics-wise",
"Cut Of The Quickened Mind"
], ],
[ "requires": "Siren, Wastrel or Stalker",
5, "requires_expr": [
"General" "siren",
"wastrel",
"stalker"
] ]
], },
"traits": [ "Recluse": {
1, "time": 225,
"Vengeful" "res": 25,
], "stat": [
"requires": "Eremite or any three Dark Elf lifepaths", [
"requires_expr": [ 1,
"+or", "p"
[ ]
"eremite" ],
"skills": [
[
2,
"Ancient History",
"Dwarf-wise",
"Elven Politics-wise",
"Cut Of The Quickened Mind"
],
[
5,
"General"
]
],
"traits": [
1,
"Vengeful"
], ],
[ "requires": "Eremite or any three Dark Elf lifepaths",
"+has_n_lifepaths_in", "requires_expr": [
3, "+or",
"path of spite subsetting:griever", [
"path of spite subsetting:wastrel", "eremite"
"path of spite subsetting:thief", ],
"path of spite subsetting:assassin", [
"path of spite subsetting:stalker", "+has_n_lifepaths_in",
"path of spite subsetting:deceiver", 3,
"path of spite subsetting:liar", "path of spite subsetting:griever",
"path of spite subsetting:siren" "path of spite subsetting:wastrel",
"path of spite subsetting:thief",
"path of spite subsetting:assassin",
"path of spite subsetting:stalker",
"path of spite subsetting:deceiver",
"path of spite subsetting:liar",
"path of spite subsetting:siren"
]
] ]
] }
} }
} }
} }

@ -1,114 +1,117 @@
[ {
{ "stock": "elf",
"name": "Bitter Poison", "resources": [
"type": "gear", {
"rp": 10 "name": "Bitter Poison",
}, "type": "gear",
{ "rp": 10
"name": "Spiteful Poison", },
"type": "gear", {
"rp": 20 "name": "Spiteful Poison",
}, "type": "gear",
{ "rp": 20
"name": "Lock Picks", },
"type": "gear", {
"rp": 10 "name": "Lock Picks",
}, "type": "gear",
{ "rp": 10
"name": "Long Knife", },
"type": "gear", {
"rp": 5 "name": "Long Knife",
}, "type": "gear",
{ "rp": 5
"name": "Barbed Javelins", },
"type": "gear", {
"rp": 3 "name": "Barbed Javelins",
}, "type": "gear",
{ "rp": 3
"name": "Garrote", },
"type": "gear", {
"rp": 3 "name": "Garrote",
}, "type": "gear",
{ "rp": 3
"name": "Caltrops", },
"type": "gear", {
"rp": 3 "name": "Caltrops",
}, "type": "gear",
{ "rp": 3
"name": "Tools Of The Trade", },
"type": "gear", {
"rp": 9 "name": "Tools Of The Trade",
}, "type": "gear",
{ "rp": 9
"name": "Cloak Of Darkness", },
"type": "gear", {
"rp": 30 "name": "Cloak Of Darkness",
}, "type": "gear",
{ "rp": 30
"name": "Climbing Claws", },
"type": "gear", {
"rp": 5 "name": "Climbing Claws",
}, "type": "gear",
{ "rp": 5
"name": "Remote Refuge", },
"type": "property", {
"resources": [ "name": "Remote Refuge",
{ "type": "property",
"name": "Wasteland", "resources": [
"rp": 20 {
}, "name": "Wasteland",
{ "rp": 20
"name": "Isolated Manor And Moorland", },
"rp": 50 {
}, "name": "Isolated Manor And Moorland",
{ "rp": 50
"name": "Hidden Fortress", },
"rp": 100 {
}, "name": "Hidden Fortress",
{ "rp": 100
"name": "Dark Forest, Cove Or Lonely Mountain", },
"rp": 150 {
}, "name": "Dark Forest, Cove Or Lonely Mountain",
{ "rp": 150
"name": "Safe House", },
"rp": 25 {
} "name": "Safe House",
] "rp": 25
}, }
{ ]
"name": "Morlin Armor", },
"type": "gear", {
"resources": [ "name": "Morlin Armor",
{ "type": "gear",
"name": "Light Mail", "resources": [
"rp": 30 {
}, "name": "Light Mail",
{ "rp": 30
"name": "Heavy Mail", },
"rp": 40 {
}, "name": "Heavy Mail",
{ "rp": 40
"name": "Plated Mail", },
"rp": 100 {
} "name": "Plated Mail",
] "rp": 100
}, }
{ ]
"name": "Morlin Weapons", },
"type": "gear", {
"resources": [ "name": "Morlin Weapons",
{ "type": "gear",
"name": "+1 speed", "resources": [
"rp": 15 {
}, "name": "+1 speed",
{ "rp": 15
"name": "+1 VA", },
"rp": 15 {
}, "name": "+1 VA",
{ "rp": 15
"name": "+1 Power", },
"rp": 30 {
} "name": "+1 Power",
] "rp": 30
} }
] ]
}
]
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -1,152 +1,155 @@
[ {
{ "stock": "dwarf",
"name": "Shoddy Arms", "resources": [
"rp": 5, {
"type": "gear" "name": "Shoddy Arms",
}, "rp": 5,
{ "type": "gear"
"name": "Dwarven Arms", },
"rp": 20, {
"type": "gear" "name": "Dwarven Arms",
}, "rp": 20,
{ "type": "gear"
"name": "Shoddy Crossbow", },
"rp": 6, {
"type": "gear" "name": "Shoddy Crossbow",
}, "rp": 6,
{ "type": "gear"
"name": "Dwarven Arbalest", },
"rp": 20, {
"type": "gear" "name": "Dwarven Arbalest",
}, "rp": 20,
{ "type": "gear"
"name": "Dwarven-made Light Mail", },
"rp": 9, {
"type": "gear" "name": "Dwarven-made Light Mail",
}, "rp": 9,
{ "type": "gear"
"name": "Dwarven-made Heavy Mail", },
"rp": 10, {
"type": "gear" "name": "Dwarven-made Heavy Mail",
}, "rp": 10,
{ "type": "gear"
"name": "Dwarven-made Plated Mail", },
"rp": 20, {
"type": "gear" "name": "Dwarven-made Plated Mail",
}, "rp": 20,
{ "type": "gear"
"name": "Dwarven Mail", },
"rp": 100, {
"type": "gear" "name": "Dwarven Mail",
}, "rp": 100,
{ "type": "gear"
"name": "Forge Mask", },
"rp": 40, {
"type": "gear" "name": "Forge Mask",
}, "rp": 40,
{ "type": "gear"
"name": "Dwarven Shield", },
"rp": 20, {
"type": "gear" "name": "Dwarven Shield",
}, "rp": 20,
{ "type": "gear"
"name": "Riding Mount Or Pack Animal", },
"rp": 8, {
"type": "gear" "name": "Riding Mount Or Pack Animal",
}, "rp": 8,
{ "type": "gear"
"name": "Clothes", },
"rp": 1, {
"type": "gear" "name": "Clothes",
}, "rp": 1,
{ "type": "gear"
"name": "Traveling Gear", },
"rp": 1, {
"type": "gear" "name": "Traveling Gear",
}, "rp": 1,
{ "type": "gear"
"name": "Sturdy Shoes", },
"rp": 1, {
"type": "gear" "name": "Sturdy Shoes",
}, "rp": 1,
{ "type": "gear"
"name": "Finery", },
"rp": 5, {
"type": "gear" "name": "Finery",
}, "rp": 5,
{ "type": "gear"
"name": "Chronicles", },
"rp": 15, {
"type": "gear" "name": "Chronicles",
}, "rp": 15,
{ "type": "gear"
"name": "Keg O' Nog", },
"rp": 20, {
"type": "gear" "name": "Keg O' Nog",
}, "rp": 20,
{ "type": "gear"
"name": "Small Dwarven House", },
"rp": 10, {
"type": "property" "name": "Small Dwarven House",
}, "rp": 10,
{ "type": "property"
"name": "Large Dwarven House", },
"rp": 15, {
"type": "property" "name": "Large Dwarven House",
}, "rp": 15,
{ "type": "property"
"name": "A Dwarven Hall", },
"rp": 30, {
"type": "property" "name": "A Dwarven Hall",
}, "rp": 30,
{ "type": "property"
"name": "A Graybeard's Hold", },
"rp": 40, {
"type": "property" "name": "A Graybeard's Hold",
}, "rp": 40,
{ "type": "property"
"name": "An Engineer's Hold", },
"rp": 45, {
"type": "property" "name": "An Engineer's Hold",
}, "rp": 45,
{ "type": "property"
"name": "A Master Artificer's Hold", },
"rp": 60, {
"type": "property" "name": "A Master Artificer's Hold",
}, "rp": 60,
{ "type": "property"
"name": "A Warden's Hold", },
"rp": 75, {
"type": "property" "name": "A Warden's Hold",
}, "rp": 75,
{ "type": "property"
"name": "A High Captain's Hold", },
"rp": 90, {
"type": "property" "name": "A High Captain's Hold",
}, "rp": 90,
{ "type": "property"
"name": "A Prince's Hold", },
"rp": 105, {
"type": "property" "name": "A Prince's Hold",
}, "rp": 105,
{ "type": "property"
"name": "A Workshop", },
"rp": 60, {
"type": "property" "name": "A Workshop",
}, "rp": 60,
{ "type": "property"
"name": "Dwarven Tools", },
"rp": 10, {
"type": "gear" "name": "Dwarven Tools",
}, "rp": 10,
{ "type": "gear"
"name": "Shoddy Tools", },
"rp": 5, {
"type": "gear" "name": "Shoddy Tools",
}, "rp": 5,
{ "type": "gear"
"name": "Carts And Baggage", },
"rp": 15, {
"type": "gear" "name": "Carts And Baggage",
} "rp": 15,
] "type": "gear"
}
]
}

@ -1,176 +1,179 @@
[ {
{ "stock": "elf",
"name": "Run Of The Mill Bow", "resources": [
"type": "gear", {
"rp": 5 "name": "Run Of The Mill Bow",
}, "type": "gear",
{ "rp": 5
"name": "Run Of The Mill Arms", },
"type": "gear", {
"rp": 5 "name": "Run Of The Mill Arms",
}, "type": "gear",
{ "rp": 5
"name": "Reinforced Leather", },
"type": "gear", {
"rp": 3 "name": "Reinforced Leather",
}, "type": "gear",
{ "rp": 3
"name": "Light Mail", },
"type": "gear", {
"rp": 6 "name": "Light Mail",
}, "type": "gear",
{ "rp": 6
"name": "Heavy Mail", },
"type": "gear", {
"rp": 10 "name": "Heavy Mail",
}, "type": "gear",
{ "rp": 10
"name": "Plated Mail", },
"type": "gear", {
"rp": 20 "name": "Plated Mail",
}, "type": "gear",
{ "rp": 20
"name": "Elven Armor", },
"type": "gear", {
"resources": [ "name": "Elven Armor",
{ "type": "gear",
"name": "Gambeson", "resources": [
"rp": 9 {
}, "name": "Gambeson",
{ "rp": 9
"name": "Reinforced Leather", },
"resources": null, {
"rp": 20 "name": "Reinforced Leather",
}, "resources": null,
{ "rp": 20
"name": "Light Mail", },
"resources": null, {
"rp": 30 "name": "Light Mail",
}, "resources": null,
{ "rp": 30
"name": "Heavy Mail", },
"rp": 40 {
}, "name": "Heavy Mail",
{ "rp": 40
"name": "Plated Mail", },
"rp": 75 {
} "name": "Plated Mail",
] "rp": 75
}, }
{ ]
"name": "Elven Arms", },
"type": "gear", {
"rp": 15 "name": "Elven Arms",
}, "type": "gear",
{ "rp": 15
"name": "Elven Bow", },
"type": "gear", {
"rp": 25 "name": "Elven Bow",
}, "type": "gear",
{ "rp": 25
"name": "Elven Cloak", },
"type": "gear", {
"rp": 30 "name": "Elven Cloak",
}, "type": "gear",
{ "rp": 30
"name": "Elven Steed", },
"type": "gear", {
"rp": 8 "name": "Elven Steed",
}, "type": "gear",
{ "rp": 8
"name": "Elven Clothes", },
"type": "gear", {
"rp": 2 "name": "Elven Clothes",
}, "type": "gear",
{ "rp": 2
"name": "Elven Shoes", },
"type": "gear", {
"rp": 1 "name": "Elven Shoes",
}, "type": "gear",
{ "rp": 1
"name": "Elven Finery", },
"type": "gear", {
"rp": 5 "name": "Elven Finery",
}, "type": "gear",
{ "rp": 5
"name": "Elven Rope", },
"type": "gear", {
"rp": 12 "name": "Elven Rope",
}, "type": "gear",
{ "rp": 12
"name": "Elven Bread", },
"type": "gear", {
"rp": 10 "name": "Elven Bread",
}, "type": "gear",
{ "rp": 10
"name": "Elven Mirrorwine", },
"type": "gear", {
"rp": 8 "name": "Elven Mirrorwine",
}, "type": "gear",
{ "rp": 8
"name": "Starlight", },
"type": "gear", {
"rp": 50 "name": "Starlight",
}, "type": "gear",
{ "rp": 50
"name": "Tome Of Lore", },
"type": "gear", {
"rp": 20 "name": "Tome Of Lore",
}, "type": "gear",
{ "rp": 20
"name": "Elven Instrument", },
"type": "gear", {
"rp": 6 "name": "Elven Instrument",
}, "type": "gear",
{ "rp": 6
"name": "Personal Effects", },
"type": "gear", {
"rp": 1 "name": "Personal Effects",
}, "type": "gear",
{ "rp": 1
"name": "Elven Smithy", },
"type": "property", {
"rp": 50 "name": "Elven Smithy",
}, "type": "property",
{ "rp": 50
"name": "Artisan's Shop", },
"type": "property", {
"rp": 60 "name": "Artisan's Shop",
}, "type": "property",
{ "rp": 60
"name": "Skill Tools", },
"type": "gear", {
"rp": 9 "name": "Skill Tools",
}, "type": "gear",
{ "rp": 9
"name": "Elven Ship", },
"type": "gear", {
"rp": 80 "name": "Elven Ship",
}, "type": "gear",
{ "rp": 80
"name": "Elven Land", },
"type": "property", {
"resources": [ "name": "Elven Land",
{ "type": "property",
"name": "Pastoral", "resources": [
"rp": 20 {
}, "name": "Pastoral",
{ "rp": 20
"name": "Large Country Manor And Land", },
"rp": 50 {
}, "name": "Large Country Manor And Land",
{ "rp": 50
"name": "Palace", },
"rp": 100 {
}, "name": "Palace",
{ "rp": 100
"name": "A Forest, Bay Or Mountain", },
"rp": 150 {
}, "name": "A Forest, Bay Or Mountain",
{ "rp": 150
"name": "Apartment In The Citadel", },
"rp": 25 {
} "name": "Apartment In The Citadel",
] "rp": 25
} }
] ]
}
]
}

@ -1,434 +1,437 @@
[ {
{ "stock": "man",
"name": "Arms", "resources": [
"type": "gear", {
"resources": [ "name": "Arms",
{ "type": "gear",
"name": "Poor Quality", "resources": [
"rp": 3 {
}, "name": "Poor Quality",
{ "rp": 3
"name": "Run Of The Mill Quality", },
"rp": 5 {
}, "name": "Run Of The Mill Quality",
{ "rp": 5
"name": "Superior Quality", },
"rp": 20 {
} "name": "Superior Quality",
] "rp": 20
}, }
{ ]
"name": "Missile Weapons", },
"type": "gear", {
"resources": [ "name": "Missile Weapons",
{ "type": "gear",
"name": "Throwing Weapons", "resources": [
"resources": [ {
{ "name": "Throwing Weapons",
"name": "Poor Quality", "resources": [
"rp": 2 {
}, "name": "Poor Quality",
{ "rp": 2
"name": "Run Of The Mill Quality", },
"rp": 3 {
}, "name": "Run Of The Mill Quality",
{ "rp": 3
"name": "Superior Quality", },
"rp": 9 {
} "name": "Superior Quality",
] "rp": 9
}, }
{ ]
"name": "Hunting Bow", },
"resources": [ {
{ "name": "Hunting Bow",
"name": "Poor Quality", "resources": [
"rp": 3 {
}, "name": "Poor Quality",
{ "rp": 3
"name": "Run Of The Mill Quality", },
"rp": 5 {
}, "name": "Run Of The Mill Quality",
{ "rp": 5
"name": "Superior Quality", },
"rp": 15 {
} "name": "Superior Quality",
] "rp": 15
}, }
{ ]
"name": "Great Bow", },
"resources": [ {
{ "name": "Great Bow",
"name": "Poor Quality", "resources": [
"rp": 5 {
}, "name": "Poor Quality",
{ "rp": 5
"name": "Run Of The Mill Quality", },
"rp": 10 {
}, "name": "Run Of The Mill Quality",
{ "rp": 10
"name": "Superior Quality", },
"rp": 30 {
} "name": "Superior Quality",
] "rp": 30
}, }
{ ]
"name": "Crossbow", },
"resources": [ {
{ "name": "Crossbow",
"name": "Poor Quality", "resources": [
"rp": 4 {
}, "name": "Poor Quality",
{ "rp": 4
"name": "Run Of The Mill Quality", },
"rp": 7 {
}, "name": "Run Of The Mill Quality",
{ "rp": 7
"name": "Superior Quality", },
"rp": 21 {
} "name": "Superior Quality",
] "rp": 21
}, }
{ ]
"name": "Heavy Crossbow", },
"resources": [ {
{ "name": "Heavy Crossbow",
"name": "Poor Quality", "resources": [
"rp": 6 {
}, "name": "Poor Quality",
{ "rp": 6
"name": "Run Of The Mill Quality", },
"rp": 12 {
}, "name": "Run Of The Mill Quality",
{ "rp": 12
"name": "Superior Quality", },
"rp": 36 {
} "name": "Superior Quality",
] "rp": 36
}, }
{ ]
"name": "Pistol", },
"resources": [ {
{ "name": "Pistol",
"name": "Poor Quality", "resources": [
"rp": 8 {
}, "name": "Poor Quality",
{ "rp": 8
"name": "Run Of The Mill Quality", },
"rp": 15 {
}, "name": "Run Of The Mill Quality",
{ "rp": 15
"name": "Superior Quality", },
"rp": 45 {
} "name": "Superior Quality",
] "rp": 45
}, }
{ ]
"name": "Arquebus", },
"resources": [ {
{ "name": "Arquebus",
"name": "Poor Quality", "resources": [
"rp": 10 {
}, "name": "Poor Quality",
{ "rp": 10
"name": "Run Of The Mill Quality", },
"rp": 20 {
}, "name": "Run Of The Mill Quality",
{ "rp": 20
"name": "Superior Quality", },
"rp": 60 {
} "name": "Superior Quality",
] "rp": 60
} }
] ]
}, }
{ ]
"name": "Armor", },
"type": "gear", {
"resources": [ "name": "Armor",
{ "type": "gear",
"name": "Gambeson", "resources": [
"resources": [ {
{ "name": "Gambeson",
"name": "Poor Quality", "resources": [
"rp": 2 {
}, "name": "Poor Quality",
{ "rp": 2
"name": "Run Of The Mill Quality", },
"rp": 3 {
}, "name": "Run Of The Mill Quality",
{ "rp": 3
"name": "Superior Quality", },
"rp": 12 {
} "name": "Superior Quality",
] "rp": 12
}, }
{ ]
"name": "Reinforced Leather", },
"resources": [ {
{ "name": "Reinforced Leather",
"name": "Poor Quality", "resources": [
"rp": 3 {
}, "name": "Poor Quality",
{ "rp": 3
"name": "Run Of The Mill Quality", },
"rp": 6 {
}, "name": "Run Of The Mill Quality",
{ "rp": 6
"name": "Superior Quality", },
"rp": 24 {
} "name": "Superior Quality",
] "rp": 24
}, }
{ ]
"name": "Light Mail", },
"resources": [ {
{ "name": "Light Mail",
"name": "Poor Quality", "resources": [
"rp": 5 {
}, "name": "Poor Quality",
{ "rp": 5
"name": "Run Of The Mill Quality", },
"rp": 10 {
}, "name": "Run Of The Mill Quality",
{ "rp": 10
"name": "Superior Quality", },
"rp": 40 {
} "name": "Superior Quality",
] "rp": 40
}, }
{ ]
"name": "Heavy Mail", },
"resources": [ {
{ "name": "Heavy Mail",
"name": "Poor Quality", "resources": [
"rp": 8 {
}, "name": "Poor Quality",
{ "rp": 8
"name": "Run Of The Mill Quality", },
"rp": 15 {
}, "name": "Run Of The Mill Quality",
{ "rp": 15
"name": "Superior Quality", },
"rp": 60 {
} "name": "Superior Quality",
] "rp": 60
}, }
{ ]
"name": "Plated Mail", },
"resources": [ {
{ "name": "Plated Mail",
"name": "Poor Quality", "resources": [
"rp": 10 {
}, "name": "Poor Quality",
{ "rp": 10
"name": "Run Of The Mill Quality", },
"rp": 20 {
}, "name": "Run Of The Mill Quality",
{ "rp": 20
"name": "Superior Quality", },
"rp": 80 {
} "name": "Superior Quality",
] "rp": 80
}, }
{ ]
"name": "Full Plated Mail", },
"resources": [ {
{ "name": "Full Plated Mail",
"name": "Poor Quality", "resources": [
"rp": 25 {
}, "name": "Poor Quality",
{ "rp": 25
"name": "Run Of The Mill Quality", },
"rp": 50 {
}, "name": "Run Of The Mill Quality",
{ "rp": 50
"name": "Superior Quality", },
"rp": 200 {
} "name": "Superior Quality",
] "rp": 200
} }
] ]
}, }
{ ]
"name": "Riding Mount Or Pack Animal", },
"rp": 5, {
"type": "gear" "name": "Riding Mount Or Pack Animal",
}, "rp": 5,
{ "type": "gear"
"name": "Warhorse", },
"rp": 12, {
"type": "gear" "name": "Warhorse",
}, "rp": 12,
{ "type": "gear"
"name": "Clothes", },
"rp": 1, {
"type": "gear" "name": "Clothes",
}, "rp": 1,
{ "type": "gear"
"name": "Traveling Gear", },
"rp": 1, {
"type": "gear" "name": "Traveling Gear",
}, "rp": 1,
{ "type": "gear"
"name": "Shoes", },
"rp": 1, {
"type": "gear" "name": "Shoes",
}, "rp": 1,
{ "type": "gear"
"name": "Personal Effects", },
"rp": 1, {
"type": "gear" "name": "Personal Effects",
}, "rp": 1,
{ "type": "gear"
"name": "Finery", },
"rp": 5, {
"type": "gear" "name": "Finery",
}, "rp": 5,
{ "type": "gear"
"name": "Cash", },
"rp": 6, {
"type": "gear" "name": "Cash",
}, "rp": 6,
{ "type": "gear"
"name": "Skill Toolkit", },
"rp": 8, {
"type": "gear" "name": "Skill Toolkit",
}, "rp": 8,
{ "type": "gear"
"name": "Workshop", },
"rp": 20, {
"type": "property" "name": "Workshop",
}, "rp": 20,
{ "type": "property"
"name": "Companion Animal", },
"rp": 3, {
"type": "gear" "name": "Companion Animal",
}, "rp": 3,
{ "type": "gear"
"name": "Herd Of Animals", },
"rp": 20, {
"type": "property" "name": "Herd Of Animals",
}, "rp": 20,
{ "type": "property"
"name": "Rent", },
"rp": 5, {
"type": "property" "name": "Rent",
}, "rp": 5,
{ "type": "property"
"name": "Property", },
"type": "property", {
"resources": [ "name": "Property",
{ "type": "property",
"name": "A Leaky Shack", "resources": [
"rp": 1 {
}, "name": "A Leaky Shack",
{ "rp": 1
"name": "A Small Cottage", },
"rp": 3 {
}, "name": "A Small Cottage",
{ "rp": 3
"name": "A House", },
"rp": 10 {
}, "name": "A House",
{ "rp": 10
"name": "A \"Cottage Industry\" Like A Weaver", },
"rp": 10 {
}, "name": "A \"Cottage Industry\" Like A Weaver",
{ "rp": 10
"name": "A Villa Or Farm", },
"rp": 15 {
}, "name": "A Villa Or Farm",
{ "rp": 15
"name": "A Small Business", },
"rp": 20 {
}, "name": "A Small Business",
{ "rp": 20
"name": "Moderate-sized Business", },
"rp": 30 {
}, "name": "Moderate-sized Business",
{ "rp": 30
"name": "A Manor Or Small Estate", },
"rp": 40 {
}, "name": "A Manor Or Small Estate",
{ "rp": 40
"name": "An Urban Hotel", },
"rp": 40 {
}, "name": "An Urban Hotel",
{ "rp": 40
"name": "A Well-paid Position (Like Mayor)", },
"rp": 45 {
}, "name": "A Well-paid Position (Like Mayor)",
{ "rp": 45
"name": "A Successful Small Business", },
"rp": 60 {
}, "name": "A Successful Small Business",
{ "rp": 60
"name": "A Large Business", },
"rp": 60 {
}, "name": "A Large Business",
{ "rp": 60
"name": "A Keep", },
"rp": 60 {
}, "name": "A Keep",
{ "rp": 60
"name": "A Fortress", },
"rp": 75 {
}, "name": "A Fortress",
{ "rp": 75
"name": "A Moderate-sized Estate", },
"rp": 75 {
}, "name": "A Moderate-sized Estate",
{ "rp": 75
"name": "A Castle With Attendant Town", },
"rp": 90 {
}, "name": "A Castle With Attendant Town",
{ "rp": 90
"name": "A Large Estate", },
"rp": 90 {
}, "name": "A Large Estate",
{ "rp": 90
"name": "A Palace", },
"rp": 105 {
}, "name": "A Palace",
{ "rp": 105
"name": "A Government Position In A Prosperous Town", },
"rp": 105 {
} "name": "A Government Position In A Prosperous Town",
] "rp": 105
}, }
{ ]
"name": "Boat", },
"type": "property", {
"resources": [ "name": "Boat",
{ "type": "property",
"name": "A Rowboat Or Skiff", "resources": [
"rp": 5 {
}, "name": "A Rowboat Or Skiff",
{ "rp": 5
"name": "A Longboat", },
"rp": 10 {
}, "name": "A Longboat",
{ "rp": 10
"name": "A Junk", },
"rp": 15 {
}, "name": "A Junk",
{ "rp": 15
"name": "A Felucca", },
"rp": 30 {
}, "name": "A Felucca",
{ "rp": 30
"name": "A Carrack", },
"rp": 60 {
}, "name": "A Carrack",
{ "rp": 60
"name": "A Caravel", },
"rp": 75 {
}, "name": "A Caravel",
{ "rp": 75
"name": "Treasure Ship", },
"rp": 105 {
} "name": "Treasure Ship",
] "rp": 105
} }
] ]
}
]
}

@ -1,211 +1,214 @@
[ {
{ "stock": "orc",
"name": "Rags", "resources": [
"rp": 1, {
"type": "gear" "name": "Rags",
}, "rp": 1,
{ "type": "gear"
"name": "Traveling Gear", },
"rp": 3, {
"type": "gear" "name": "Traveling Gear",
}, "rp": 3,
{ "type": "gear"
"name": "Hobnailed Boots", },
"rp": 1, {
"type": "gear" "name": "Hobnailed Boots",
}, "rp": 1,
{ "type": "gear"
"name": "Orc Arms", },
"type": "gear", {
"resources": [ "name": "Orc Arms",
{ "type": "gear",
"name": "Poor Quality", "resources": [
"rp": 3 {
}, "name": "Poor Quality",
{ "rp": 3
"name": "Run Of The Mill Quality", },
"rp": 5 {
} "name": "Run Of The Mill Quality",
] "rp": 5
}, }
{ ]
"name": "Armor", },
"type": "gear", {
"resources": [ "name": "Armor",
{ "type": "gear",
"name": "Hides", "resources": [
"resources": [ {
{ "name": "Hides",
"name": "Poor Quality", "resources": [
"rp": 1 {
} "name": "Poor Quality",
] "rp": 1
}, }
{ ]
"name": "Reinforced Hides", },
"resources": [ {
{ "name": "Reinforced Hides",
"name": "Poor Quality", "resources": [
"rp": 3 {
} "name": "Poor Quality",
] "rp": 3
}, }
{ ]
"name": "Reinforced Leather", },
"resources": [ {
{ "name": "Reinforced Leather",
"name": "Run Of The Mill Quality", "resources": [
"rp": 8 {
}, "name": "Run Of The Mill Quality",
{ "rp": 8
"name": "Superior Quality", },
"rp": 25 {
} "name": "Superior Quality",
] "rp": 25
}, }
{ ]
"name": "Light Mail", },
"resources": [ {
{ "name": "Light Mail",
"name": "Poor Quality", "resources": [
"rp": 5 {
}, "name": "Poor Quality",
{ "rp": 5
"name": "Run Of The Mill Quality", },
"rp": 12 {
} "name": "Run Of The Mill Quality",
] "rp": 12
}, }
{ ]
"name": "Heavy Mail", },
"resources": [ {
{ "name": "Heavy Mail",
"name": "Poor Quality", "resources": [
"rp": 8 {
}, "name": "Poor Quality",
{ "rp": 8
"name": "Run Of The Mill Quality", },
"rp": 20 {
} "name": "Run Of The Mill Quality",
] "rp": 20
} }
] ]
}, }
{ ]
"name": "Missile Weapons", },
"type": "gear", {
"resources": [ "name": "Missile Weapons",
{ "type": "gear",
"name": "Bow", "resources": [
"resources": [ {
{ "name": "Bow",
"name": "Poor Quality", "resources": [
"rp": 3 {
}, "name": "Poor Quality",
{ "rp": 3
"name": "Run Of The Mill Quality", },
"rp": 5 {
} "name": "Run Of The Mill Quality",
] "rp": 5
}, }
{ ]
"name": "Crossbow", },
"resources": [ {
{ "name": "Crossbow",
"name": "Poor Quality", "resources": [
"rp": 4 {
}, "name": "Poor Quality",
{ "rp": 4
"name": "Run Of The Mill Quality", },
"rp": 6 {
} "name": "Run Of The Mill Quality",
] "rp": 6
}, }
{ ]
"name": "Iron-cased Bombs", },
"resources": null, {
"rp": 10 "name": "Iron-cased Bombs",
} "resources": null,
] "rp": 10
}, }
{ ]
"name": "Black Iron Helmet", },
"rp": 5, {
"type": "gear" "name": "Black Iron Helmet",
}, "rp": 5,
{ "type": "gear"
"name": "Black Iron Shield", },
"rp": 4, {
"type": "gear" "name": "Black Iron Shield",
}, "rp": 4,
{ "type": "gear"
"name": "Riding Mount Or Pack Animal", },
"rp": 5, {
"type": "gear" "name": "Riding Mount Or Pack Animal",
}, "rp": 5,
{ "type": "gear"
"name": "Great Wolf Mount", },
"rp": 15, {
"type": "gear" "name": "Great Wolf Mount",
}, "rp": 15,
{ "type": "gear"
"name": "Whip", },
"rp": 2, {
"type": "gear" "name": "Whip",
}, "rp": 2,
{ "type": "gear"
"name": "Poison", },
"rp": 5, {
"type": "gear" "name": "Poison",
}, "rp": 5,
{ "type": "gear"
"name": "Brazen Horn", },
"rp": 9, {
"type": "gear" "name": "Brazen Horn",
}, "rp": 9,
{ "type": "gear"
"name": "Clan Banner", },
"rp": 9, {
"type": "gear" "name": "Clan Banner",
}, "rp": 9,
{ "type": "gear"
"name": "Skill Tools", },
"rp": 9, {
"type": "gear" "name": "Skill Tools",
}, "rp": 9,
{ "type": "gear"
"name": "Riding Harness For Wolf", },
"rp": 5, {
"type": "gear" "name": "Riding Harness For Wolf",
}, "rp": 5,
{ "type": "gear"
"name": "Servant's Black Robes", },
"rp": 1, {
"type": "gear" "name": "Servant's Black Robes",
}, "rp": 1,
{ "type": "gear"
"name": "Servant's Leather Apron", },
"rp": 1, {
"type": "gear" "name": "Servant's Leather Apron",
}, "rp": 1,
{ "type": "gear"
"name": "Ceremonial Knives", },
"rp": 3, {
"type": "gear" "name": "Ceremonial Knives",
}, "rp": 3,
{ "type": "gear"
"name": "Ceremonial Axe Or Sword", },
"rp": 7, {
"type": "gear" "name": "Ceremonial Axe Or Sword",
}, "rp": 7,
{ "type": "gear"
"name": "Servant's Tools Of The Trade", },
"rp": 7, {
"type": "gear" "name": "Servant's Tools Of The Trade",
}, "rp": 7,
{ "type": "gear"
"name": "Poisoner's Toolkit", },
"rp": 7, {
"type": "gear" "name": "Poisoner's Toolkit",
} "rp": 7,
] "type": "gear"
}
]
}

@ -1,139 +1,142 @@
[ {
{ "stock": "roden",
"name": "Arms", "resources": [
"rp": 5, {
"type": "gear" "name": "Arms",
}, "rp": 5,
{ "type": "gear"
"name": "Roden Throwing Blades", },
"rp": 15, {
"type": "gear" "name": "Roden Throwing Blades",
}, "rp": 15,
{ "type": "gear"
"name": "Wooden Shield", },
"rp": 2, {
"type": "gear" "name": "Wooden Shield",
}, "rp": 2,
{ "type": "gear"
"name": "Armor", },
"type": "gear", {
"resources": [ "name": "Armor",
{ "type": "gear",
"name": "Gambeson", "resources": [
"rp": 5 {
}, "name": "Gambeson",
{ "rp": 5
"name": "Reinforced Leather", },
"rp": 10 {
}, "name": "Reinforced Leather",
{ "rp": 10
"name": "Light Mail", },
"rp": 15 {
}, "name": "Light Mail",
{ "rp": 15
"name": "Heavy Mail", },
"rp": 20 {
} "name": "Heavy Mail",
] "rp": 20
}, }
{ ]
"name": "Property", },
"type": "property", {
"resources": [ "name": "Property",
{ "type": "property",
"name": "Rat's Nest Property", "resources": [
"resources": [ {
{ "name": "Rat's Nest Property",
"name": "Den", "resources": [
"rp": 7 {
}, "name": "Den",
{ "rp": 7
"name": "Nest", },
"rp": 10 {
}, "name": "Nest",
{ "rp": 10
"name": "Apiary", },
"rp": 10 {
}, "name": "Apiary",
{ "rp": 10
"name": "Fields", },
"rp": 15 {
} "name": "Fields",
] "rp": 15
} }
] ]
}, }
{ ]
"name": "Workshop", },
"type": "property", {
"rp": 20 "name": "Workshop",
}, "type": "property",
{ "rp": 20
"name": "Animal Herd", },
"type": "property", {
"rp": 10 "name": "Animal Herd",
}, "type": "property",
{ "rp": 10
"name": "Clothes", },
"type": "gear", {
"rp": 1 "name": "Clothes",
}, "type": "gear",
{ "rp": 1
"name": "Traveling Gear", },
"type": "gear", {
"rp": 1 "name": "Traveling Gear",
}, "type": "gear",
{ "rp": 1
"name": "Shoes", },
"type": "gear", {
"rp": 3 "name": "Shoes",
}, "type": "gear",
{ "rp": 3
"name": "Tool Kit", },
"type": "gear", {
"rp": 9 "name": "Tool Kit",
}, "type": "gear",
{ "rp": 9
"name": "Firebombs", },
"type": "gear", {
"rp": 20 "name": "Firebombs",
}, "type": "gear",
{ "rp": 20
"name": "Robes Of The Ordained", },
"type": "gear", {
"rp": 1 "name": "Robes Of The Ordained",
}, "type": "gear",
{ "rp": 1
"name": "Honeyed Oatcakes", },
"type": "gear", {
"rp": 5 "name": "Honeyed Oatcakes",
}, "type": "gear",
{ "rp": 5
"name": "Dandewine", },
"type": "gear", {
"rp": 5 "name": "Dandewine",
}, "type": "gear",
{ "rp": 5
"name": "Blood Blossom", },
"type": "gear", {
"rp": 5 "name": "Blood Blossom",
}, "type": "gear",
{ "rp": 5
"name": "Visionary Cult", },
"type": "affiliation", {
"resources": [ "name": "Visionary Cult",
{ "type": "affiliation",
"name": "1d Cult", "resources": [
"rp": 10 {
}, "name": "1d Cult",
{ "rp": 10
"name": "2d Cult", },
"rp": 25 {
}, "name": "2d Cult",
{ "rp": 25
"name": "3d Cult", },
"rp": 50 {
} "name": "3d Cult",
] "rp": 50
} }
] ]
}
]
}

@ -1,42 +1,45 @@
[ {
{ "stock": "wolf",
"name": "Territory", "resources": [
"type": "property", {
"resources": [ "name": "Territory",
{ "type": "property",
"name": "Barren", "resources": [
"rp": 5 {
}, "name": "Barren",
{ "rp": 5
"name": "Wild Grounds", },
"rp": 10 {
}, "name": "Wild Grounds",
{ "rp": 10
"name": "Plentiful Range", },
"rp": 15 {
} "name": "Plentiful Range",
] "rp": 15
}, }
{ ]
"name": "Armor", },
"type": "gear", {
"resources": [ "name": "Armor",
{ "type": "gear",
"name": "Plated Leather Chanfron", "resources": [
"rp": 3 {
}, "name": "Plated Leather Chanfron",
{ "rp": 3
"name": "Leather Collar", },
"rp": 2 {
}, "name": "Leather Collar",
{ "rp": 2
"name": "Plated Body Armor", },
"rp": 6 {
}, "name": "Plated Body Armor",
{ "rp": 6
"name": "Leather Greaves And Cuissarts", },
"rp": 2 {
} "name": "Leather Greaves And Cuissarts",
] "rp": 2
} }
] ]
}
]
}

@ -1,114 +0,0 @@
[
{
"range": [
1,
20
],
"m": 6,
"p": 13
},
{
"range": [
21,
30
],
"m": 7,
"p": 13
},
{
"range": [
31,
50
],
"m": 7,
"p": 14
},
{
"range": [
51,
76
],
"m": 8,
"p": 15
},
{
"range": [
77,
111
],
"m": 8,
"p": 16
},
{
"range": [
112,
151
],
"m": 9,
"p": 16
},
{
"range": [
152,
199
],
"m": 9,
"p": 17
},
{
"range": [
200,
245
],
"m": 10,
"p": 18
},
{
"range": [
246,
300
],
"m": 11,
"p": 17
},
{
"range": [
301,
345
],
"m": 11,
"p": 16
},
{
"range": [
346,
396
],
"m": 12,
"p": 15
},
{
"range": [
397,
445
],
"m": 11,
"p": 14
},
{
"range": [
446,
525
],
"m": 11,
"p": 13
},
{
"range": [
526,
600
],
"m": 10,
"p": 12
}
]

@ -1,146 +0,0 @@
[
{
"range": [
1,
25
],
"m": 7,
"p": 13
},
{
"range": [
26,
60
],
"m": 8,
"p": 13
},
{
"range": [
61,
100
],
"m": 9,
"p": 14
},
{
"range": [
101,
125
],
"m": 9,
"p": 15
},
{
"range": [
126,
160
],
"m": 10,
"p": 16
},
{
"range": [
161,
225
],
"m": 10,
"p": 17
},
{
"range": [
226,
325
],
"m": 11,
"p": 17
},
{
"range": [
326,
425
],
"m": 12,
"p": 17
},
{
"range": [
426,
525
],
"m": 13,
"p": 18
},
{
"range": [
526,
625
],
"m": 13,
"p": 19
},
{
"range": [
626,
725
],
"m": 14,
"p": 19
},
{
"range": [
726,
825
],
"m": 14,
"p": 20
},
{
"range": [
826,
925
],
"m": 15,
"p": 20
},
{
"range": [
926,
1025
],
"m": 15,
"p": 21
},
{
"range": [
1026,
1125
],
"m": 15,
"p": 22
},
{
"range": [
1126,
1225
],
"m": 15,
"p": 23
},
{
"range": [
1226,
1325
],
"m": 15,
"p": 24
},
{
"range": [
1326,
9999
],
"m": 16,
"p": 24
}
]

@ -1,90 +0,0 @@
[
{
"range": [
1,
10
],
"m": 5,
"p": 10
},
{
"range": [
11,
14
],
"m": 6,
"p": 13
},
{
"range": [
15,
16
],
"m": 6,
"p": 16
},
{
"range": [
17,
25
],
"m": 7,
"p": 16
},
{
"range": [
26,
29
],
"m": 7,
"p": 15
},
{
"range": [
30,
35
],
"m": 7,
"p": 14
},
{
"range": [
36,
40
],
"m": 7,
"p": 13
},
{
"range": [
41,
55
],
"m": 7,
"p": 12
},
{
"range": [
56,
65
],
"m": 7,
"p": 11
},
{
"range": [
66,
79
],
"m": 7,
"p": 10
},
{
"range": [
80,
100
],
"m": 6,
"p": 9
}
]

@ -1,98 +0,0 @@
[
{
"range": [
1,
10
],
"m": 3,
"p": 10
},
{
"range": [
11,
16
],
"m": 4,
"p": 11
},
{
"range": [
17,
22
],
"m": 5,
"p": 12
},
{
"range": [
23,
30
],
"m": 5,
"p": 13
},
{
"range": [
31,
40
],
"m": 6,
"p": 14
},
{
"range": [
41,
50
],
"m": 6,
"p": 15
},
{
"range": [
51,
60
],
"m": 7,
"p": 16
},
{
"range": [
61,
80
],
"m": 7,
"p": 17
},
{
"range": [
81,
99
],
"m": 8,
"p": 17
},
{
"range": [
100,
125
],
"m": 8,
"p": 18
},
{
"range": [
126,
150
],
"m": 9,
"p": 18
},
{
"range": [
151,
9999
],
"m": 9,
"p": 19
}
]

@ -1,74 +0,0 @@
[
{
"range": [
1,
5
],
"m": 6,
"p": 10
},
{
"range": [
6,
9
],
"m": 7,
"p": 13
},
{
"range": [
10,
15
],
"m": 7,
"p": 14
},
{
"range": [
16,
24
],
"m": 8,
"p": 15
},
{
"range": [
25,
30
],
"m": 8,
"p": 14
},
{
"range": [
31,
36
],
"m": 7,
"p": 13
},
{
"range": [
37,
40
],
"m": 7,
"p": 12
},
{
"range": [
41,
45
],
"m": 7,
"p": 11
},
{
"range": [
46,
49
],
"m": 6,
"p": 10
}
]

@ -1,58 +0,0 @@
[
{
"range": [
1,
1.5
],
"m": 6,
"p": 12
},
{
"range": [
2,
3.5
],
"m": 7,
"p": 16
},
{
"range": [
4,
5.5
],
"m": 7,
"p": 17
},
{
"range": [
6,
7.5
],
"m": 7,
"p": 16
},
{
"range": [
8,
9.5
],
"m": 6,
"p": 14
},
{
"range": [
10,
11.5
],
"m": 6,
"p": 12
},
{
"range": [
12,
15.5
],
"m": 5,
"p": 10
}
]

@ -0,0 +1,130 @@
{
"key": "dwarf",
"name": "Dwarf",
"stride": 6,
"adjective": "dwarven",
"common_traits": [
"Accustomed To The Dark",
"Bearded",
"Greed",
"Oathsworn",
"Shaped From Earth And Stone",
"Stout",
"Tough"
],
"starting_stats":
[
{
"range": [
1,
20
],
"m": 6,
"p": 13
},
{
"range": [
21,
30
],
"m": 7,
"p": 13
},
{
"range": [
31,
50
],
"m": 7,
"p": 14
},
{
"range": [
51,
76
],
"m": 8,
"p": 15
},
{
"range": [
77,
111
],
"m": 8,
"p": 16
},
{
"range": [
112,
151
],
"m": 9,
"p": 16
},
{
"range": [
152,
199
],
"m": 9,
"p": 17
},
{
"range": [
200,
245
],
"m": 10,
"p": 18
},
{
"range": [
246,
300
],
"m": 11,
"p": 17
},
{
"range": [
301,
345
],
"m": 11,
"p": 16
},
{
"range": [
346,
396
],
"m": 12,
"p": 15
},
{
"range": [
397,
445
],
"m": 11,
"p": 14
},
{
"range": [
446,
525
],
"m": 11,
"p": 13
},
{
"range": [
526,
600
],
"m": 10,
"p": 12
}
]
}

@ -0,0 +1,161 @@
{
"key": "elf",
"name": "Elf",
"stride": 8,
"adjective": "elven",
"common_traits": [
"Born Under The Silver Stars",
"Essence Of The Earth",
"Fair And Statuesque",
"First Born",
"Grief",
"Keen Sight"
],
"starting_stats":
[
{
"range": [
1,
25
],
"m": 7,
"p": 13
},
{
"range": [
26,
60
],
"m": 8,
"p": 13
},
{
"range": [
61,
100
],
"m": 9,
"p": 14
},
{
"range": [
101,
125
],
"m": 9,
"p": 15
},
{
"range": [
126,
160
],
"m": 10,
"p": 16
},
{
"range": [
161,
225
],
"m": 10,
"p": 17
},
{
"range": [
226,
325
],
"m": 11,
"p": 17
},
{
"range": [
326,
425
],
"m": 12,
"p": 17
},
{
"range": [
426,
525
],
"m": 13,
"p": 18
},
{
"range": [
526,
625
],
"m": 13,
"p": 19
},
{
"range": [
626,
725
],
"m": 14,
"p": 19
},
{
"range": [
726,
825
],
"m": 14,
"p": 20
},
{
"range": [
826,
925
],
"m": 15,
"p": 20
},
{
"range": [
926,
1025
],
"m": 15,
"p": 21
},
{
"range": [
1026,
1125
],
"m": 15,
"p": 22
},
{
"range": [
1126,
1225
],
"m": 15,
"p": 23
},
{
"range": [
1226,
1325
],
"m": 15,
"p": 24
},
{
"range": [
1326,
9999
],
"m": 16,
"p": 24
}
]
}

@ -0,0 +1,99 @@
{
"key": "man",
"name": "Man",
"stride": 7,
"adjective": "mannish",
"common_traits": [
],
"starting_stats":
[
{
"range": [
1,
10
],
"m": 5,
"p": 10
},
{
"range": [
11,
14
],
"m": 6,
"p": 13
},
{
"range": [
15,
16
],
"m": 6,
"p": 16
},
{
"range": [
17,
25
],
"m": 7,
"p": 16
},
{
"range": [
26,
29
],
"m": 7,
"p": 15
},
{
"range": [
30,
35
],
"m": 7,
"p": 14
},
{
"range": [
36,
40
],
"m": 7,
"p": 13
},
{
"range": [
41,
55
],
"m": 7,
"p": 12
},
{
"range": [
56,
65
],
"m": 7,
"p": 11
},
{
"range": [
66,
79
],
"m": 7,
"p": 10
},
{
"range": [
80,
100
],
"m": 6,
"p": 9
}
]
}

@ -0,0 +1,114 @@
{
"key": "orc",
"name": "Orc",
"stride": 7,
"adjective": "orcish",
"common_traits": [
"Cannibal",
"Cold Black Blood",
"Breeder",
"Fanged And Clawed",
"Loathsome And Twisted",
"Lynx-eyed, Like Burning Coals",
"Vile Language"
],
"starting_stats":
[
{
"range": [
1,
10
],
"m": 3,
"p": 10
},
{
"range": [
11,
16
],
"m": 4,
"p": 11
},
{
"range": [
17,
22
],
"m": 5,
"p": 12
},
{
"range": [
23,
30
],
"m": 5,
"p": 13
},
{
"range": [
31,
40
],
"m": 6,
"p": 14
},
{
"range": [
41,
50
],
"m": 6,
"p": 15
},
{
"range": [
51,
60
],
"m": 7,
"p": 16
},
{
"range": [
61,
80
],
"m": 7,
"p": 17
},
{
"range": [
81,
99
],
"m": 8,
"p": 17
},
{
"range": [
100,
125
],
"m": 8,
"p": 18
},
{
"range": [
126,
150
],
"m": 9,
"p": 18
},
{
"range": [
151,
9999
],
"m": 9,
"p": 19
}
]
}

@ -0,0 +1,90 @@
{
"key": "roden",
"name": "Roden",
"stride": 8,
"adjective": "roden",
"common_traits": [
"Aecer's Likeness",
"Coat Of Fur",
"Communal",
"Enlarged Incisors",
"Quick-blooded",
"Tail",
"Large Ears"
],
"starting_stats":
[
{
"range": [
1,
5
],
"m": 6,
"p": 10
},
{
"range": [
6,
9
],
"m": 7,
"p": 13
},
{
"range": [
10,
15
],
"m": 7,
"p": 14
},
{
"range": [
16,
24
],
"m": 8,
"p": 15
},
{
"range": [
25,
30
],
"m": 8,
"p": 14
},
{
"range": [
31,
36
],
"m": 7,
"p": 13
},
{
"range": [
37,
40
],
"m": 7,
"p": 12
},
{
"range": [
41,
45
],
"m": 7,
"p": 11
},
{
"range": [
46,
49
],
"m": 6,
"p": 10
}
]
}

@ -0,0 +1,75 @@
{
"key": "wolf",
"name": "Wolf",
"stride": 11,
"adjective": "wolfish",
"common_traits": [
"Crushing Jaws",
"Deep Fur",
"Great Lupine Form",
"Lupine Intellect",
"Long-legged",
"Wolf's Eyes",
"Wolf's Snout",
"Woodland Ear"
],
"starting_stats":
[
{
"range": [
1,
1.5
],
"m": 6,
"p": 12
},
{
"range": [
2,
3.5
],
"m": 7,
"p": 16
},
{
"range": [
4,
5.5
],
"m": 7,
"p": 17
},
{
"range": [
6,
7.5
],
"m": 7,
"p": 16
},
{
"range": [
8,
9.5
],
"m": 6,
"p": 14
},
{
"range": [
10,
11.5
],
"m": 6,
"p": 12
},
{
"range": [
12,
15.5
],
"m": 5,
"p": 10
}
]
}

File diff suppressed because it is too large Load Diff

@ -1,57 +1,60 @@
[ {
{ "stock": "troll",
"name": "Rags", "resources": [
"type": "gear", {
"rp": 1 "name": "Rags",
}, "type": "gear",
{ "rp": 1
"name": "Troll Shoes", },
"type": "gear", {
"rp": 1 "name": "Troll Shoes",
}, "type": "gear",
{ "rp": 1
"name": "Sack", },
"type": "gear", {
"rp": 1 "name": "Sack",
}, "type": "gear",
{ "rp": 1
"name": "Chest or Footlocker", },
"type": "gear", {
"rp": 3 "name": "Chest or Footlocker",
}, "type": "gear",
{ "rp": 3
"name": "Trophies", },
"type": "gear", {
"rp": 3 "name": "Trophies",
}, "type": "gear",
{ "rp": 3
"name": "Shiny Trophies", },
"type": "gear", {
"rp": 7 "name": "Shiny Trophies",
}, "type": "gear",
{ "rp": 7
"name": "Pile of Rocks", },
"type": "gear", {
"rp": 2 "name": "Pile of Rocks",
}, "type": "gear",
{ "rp": 2
"name": "Troll Lash", },
"type": "gear", {
"rp": 5 "name": "Troll Lash",
}, "type": "gear",
{ "rp": 5
"name": "Mattock", },
"type": "gear", {
"rp": 10 "name": "Mattock",
}, "type": "gear",
{ "rp": 10
"name": "Black Iron Shield", },
"type": "gear", {
"rp": 5 "name": "Black Iron Shield",
}, "type": "gear",
{ "rp": 5
"name": "Cave Hole", },
"type": "property", {
"rp": 5 "name": "Cave Hole",
} "type": "property",
] "rp": 5
}
]
}

@ -1,82 +0,0 @@
[
{
"range": [
1,
5
],
"m": 3,
"p": 11
},
{
"range": [
6,
12
],
"m": 4,
"p": 14
},
{
"range": [
13,
19
],
"m": 4,
"p": 17
},
{
"range": [
20,
27
],
"m": 4,
"p": 19
},
{
"range": [
28,
57
],
"m": 4,
"p": 20
},
{
"range": [
58,
80
],
"m": 4,
"p": 19
},
{
"range": [
81,
124
],
"m": 4,
"p": 18
},
{
"range": [
125,
213
],
"m": 5,
"p": 17
},
{
"range": [
214,
390
],
"m": 5,
"p": 16
},
{
"range": [
391,
712
],
"m": 6,
"p": 15
}
]

@ -0,0 +1,100 @@
{
"key": "troll",
"name": "Troll",
"stride": 7,
"adjective": "trollish",
"common_traits": [
"Black Nails",
"Fangs",
"Night Blooded",
"Night Eyed (Troll)",
"Massive Stature (Troll)",
"Stone's Age",
"Tough (Troll)",
"Troll Skin",
"Voracious Carnivore"
],
"starting_stats":
[
{
"range": [
1,
5
],
"m": 3,
"p": 11
},
{
"range": [
6,
12
],
"m": 4,
"p": 14
},
{
"range": [
13,
19
],
"m": 4,
"p": 17
},
{
"range": [
20,
27
],
"m": 4,
"p": 19
},
{
"range": [
28,
57
],
"m": 4,
"p": 20
},
{
"range": [
58,
80
],
"m": 4,
"p": 19
},
{
"range": [
81,
124
],
"m": 4,
"p": 18
},
{
"range": [
125,
213
],
"m": 5,
"p": 17
},
{
"range": [
214,
390
],
"m": 5,
"p": 16
},
{
"range": [
391,
712
],
"m": 6,
"p": 15
}
]
}

File diff suppressed because it is too large Load Diff

@ -1,7 +1,11 @@
require 'deep_merge'
require_relative 'data/gold' require_relative 'data/gold'
require_relative 'data/wizard' require_relative 'data/wizard'
require_relative 'data/dark_elf' require_relative 'data/dark_elf'
require_relative 'data/troll' require_relative 'data/troll'
require_relative 'stock'
require_relative 'data/custom'
module Charred module Charred
class Data class Data
@ -9,11 +13,13 @@ module Charred
include Charred::Wizard include Charred::Wizard
include Charred::DarkElf include Charred::DarkElf
include Charred::Troll include Charred::Troll
include Charred::Custom
attr :data attr :data
def initialize def initialize
@data = {} @data = {}
@data[:stocks] = {}
puts 'loading gold' puts 'loading gold'
load_gold(@data) load_gold(@data)
@ -27,6 +33,9 @@ module Charred
puts 'loading trolls' puts 'loading trolls'
load_troll(@data) load_troll(@data)
puts 'loading custom stocks'
load_custom(@data)
@data[:traits] = @data[:traits].sort.to_h @data[:traits] = @data[:traits].sort.to_h
@data[:skills] = @data[:skills].sort.to_h @data[:skills] = @data[:skills].sort.to_h
end end
@ -53,5 +62,9 @@ module Charred
[] []
end end
end end
def json_get(filename)
JSON.parse(File.read(filename))
end
end end
end end

@ -0,0 +1,27 @@
require 'json'
module Charred
module Custom
def load_custom(data)
Dir.glob("data/custom/**/*") { |file|
if File.file?(file)
case File.extname(file)
when ".skills"
verbose_merge data[:skills], json_get(file)
when ".traits"
verbose_merge data[:traits], json_get(file)
when ".stock"
stock = Stock.new(json_get(file))
data[:stocks].deep_merge!({ stock.key => stock })
when ".lifepaths"
contents = json_get(file)
data[:lifepaths].ko_deep_merge!({ contents["stock"] => contents["settings"]})
when ".resources"
contents = json_get(file)
data[:resources].ko_deep_merge!({ contents["stock"] => contents["resources"]})
end
end
}
end
end
end

@ -12,10 +12,12 @@ module Charred
verbose_merge data[:traits], traits verbose_merge data[:traits], traits
file = File.read('data/dark_elf/lifepaths.json') file = File.read('data/dark_elf/lifepaths.json')
lifepaths = JSON.parse(file) contents = JSON.parse(file)
lifepaths = contents["settings"]
file = File.read("data/dark_elf/resources.json") file = File.read("data/dark_elf/resources.json")
resources = JSON.parse(file) contents = JSON.parse(file)
resources = contents["resources"]
data[:resources]['elf'] += resources data[:resources]['elf'] += resources
elf = data[:lifepaths]['elf'] elf = data[:lifepaths]['elf']
@ -32,4 +34,4 @@ module Charred
data[:lifepaths]['elf'] = elf data[:lifepaths]['elf'] = elf
end end
end end
end end

@ -1,4 +1,5 @@
require 'json' require 'json'
require_relative '../stock'
module Charred module Charred
module Gold module Gold
@ -11,29 +12,30 @@ module Charred
lifepaths = {} lifepaths = {}
resources = {} resources = {}
stat_pts = {} stocks = {}
stocks = ['dwarf', 'elf', 'man', 'orc', 'roden', 'wolf'] gold_stocks = ['dwarf', 'elf', 'man', 'orc', 'roden', 'wolf']
stocks.each do |stock| gold_stocks.each do |stock|
file = File.read("data/gold/lifepaths/#{stock}.json") file = File.read("data/gold/lifepaths/#{stock}.json")
lifepaths[stock] = JSON.parse(file) contents = JSON.parse(file)
lifepaths[stock] = contents["settings"]
file = File.read("data/gold/resources/#{stock}.json") file = File.read("data/gold/resources/#{stock}.json")
resources[stock] = JSON.parse(file) contents = JSON.parse(file)
resources[stock] = contents["resources"]
file = File.read("data/gold/starting_stat_pts/#{stock}.json") file = File.read("data/gold/stocks/#{stock}.json")
stat_pts[stock] = JSON.parse(file) stocks[stock] = Stock.new(JSON.parse(file))
end end
data.merge!({ data.merge!({
:stocks => stocks,
:skills => skills, :skills => skills,
:traits => traits, :traits => traits,
:lifepaths => lifepaths, :lifepaths => lifepaths,
:resources => resources, :resources => resources,
:stat_pts => stat_pts :stocks => stocks
}) })
end end
end end
end end

@ -1,10 +1,9 @@
require 'json' require 'json'
require_relative '../stock'
module Charred module Charred
module Troll module Troll
def load_troll(data) def load_troll(data)
data[:stocks] << 'troll'
file = File.read('data/troll/skills.json') file = File.read('data/troll/skills.json')
skills = JSON.parse(file) skills = JSON.parse(file)
verbose_merge data[:skills], skills verbose_merge data[:skills], skills
@ -14,16 +13,18 @@ module Charred
verbose_merge data[:traits], traits verbose_merge data[:traits], traits
file = File.read('data/troll/lifepaths.json') file = File.read('data/troll/lifepaths.json')
lifepaths = JSON.parse(file) contents = JSON.parse(file)
lifepaths = contents["settings"]
data[:lifepaths]['troll'] = lifepaths data[:lifepaths]['troll'] = lifepaths
file = File.read("data/troll/resources.json") file = File.read("data/troll/resources.json")
resources = JSON.parse(file) contents = JSON.parse(file)
resources = contents["resources"]
data[:resources]['troll'] = resources data[:resources]['troll'] = resources
file = File.read("data/troll/starting_stat_pts.json") file = File.read("data/troll/stock.json")
stats = JSON.parse(file) stock = JSON.parse(file)
data[:stat_pts]['troll'] = stats data[:stocks]['troll'] = Stock.new(stock)
end end
end end
end end

@ -4,7 +4,8 @@ module Charred
module Wizard module Wizard
def load_wizard(data) def load_wizard(data)
file = File.read('data/wizard/lifepaths.json') file = File.read('data/wizard/lifepaths.json')
wizard_data = JSON.parse(file) contents = JSON.parse(file)
wizard_data = contents["settings"]
file = File.read('data/wizard/skills.json') file = File.read('data/wizard/skills.json')
wizard_skills = JSON.parse(file) wizard_skills = JSON.parse(file)
@ -116,4 +117,4 @@ module Charred
data data
end end
end end
end end

@ -0,0 +1,34 @@
module Charred
class Stock
@@default_stride = 7
attr :key
attr :name
attr :stride
attr :common_traits
attr :starting_stats
def initialize(h)
@key = h["key"]
@name = h["name"] || @key
@stride = h["stride"] || @@default_stride
@adjective = h["adjective"] || @key+"ish"
@common_traits = h["common_traits"]
@starting_stats = h["starting_stats"]
end
def as_json(options = {})
{
"key" => @key,
"name" => @name,
"stride" => @stride,
"adjective" => @adjective,
"common_traits" => @common_traits,
"starting_stats" => @starting_stats
}
end
def to_json(*a)
as_json.to_json(*a)
end
end
end

@ -1,8 +1,8 @@
function loadCurrentCharacterFromStruct($scope, charStruct, burningData, appropriateWeapons){ function loadCurrentCharacterFromStruct($scope, charStruct, burningData, appropriateWeapons){
$scope.name = charStruct.name; $scope.name = charStruct.name;
$scope.gender = charStruct.gender; $scope.gender = charStruct.gender;
$scope.stock = charStruct.stock; $scope.stock = charStruct.stock;
$scope.ensureStockLoaded($scope.stock).then(() => {
// Appropriate weapons must be loaded before calculateLifepathSkills is called. // Appropriate weapons must be loaded before calculateLifepathSkills is called.
if(serverSettings.storageType != 'server'){ if(serverSettings.storageType != 'server'){
appropriateWeapons.appropriateWeapons = charStruct.approp_weapons; appropriateWeapons.appropriateWeapons = charStruct.approp_weapons;
@ -15,8 +15,8 @@ function loadCurrentCharacterFromStruct($scope, charStruct, burningData, appropr
var selectedLifepaths = []; var selectedLifepaths = [];
for(var i = 0; i < charStruct.lifepaths.length; i++){ for(var i = 0; i < charStruct.lifepaths.length; i++){
var lp = charStruct.lifepaths[i]; var lp = charStruct.lifepaths[i];
// lp[0] is setting name, lp[1] is lifepath name. // lp[0] is setting name, lp[1] is lifepath name.
// lp[2] is brutalLifeDOF, lp[3] is brutalLifeTraitName, // lp[2] is brutalLifeDOF, lp[3] is brutalLifeTraitName,
// lp[4] is lifepath time, if it's variable and the user selected a value // lp[4] is lifepath time, if it's variable and the user selected a value
// lp[5] is the replacement skill for 'Weapon Of Choice' if it's present. // lp[5] is the replacement skill for 'Weapon Of Choice' if it's present.
// lp[6] is the replacement stat array, if present. This is needed if the // lp[6] is the replacement stat array, if present. This is needed if the
@ -128,19 +128,19 @@ function loadCurrentCharacterFromStruct($scope, charStruct, burningData, appropr
// Load Resources // Load Resources
$scope.gear = {}; $scope.gear = {};
for(var i = 0; i < charStruct.gear.length; i++){ for(var i = 0; i < charStruct.gear.length; i++){
var gear = charStruct.gear[i]; var gear = charStruct.gear[i];
$scope.gear[gear.desc] = new DisplayGear(gear.desc, gear.cost); $scope.gear[gear.desc] = new DisplayGear(gear.desc, gear.cost);
} }
$scope.property = {}; $scope.property = {};
for(var i = 0; i < charStruct.property.length; i++){ for(var i = 0; i < charStruct.property.length; i++){
var property = charStruct.property[i]; var property = charStruct.property[i];
$scope.property[property.desc] = new DisplayGear(property.desc, property.cost); $scope.property[property.desc] = new DisplayGear(property.desc, property.cost);
} }
$scope.relationships = {}; $scope.relationships = {};
for(var i = 0; i < charStruct.relationships.length; i++){ for(var i = 0; i < charStruct.relationships.length; i++){
var rel = charStruct.relationships[i]; var rel = charStruct.relationships[i];
$scope.relationships[rel.desc] = new DisplayRelationship( $scope.relationships[rel.desc] = new DisplayRelationship(
rel.desc, rel.desc,
@ -154,13 +154,13 @@ function loadCurrentCharacterFromStruct($scope, charStruct, burningData, appropr
} }
$scope.affiliations = {}; $scope.affiliations = {};
for(var i = 0; i < charStruct.affiliations.length; i++){ for(var i = 0; i < charStruct.affiliations.length; i++){
var affil = charStruct.affiliations[i]; var affil = charStruct.affiliations[i];
$scope.affiliations[affil.desc] = new DisplayAffiliation(affil.desc, affil.importance); $scope.affiliations[affil.desc] = new DisplayAffiliation(affil.desc, affil.importance);
} }
$scope.reputations = {}; $scope.reputations = {};
for(var i = 0; i < charStruct.reputations.length; i++){ for(var i = 0; i < charStruct.reputations.length; i++){
var rep = charStruct.reputations[i]; var rep = charStruct.reputations[i];
$scope.reputations[rep.desc] = new DisplayReputation(rep.desc, rep.importance); $scope.reputations[rep.desc] = new DisplayReputation(rep.desc, rep.importance);
} }
@ -173,14 +173,15 @@ function loadCurrentCharacterFromStruct($scope, charStruct, burningData, appropr
$scope.attributeModifierQuestionResults = loadAttributeModifierQuestionResultsFromSave($scope, charStruct.attr_mod_questions); $scope.attributeModifierQuestionResults = loadAttributeModifierQuestionResultsFromSave($scope, charStruct.attr_mod_questions);
$scope.brutalLifeWithdrawn = charStruct.brutal_life_withdrawn; $scope.brutalLifeWithdrawn = charStruct.brutal_life_withdrawn;
$scope.$digest();
});
} }
function convertCurrentCharacterToStruct($scope, appropriateWeapons) { function convertCurrentCharacterToStruct($scope, appropriateWeapons) {
// To serialize: // To serialize:
// - Serialized version // - Serialized version
// - Character name // - Character name
// - Stock // - Stock
// - Gender // - Gender
// - A list Lifepath names, with setting: [setting, lifepath] // - A list Lifepath names, with setting: [setting, lifepath]
// - How many points were spent on which stat // - How many points were spent on which stat
@ -225,10 +226,10 @@ function convertCurrentCharacterToStruct($scope, appropriateWeapons) {
var displayStat = $scope.stats[i]; var displayStat = $scope.stats[i];
stats.push({ stats.push({
"name" : displayStat.name, "name" : displayStat.name,
"shade" : displayStat.shade, "shade" : displayStat.shade,
"mentalPoints" : displayStat.mentalPointsSpent, "mentalPoints" : displayStat.mentalPointsSpent,
"physicalPoints" : displayStat.physicalPointsSpent, "physicalPoints" : displayStat.physicalPointsSpent,
"eitherPoints" : displayStat.eitherPointsSpent "eitherPoints" : displayStat.eitherPointsSpent
}); });
} }
@ -277,7 +278,7 @@ function convertCurrentCharacterToStruct($scope, appropriateWeapons) {
} }
var res = serializeResource( $scope.gear, function(display){ var res = serializeResource( $scope.gear, function(display){
return { return {
"cost" : display.cost, "cost" : display.cost,
"desc" : display.desc "desc" : display.desc
}; };
@ -285,7 +286,7 @@ function convertCurrentCharacterToStruct($scope, appropriateWeapons) {
chardata.gear = res; chardata.gear = res;
var res = serializeResource( $scope.property, function(display){ var res = serializeResource( $scope.property, function(display){
return { return {
"cost" : display.cost, "cost" : display.cost,
"desc" : display.desc "desc" : display.desc
}; };
@ -293,7 +294,7 @@ function convertCurrentCharacterToStruct($scope, appropriateWeapons) {
chardata.property = res; chardata.property = res;
var res = serializeResource( $scope.relationships, function(display){ var res = serializeResource( $scope.relationships, function(display){
return { return {
"desc" : display.desc, "desc" : display.desc,
"importance" : display.importance, "importance" : display.importance,
"isImmedFam" : display.isImmedFam, "isImmedFam" : display.isImmedFam,
@ -306,7 +307,7 @@ function convertCurrentCharacterToStruct($scope, appropriateWeapons) {
chardata.relationships = res; chardata.relationships = res;
var res = serializeResource( $scope.affiliations, function(display){ var res = serializeResource( $scope.affiliations, function(display){
return { return {
"desc" : display.desc, "desc" : display.desc,
"importance" : display.importance "importance" : display.importance
}; };
@ -314,7 +315,7 @@ function convertCurrentCharacterToStruct($scope, appropriateWeapons) {
chardata.affiliations = res; chardata.affiliations = res;
var res = serializeResource( $scope.reputations, function(display){ var res = serializeResource( $scope.reputations, function(display){
return { return {
"desc" : display.desc, "desc" : display.desc,
"importance" : display.importance "importance" : display.importance
}; };

@ -1,4 +1,4 @@
var DEBUG = false;
/**** Class Settings (Angular Service) ****/ /**** Class Settings (Angular Service) ****/
function Settings() { function Settings() {
this.enforceLifepathReqts = true; this.enforceLifepathReqts = true;
@ -9,7 +9,7 @@ function Settings() {
/**** Class AppropriateWeaponsService (Angular Service) ****/ /**** Class AppropriateWeaponsService (Angular Service) ****/
function AppropriateWeaponsService($modal, $http) { function AppropriateWeaponsService($modal, $http) {
// This class will store a hash which maps lifepath names to a list of // This class will store a hash which maps lifepath names to a list of
// weapons that are appropriate for that lifepath. // weapons that are appropriate for that lifepath.
this.appropriateWeapons = {}; this.appropriateWeapons = {};
@ -167,7 +167,7 @@ function WeaponOfChoiceService($modal, $http) {
} }
return has; return has;
} }
this.selectWeaponOfChoice = function (displayLp, onSelect){ this.selectWeaponOfChoice = function (displayLp, onSelect){
if( this.hasWeaponOfChoice(displayLp) ){ if( this.hasWeaponOfChoice(displayLp) ){
this.selectWeaponOfChoiceByModal(displayLp.name, function(selected){ this.selectWeaponOfChoiceByModal(displayLp.name, function(selected){
@ -218,13 +218,14 @@ function CharacterStorageService($http) {
/* Load character names from server */ /* Load character names from server */
this.loadCharacterNames = function(){ this.loadCharacterNames = function(){
$http.get("/list_chars/user1", {'timeout': 3000} ). fetch("/list_chars/user1")
success(function(data,status,headers,config){ .then((response) => response.json())
.then((data) => {
myself.characterIdAndNames = data; myself.characterIdAndNames = data;
console.log("Loaded saved character names"); console.log("Loaded saved character names");
}). })
error(function(data,status,headers,config){ .catch((error) => {
console.log("Error: Loading saved character names from server failed: HTTP code " + status + ": " + data); console.log("Error: Loading saved character names from server failed: "+error);
}); });
} }
@ -236,6 +237,10 @@ function CharacterStorageService($http) {
/**** Class BurningDataService (Angular Service) ****/ /**** Class BurningDataService (Angular Service) ****/
// This service is used to load the lifepaths, skills, traits, etc. from the server. // This service is used to load the lifepaths, skills, traits, etc. from the server.
function BurningDataService($http) { function BurningDataService($http) {
// Used to reference the object from within functions and callbacks
var myself = this;
/* JSON Data structure representing lifepaths. The structure is: /* JSON Data structure representing lifepaths. The structure is:
stock: stock:
setting_name: setting_name:
@ -250,135 +255,101 @@ function BurningDataService($http) {
roots: [root1, root2, ...] roots: [root1, root2, ...]
skill_name: skill_name:
roots: [root1, root2, ...] roots: [root1, root2, ...]
*/ */
this.skills = {}; this.skills = {};
/* JSON data structure representing all available traits */ /* JSON data structure representing all available traits */
this.traits = {}; this.traits = {};
/* JSON data structure representing all available resources (gear/property) */ /* JSON data structure representing all available resources (gear/property) */
this.resources = {}; this.resources = {};
// A hash of StartingStatPoints objects keyed by stock. // A hash of StartingStatPoints objects keyed by stock.
this.startingStatPts = {}; this.startingStatPts = {};
this.dataSetsLoaded = 0; /* Loading of stocks, skills, and traits begins on initializing the service
// Total data sets:
// lifepaths: 7 (man, dwarf, elf, orc, roden, wolf, troll)
// stat points: 7 (man, dwarf, elf, orc, roden, wolf, troll)
// skills
// traits
// resources: 7 (man, dwarf, elf, orc, roden, wolf. troll)
// TOTAL: 23
this.totalDataSets = 23;
this.onAllDatasetsLoaded = null;
this.registerOnAllDatasetsLoaded = function(callback){
if ( this.dataSetsLoaded >= this.totalDataSets ){
callback();
}
this.onAllDatasetsLoaded = callback;
}
this.datasetLoaded = function(){
this.dataSetsLoaded += 1;
if ( this.onAllDatasetsLoaded && (this.dataSetsLoaded >= this.totalDataSets) ){
this.onAllDatasetsLoaded();
}
if ( this.dataSetsLoaded > this.totalDataSets){
console.log("Error: the totalDataSets setting in BurningDataService is too low! This will cause wierd errors. Please adjust it");
}
}
var stocks = ["man", "dwarf", "elf", "orc", "roden", "wolf", "troll"];
var myself = this;
/* Load lifepaths from server */
var loadLifepathsForStock = function(stock){
if( ! isValidStock(stock) ){
console.log("Loading lifepaths failed: asked to load lifepaths for invalid stock " + stock);
return
}
$http.get("/lifepaths/" + stock, {'timeout': 3000} ).
success(function(data,status,headers,config){
myself.lifepaths[stock] = data;
myself.datasetLoaded();
console.log("Loaded "+stock+" lifepaths. " + Object.keys(myself.lifepaths).length + " settings");
}).
error(function(data,status,headers,config){
myself.datasetLoaded();
console.log("Error: Getting "+stock+" lifepaths from server failed: HTTP code " + status + ": " + data);
});
}
/* Load starting stat points table from server */
var loadStartingStatPtsForStock = function(stock){
if( ! isValidStock(stock) ){
console.log("Loading starting stat points failed: asked to load pts for invalid stock " + stock);
return
}
$http.get("/starting_stat_pts/" + stock, {'timeout': 3000} ). /* Load stocks from server */
success(function(data,status,headers,config){ this.whenStocksLoaded = fetch("/stocks")
myself.startingStatPts[stock] = new StartingStatPoints(data); .then((response) => response.json())
myself.datasetLoaded(); .then((data) => {
console.log("Loaded "+stock+" starting stat points. "); if(DEBUG) {
}). console.log("Loaded stock data:");
error(function(data,status,headers,config){ console.log(data);
myself.datasetLoaded(); }
console.log("Error: Getting "+stock+" stat points from server failed: HTTP code " + status + ": " + data); myself.stocks = data;
}); for (var stock of Object.keys(data)) {
} myself.startingStatPts[stock] = new StartingStatPoints(myself.stocks[stock].starting_stats);
}
/* Load starting stat points table from server */ })
var loadResourcesForStock = function(stock){ .catch((error) => {
if( ! isValidStock(stock) ){ console.log("Error: Getting stocks from server failed: "+error);
console.log("Loading resources failed: asked to load for invalid stock " + stock); });
return
}
$http.get("/resources/" + stock, {'timeout': 3000} ).
success(function(data,status,headers,config){
myself.resources[stock] = data;
myself.datasetLoaded();
console.log("Loaded "+stock+" resources. ");
}).
error(function(data,status,headers,config){
myself.datasetLoaded();
console.log("Error: Getting "+stock+" stat points from server failed: HTTP code " + status + ": " + data);
});
}
for (var i = 0; i < stocks.length; i++) {
loadLifepathsForStock(stocks[i]);
loadStartingStatPtsForStock(stocks[i]);
loadResourcesForStock(stocks[i]);
}
/* Load skills from server */ /* Load skills from server */
$http.get("/skills", {'timeout': 3000} ). this.whenSkillsLoaded = fetch("/skills")
success(function(data,status,headers,config){ .then((response) => response.json())
.then((data) => {
myself.skills = data; myself.skills = data;
myself.datasetLoaded(); if(DEBUG) {
console.log("Loaded skills. "); console.log("Loaded skill data:");
}). console.log(data);
error(function(data,status,headers,config){ }
myself.datasetLoaded(); })
console.log("Error: Getting skills from server failed: HTTP code " + status + ": " + data); .catch((error) => {
console.log("Error: Getting skills from server failed: "+error);
}); });
/* Load traits from server */ /* Load traits from server */
$http.get("/traits", {'timeout': 3000} ). this.whenTraitsLoaded = fetch("/traits")
success(function(data,status,headers,config){ .then((response) => response.json())
.then((data) => {
myself.traits = data; myself.traits = data;
myself.datasetLoaded(); if(DEBUG) {
console.log("Loaded traits. "); console.log("Loaded trait data:");
}). console.log(data);
error(function(data,status,headers,config){ }
myself.datasetLoaded(); })
console.log("Error: Getting traits from server failed: HTTP code " + status + ": " + data); .catch((error) => {
console.log("Error: Getting traits from server failed: "+error);
}); });
/* Lifepaths and resources defer until their stock is selected */
this.whenLifePathsLoadedForStock = {};
/* Load lifepaths from server */
this.loadLifepathsForStock = function(stock){
return myself.whenLifePathsLoadedForStock[stock] = fetch("/lifepaths/" + stock)
.then((response) => response.json())
.then((data) => {
myself.lifepaths[stock] = data;
if(DEBUG) {
console.log("Loaded "+stock+" lifepaths:");
console.log(data);
}
})
.catch((error) => {
console.log("Error: Getting "+stock+" lifepaths from server failed: "+error);
});
};
/* Load resources from server */
this.whenResourcesLoadedForStock = {};
this.loadResourcesForStock = function(stock){
return myself.whenResourcesLoadedForStock[stock] = fetch("/resources/" + stock)
.then((response) => response.json())
.then((data) => {
myself.resources[stock] = data;
if(DEBUG) {
console.log("Loaded "+stock+" resources:");
console.log(data);
}
})
.catch((error) => {
console.log("Error: Getting "+stock+" resources from server failed: "+error);
});
};
} }
/**** End BurningDataService ****/ /**** End BurningDataService ****/

File diff suppressed because it is too large Load Diff

@ -1,5 +1,5 @@
var serverSettings = { var serverSettings = {
'versionString' : '2.3.0', 'versionString' : '3.0.0',
'storageType' : 'client', 'storageType' : 'client',
'displayAttrMath' : 'false' 'displayAttrMath' : 'false'
} }

@ -94,14 +94,7 @@
</strong> </strong>
</div> </div>
<div class='col-md-2'> <div class='col-md-2'>
<select class='form-control' ng-change='onStockChange()' ng-model='stock'> <select class='form-control' ng-change='onStockChange()' ng-model='stock' ng-options='s.key as s.name for s in stocks'>
<option value='man'>Man</option>
<option value='dwarf'>Dwarf</option>
<option value='elf'>Elf</option>
<option value='orc'>Orc</option>
<option value='roden'>Roden</option>
<option value='wolf'>Great Wolf</option>
<option value='troll'>Troll</option>
</select> </select>
</div> </div>
<div class='col-md-1'> <div class='col-md-1'>

@ -0,0 +1,133 @@
{
"stock": "test",
"settings": {
"Test Setting": {
"Born Test": {
"time": 7,
"res": 5,
"skills": [
[
1,
"General"
]
],
"traits": [
2
],
"leads": [
"Nowhere"
],
"key_leads": [
"Nowhere Setting"
]
},
"A thing": {
"time": 5,
"res": 2,
"stat": [
[
2,
"p"
]
],
"skills": [
[
4,
"Testing",
"Forest-wise",
"Stealthy"
]
],
"traits": [
1
],
"leads": [
"Nowhere"
],
"key_leads": [
"Nowhere Setting"
]
}
},
"Nowhere Setting": {
"Born Nothing": {
"time": 0,
"res": 0,
"skills": [
],
"traits": [
],
"leads": [
],
"key_leads": [
]
},
"Not A Thing": {
"time": 15,
"res": 1,
"stat": [
[
1,
"pm"
]
],
"skills": [
[
2,
"Nothinging",
"Voiding"
]
],
"traits": [
3
],
"leads": [
"Somewhere"
],
"key_leads": [
"Somewhere Subsetting"
]
}
},
"Somewhere Subsetting": {
"Something Special": {
"time": 30,
"res": 21,
"stat": [
[
1,
"m"
],[
1,
"p"
],[
1,
"pm"
]
],
"skills": [
[
7,
"Specializing",
"Soothing",
"History",
"Sorcery",
"Spirit Binding",
"Harming"
]
],
"traits": [
3,
"Stubborn",
"Shy"
],
"leads": [
"Nowhere"
],
"key_leads": [
"Nowhere Setting"
]
}
}
}
}

@ -0,0 +1,25 @@
{
"stock": "test",
"resources": [
{
"name": "Rags",
"type": "gear",
"rp": 1
},
{
"name": "Riches",
"type": "gear",
"rp": 50
},
{
"name": "A firey soul",
"type": "gear",
"rp": 3
},
{
"name": "Chest or Footlocker",
"type": "gear",
"rp": 3
}
]
}

@ -0,0 +1,39 @@
{
"Testing": {
"stock": "testish",
"roots": [
"Perception"
]
},
"Nothinging": {
"stock": "testish",
"roots": [
"Will",
"Agility"
]
},
"Voiding": {
"stock": "testish",
"roots": [
"Speed"
]
},
"Specializing": {
"stock": "testish",
"roots": [
"Forte"
]
},
"Soothing": {
"stock": "testish",
"roots": [
"Power"
]
},
"Harming": {
"stock": "testish",
"roots": [
"Will"
]
}
}

@ -0,0 +1,95 @@
{
"key": "test",
"name": "Test",
"stride": 9,
"adjective": "testish",
"common_traits": [
"Trait 1",
"testy",
"Trait #3",
"Night Eyed (Test)"
],
"starting_stats":
[
{
"range": [
1,
10
],
"m": 1,
"p": 2
},
{
"range": [
11,
20
],
"m": 2,
"p": 4
},
{
"range": [
21,
30
],
"m": 3,
"p": 6
},
{
"range": [
31,
40
],
"m": 4,
"p": 8
},
{
"range": [
41,
50
],
"m": 5,
"p": 10
},
{
"range": [
51,
60
],
"m": 6,
"p": 12
},
{
"range": [
61,
70
],
"m": 7,
"p": 14
},
{
"range": [
71,
80
],
"m": 8,
"p": 16
},
{
"range": [
81,
90
],
"m": 9,
"p": 18
},
{
"range": [
91,
100
],
"m": 10,
"p": 20
}
]
}

@ -0,0 +1,55 @@
{
"Trait 1": {
"cost": 0,
"type": "die",
"restrict": [
"testish",
"common"
],
"desc": ""
},
"testy": {
"cost": 0,
"type": "die",
"restrict": [
"testish",
"common"
],
"desc": ""
},
"Trait #3": {
"cost": 0,
"type": "die",
"restrict": [
"testish",
"common"
],
"desc": ""
},
"Night Eyed (Test)": {
"cost": 1,
"type": "die",
"restrict": [
"testish",
"common"
],
"desc": "The test version"
},
"Shy": {
"cost": 1,
"type": "character",
"restrict": [
"testish",
"lifepath"
]
},
"Special": {
"cost": 3,
"type": "die",
"restrict": [
"testish",
"special"
],
"desc": "Snowflake"
}
}
Loading…
Cancel
Save