add spite emotional attribute

pull/1/head
Michael Hansen 5 years ago
parent d7b0dc37d1
commit 04b2a916a7
  1. 0
      Dockerfile
  2. 0
      Dockerfile.dev
  3. 0
      Gemfile
  4. 0
      Gemfile.lock
  5. 132
      deploy.md
  6. 0
      src/app.rb
  7. 0
      src/data/caliban.ttf
  8. 0
      src/data/dark_elf/lifepaths.json
  9. 0
      src/data/dark_elf/resources.json
  10. 2
      src/data/dark_elf/skills.json
  11. 0
      src/data/dark_elf/traits.json
  12. 0
      src/data/gold.pdf
  13. 0
      src/data/gold/lifepaths/dwarf.json
  14. 0
      src/data/gold/lifepaths/elf.json
  15. 0
      src/data/gold/lifepaths/man.json
  16. 0
      src/data/gold/lifepaths/orc.json
  17. 0
      src/data/gold/lifepaths/roden.json
  18. 0
      src/data/gold/lifepaths/wolf.json
  19. 0
      src/data/gold/resources/dwarf.json
  20. 0
      src/data/gold/resources/elf.json
  21. 0
      src/data/gold/resources/man.json
  22. 0
      src/data/gold/resources/orc.json
  23. 0
      src/data/gold/resources/roden.json
  24. 0
      src/data/gold/resources/wolf.json
  25. 0
      src/data/gold/skills.json
  26. 0
      src/data/gold/starting_stat_pts/dwarf.json
  27. 0
      src/data/gold/starting_stat_pts/elf.json
  28. 0
      src/data/gold/starting_stat_pts/man.json
  29. 0
      src/data/gold/starting_stat_pts/orc.json
  30. 0
      src/data/gold/starting_stat_pts/roden.json
  31. 0
      src/data/gold/starting_stat_pts/wolf.json
  32. 0
      src/data/gold/traits.json
  33. 0
      src/data/wizard/lifepaths.json
  34. 0
      src/data/wizard/skills.json
  35. 0
      src/data/wizard/traits.json
  36. 0
      src/lib/cache.rb
  37. 0
      src/lib/data.rb
  38. 0
      src/lib/data/dark_elf.rb
  39. 0
      src/lib/data/gold.rb
  40. 0
      src/lib/data/wizard.rb
  41. 0
      src/lib/pdf.rb
  42. 0
      src/public/css/bootstrap.min.css
  43. 0
      src/public/css/style.css
  44. 0
      src/public/fonts/post-mediaeval.ttf
  45. 0
      src/public/js/angular-resource.js
  46. 0
      src/public/js/angular-route.js
  47. 0
      src/public/js/angular.min.js
  48. 0
      src/public/js/bootstrap.min.js
  49. 0
      src/public/js/burning-classes.js
  50. 0
      src/public/js/burning-modal.js
  51. 0
      src/public/js/burning-serialize.js
  52. 0
      src/public/js/burning-service.js
  53. 0
      src/public/js/burning-util.js
  54. 80
      src/public/js/burning.js
  55. 0
      src/public/js/jquery-1.10.2.min.js
  56. 0
      src/public/js/server_settings.js
  57. 0
      src/public/js/ui-bootstrap-tpls-0.11.0.js
  58. 0
      src/views/index.erb
  59. 0
      src/views/partials/choose_appropriate_weapons.erb
  60. 0
      src/views/partials/choose_character.erb
  61. 0
      src/views/partials/choose_stat_penalty.erb
  62. 0
      src/views/partials/choose_trait.erb
  63. 0
      src/views/partials/choose_weapon_of_choice.erb
  64. 0
      src/views/partials/config.erb
  65. 0
      src/views/partials/emotional_attr_questions.erb
  66. 0
      src/views/partials/help.erb
  67. 0
      src/views/partials/main.erb
  68. 0
      src/views/partials/upload_character.erb

