ENH: Layout rework

master
U~man 2020-07-03 14:37:49 +02:00
parent 2dfdfdf986
commit 6141ae7693
14 changed files with 394 additions and 83 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

@ -57,8 +57,12 @@
"OSE.HealthShort": "HP",
"OSE.HitDice": "Hit Dice",
"OSE.HitDiceShort": "HD",
"OSE.Movement": "Movement",
"OSE.MovementShort": "MOV",
"OSE.Movement": "Movement Rate",
"OSE.MovementEncounter": "Encounter Movement Rate",
"OSE.MovementEncounterShort": "ENC",
"OSE.MovementOverland": "Overland Movement Rate",
"OSE.MovementOverlandShort": "OVE",
"OSE.MovementShort": "MR",
"OSE.ArmorClass": "Armor Class",
"OSE.ArmorClassShort": "AC",
"OSE.AscArmorClassShort": "AAC",
@ -67,8 +71,10 @@
"OSE.Thac0": "THAC0",
"OSE.MeleeShort": "MEL",
"OSE.Melee": "Melee",
"OSE.MeleeBonus": "Melee Bonus",
"OSE.MissileShort": "MIS",
"OSE.Missile": "Missile",
"OSE.MissileBonus": "Missile Bonus",
"OSE.Initiative": "Initiative",
"OSE.InitiativeShort": "INIT",
"OSE.Attacks": "Attacks Usable per Round",

View File

@ -85,6 +85,13 @@ export class OseActorSheet extends ActorSheet {
});
});
html.find(".item-image").click(async (ev) => {
const li = $(ev.currentTarget).parents(".item");
const item = this.actor.getOwnedItem(li.data("itemId"));
item.roll();
});
super.activateListeners(html);
}

View File

@ -12,6 +12,14 @@ export const registerHelpers = async function () {
return parseInt(rh) - parseInt(lh);
});
Handlebars.registerHelper("divide", function (lh, rh) {
return Math.floor(parseFloat(lh) / parseFloat(rh));
});
Handlebars.registerHelper("mult", function (lh, rh) {
return parseInt(lh) * parseInt(rh);
});
Handlebars.registerHelper("counter", function (status, value, max) {
return status ? Math.clamped((100.0 * value) / max, 0, 100) : Math.clamped(100 - (100.0 * value) / max, 0, 100);
});

View File

@ -12,4 +12,79 @@ export class OseItem extends Item {
prepareData() {
super.prepareData();
}
getChatData(htmlOptions) {
const data = duplicate(this.data.data);
// Rich text description
data.description = TextEditor.enrichHTML(data.description, htmlOptions);
// Item properties
const props = [];
const labels = this.labels;
if (this.data.type == "weapon") {
props.push(data.qualities);
}
if (this.data.type == "spell") {
props.push(
`${data.class} ${data.lvl}`,
data.range,
data.duration
);
}
if (data.hasOwnProperty("equipped")) {
props.push(data.equipped ? "Equipped" : "Not Equipped");
}
// Filter properties and return
data.properties = props.filter((p) => !!p);
return data;
}
/**
* Roll the item to Chat, creating a chat card which contains follow up attack or damage roll options
* @return {Promise}
*/
async roll({ configureDialog = true } = {}) {
// Basic template rendering data
const token = this.actor.token;
const templateData = {
actor: this.actor,
tokenId: token ? `${token.scene._id}.${token.id}` : null,
item: this.data,
data: this.getChatData(),
labels: this.labels,
hasAttack: this.hasAttack,
isHealing: this.isHealing,
hasDamage: this.hasDamage,
isSpell: this.data.type === "spell",
hasSave: this.hasSave,
};
// Render the chat card template
const template = `systems/ose/templates/chat/item-card.html`;
const html = await renderTemplate(template, templateData);
// Basic chat message data
const chatData = {
user: game.user._id,
type: CONST.CHAT_MESSAGE_TYPES.OTHER,
content: html,
speaker: {
actor: this.actor._id,
token: this.actor.token,
alias: this.actor.name,
},
};
// Toggle default roll mode
let rollMode = game.settings.get("core", "rollMode");
if (["gmroll", "blindroll"].includes(rollMode))
chatData["whisper"] = ChatMessage.getWhisperRecipients("GM");
if (rollMode === "blindroll") chatData["blind"] = true;
// Create the chat message
return ChatMessage.create(chatData);
}
}

View File

