Adds stress-as-counter with max and current value

This commit is contained in:
Megastruktur 2020-08-18 17:22:07 +03:00
parent 96b1a3a3b7
commit c2ff5bd704
11 changed files with 112 additions and 46 deletions

View File

@ -1,3 +1,10 @@
v2.0
- Refactored the Stress to have dynamic Max value
- Added Hull
- Added Ghost
- Added Vampire
- Added Logic field to Item, Class and Ability
v1.2
- Non-Turf claims are no longer counted against Rep-Turf limit
@ -11,4 +18,7 @@ v1.0
- Added Russian localization (Cododoc)
- Added design improvements and quality of life hinting to character sheet (OctarineSourcerer)
- Changed the Versioning for easier tracking
TODOs:
- Remove and Re-add ALL items, when the item is removed to implement logic.

View File

@ -46,6 +46,19 @@ Crew Types:
![alt screen][screenshot_roll_1]
![alt screen][screenshot_roll_2]
## Logic field
Logic field is a json with params which allows to implement some logic when the Item of corresponding type is added or removed.
### Example (from the Vault 1 crew upgrade)
`{"attribute":"data.vault.max","operator":"addition","value":4,"requirement":""}`
- `attribute` - the attribute to affect
- `operator` - what is done to attribute
- `value` - the value for operator
- `requirement` - is not used
### Operators list
- `addition` - is added when item is attached and substracted when removed
## To be done in the nearest future
- Friends/rivals section
- Stress/Harm dynamic values (can be modified by abilities but for now are hardcoded)

View File