@ -8,3 +8,135 @@ heroku container:login
heroku container:push web -a charred-black heroku container:push web -a charred-black
heroku container:release web -a charred-black heroku container:release web -a charred-black
heroku open heroku open
## Changelog
2.0.1 - update
First Mate LP should be selectable with 2 seafaring LPs. If Son of a Gun is the first LP, it is not selectable.
Example: Son of a Gun -> Officer's Mate -> First Mate.
2.0.0 - Charred Black release
gold character pdf
wizard burner lifepaths
## Beliefs
I welcome community contributions, and you are welcome to fork this source code if you want to go your own way. As the maintainer,
here's what you can expect from me when I judge contributions.
### Do One Thing Well
Charred Black is a character creation utility. You are welcome to use the data, source code, or character files in the creation
of other gaming tools, but let's keep this tool focused on one thing and do it really well.
### Stick To Published Material
In order to keep the scope of my maintainership finite, I'm not planning to accept community-made lifepaths et al. for inclusion
in this codebase. Each additional data set increases Charred Black's startup time and memory requirements. Additionally, that
makes me an arbiter of quality, and I'd prefer not to have the Enmity Clause invoked because I rejected someone's homebrew content.
I am working on a solution for uploading lifepaths et. al which would be stored locally in your browser and not permanently on
a server. This way, you can make your data files and share them around with your friends for use with this tool. If someone else
wants to keep a repository or forum thread of data files known to work with Charred Black, I'd happily to link to it in this
documentation and from the website itself. I don't want to discourage contributions, I just want do one thing well.
### Keep It Mostly Stateless
Charred Black uses an in-memory cache to allow users to upload JSON and then download .char and .pdf files. I don't know how the
original Charred handled this, but the tradeoffs of this approach are:
1. Works as expected without an update to the frontend
2. PDF generation happens entirely in one process, limiting the amount of futzing you have to do with distributed systems
3. Because the cache is in memory, you can't scale processes horizontally
The cache has a limited number of keys, and only the first 16kb of data are used, with the aim of making this this app useless
for nefarious purposes. The average size of a 4-lifepath character is around 4kb, so this should be more than enough. If you're
trying to do something weird and your character file is bigger than this, consider using a pencil and paper.
More guidelines:
* Only JSON should be stored in the cache.
* Cached items should be invalidated upon access (by using the delete method to get the data) to restrict the usefulness of this app
to bad actors.
* Only .pdf and .char file formats should be returned as responses when getting data out of the cache. I'll consider other formats
on a case-by-case basis: for example, I'd be open to a format which could be used with Roll20.
## Guide
### Best Practices
No matter what's in the book, always Capital Case for skills, traits, lifepaths and settings:
e.g.
Path Of Spite Subsetting
Never A Moment Of Peace
Ages Of The Etharch
Reeks Of Alcohol
Hyphens: the word after the hyphen is not capitalized:
Rabble-rouser
Burden Of The Crown-wise
Anatomy of a lifepath
```
{
"Example Setting": {
"Example Lifepath": {
"time": 1,
"res": 1,
"stat": [
[
1,
"m"
],
[
1,
"p"
]
],
"skills": [
[
3,
"Inconspicuous"
],
[
1,
"General"
]
],
"traits": [
1,
""
],
"requires": "",
"requires_expr": [
],
"leads": [
"Peasant",
"Villager",
"City",
"Court",
"Servitude",
"Outcast",
"Soldier",
"Seafaring",
"Religious"
],
"key_leads": [
"Peasant Setting",
"Villager Setting",
"City Dweller Setting",
"Noble Court Subsetting",
"Servitude And Captive Setting",
"Outcast Subsetting",
"Professional Soldier Subsetting",
"Seafaring Setting",
"Religious Subsetting"
]
}
}
}
```