@ -95,7 +95,7 @@
padding: 0;
.attribute {
position: relative;
margin: 10px;
margin: 8px;
border: 1px solid $colorTan;
.attribute-name {
color: whitesmoke;
@ -104,25 +104,31 @@
background: $colorDark;
text-align: center;
}
.attribute-value {
padding: 4px;
display: flex;
flex-direction: row;
&.multiple input {
min-width: 28px;
&.attribute-secondaries {
margin: 10px 5px;
}
&.ability-score {
height: 40px;
.attribute-value {
line-height: 36px;
}
}
.attribute-value {
text-align: center;
padding: 4px;
}
.attribute-mod {
position: absolute;
color: $colorTan;
right: 5px;
top: 0;
top: -5px;
font-size: 13px;
}
}
}
.attribute-group {
flex: 0 0 105px;
margin: auto 0;
.attributes {
.attribute {
display: flex;
@ -130,7 +136,7 @@
.attribute-name {
width: 40px;
margin: 0;
line-height: 28px;
line-height: 38px;
a {
margin: auto;
}

View File

@ -0,0 +1,97 @@
.ose.chat-card {
font-style: normal;
font-size: 12px;
.card-header {
padding: 3px 0;
border-top: 2px groove #FFF;
border-bottom: 2px groove #FFF;
img {
flex: 0 0 36px;
margin-right: 5px;
}
h3 {
flex: 1;
margin: 0;
line-height: 36px;
color: $colorOlive;
&:hover {
color: #111;
text-shadow: 0 0 10px red;
}
}
}
.card-content {
margin: 5px 0;
h3 {
font-size: 12px;
margin: 0;
font-weight: bold;
}
> * {
-webkit-user-select: text;
-moz-user-select: text;
-ms-user-select: text;
user-select: text;
}
}
.card-buttons {
margin: 5px 0;
span {
display: block;
line-height: 28px;
text-align: center;
border: 1px solid $colorTan;
}
button {
font-size: 12px;
height: 24px;
line-height: 20px;
margin: 2px 0;
}
}
.card-footer {
padding: 3px 0 0;
border-top: 2px groove #FFF;
span {
border-right: 2px groove #FFF;
padding: 0 5px 0 0;
font-size: 10px;
&:last-child {
border-right: none;
padding-right: 0;
}
}
}
}
.dice-roll .dice-total {
&.success {
color: inherit;
background: #c7d0c0;
border: 1px solid #006c00;
}
&.failure {
color: inherit;
background: #ffdddd;
border: 1px solid #6e0000;
}
&.critical {
color: green;
}
&.fumble {
color: red;
}
}

View File

@ -28,10 +28,10 @@
.health {
&.armor-class {
background: url('/systems/ose/assets/shield.png') no-repeat center;
background-size: 90px;
background-size: 70px;
}
margin: 10px 0;
height: 90px;
height: 70px;
position: relative;
input {
font-size: 16px;
@ -42,25 +42,25 @@
border-bottom: none;
position: absolute;
font-size: 24px;
top: 28px;
top: 10px;
width: 70px;
left: calc(50% - 35px);
}
.health-bottom {
border-bottom: none;
position: absolute;
bottom: 12px;
bottom: 8px;
width: 40px;
right: calc(50% + -20px);
}
.health-empty {
background: url('/systems/ose/assets/heart_empty.png') no-repeat center;
background-size: 90px;
background-size: 70px;
background-position: top;
}
.health-full {
background: url('/systems/ose/assets/heart_full.png') no-repeat center;
background-size: 90px;
background-size: 70px;
background-position: bottom;
}
}

View File

@ -24,7 +24,10 @@
},
"thac0": {
"value": 19,
"mod": 0
"mod": {
"missile": 0,
"melee": 0
}
},
"saves": {
"death": 10,
@ -34,8 +37,7 @@
"spell": 10
},
"movement": {
"base": 0,
"encounter": 0
"base": 120
}
},
"spellcaster": {

View File

@ -35,6 +35,28 @@
/>
</div>
</div>
<div class="form-group">
<label>{{localize "OSE.MeleeBonus"}}</label>
<div class="form-fields">
<input
type="text"
name="data.thac0.mod.melee"
id="melee"
value="{{data.thac0.mod.melee}}"
/>
</div>
</div>
<div class="form-group">
<label>{{localize "OSE.MissileBonus"}}</label>
<div class="form-fields">
<input
type="text"
name="data.thac0.mod.missile"
id="missile"
value="{{data.thac0.mod.missile}}"
/>
</div>
</div>
{{/if}}
<footer class="sheet-footer">
<button type="submit">

View File

@ -1,49 +1,3 @@
<section class="flexrow">
<ul class="attributes flexrow">
<li class="attribute">
<h4 class="attribute-name box-title" title="{{ localize 'OSE.HitDice' }}">{{ localize "OSE.HitDiceShort" }}
</h4>
<div class="attribute-value">
<input name="data.hp.hd" type="text" value="{{data.hp.hd}}" placeholder="0" data-dtype="String" />
</div>
</li>
<li class="attribute">
<h4 class="attribute-name box-title" title="{{ localize 'OSE.Thac0' }}">{{ localize "OSE.Thac0" }}</h4>
<div class="attribute-value">
<input name="data.thac0.value" type="text" value="{{data.thac0.value}}" placeholder="0"
data-dtype="Number" />
</div>
</li>
{{#if config.individualInit}}
<li class="attribute">
<h4 class="attribute-name box-title" title="{{ localize 'OSE.Initiative' }}">
{{ localize "OSE.InitiativeShort" }}</h4>
<div class="attribute-value">
<input name="data.initiative.value" type="text" value="{{data.initiative.value}}" placeholder="0"
data-dtype="Number" />
</div>
</li>
{{/if}}
{{#if data.retainer.enabled}}
<li class="attribute">
<h4 class="attribute-name box-title" title="{{ localize 'OSE.Loyalty' }}">{{ localize "OSE.LoyaltyShort" }}
</h4>
<div class="attribute-value">
<input name="data.retainer.loyalty" type="text" value="{{data.retainer.loyalty}}" placeholder="0"
data-dtype="Number" />
</div>
</li>
{{/if}}
<li class="attribute">
<h4 class="attribute-name box-title" title="{{ localize 'OSE.Movement' }}">
{{ localize "OSE.MovementShort" }}</h4>
<div class="attribute-value">
<input name="data.movement.value" type="text" value="{{data.movement.value}}" placeholder="0"
data-dtype="Number" />
</div>
</li>
</ul>
</section>
<section class="flexrow">
{{!-- Scores --}}
<div class="attribute-group">
@ -96,28 +50,124 @@
data-dtype="Number" />
<span class="attribute-mod">{{mods.cha}}</span>
</li>
{{#if data.retainer.enabled}}
<li class="attribute">
<h4 class="attribute-name box-title" title="{{ localize 'OSE.Loyalty' }}">
{{ localize "OSE.LoyaltyShort" }}
</h4>
<div class="attribute-value">
<input name="data.retainer.loyalty" type="text" value="{{data.retainer.loyalty}}" placeholder="0"
data-dtype="Number" />
</div>
</li>
{{/if}}
</ul>
</div>
{{!-- Resource Tracking --}}
<div class="flex2">
<div class="health">
<input class="health-top" name="data.hp.value" type="text" value="{{data.hp.value}}" data-dtype="Number"
placeholder="0" title="{{localize 'OSE.Health'}}" />
<input class="health-bottom" name="data.hp.max" type="text" value="{{data.hp.max}}" data-dtype="Number"
placeholder="0" title="{{localize 'OSE.HealthMax'}}" />
<div class="health-empty" style="height:{{counter false data.hp.value data.hp.max}}%"></div>
<div class="health-full" style="height:{{counter true data.hp.value data.hp.max}}%"></div>
<div class="flexrow">
<div class="health">
<input class="health-top" name="data.hp.value" type="text" value="{{data.hp.value}}" data-dtype="Number"
placeholder="0" title="{{localize 'OSE.Health'}}" />
<input class="health-bottom" name="data.hp.max" type="text" value="{{data.hp.max}}" data-dtype="Number"
placeholder="0" title="{{localize 'OSE.HealthMax'}}" />
<div class="health-empty" style="height:{{counter false data.hp.value data.hp.max}}%"></div>
<div class="health-full" style="height:{{counter true data.hp.value data.hp.max}}%"></div>
</div>
<div class="health armor-class">
{{#if config.ascendingAC}}
<input class="health-top" name="data.aac.value" type="text" value="{{data.aac.value}}"
data-dtype="Number" placeholder="0" title="{{localize 'OSE.ArmorClass'}}" />
<input class="health-bottom" type="text" value="{{add 10 mods.dex}}"
title="{{localize 'OSE.ArmorClass'}}" disabled />
{{else}}
<input class="health-top" name="data.ac.value" type="text" value="{{data.ac.value}}" data-dtype="Number"
placeholder="0" title="{{localize 'OSE.ArmorClass'}}" />
<input class="health-bottom" type="text" value="{{subtract mods.dex 9}}"
title="{{localize 'OSE.ArmorClass'}}" disabled />
{{/if}}
</div>
</div>
<div class="health armor-class">
{{#if config.ascendingAC}}
<input class="health-top" name="data.aac.value" type="text" value="{{data.aac.value}}" data-dtype="Number"
placeholder="0" title="{{localize 'OSE.ArmorClass'}}" />
<input class="health-bottom" type="text" value="{{add 10 mods.dex}}" title="{{localize 'OSE.ArmorClass'}}" disabled/>
{{else}}
<input class="health-top" name="data.ac.value" type="text" value="{{data.ac.value}}" data-dtype="Number"
placeholder="0" title="{{localize 'OSE.ArmorClass'}}" />
<input class="health-bottom" type="text" value="{{subtract 9 mods.dex}}" title="{{localize 'OSE.ArmorClass'}}" disabled/>
{{/if}}
<div class="flexrow">
<ul class="attributes flexrow">
<li class="attribute">
<h4 class="attribute-name box-title" title="{{ localize 'OSE.HitDice' }}">
{{ localize "OSE.HitDiceShort" }}
</h4>
<div class="attribute-value">
<input name="data.hp.hd" type="text" value="{{data.hp.hd}}" placeholder="0"
data-dtype="String" />
</div>
</li>
{{#if config.individualInit}}
<li class="attribute">
<h4 class="attribute-name box-title" title="{{ localize 'OSE.Initiative' }}">
{{ localize "OSE.InitiativeShort" }}</h4>
<div class="attribute-value">
<input name="data.initiative.value" type="text" value="{{data.initiative.value}}"
placeholder="0" data-dtype="Number" />
</div>
</li>
{{/if}}
</ul>
</div>
<div class="flexrow">
<ul class="attributes flexrow">
<li class="attribute attribute-secondaries">
<h4 class="attribute-name box-title" title="{{localize 'OSE.Melee'}}">{{localize 'OSE.MeleeShort'}}</h4>
<div class="flexrow">
<div class="attribute-value">
{{subtract data.thac0.mod.melee (subtract mods.str data.thac0.value)}}
</div>
</div>
</li>
<li class="attribute">
<h4 class="attribute-name box-title" title="{{ localize 'OSE.Thac0' }}">{{ localize "OSE.Thac0" }}
</h4>
<div class="flexrow">
<div class="attribute-value">
<input name="data.thac0.value" type="text" value="{{data.thac0.value}}" placeholder="0"
data-dtype="Number" />
</div>
</div>
</li>
<li class="attribute attribute-secondaries">
<h4 class="attribute-name box-title" title="{{localize 'OSE.Missile'}}">{{localize 'OSE.MissileShort'}}</h4>
<div class="flexrow">
<div class="attribute-value">
{{subtract data.thac0.mod.missile (subtract mods.dex data.thac0.value)}}
</div>
</div>
</li>
</ul>
</div>
<div class="flexrow">
<ul class="attributes flexrow">
<li class="attribute attribute-secondaries">
<h4 class="attribute-name box-title" title="{{localize 'OSE.MovementEncounter'}}">{{localize 'OSE.MovementEncounterShort'}}</h4>
<div class="flexrow">
<div class="attribute-value">
{{divide data.movement.base 3}}
</div>
</div>
</li>
<li class="attribute">
<h4 class="attribute-name box-title" title="{{ localize 'OSE.Movement' }}">
{{ localize "OSE.MovementShort" }}</h4>
<div class="attribute-value flexrow">
<input name="data.movement.base" type="text" value="{{data.movement.base}}" placeholder="0"
data-dtype="Number" />
</div>
</li>
<li class="attribute attribute-secondaries">
<h4 class="attribute-name box-title" title="{{localize 'OSE.MovementOverland'}}">{{localize 'OSE.MovementOverlandShort'}}</h4>
<div class="flexrow">
<div class="attribute-value">
{{divide data.movement.base 5}}
</div>
</div>
</li>
</ul>
</div>
</div>
{{!-- Saving throws --}}

View File

@ -0,0 +1,38 @@
<div class="ose chat-card item-card" data-actor-id="{{actor._id}}" data-item-id="{{item._id}}"
{{#if tokenId}}data-token-id="{{tokenId}}"{{/if}}>
<header class="card-header flexrow">
<img src="{{item.img}}" title="{{item.name}}" width="36" height="36"/>
<h3 class="item-name">{{item.name}}</h3>
</header>
<div class="card-content">
{{{data.description}}}
</div>
<div class="card-buttons">
{{#if hasAttack}}<button data-action="attack">{{ localize "OSE.Attack" }}</button>{{/if}}
{{#if hasDamage}}
<button data-action="damage">
{{#if isHealing}}{{ localize "OSE.Healing" }}
{{else}}{{localize "OSE.Damage" }}{{/if}}
</button>
{{/if}}
{{#if hasSave}}
<button data-action="save" data-ability="{{data.save.ability}}" disabled>
{{ localize "OSE.SavingThrow" }} {{labels.save}}
</button>
{{/if}}
{{#if data.formula}}
<button data-action="formula">{{ localize "OSE.OtherFormula"}}</button>
{{/if}}
</div>
<footer class="card-footer">
{{#each data.properties}}
<span>{{this}}</span>
{{/each}}
</footer>
</div>