@ -120,6 +120,9 @@ export class BladesHelpers {
/**
* Undo Item modifications when item is removed.
* @todo
* - Remove all items and then Add them back to
* sustain the logic mods
* @param {Object} item_data
* @param {Entity} entity
*/

View File

@ -52,7 +52,7 @@ Hooks.once("init", async function() {
let html = options.fn(this);
if (typeof selected != 'undefined') {
if (typeof selected !== 'undefined') {
selected.forEach(selected_value => {
if (selected_value !== false) {
const escapedValue = RegExp.escape(Handlebars.escapeExpression(selected_value));
@ -128,6 +128,22 @@ Hooks.once("init", async function() {
return new Handlebars.SafeString(text);;
});
// "N Times" loop for handlebars.
// Block is executed N times starting from n=1.
//
// Usage:
// {{#times_from_1 10}}
// <span>{{this}}</span>
// {{/times_from_1}}
Handlebars.registerHelper('times_from_1', function(n, block) {
var accum = '';
for (var i = 1; i <= n; ++i) {
accum += block.fn(i);
}
return accum;
});
});
/**
@ -137,10 +153,10 @@ Hooks.once("ready", function() {
// Determine whether a system migration is required
const currentVersion = game.settings.get("bitd", "systemMigrationVersion");
const NEEDS_MIGRATION_VERSION = 1.0;
const NEEDS_MIGRATION_VERSION = 1.2;
let needMigration = (currentVersion < NEEDS_MIGRATION_VERSION) || (currentVersion === null);
// Perform the migration
if ( needMigration && game.user.isGM ) {
migrations.migrateWorld();

View File

@ -9,7 +9,7 @@ export const migrateWorld = async function() {
for ( let a of game.actors.entities ) {
if (a.data.type === 'character') {
try {
const updateData = _migrateActorSkills(a.data);
const updateData = _migrateActor(a.data);
if ( !isObjectEmpty(updateData) ) {
console.log(`Migrating Actor entity ${a.name}`);
await a.update(updateData, {enforceTypes: false});
@ -32,15 +32,16 @@ export const migrateWorld = async function() {
/* -------------------------------------------- */
/**
* Migrate the actor skills
* Migrate the actor attributes
* @param {Actor} actor The actor to Update
* @return {Object} The updateData to apply
*/
function _migrateActorSkills(actor) {
function _migrateActor(actor) {
let updateData = {}
const attributes = game.system.model.Actor.character.attributes;
// Migrate Skills
const attributes = game.system.model.Actor.character.attributes;
for ( let attribute_name of Object.keys(actor.data.attributes || {}) ) {
// Insert attribute label
@ -65,6 +66,24 @@ function _migrateActorSkills(actor) {
}
}
// Migrate Stress to Array
if (typeof actor.data.stress[0] !== 'undefined') {
updateData[`data.stress.value`] = actor.data.stress;
updateData[`data.stress.max`] = 9;
updateData[`data.stress.max_default`] = 9;
updateData[`data.stress.name_default`] = "BITD.Stress";
updateData[`data.stress.name`] = "BITD.Stress";
}
// Migrate Trauma to Array
if (typeof actor.data.trauma === 'undefined') {
updateData[`data.trauma.list`] = actor.data.traumas;
updateData[`data.trauma.max`] = 4;
updateData[`data.trauma.max_default`] = 4;
updateData[`data.trauma.name_default`] = "BITD.Trauma";
updateData[`data.trauma.name`] = "BITD.Trauma";
}
return updateData;
// for ( let k of Object.keys(actor.data.attributes || {}) ) {

View File

@ -1,7 +1,10 @@
{"_id":"8jExf4Zqad6e3bvn","name":"Leech","permission":{"default":0},"type":"class","data":{"description":"A saboteur and technician","base_skills":{"hunt":[0],"study":[0],"survey":[0],"tinker":[0],"finesse":[0],"prowl":[0],"skirmish":[0],"wreck":[0],"attune":[0],"command":[0],"consort":[0],"sway":[0]},"experience_clues":"- You addressed a challenge with technical skill or mayhem."},"sort":400000,"flags":{},"img":"systems/blades-in-the-dark/styles/assets/icons/Icons8_64.png"}
{"_id":"CAHfNrPDJZKVNMrH","name":"Lurk","permission":{"default":0},"type":"class","data":{"description":"A stealthy infiltrator and burglar","base_skills":{"hunt":[0],"study":[0],"survey":[0],"tinker":[0],"finesse":[0],"prowl":[0],"skirmish":[0],"wreck":[0],"attune":[0],"command":[0],"consort":[0],"sway":[0]},"experience_clues":"- You addressed a challenge with stealth or evasion."},"sort":500000,"flags":{},"img":"systems/blades-in-the-dark/styles/assets/icons/Icon.2_68.png"}
{"_id":"Gqx9W2P3YB4ishZB","name":"Ghost","permission":{"default":0,"BwbqQh8sHfeKmUax":3},"type":"class","data":{"description":"A disembodied spirit, craving vengeance","experience_clues":"- You exact vengeance upon those you deem deserving\n- You you express your outrage or anger.","base_skills":{"hunt":[1],"study":[0],"survey":[0],"tinker":[0],"finesse":[0],"prowl":[1],"skirmish":[0],"wreck":[0],"attune":[1],"command":[0],"consort":[0],"sway":[0]}},"sort":100001,"flags":{},"img":"systems/blades-in-the-dark/styles/assets/icons/Icon.6_18.png"}
{"_id":"JGxBjlbooxuUHe4E","name":"Hound","permission":{"default":0},"type":"class","data":{"description":"A deadly sharpshooter and tracker","base_skills":{"hunt":[0],"study":[0],"survey":[0],"tinker":[0],"finesse":[0],"prowl":[0],"skirmish":[0],"wreck":[0],"attune":[0],"command":[0],"consort":[0],"sway":[0]},"experience_clues":"- You addressed a challenge with tracking or violence."},"sort":100000,"flags":{},"img":"systems/blades-in-the-dark/styles/assets/icons/Icon.3_33.png"}
{"_id":"MePRPmnacRts4Wao","name":"Vampire","permission":{"default":0,"BwbqQh8sHfeKmUax":3},"type":"class","data":{"description":"A spirit animating an undead body","experience_clues":"- You display your dominance or slay without mercy (OVERRIDES DEFAULT EXP CLUES).","base_skills":{"hunt":[1],"study":[0],"survey":[0],"tinker":[0],"finesse":[0],"prowl":[1],"skirmish":[1],"wreck":[0],"attune":[1],"command":[1],"consort":[0],"sway":[1]}},"sort":100001,"flags":{},"img":"systems/blades-in-the-dark/styles/assets/icons/Icon.1_19.png"}
{"_id":"P6LMZBrG5U9eCjhX","name":"Spider","permission":{"default":0},"type":"class","data":{"description":"A devious mastermind","base_skills":{"hunt":[0],"study":[0],"survey":[0],"tinker":[0],"finesse":[0],"prowl":[0],"skirmish":[0],"wreck":[0],"attune":[0],"command":[0],"consort":[0],"sway":[0]},"experience_clues":"- You addressed a challenge with calculation or conspiracy."},"sort":700000,"flags":{},"img":"systems/blades-in-the-dark/styles/assets/icons/Icon.7_60.png"}
{"_id":"YUGDdyADj0PTBVcP","name":"Slide","permission":{"default":0},"type":"class","data":{"description":"A subtle manipulator and spy","base_skills":{"hunt":[0],"study":[0],"survey":[0],"tinker":[0],"finesse":[0],"prowl":[0],"skirmish":[0],"wreck":[0],"attune":[0],"command":[0],"consort":[0],"sway":[0]},"experience_clues":"- You addressed a challenge with deception or influence."},"sort":600000,"flags":{},"img":"systems/blades-in-the-dark/styles/assets/icons/Icon.3_39.png"}
{"_id":"tEob41rtEbHcswNM","name":"Cutter","permission":{"default":0},"type":"class","data":{"description":"A dangerous & intimidating fighter","base_skills":{"hunt":[0],"study":[0],"survey":[0],"tinker":[0],"finesse":[0],"prowl":[0],"skirmish":[0],"wreck":[0],"attune":[0],"command":[0],"consort":[0],"sway":[0]},"experience_clues":"- You addressed a challenge with violence or coercion."},"sort":300000,"flags":{},"img":"systems/blades-in-the-dark/styles/assets/icons/Icon.2_43.png"}
{"_id":"ti2GzB1JlnYAVvBd","name":"Hull","permission":{"default":0,"BwbqQh8sHfeKmUax":3},"type":"class","data":{"description":"A spirit animating a spark-craft frame","experience_clues":"- You fulfill your functions despite difficulty or danger.\n- You suppress or ignore your former human qualities (OVERRIDES DEFAULT EXP CLUES).","base_skills":{"hunt":[0],"study":[0],"survey":[0],"tinker":[0],"finesse":[0],"prowl":[0],"skirmish":[1],"wreck":[0],"attune":[1],"command":[0],"consort":[0],"sway":[0]}},"sort":100001,"flags":{},"img":"systems/blades-in-the-dark/styles/assets/icons/Icon.1_80.png","logic":"{\"attribute\":\"data.stress.max\",\"operator\":\"addition\",\"value\":1,\"requirement\":\"\"}"}
{"_id":"zOg14xy8ZEku6bNq","name":"Whisper","permission":{"default":0},"type":"class","data":{"description":"An Arcane adept and channeler","base_skills":{"hunt":[0],"study":[0],"survey":[0],"tinker":[0],"finesse":[0],"prowl":[0],"skirmish":[0],"wreck":[0],"attune":[0],"command":[0],"consort":[0],"sway":[0]},"experience_clues":"- You addressed a challenge with knowledge or arcane power."},"sort":200000,"flags":{},"img":"systems/blades-in-the-dark/styles/assets/icons/Icon.6_88.png"}

View File

@ -4,7 +4,7 @@
"description": "Blades in the dark game system.",
"version": "1.2",
"minimumCoreVersion": "0.5.3",
"compatibleCoreVersion": "0.7.0",
"compatibleCoreVersion": "0.7.2",
"templateVersion": 1,
"author": "megastruktur",
"esmodules": [

View File

@ -3,8 +3,20 @@
"types": ["character", "crew"],
"character": {
"alias": "",
"stress": [0],
"traumas": [0],
"stress": {
"value": [0],
"max": 9,
"max_default": 9,
"name_default": "BITD.Stress",
"name": "BITD.Stress"
},
"trauma": {
"max": 4,
"max_default": 4,
"name": "BITD.Trauma",
"name_default": "BITD.Trauma",
"list": [0]
},
"healing-clock": [0],
"experience": [0],
"coins": [0],
@ -141,12 +153,12 @@
}
},
"item": {
"templates": ["default"],
"templates": ["default", "logic"],
"class": "",
"load": 0
},
"class": {
"templates": ["default"],
"templates": ["default", "logic"],
"experience_clues": "",
"base_skills": {
"hunt": [0],
@ -164,7 +176,7 @@
}
},
"ability": {
"templates": ["ability"]
"templates": ["ability", "logic"]
},
"heritage": {
"templates": ["default"]

View File

@ -92,51 +92,37 @@
{{!-- Stress and Trauma --}}
<div id="stress-trauma" class="section big-teeth-section">
<div id="character-stress" class="big-teeth">
{{#multiboxes data.stress}}
{{#multiboxes data.stress.value}}
<input type="radio" id="character-stress-0" name="data.stress" value="0" dtype="Radio">
<label class="black-label" for="character-stress-0">{{localize "BITD.Stress"}}</label>
<input type="radio" id="character-stress-1" name="data.stress" value="1" dtype="Radio">
<label for="character-stress-1"></label>
<input type="radio" id="character-stress-2" name="data.stress" value="2" dtype="Radio">
<label for="character-stress-2"></label>
<input type="radio" id="character-stress-3" name="data.stress" value="3" dtype="Radio">
<label for="character-stress-3"></label>
<input type="radio" id="character-stress-4" name="data.stress" value="4" dtype="Radio">
<label for="character-stress-4"></label>
<input type="radio" id="character-stress-5" name="data.stress" value="5" dtype="Radio">
<label for="character-stress-5"></label>
<input type="radio" id="character-stress-6" name="data.stress" value="6" dtype="Radio">
<label for="character-stress-6"></label>
<input type="radio" id="character-stress-7" name="data.stress" value="7" dtype="Radio">
<label for="character-stress-7"></label>
<input type="radio" id="character-stress-8" name="data.stress" value="8" dtype="Radio">
<label for="character-stress-8"></label>
<input type="radio" id="character-stress-9" name="data.stress" value="9" dtype="Radio">
<label for="character-stress-9"></label>
<label class="black-label" for="character-stress-0">{{localize data.stress.name}}</label>
{{#times_from_1 data.stress.max}}
<input type="radio" id="character-stress-{{this}}" name="data.stress" value="{{this}}" dtype="Radio">
<label for="character-stress-{{this}}"></label>
{{/times_from_1}}
{{/multiboxes}}
</div>
<div id="character-trauma-container" class="small-teeth-container">
{{#traumacounter data.traumas}}
{{#traumacounter data.trauma.list}}
<div id="character-trauma" class="small-teeth-wrap">
<label class="black-label" for="character-trauma-counter-0">{{localize "BITD.Trauma"}}</label>
<div id="trauma-teeth" class="small-teeth">
<input type="radio" id="character-trauma-counter-0" name="trauma-counter" value="0">
<input type="radio" id="character-trauma-counter-1" name="trauma-counter" value="1">
<label for="character-trauma-counter-1"></label>
<input type="radio" id="character-trauma-counter-2" name="trauma-counter" value="2">
<label for="character-trauma-counter-2"></label>
<input type="radio" id="character-trauma-counter-3" name="trauma-counter" value="3">
<label for="character-trauma-counter-3"></label>
<input type="radio" id="character-trauma-counter-4" name="trauma-counter" value="4">
<label for="character-trauma-counter-4"></label>
{{#times_from_1 data.trauma.max}}
<input type="radio" id="character-trauma-counter-{{this}}" name="trauma-counter" value="{{this}}">
<label for="character-trauma-counter-{{this}}"></label>
{{/times_from_1}}
</div>
</div>
{{/traumacounter}}
</div>
<div id="trauma-list">
{{#multiboxes data.traumas}}
{{#multiboxes data.trauma.list}}
<label>
<input type="checkbox" name="data.traumas" value="cold">
<span class="checkmark">{{localize "BITD.TraumaCold"}}</span>

View File

@ -15,6 +15,10 @@
<div><i>- {{localize "BITD.ClassExpClue2"}}</i></div>
<div><i>- {{localize "BITD.ClassExpClue3"}}</i></div>
<textarea name="data.experience_clues">{{data.experience_clues}}</textarea>
{{isG}}
<label class="label-stripe">{{localize "BITD.Logic"}}</label>
<textarea name="data.logic">{{data.logic}}</textarea>
</section>
</form>

View File

@ -15,6 +15,6 @@
<label class="label-stripe">{{localize "BITD.Price"}}</label>
<input type="text" name="data.price" value="{{data.price}}">
<label class="label-stripe">{{localize "BITD.Logic"}}</label>
<textarea name="data.logic">{{data.logic}}</textarea>
{{editor content=data.logic target="data.logic" button=true owner=owner editable=editable}}
</section>
</form>