ENH: Chargen

master
U~man 2020-07-19 16:10:28 +02:00
parent 0ea0e25fba
commit 197d88eeb3
12 changed files with 147 additions and 53 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 259 KiB

After

Width:  |  Height:  |  Size: 232 KiB

View File

@ -110,11 +110,6 @@
wether your monster has a survival instinct or will fight till the wether your monster has a survival instinct or will fight till the
end. end.
</li> </li>
<li><strong>Variable weapon damage</strong>:By default, even if the
damage field is shown in the weapons sheets, the rolled damage
will always be a d6, except for monsters. With this enabled, the
damage displayed will be effectively used for characters.
</li>
<li><strong>Encumbrance</strong>:The weight a character is carrying <li><strong>Encumbrance</strong>:The weight a character is carrying
is a significant part of the players treasure hunting adventures. is a significant part of the players treasure hunting adventures.
You have three options here. You have three options here.
@ -493,7 +488,7 @@
<img src="./images/treasure-toggle.png" /> <img src="./images/treasure-toggle.png" />
</p> </p>
<p> <p>
You can toggle between the default rollable tables and the treasure table. You can toggle between the default rollable tables and the treasure table with the Chest icon right next to the table name.
The default tables are selecting an entry by rolling a dice and returning the matching result. Treasure tables however, have a different behavior. Each entry is rolled with 1d100 and the value is compared to the 'chance field'. So it can return multiple items. The default tables are selecting an entry by rolling a dice and returning the matching result. Treasure tables however, have a different behavior. Each entry is rolled with 1d100 and the value is compared to the 'chance field'. So it can return multiple items.
</p> </p>
<p> <p>

View File

@ -15,7 +15,9 @@
"OSE.dialog.partysheet": "Party Overview", "OSE.dialog.partysheet": "Party Overview",
"OSE.dialog.selectActors": "Select PCs", "OSE.dialog.selectActors": "Select PCs",
"OSE.dialog.dealXP": "Deal XP", "OSE.dialog.dealXP": "Deal XP",
"OSE.dialog.generator": "Character generator",
"OSE.dialog.generateSaves": "Generate Saves", "OSE.dialog.generateSaves": "Generate Saves",
"OSE.dialog.generateScore": "Rolling {score}",
"OSE.Formula": "Formula", "OSE.Formula": "Formula",
"OSE.SitMod": "Situational Modifier", "OSE.SitMod": "Situational Modifier",
@ -162,8 +164,6 @@
"OSE.Setting.AscendingACHint": "The more the better", "OSE.Setting.AscendingACHint": "The more the better",
"OSE.Setting.Morale": "Enable monsters Morale Rating", "OSE.Setting.Morale": "Enable monsters Morale Rating",
"OSE.Setting.MoraleHint": "Morale Rating is shown on monster sheets", "OSE.Setting.MoraleHint": "Morale Rating is shown on monster sheets",
"OSE.Setting.VariableWeaponDamage": "Variable Weapon Damage",
"OSE.Setting.VariableWeaponDamageHint": "Weapons have different damage dice",
"OSE.Setting.Encumbrance": "Encumbrance", "OSE.Setting.Encumbrance": "Encumbrance",
"OSE.Setting.EncumbranceHint": "Choose the way encumbrance is calculated", "OSE.Setting.EncumbranceHint": "Choose the way encumbrance is calculated",
"OSE.Setting.EncumbranceDisabled": "Disabled", "OSE.Setting.EncumbranceDisabled": "Disabled",

View File

@ -147,8 +147,6 @@
"OSE.Setting.AscendingACHint": "En cuanto más mejor", "OSE.Setting.AscendingACHint": "En cuanto más mejor",
"OSE.Setting.Morale": "Activar puntuación de Moral para monstruos", "OSE.Setting.Morale": "Activar puntuación de Moral para monstruos",
"OSE.Setting.MoraleHint": "La puntuación de moral se ve en las hojas de monstruo", "OSE.Setting.MoraleHint": "La puntuación de moral se ve en las hojas de monstruo",
"OSE.Setting.VariableWeaponDamage": "Daño de arma variable",
"OSE.Setting.VariableWeaponDamageHint": "Las armas tienen diferente dado de daño",
"OSE.Setting.Encumbrance": "Carga", "OSE.Setting.Encumbrance": "Carga",
"OSE.Setting.EncumbranceHint": "Elige como se calcula la Carga", "OSE.Setting.EncumbranceHint": "Elige como se calcula la Carga",
"OSE.Setting.EncumbranceDisabled": "Disabled", "OSE.Setting.EncumbranceDisabled": "Disabled",