@ -48,7 +48,7 @@
"Will" "Will"
] ]
}, },
"Surrow Of Truth": { "Sorrow Of Truth": {
"stock": "elven", "stock": "elven",
"magic": 1, "magic": 1,
"roots": [ "roots": [

@ -150,6 +150,15 @@ function BurningCtrl($scope, $http, $modal, $timeout, settings, appropriateWeapo
return $scope.attribute("Ancestral Taint").shade; return $scope.attribute("Ancestral Taint").shade;
} }
}; };
$scope.statsForSkillCalc["Spite"] = {
"exp": function(){
// Note: this function can't be called until $scope.attribute is defined!
return $scope.attribute("Spite").exp;
},
"calcshade": function(){
return $scope.attribute("Spite").shade;
}
};
// Setting names for use in the Add Lifepath section // Setting names for use in the Add Lifepath section
$scope.settingNames = ["Loading..."] $scope.settingNames = ["Loading..."]
$scope.currentSettingLifepathNames = []; $scope.currentSettingLifepathNames = [];
@ -248,7 +257,7 @@ function BurningCtrl($scope, $http, $modal, $timeout, settings, appropriateWeapo
/* Used to keep track of whether the user shade-shifted an attribute, for those attributes that /* Used to keep track of whether the user shade-shifted an attribute, for those attributes that
allow shade shifting */ allow shade shifting */
$scope.attributeShade = {'Steel': 'B', 'Grief' : 'B', 'Greed' : 'B', 'Hatred' : 'B'}; $scope.attributeShade = {'Steel': 'B', 'Grief' : 'B', 'Greed' : 'B', 'Hatred' : 'B', 'Spite' : 'B'};
$scope.ptgs = new PTGS(); $scope.ptgs = new PTGS();
@ -329,6 +338,10 @@ function BurningCtrl($scope, $http, $modal, $timeout, settings, appropriateWeapo
} }
else if ( $scope.stock == "elf" ){ else if ( $scope.stock == "elf" ){
result.push("Grief"); result.push("Grief");
// Spite must be calculated after Grief
if ( $scope.hasTrait("Spite") ) {
result.push("Spite");
}
} }
else if ( $scope.stock == "dwarf" ){ else if ( $scope.stock == "dwarf" ){
result.push("Greed"); result.push("Greed");
@ -933,7 +946,6 @@ function BurningCtrl($scope, $http, $modal, $timeout, settings, appropriateWeapo
} }
} }
// Return the value of the attribute with the specified name as a hash of [shade : S, exp : E, modifyable : flag] // Return the value of the attribute with the specified name as a hash of [shade : S, exp : E, modifyable : flag]
$scope.attribute = function(name){ $scope.attribute = function(name){
@ -1081,6 +1093,14 @@ function BurningCtrl($scope, $http, $modal, $timeout, settings, appropriateWeapo
grief += bonus; grief += bonus;
return { "shade" : $scope.attributeShade[name], "exp" : grief, "modifyable" : true}; return { "shade" : $scope.attributeShade[name], "exp" : grief, "modifyable" : true};
} }
else if ( "Spite" == name ){
var spite = computeModifiers(name);
if($scope.attributeShade[name] == 'G'){
spite -= 5;
}
spite += bonus;
return { "shade" : $scope.attributeShade[name], "exp" : spite, "modifyable" : true};
}
else if ( "Faith" == name ){ else if ( "Faith" == name ){
var faith = 3 + computeModifiers(name); var faith = 3 + computeModifiers(name);
faith += bonus; faith += bonus;
@ -1092,7 +1112,6 @@ function BurningCtrl($scope, $http, $modal, $timeout, settings, appropriateWeapo
taint += bonus; taint += bonus;
return { "shade" : $scope.statsByName["Will"].shade, "exp" : taint, "modifyable" : true}; return { "shade" : $scope.statsByName["Will"].shade, "exp" : taint, "modifyable" : true};
} }
} }
$scope.distributeStats = function(){ $scope.distributeStats = function(){
@ -3043,14 +3062,12 @@ function attributeModifyingQuestions($scope, attribute)
for(key in skills) for(key in skills)
{ {
var skill = skills[key]; var skill = skills[key];
if( skill.exp($scope.statsForSkillCalc) > 0 && beginsWith(key.toLowerCase(), "lament") ) // Dark Elves have no laments, therefore we check if the skill is a lament BEFORE we calculate
return 0; // the exponent because we don't want to it to get sent into an infinite loop, i.e.
} // calculate spite -> calc grief -> calc spite skill exponent -> spite -> grief -> ...
for(var i = 0; i < skills.length; i++){ if( beginsWith(key.toLowerCase(), "lament") && skill.exp($scope.statsForSkillCalc) > 0 )
if( beginsWith(skills[i].name.toLowerCase(), "lament") )
return 0; return 0;
} }
return 1; return 1;
} }
@ -3077,9 +3094,48 @@ function attributeModifyingQuestions($scope, attribute)
{question: "Has the character lived among non-Elven people?", math_label: "(+1 Grief)", modifier: 1}, {question: "Has the character lived among non-Elven people?", math_label: "(+1 Grief)", modifier: 1},
{question: "+1 Grief for each point of Steel above 5.", computed: true, compute: steelMod}, {question: "+1 Grief for each point of Steel above 5.", computed: true, compute: steelMod},
{question: "+1 Grief if the characters Perception is above 5.", computed: true, compute: percMod}, {question: "+1 Grief if the characters Perception is above 5.", computed: true, compute: percMod},
{question: "+1 Greed if the character is over 500 years old.", computed: true, compute: ageMod(500)}, {question: "+1 Grief if the character is over 500 years old.", computed: true, compute: ageMod(500)},
{question: "+1 Greed if the character is over 750 years old.", computed: true, compute: ageMod(750)}, {question: "+1 Grief if the character is over 750 years old.", computed: true, compute: ageMod(750)},
{question: "+1 Greed if the character is over 1000 years old.", computed: true, compute: ageMod(1000)} {question: "+1 Grief if the character is over 1000 years old.", computed: true, compute: ageMod(1000)}
);
}
else if ( attribute == "Spite" )
{
var griefMod = function() {
var grief = $scope.attribute("Grief").exp
return grief;
}
var traitsMod = function(){
var val = 0;
if($scope.hasTrait('Slayer'))
val++;
if($scope.hasTrait('Exile'))
val++;
if($scope.hasTrait('Feral'))
val++;
if($scope.hasTrait('Murderous'))
val++;
if($scope.hasTrait('Saturnine'))
val++;
if($scope.hasTrait('Femme Fatale/Homme Fatale'))
val++;
if($scope.hasTrait('Cold'))
val++;
if($scope.hasTrait('Bitter'))
val++;
return val;
}
result.push(
{question: "+1 Spite for every point of Grief", computed: true, compute: griefMod},
{question: "+1 Spite for each of several spiteful traits", computed: true, compute: traitsMod},
{question: "Has the character been betrayed by their friends?", math_label: "(+1 Spite)", modifier: 1},
{question: "Is the character lovesick or broken hearted?", math_label: "(+1 Spite)", modifier: 1},
{question: "Has the character been abandoned by those they held dear?", math_label: "(+1 Spite)", modifier: 1},
{question: "Has the character been abused or tortured?", math_label: "(+1 Spite)", modifier: 1},
{question: "Does the character still respect or admire someone on the other side?", math_label: "(-1 Spite)", modifier: -1},
{question: "Does the character still love someone on the other side?", math_label: "(-2 Spite)", modifier: -2}
); );
} }
else if ( attribute == "Hatred" ) else if ( attribute == "Hatred" )

Loading…
Cancel
Save