View File

@ -161,8 +161,6 @@
"OSE.Setting.AscendingACHint": "Le plus est le mieux", "OSE.Setting.AscendingACHint": "Le plus est le mieux",
"OSE.Setting.Morale": "Activer le Score de Moral", "OSE.Setting.Morale": "Activer le Score de Moral",
"OSE.Setting.MoraleHint": "Le Score de Moral est affiché sur la fiche de Monstre", "OSE.Setting.MoraleHint": "Le Score de Moral est affiché sur la fiche de Monstre",
"OSE.Setting.VariableWeaponDamage": "Dégâts d'Arme Variables",
"OSE.Setting.VariableWeaponDamageHint": "Les Armes peuvent avoir des dégâts d'arme différents",
"OSE.Setting.Encumbrance": "Encombrement", "OSE.Setting.Encumbrance": "Encombrement",
"OSE.Setting.EncumbranceHint": "Choisissez comment l'encombrement est calculé", "OSE.Setting.EncumbranceHint": "Choisissez comment l'encombrement est calculé",
"OSE.Setting.EncumbranceDisabled": "Désactivé", "OSE.Setting.EncumbranceDisabled": "Désactivé",

View File

@ -57,11 +57,6 @@ export class OseActorSheetCharacter extends OseActorSheet {
getData() { getData() {
const data = super.getData(); const data = super.getData();
// Settings
data.config.variableWeaponDamage = game.settings.get(
"ose",
"variableWeaponDamage"
);
data.config.ascendingAC = game.settings.get("ose", "ascendingAC"); data.config.ascendingAC = game.settings.get("ose", "ascendingAC");
data.config.individualInit = game.settings.get("ose", "individualInit"); data.config.individualInit = game.settings.get("ose", "individualInit");
data.config.encumbrance = game.settings.get("ose", "encumbranceOption"); data.config.encumbrance = game.settings.get("ose", "encumbranceOption");

View File

@ -274,6 +274,9 @@ export class OseActor extends Actor {
rollHitDice(options = {}) { rollHitDice(options = {}) {
const label = game.i18n.localize(`OSE.roll.hd`); const label = game.i18n.localize(`OSE.roll.hd`);
const rollParts = [this.data.data.hp.hd]; const rollParts = [this.data.data.hp.hd];
if (this.data.type == 'character') {
rollParts.push(this.data.data.scores.con.mod);
}
const data = { const data = {
...this.data, ...this.data,
@ -373,10 +376,7 @@ export class OseActor extends Actor {
}; };
let dmgParts = []; let dmgParts = [];
if ( if (!attData.dmg) {
(!attData.dmg || !game.settings.get("ose", "variableWeaponDamage")) &&
this.type == "character"
) {
dmgParts.push("1d6"); dmgParts.push("1d6");
} else { } else {
dmgParts.push(attData.dmg); dmgParts.push(attData.dmg);
@ -404,11 +404,7 @@ export class OseActor extends Actor {
const rollParts = ["1d20"]; const rollParts = ["1d20"];
const dmgParts = []; const dmgParts = [];
let label = game.i18n.format("OSE.roll.attacks", { name: this.data.name }); let label = game.i18n.format("OSE.roll.attacks", { name: this.data.name });
if ( if (!attData.dmg) {
!attData.dmg ||
(!game.settings.get("ose", "variableWeaponDamage") &&
this.data.type == "character")
) {
dmgParts.push("1d6"); dmgParts.push("1d6");
} else { } else {
label = game.i18n.format("OSE.roll.attacksWith", { name: attData.label }); label = game.i18n.format("OSE.roll.attacksWith", { name: attData.label });

View File

@ -1,13 +1,14 @@
// eslint-disable-next-line no-unused-vars
import { OseActor } from '../actor/entity.js'; import { OseActor } from '../actor/entity.js';
import { OseDice } from "../dice.js";
export class OseCharacterCreator extends FormApplication { export class OseCharacterCreator extends FormApplication {
static get defaultOptions() { static get defaultOptions() {
const options = super.defaultOptions; const options = super.defaultOptions;
options.classes = ["ose", "dialog", "creator"],
options.id = 'character-creator'; options.id = 'character-creator';
options.template = options.template =
'systems/ose/templates/actors/dialogs/character-creation.html'; 'systems/ose/templates/actors/dialogs/character-creation.html';
options.width = 380; options.width = 235;
return options; return options;
} }
@ -18,7 +19,7 @@ export class OseCharacterCreator extends FormApplication {
* @type {String} * @type {String}
*/ */
get title() { get title() {
return `${this.object.name}: ${game.i18n.localize('OSE.dialog.tweaks')}`; return `${this.object.name}: ${game.i18n.localize('OSE.dialog.generator')}`;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -36,9 +37,66 @@ export class OseCharacterCreator extends FormApplication {
/* -------------------------------------------- */ /* -------------------------------------------- */
doStats(ev) {
let list = $(ev.currentTarget).closest('.attribute-list');
let values = [];
list.find('.score-value').each((i, s) => {
if (s.value != 0) {
values.push(parseInt(s.value));
}
})
let n = values.length;
let sum = values.reduce((a,b) => a+b);
let mean = parseFloat(sum) / n;
let std = Math.sqrt(values.map(x => Math.pow(x-mean,2)).reduce((a,b) => a+b)/n);
let stats = list.siblings('.roll-stats');
stats.find('.sum').text(sum);
stats.find('.avg').text(Math.round(10 * sum / n) / 10);
stats.find('.std').text(Math.round(100 * std) / 100);
if (n >= 6) {
$(ev.currentTarget).closest('form').find('button[type="submit"]').removeAttr('disabled');
}
}
rollScore(score, options={}) {
const label = game.i18n.localize(`OSE.scores.${score}.long`);
const rollParts = ["3d6"];
const data = {
...this.object.data,
...{
rollData: {
type: "result"
},
},
};
// Roll and return
return OseDice.Roll({
event: options.event,
parts: rollParts,
data: data,
skipDialog: true,
speaker: ChatMessage.getSpeaker({ actor: this }),
flavor: game.i18n.format('OSE.dialog.generateScore', {score: label}),
title: game.i18n.format('OSE.dialog.generateScore', {score: label}),
});
}
/** @override */ /** @override */
activateListeners(html) { activateListeners(html) {
super.activateListeners(html); super.activateListeners(html);
html.find('a.score-roll').click((ev) => {
let el = ev.currentTarget.parentElement.parentElement;
let score = el.dataset.score;
this.rollScore(score, {event: ev}).then(r => {
$(el).find('input').val(r.total).trigger('change');
});
});
html.find('input.score-value').change(ev => {
this.doStats(ev);
})
} }
/** /**

View File

@ -103,12 +103,12 @@ export class OseDice {
) )
.then((displayed) => { .then((displayed) => {
ChatMessage.create(chatData); ChatMessage.create(chatData);
resolve(); resolve(roll);
}); });
} else { } else {
chatData.sound = CONFIG.sounds.dice; chatData.sound = CONFIG.sounds.dice;
ChatMessage.create(chatData); ChatMessage.create(chatData);
resolve(); resolve(roll);
} }
}); });
}); });
@ -215,17 +215,17 @@ export class OseDice {
) )
.then(() => { .then(() => {
ChatMessage.create(chatData); ChatMessage.create(chatData);
resolve(); resolve(roll);
}); });
} else { } else {
ChatMessage.create(chatData); ChatMessage.create(chatData);
resolve(); resolve(roll);
} }
}); });
} else { } else {
chatData.sound = CONFIG.sounds.dice; chatData.sound = CONFIG.sounds.dice;
ChatMessage.create(chatData); ChatMessage.create(chatData);
resolve(); resolve(roll);
} }
}); });
}); });

View File

@ -28,15 +28,6 @@ export const registerSettings = function () {
config: true, config: true,
}); });
game.settings.register("ose", "variableWeaponDamage", {
name: game.i18n.localize("OSE.Setting.VariableWeaponDamage"),
hint: game.i18n.localize("OSE.Setting.VariableWeaponDamageHint"),
default: false,
scope: "world",
type: Boolean,
config: true,
});
game.settings.register("ose", "encumbranceOption", { game.settings.register("ose", "encumbranceOption", {
name: game.i18n.localize("OSE.Setting.Encumbrance"), name: game.i18n.localize("OSE.Setting.Encumbrance"),
hint: game.i18n.localize("OSE.Setting.EncumbranceHint"), hint: game.i18n.localize("OSE.Setting.EncumbranceHint"),

View File

@ -5,6 +5,33 @@
} }
} }
.ose.dialog.creator {
.attribute-list {
.form-fields {
flex: 0 0 50px;
input {
text-align: center;
font-weight: bold;
}
}
}
.roll-stats {
flex: 0 0 65px;
padding: 5px;
margin-left: 4px;
border-left: 1px solid $colorTan;
.form-group {
.form-fields {
span {
text-align: center;
line-height: 24px;
flex: 0;
}
}
}
}
}
.ose.dialog.party-sheet { .ose.dialog.party-sheet {
min-width: 250px; min-width: 250px;
min-height: 250px; min-height: 250px;
@ -45,7 +72,7 @@
margin-bottom: 2px; margin-bottom: 2px;
font-size: 12px; font-size: 12px;
text-align: center; text-align: center;
.fields .field-row{ .fields .field-row {
&:nth-child(odd) { &:nth-child(odd) {
background-color: rgba(0, 0, 0, 0.1); background-color: rgba(0, 0, 0, 0.1);
} }
@ -120,7 +147,7 @@
flex: 0 0 30px; flex: 0 0 30px;
font-size: 26px; font-size: 26px;
line-height: 25px; line-height: 25px;
color:white; color: white;
margin: 0 2px 5px 8px; margin: 0 2px 5px 8px;
border-radius: 8px; border-radius: 8px;
background: url("/systems/ose/assets/chest.png") no-repeat center; background: url("/systems/ose/assets/chest.png") no-repeat center;
@ -128,7 +155,8 @@
padding: 5px 8px; padding: 5px 8px;
cursor: pointer; cursor: pointer;
filter: grayscale(1) opacity(0.5); filter: grayscale(1) opacity(0.5);
&.active,&:hover { &.active,
&:hover {
filter: none; filter: none;
} }
} }
@ -172,12 +200,15 @@
box-shadow: 0 0 2px #fff inset; box-shadow: 0 0 2px #fff inset;
.chat-title { .chat-title {
margin: 4px 0; margin: 4px 0;
height: 30px;
overflow: hidden;
h2 { h2 {
border: none; border: none;
line-height: 34px; line-height: 34px;
margin: 0; margin: 0;
text-indent: 10px; text-indent: 10px;
font-size: 16px; font-size: 16px;
word-break: break-all;
} }
} }
.chat-img { .chat-img {

View File

@ -1,7 +1,39 @@
<form autocomplete="off" onsubmit="event.preventDefault();"> <form autocomplete="off" onsubmit="event.preventDefault();">
<ol class="attribute-list"> <div class="flexrow">
{{#each config.scores as |score id| }} <div class="attribute-list">
<li data-score="{{id}}">{{score}}</li> {{#each config.scores as |score id| }}
{{/each}} <div data-score="{{id}}" class="form-group">
</ol> <label><a class="score-roll"><i class="fas fa-dice"></i></a> {{score}}</label>
<div class="form-fields">
<input class="score-value" name="data.scores.{{id}}.value" type="text" value="0" data-dtype="Number"/>
</div>
</div>
{{/each}}
</div>
<div class="roll-stats">
<div class="form-group">
<label>Sum</label>
<div class="form-fields">
<span class="sum">0</span>
</div>
</div>
<div class="form-group">
<label>Avg</label>
<div class="form-fields">
<span class="avg">0</span>
</div>
</div>
<div class="form-group">
<label>σ</label>
<div class="form-fields">
<span class="std">0</span>
</div>
</div>
</div>
</div>
<footer class="sheet-footer">
<button type="submit" disabled>
<i class="fas fa-save"></i>{{localize "Save Changes"}}
</button>
</footer>
</form> </form>