finally fixes the stubborn tab error

feature/applicationv2
macniel 2025-10-17 21:52:40 +02:00
parent d0c2d74721
commit 355f55e2bd
25 changed files with 1004 additions and 748 deletions

View File

@ -21,6 +21,7 @@ import {SpecialAbilitySheet} from "./module/sheets/specialAbilitySheet.mjs";
import {ActiveEffectSheet} from "./module/sheets/ActiveEffectSheet.mjs";
import {ActiveEffectDataModel} from "./module/data/activeeffect.mjs";
import {Trefferzone, Wunde, Zonenruestung, Zonenwunde} from "./module/data/Trefferzone.js";
import {ProfessionDataModel} from "./module/data/profession.mjs";
async function preloadHandlebarsTemplates() {
return foundry.applications.handlebars.loadTemplates([
@ -70,6 +71,7 @@ Hooks.once("init", () => {
Blessing: BlessingDataModel,
SpecialAbility: SpecialAbilityDataModel,
ActiveEffect: ActiveEffectDataModel,
Profession: ProfessionDataModel,
}
CONFIG.Combat.initiative = {
@ -126,7 +128,6 @@ Hooks.once("init", () => {
makeDefault: true,
label: 'DSA41.SpecialAbilityLabels.Item'
})
foundry.documents.collections.Items.registerSheet('dsa41.activeEffect', ActiveEffectSheet, {
types: ['ActiveEffect'],
makeDefault: true,

View File

@ -29,6 +29,8 @@ export class PlayerCharacterDataModel extends foundry.abstract.TypeDataModel {
familie: new HTMLField(),
titel: new StringField(),
stand: new StringField(),
verbindungen: new HTMLField(),
notizen: new HTMLField(),
}),
setEquipped: new NumberField({required: true, initial: 0, max: 3, integer: true}),
ini: new SchemaField({

View File

@ -0,0 +1,14 @@
import BaseItem from "./base-item.mjs";
const {BooleanField, StringField, HTMLField} = foundry.data.fields;
export class ProfessionDataModel extends BaseItem {
static defineSchema() {
return {
description: new HTMLField(),
revealed: new BooleanField(),
alias: new StringField(),
}
}
}

View File

@ -0,0 +1,9 @@
export class Profession extends Item {
/**
* Augment the basic Item data model with additional dynamic data.
*/
prepareData() {
super.prepareData();
}
}

View File

@ -0,0 +1,20 @@
export default {
_prepareContext: (context, object) => {
const actorData = context.document
context.system = actorData.system
context.flags = actorData.flags
context.derived = context.document.system
context.originalName = actorData.name
context.name = context.derived.name ?? actorData.name
context.effects = actorData.effects ?? []
return context
},
_onRender: (context, options) => {
},
_getTabConfig: (group) => {
group.tabs.push({id: "social", group: "sheet", label: "Soziales"})
},
template: `systems/DSA_4-1/templates/actor/character/tab-social.hbs`
}

View File

@ -1,11 +1,12 @@
import Meta from "./character/meta.mjs"
import Attributes from "./character/attributes.mjs"
import Combat from "./character/combat.mjs"
import Equipment from "./character/equipment.mjs"
import Skills from "./character/skills.mjs"
import Spells from "./character/spells.mjs"
import Liturgies from "./character/liturgies.mjs"
import Effects from "./character/effects.mjs"
import Equipment from "./character/equipment.mjs"
import Liturgies from "./character/liturgies.mjs"
import Meta from "./character/meta.mjs"
import Skills from "./character/skills.mjs"
import Social from "./character/social.mjs";
import Spells from "./character/spells.mjs"
const {HandlebarsApplicationMixin} = foundry.applications.api
const {ActorSheetV2} = foundry.applications.sheets
@ -36,15 +37,7 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) {
static TABS = {
sheet: {
tabs: [
{id: 'meta', group: 'sheet', label: 'Meta'},
// {id: 'attributes', group: 'sheet', label: 'Eigenschaften'},
// {id: 'combat', group: 'sheet', label: 'Kampf'},
// {id: 'equipment', group: 'sheet', label: 'Inventar'},
// {id: 'skills', group: 'sheet', label: 'Talente'},
// {id: 'spells', group: 'sheet', label: 'Zauber'},
// {id: 'liturgies', group: 'sheet', label: 'Liturgien'},
],
tabs: [],
initial: 'meta'
}
}
@ -57,6 +50,9 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) {
meta: {
template: Meta.template
},
social: {
template: Social.template
},
attributes: {
template: Attributes.template
},
@ -69,6 +65,9 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) {
skills: {
template: Skills.template
},
spells: {
template: Spells.template
},
liturgies: {
template: Liturgies.template
},
@ -112,6 +111,8 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) {
_getTabsConfig(group) {
const tabs = foundry.utils.deepClone(super._getTabsConfig(group))
Meta._getTabConfig(tabs, this);
Social._getTabConfig(tabs, this);
Attributes._getTabConfig(tabs, this)
Combat._getTabConfig(tabs, this)
Equipment._getTabConfig(tabs, this)
@ -125,12 +126,36 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) {
async _preparePartContext(partId, context) {
switch (partId) {
case "form":
const findEquipmentOnSlot = (slot, setNumber, object) => {
return object.items.get(object.system.heldenausruestung[setNumber]?.[slot])
}
const actorData = context.document
context.system = actorData.system
context.isOwner = actorData.isOwner
context.flags = actorData.flags
context.derived = context.document.system
context.professions = actorData.items.filter(p => p.type === 'Profession').map(p => {
// is tarnidentitaet revealed?
if (p.system.revealed) {
return {
id: p.id,
name: p.name,
alias: p.system.alias,
}
} else {
return {
id: p.id,
name: p.system.alias ?? p.name,
alias: p.name,
}
}
})
context.originalName = actorData.name
context.name = context.derived.name ?? actorData.name
context.img = actorData.img
context.effects = actorData.effects ?? []
context.maxWounds = actorData.system.wunden.max ?? 3
@ -145,6 +170,89 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) {
context.ausdauer = game.settings.get("DSA_4-1", "optional_ausdauer")
context.colorfulDice = game.settings.get('DSA_4-1', 'optional_colorfuldice')
context.inidice = actorData.system.ini.wuerfel
context.inivalue = actorData.system.ini.aktuell
context.inimod = actorData.system.ini.mod
context.aupper = Math.min((actorData.system.aup.aktuell / actorData.system.aup.max) * 100, 100)
context.lepper = Math.min((actorData.system.lep.aktuell / actorData.system.lep.max) * 100, 100)
context.keper = Math.min((actorData.system.kap.aktuell / actorData.system.kap.max) * 100, 100)
context.aspper = Math.min((actorData.system.asp.aktuell / actorData.system.asp.max) * 100, 100)
context.lepcurrent = actorData.system.lep.aktuell ?? 0
context.aupcurrent = actorData.system.aup.aktuell ?? 0
const fernkampf = findEquipmentOnSlot("fernkampf", actorData.system.setEquipped, actorData)
const links = findEquipmentOnSlot("links", actorData.system.setEquipped, actorData)
const rechts = findEquipmentOnSlot("rechts", actorData.system.setEquipped, actorData)
context.attacks = [];
if (fernkampf) {
const fkitems = fernkampf.system.rangedSkills.map((skillInQuestion) => actorData.items.find(p => p.name === skillInQuestion))
fkitems.forEach(async skill => {
const obj = await skill
context.attacks.push({
name: obj.name,
using: fernkampf.name,
atroll: `1d20cs<${object.system.fk.aktuell + obj.system.at}`,
at: `${object.system.fk.aktuell + obj.system.at}`,
tproll: `${fernkampf.system.rangedAttackDamage}`, // TODO consider adding TP/KK mod and Range mod
tp: `${fernkampf.system.rangedAttackDamage}`,
iniroll: `(${context.inidice})d6 + ${context.inivalue + fernkampf.system.iniModifier ?? 0}`,
ini: `${context.inidice}w6 + ${context.inivalue + fernkampf.system.iniModifier ?? 0}`,
})
})
}
if (links) {
const meitems = []
links.system.meleeSkills.forEach((skillInQuestion) => {
const item = actorData.items.find(p => p.name === skillInQuestion)
if (item) {
meitems.push(item)
}
})
meitems.forEach(skill => {
const obj = skill
context.attacks.push({
name: obj.name,
using: links.name,
atroll: `1d20cs<${object.system.at.links.aktuell + obj.system.at + links.system.attackModifier}`, // TODO consider adding W/M
at: `${object.system.at.links.aktuell + obj.system.at + links.system.attackModifier}`,
paroll: `1d20cs<${object.system.pa.links.aktuell + obj.system.pa + links.system.parryModifier}`, // TODO consider adding W/M
pa: `${object.system.pa.links.aktuell + obj.system.pa + links.system.parryModifier}`,
tproll: `${links.system.meleeAttackDamage}`, // TODO consider adding TP/KK mod
tp: `${links.system.meleeAttackDamage}`,
iniroll: `(${context.inidice})d6 + ${context.inivalue + links.system.iniModifier ?? 0}`,
ini: `${context.inidice}w6 + ${context.inivalue + links.system.iniModifier ?? 0}`,
})
})
}
if (rechts) {
const meitems = []
rechts.system.meleeSkills.forEach((skillInQuestion) => {
const item = actorData.items.find(p => p.name === skillInQuestion)
if (item) {
meitems.push(item)
}
})
meitems.forEach(skill => {
const obj = skill
context.attacks.push({
name: obj.name,
using: rechts.name,
atroll: `1d20cs<${object.system.at.rechts.aktuell + obj.system.at + rechts.system.attackModifier}`, // TODO consider adding W/M
at: `${object.system.at.rechts.aktuell + obj.system.at + rechts.system.attackModifier}`,
paroll: `1d20cs<${object.system.pa.rechts.aktuell + obj.system.pa + rechts.system.parryModifier}`, // TODO consider adding W/M
pa: `${object.system.pa.rechts.aktuell + obj.system.pa + rechts.system.parryModifier}`,
tproll: `${rechts.system.meleeAttackDamage}`, // TODO consider adding TP/KK mod
tp: `${rechts.system.meleeAttackDamage}`,
iniroll: `(${context.inidice})d6 + ${context.inivalue + rechts.system.iniModifier ?? 0}`,
ini: `${context.inidice}w6 + ${context.inivalue + rechts.system.iniModifier ?? 0}`,
})
})
}
context.attributes = [
{
eigenschaft: "mu",
@ -198,7 +306,10 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) {
break;
case "meta":
Meta._prepareContext(context, this.object)
await Meta._prepareContext(context, this.object)
break
case "social":
await Social._prepareContext(context, this.object)
break
case "attributes":
await Attributes._prepareContext(context, this.object)
@ -207,19 +318,19 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) {
await Combat._prepareContext(context, this.object)
break
case "equipment":
Equipment._prepareContext(context, this.object)
await Equipment._prepareContext(context, this.object)
break
case "skills":
Skills._prepareContext(context, this.object)
await Skills._prepareContext(context, this.object)
break
case "spells":
Spells._prepareContext(context, this.object)
await Spells._prepareContext(context, this.object)
break
case "liturgies":
Liturgies._prepareContext(context, this.object)
await Liturgies._prepareContext(context, this.object)
break
case "effects":
Effects._prepareContext(context, this.object)
await Effects._prepareContext(context, this.object)
break
}
return context
@ -227,6 +338,7 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) {
_onRender(context, options) {
Meta._onRender(context, options, this.element)
Social._onRender(context, options, this.element)
Attributes._onRender(context, options, this.element)
Combat._onRender(context, options, this.element)
Effects._onRender(context, options, this.element)

View File

@ -1,6 +1,7 @@
import {LiturgyData} from "../data/miracle/liturgydata.mjs";
import {BlessingDataModel} from "../data/blessing.mjs";
import {Blessing} from "../documents/blessing.mjs";
import {Profession} from "../documents/profession.mjs";
let months = [
"Praios",
@ -232,6 +233,28 @@ function mapMiracles(actor, liturgies) {
}
}
function mapProfessions(actor, professions) {
if (professions.string) {
professions = {hauptprofession: professions}
}
Object.values(professions).forEach(profession => {
actor.createEmbeddedDocuments('Item', [
new Profession({
name: profession.string,
type: "Profession",
system: {
description: "",
alias: profession.tarnidentitaet ? profession.tarnidentitaet : profession.string,
revealed: !profession.tarnidentitaet
}
})
])
})
// actor.update({"system.meta.professions": professions})
}
/**
* parses a json into a fitting character-json
* @param rawJson the json parsed from the Helden-Software XML
@ -244,17 +267,7 @@ function mapRawJson(actor, rawJson) {
json.meta = {}
json.meta.spezies = held.basis.rasse.string
json.meta.kultur = held.basis.kultur.string
let professions = []
for (let profession in held.basis.ausbildungen.ausbildung) {
profession = held.basis.ausbildungen.ausbildung[profession]
if (profession.tarnidentitaet) {
professions = [profession.tarnidentitaet]
break;
}
let professionString = profession.string
professions.push(professionString)
}
json.meta.professions = professions
mapProfessions(actor, held.basis.ausbildungen.ausbildung)
json.meta.geschlecht = held.basis.geschlecht.name
json.meta.haarfarbe = held.basis.rasse.aussehen.haarfarbe
json.meta.groesse = held.basis.rasse.groesse.value

View File

@ -8,6 +8,11 @@
font-weight: bold;
}
input,
.rkp .pill {
font-family: Andalus, sans-serif;
}
.editor.prosemirror.active, .editor.prosemirror.inactive {
font-family: Gentium, sans-serif;
}

View File

@ -9,10 +9,6 @@
position: relative;
.attributes {
position: absolute;
top: 8px;
right: 4px;
height: 48px;
display: flex;
.attribute.rollable {

View File

@ -0,0 +1,19 @@
.application.sheet.dsa41 {
.pill {
height: 24px;
line-height: 24px;
font-size: 14px;
vertical-align: middle;
padding: 1px 4px;
margin-right: 4px;
border-radius: 8px;
border: 1px solid orange;
color: orange;
background-color: rgba(0, 0, 0, 0.6);
box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.5), inset -1px -1px 0 rgba(0, 0, 0, 0.1);
display: inline-block;
}
}

View File

@ -1,7 +1,13 @@
.dsa41.sheet {
.application.sheet.dsa41 {
.editor.prosemirror.active, .editor.prosemirror.inactive {
.editor.prosemirror {
flex: 1;
background-color: rgba(0, 0, 0, 0.1);
box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1);
border: 1px solid #666;
outline: 1px solid transparent;
border-radius: 4px;
}
}

View File

@ -1,6 +1,14 @@
@use "sass:color";
@use "../atoms/numbers";
@use "../atoms/colours" as colour;
@use "./character-tabs/meta";
@use "./character-tabs/social";
@use "./character-tabs/attributes";
@use "./character-tabs/inventory";
@use "./character-tabs/combat";
@use "./character-tabs/spells";
@use "./character-tabs/liturgies";
.application.sheet.dsa41.actor.character {
@ -20,15 +28,24 @@
left: 0;
height: $attribute-height;
right: 0;
display: grid;
grid-template-columns: 1fr max-content;
gap: 0 8px;
.name {
border: unset;
font-size: large;
}
}
div.head-data {
position: absolute;
left: 0;
top: $attribute-height;
width: $sidebar-width;
bottom: 0;
padding: 8px;
left: 16px;
top: $attribute-height+30px;
width: $sidebar-width - 16px;
bottom: 16px;
padding: 0;
.profile-img {
@ -38,609 +55,49 @@
nav.sheet-tabs.tabs {
position: absolute;
left: $sidebar-width;
top: $attribute-height+$tabs-spacing;
right: 0;
left: $sidebar-width+16px;
top: $attribute-height+$tabs-spacing+13px;
right: 16px;
height: $tabs-height;
}
section.tab {
position: absolute;
top: $attribute-height+$tabs-height+$tabs-spacing+4px;
left: $sidebar-width;
right: 4px;
bottom: 4px;
padding: 8px;
top: $attribute-height+$tabs-height+$tabs-spacing+21px;
left: $sidebar-width+16px;
right: 16px;
bottom: 16px;
padding: 0;
overflow: auto;
}
.tab.overview.active {
display: flex;
flex-direction: column;
height: 100%;
.meta-data {
flex: 0;
columns: 2;
gap: 0 16px;
div {
break-inside: avoid;
padding: 4px 0;
}
.double {
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-areas: 'label label' 'left right';
gap: 0 8px;
label {
grid-area: label;
}
}
.editor {
background-color: rgba(0, 0, 0, 0.2)
}
& + .meta-data {
flex: 1;
}
}
.meta-data.html {
& > div {
display: flex;
flex-direction: column;
height: 100%;
label {
flex: 0;
}
.editor {
flex: 1;
}
}
}
.tab.meta.active {
@include meta.tab;
}
.tab.social.active {
@include social.tab;
}
.tab.attributes.active {
height: 100%;
.attribute {
padding: 8px 0;
display: flex;
gap: 0 8px;
label {
width: 120px;
text-align: right;
vertical-align: middle;
line-height: 24px;
}
input {
max-width: 80px;
text-align: right;
}
.mod {
color: grey;
text-shadow: 0 -1px 0 #ccc;
box-Shadow: 1px 1px 1px rgba(0, 0, 0, 0.5);
border-radius: 4px;
height: 24px;
width: 24px;
background: linear-gradient(0deg, rgba(24, 24, 24, 1) 0%, rgba(80, 80, 80, 1) 100%);;
display: inline-block;
text-align: center;
vertical-align: middle;
line-height: 24px;
margin-left: 4px;
}
}
.attributes-overview {
columns: 2;
gap: 0 16px;
}
.resource-overview {
.attribute {
}
}
.advantages, .special-abilities {
margin-bottom: 16px;
ul {
list-style-type: none;
padding: 0;
margin: 0;
text-indent: 0;
li {
display: inline-block;
}
.advantage, .special-ability {
position: relative;
border: 1px solid gold;
box-shadow: 2px 2px 4px #000;
border-radius: 8px;
height: 24px;
color: gold;
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.2);
display: inline-block;
padding: 0 8px;
margin-left: 0;
margin-bottom: 4px;
background-image: url("../../assets/velvet_button.png");
background-repeat: repeat-y;
background-size: cover;
span {
position: relative;
z-index: 2;
line-height: 24px;
vertical-align: middle;
}
&.special-ability {
&::after {
background: rgba(128, 0, 96, 0.5);
}
}
&::after {
content: "";
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
border-radius: 8px;
background: rgba(0, 128, 0, 0.5);
}
& + .advantage, & + .special-ability {
margin-left: 8px;
}
&.disadvantage {
font-style: italic;
&::after {
background: rgba(128, 0, 0, 0.5);
}
}
}
}
}
@include attributes.tab;
}
.backpack.active {
display: grid;
grid-template-columns: 1fr 320px;
grid-template-rows: 74px 1fr;
gap: 10px;
height: 100%;
grid-template-areas:
"capacity capacity"
"inventory equipment";
.capacity {
grid-area: capacity;
.resource {
position: relative;
border: 1px inset #ccc;
background-color: rgba(0, 0, 0, 0.2);
height: 8px;
span.fill {
position: absolute;
left: 0;
top: 0;
bottom: 0;
background: linear-gradient(to bottom, #0bad29 0%, #11f128 50%, #0cde24 51%, #6ff77b 100%);
}
}
}
.inventory {
grid-area: inventory;
.equipment:hover {
.item-name {
text-shadow: 0 0 10px rgb(255 0 0);
}
}
}
.inventory.active {
@include inventory.tab;
}
.tab.combat.active {
display: grid;
grid-template-columns: 1fr 320px;
grid-template-rows: 32px 32px 1fr;
grid-template-areas: "res res" "wounds wounds" "actions actions";
gap: 10px;
.tab-resources {
grid-area: res;
}
.wounds {
position: relative;
height: 24px;
display: flex;
margin-bottom: 8px;
padding-left: 130px;
grid-area: wounds;
label {
position: absolute;
left: 0;
top: 0;
line-height: 24px;
width: 120px;
bottom: 0;
vertical-align: middle;
text-align: right;
height: 24px;
display: inline-block;
z-index: 2;
}
.filled-segment {
border: 1px solid black;
background-image: url('/systems/DSA_4-1/assets/gradient.png');
background-size: 24px 100%;
position: relative;
flex: 1;
text-align: center;
vertical-align: middle;
line-height: 24px;
color: white;
text-shadow: 2px 2px 0 rgba(0, 0, 0, 0.3);
background-color: rgba(255, 0, 0, 0.8);
background-blend-mode: multiply;
}
.empty-segment {
border: 1px solid black;
background-image: url('/systems/DSA_4-1/assets/gradient.png');
background-size: 32px 100%;
position: relative;
flex: 1;
text-align: center;
vertical-align: middle;
line-height: 24px;
color: gold;
text-shadow: 2px 2px 0 rgba(0, 0, 0, 0.3);
background-color: rgba(0, 0, 0, 0.8);
background-blend-mode: multiply;
}
}
.actions {
grid-area: actions;
}
&.zones {
grid-template-areas: "res res" "wounds wounds" "actions paperdoll";
.paperdoll {
grid-area: paperdoll;
div {
position: relative;
margin-left: 9px;
margin-top: 42px;
.wound {
position: absolute;
width: 32px;
height: 32px;
border-radius: 16px;
border: 1px solid black;
background-color: rgba(0, 0, 0, 0.5);
box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.3);
line-height: 32px;
vertical-align: middle;
text-align: center;
color: red;
&.armlinks {
top: 146px;
left: 210px;
}
&.armrechts {
top: 146px;
left: 60px;
}
&.beinlinks {
top: 346px;
left: 210px;
}
&.beinrechts {
top: 346px;
left: 60px;
}
&.bauch {
top: 166px;
left: 136px;
}
&.kopf {
top: 6px;
left: 136px
}
&.brust {
top: 86px;
left: 110px;
}
}
.armor {
position: absolute;
width: 32px;
height: 32px;
border-radius: 0 0 16px 16px;
line-height: 32px;
vertical-align: middle;
text-align: center;
border: 1px solid silver;
background-color: rgba(0, 0, 0, 0.5);
box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.3);
color: silver;
&.armlinks {
top: 180px;
left: 210px;
}
&.armrechts {
top: 180px;
left: 60px;
}
&.beinlinks {
top: 380px;
left: 210px;
}
&.beinrechts {
top: 380px;
left: 60px;
}
&.bauch {
top: 200px;
left: 136px;
}
&.kopf {
top: 40px;
left: 136px
}
&.brust {
top: 120px;
left: 110px;
}
}
}
}
}
@include combat.tab;
}
.tab.spells {
tr {
height: 24px;
margin: 0;
padding: 0;
}
td {
margin: 0;
padding: 0;
height: 24px;
}
$color: #05f;
.spell.rollable svg {
width: 24px;
height: 24px;
top: 1px;
z-index: 1;
position: relative;
.border {
fill: #0000;
}
.center {
fill: $color;
stroke: colour.$rollable-die-border-color;
}
.topleft {
fill: color.adjust($color, $lightness: numbers.$lighter_factor);
stroke: colour.$rollable-die-border-color;
}
.bottomleft {
fill: color.adjust($color, $lightness: numbers.$lightest_factor);
stroke: colour.$rollable-die-border-color;
}
.topright {
fill: color.adjust($color, $lightness: numbers.$darken_factor);
stroke: colour.$rollable-die-border-color;
}
.bottomright, .bottom {
fill: color.adjust($color, $lightness: numbers.$darkest_factor);
stroke: colour.$rollable-die-border-color;
}
}
.die-column {
width: 24px;
}
.clickable {
span {
position: relative;
z-index: 1;
}
}
tbody {
tr {
position: relative;
&::after {
content: '';
background-image: linear-gradient(to right, rgba(color.scale($color, $lightness: numbers.$zebra_light), numbers.$start_gradient), rgba(color.scale($color, $lightness: numbers.$zebra_light), numbers.$end_2_gradient));
border-top-right-radius: 8px;
border-bottom-right-radius: 8px;
position: absolute;
top: 2px;
left: 12px;
bottom: 2px;
right: 33%;
z-index: 0;
pointer-events: none;
}
&:nth-child(odd) {
&::after {
background-image: linear-gradient(to right, rgba(color.scale($color, $lightness: numbers.$zebra_dark), numbers.$start_gradient), rgba(color.scale($color, $lightness: numbers.$zebra_dark), numbers.$end_2_gradient));
}
}
}
}
.merkmal-list {
list-style: none;
margin: 0;
padding: 0;
text-indent: 0;
li {
display: inline-block;
padding: 0 4px;
}
}
@include spells.tab;
}
.tab.liturgies {
table {
border-top: unset;
border-bottom: unset;
position: relative;
}
.liturgy-header {
background: unset;
border: unset;
tr {
height: 90px;
th {
vertical-align: middle;
color: black;
text-shadow: 2px 2px 1px rgba(0, 0, 0, 0.2);
}
}
}
td, th {
padding-left: 8px;
}
}
.tab-resources {
display: flex;
justify-content: center;
gap: 0 16px;
padding-bottom: 8px;
& > div {
height: 32px;
position: relative;
label {
width: 80px;
line-height: 32px;
vertical-align: middle;
}
input {
display: inline-block;
width: 40px;
height: 32px;
}
span.inline {
line-height: 32px;
vertical-align: middle;
width: 40px;
text-align: center;
}
}
@include liturgies.tab;
}
}

View File

@ -0,0 +1,121 @@
@mixin tab {
height: 100%;
.attribute {
padding: 8px 0;
display: flex;
gap: 0 8px;
label {
width: 120px;
text-align: right;
vertical-align: middle;
line-height: 24px;
}
input {
max-width: 80px;
text-align: right;
}
.mod {
color: grey;
text-shadow: 0 -1px 0 #ccc;
box-Shadow: 1px 1px 1px rgba(0, 0, 0, 0.5);
border-radius: 4px;
height: 24px;
width: 24px;
background: linear-gradient(0deg, rgba(24, 24, 24, 1) 0%, rgba(80, 80, 80, 1) 100%);;
display: inline-block;
text-align: center;
vertical-align: middle;
line-height: 24px;
margin-left: 4px;
}
}
.attributes-overview {
columns: 2;
gap: 0 16px;
}
.resource-overview {
.attribute {
}
}
.advantages, .special-abilities {
margin-bottom: 16px;
ul {
list-style-type: none;
padding: 0;
margin: 0;
text-indent: 0;
li {
display: inline-block;
}
.advantage, .special-ability {
position: relative;
border: 1px solid gold;
box-shadow: 2px 2px 4px #000;
border-radius: 8px;
height: 24px;
color: gold;
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.2);
display: inline-block;
padding: 0 8px;
margin-left: 0;
margin-bottom: 4px;
background-image: url("../../assets/velvet_button.png");
background-repeat: repeat-y;
background-size: cover;
span {
position: relative;
z-index: 2;
line-height: 24px;
vertical-align: middle;
}
&.special-ability {
&::after {
background: rgba(128, 0, 96, 0.5);
}
}
&::after {
content: "";
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
border-radius: 8px;
background: rgba(0, 128, 0, 0.5);
}
& + .advantage, & + .special-ability {
margin-left: 8px;
}
&.disadvantage {
font-style: italic;
&::after {
background: rgba(128, 0, 0, 0.5);
}
}
}
}
}
}

View File

@ -0,0 +1,190 @@
@mixin tab {
display: grid;
grid-template-columns: 1fr 320px;
grid-template-rows: 32px 32px 1fr;
grid-template-areas: "res res" "wounds wounds" "actions actions";
gap: 10px;
.tab-resources {
grid-area: res;
}
.wounds {
position: relative;
height: 24px;
display: flex;
margin-bottom: 8px;
padding-left: 130px;
grid-area: wounds;
label {
position: absolute;
left: 0;
top: 0;
line-height: 24px;
width: 120px;
bottom: 0;
vertical-align: middle;
text-align: right;
height: 24px;
display: inline-block;
z-index: 2;
}
.filled-segment {
border: 1px solid black;
background-image: url('/systems/DSA_4-1/assets/gradient.png');
background-size: 24px 100%;
position: relative;
flex: 1;
text-align: center;
vertical-align: middle;
line-height: 24px;
color: white;
text-shadow: 2px 2px 0 rgba(0, 0, 0, 0.3);
background-color: rgba(255, 0, 0, 0.8);
background-blend-mode: multiply;
}
.empty-segment {
border: 1px solid black;
background-image: url('/systems/DSA_4-1/assets/gradient.png');
background-size: 32px 100%;
position: relative;
flex: 1;
text-align: center;
vertical-align: middle;
line-height: 24px;
color: gold;
text-shadow: 2px 2px 0 rgba(0, 0, 0, 0.3);
background-color: rgba(0, 0, 0, 0.8);
background-blend-mode: multiply;
}
}
.actions {
grid-area: actions;
}
&.zones {
grid-template-areas: "res res" "wounds wounds" "actions paperdoll";
.paperdoll {
grid-area: paperdoll;
div {
position: relative;
margin-left: 9px;
margin-top: 42px;
.wound {
position: absolute;
width: 32px;
height: 32px;
border-radius: 16px;
border: 1px solid black;
background-color: rgba(0, 0, 0, 0.5);
box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.3);
line-height: 32px;
vertical-align: middle;
text-align: center;
color: red;
&.armlinks {
top: 146px;
left: 210px;
}
&.armrechts {
top: 146px;
left: 60px;
}
&.beinlinks {
top: 346px;
left: 210px;
}
&.beinrechts {
top: 346px;
left: 60px;
}
&.bauch {
top: 166px;
left: 136px;
}
&.kopf {
top: 6px;
left: 136px
}
&.brust {
top: 86px;
left: 110px;
}
}
.armor {
position: absolute;
width: 32px;
height: 32px;
border-radius: 0 0 16px 16px;
line-height: 32px;
vertical-align: middle;
text-align: center;
border: 1px solid silver;
background-color: rgba(0, 0, 0, 0.5);
box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.3);
color: silver;
&.armlinks {
top: 180px;
left: 210px;
}
&.armrechts {
top: 180px;
left: 60px;
}
&.beinlinks {
top: 380px;
left: 210px;
}
&.beinrechts {
top: 380px;
left: 60px;
}
&.bauch {
top: 200px;
left: 136px;
}
&.kopf {
top: 40px;
left: 136px
}
&.brust {
top: 120px;
left: 110px;
}
}
}
}
}
}

View File

@ -0,0 +1,42 @@
@mixin tab {
display: grid;
grid-template-columns: 1fr 320px;
grid-template-rows: 74px 1fr;
gap: 10px;
height: 100%;
grid-template-areas:
"capacity capacity"
"inventory equipment";
.capacity {
grid-area: capacity;
.resource {
position: relative;
border: 1px inset #ccc;
background-color: rgba(0, 0, 0, 0.2);
height: 8px;
span.fill {
position: absolute;
left: 0;
top: 0;
bottom: 0;
background: linear-gradient(to bottom, #0bad29 0%, #11f128 50%, #0cde24 51%, #6ff77b 100%);
}
}
}
.inventory {
grid-area: inventory;
.equipment:hover {
.item-name {
text-shadow: 0 0 10px rgb(255 0 0);
}
}
}
}

View File

@ -0,0 +1,63 @@
@mixin tab {
table {
border-top: unset;
border-bottom: unset;
position: relative;
}
.liturgy-header {
background: unset;
border: unset;
tr {
height: 90px;
th {
vertical-align: middle;
color: black;
text-shadow: 2px 2px 1px rgba(0, 0, 0, 0.2);
}
}
}
td, th {
padding-left: 8px;
}
}
.tab-resources {
display: flex;
justify-content: center;
gap: 0 16px;
padding-bottom: 8px;
& > div {
height: 32px;
position: relative;
label {
width: 80px;
line-height: 32px;
vertical-align: middle;
}
input {
display: inline-block;
width: 40px;
height: 32px;
}
span.inline {
line-height: 32px;
vertical-align: middle;
width: 40px;
text-align: center;
}
}
}

View File

@ -0,0 +1,64 @@
@mixin tab {
display: flex;
flex-direction: column;
.meta-data {
flex: 0;
height: unset;
columns: 2;
gap: 0 16px;
div {
break-inside: avoid;
}
.meta-line {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 0 8px;
padding-bottom: 8px;
}
.double {
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-areas: 'label label' 'left right';
gap: 0 8px;
label {
grid-area: label;
}
}
& + .meta-data {
flex: 1;
}
}
.meta-data.html {
height: unset;
display: flex;
flex-direction: row;
gap: 0 8px;
flex: 1;
& > div {
flex: 1;
display: flex;
flex-direction: column;
height: 100%;
label {
flex: 0;
}
.editor {
flex: 1;
}
}
}
}

View File

@ -0,0 +1,38 @@
@mixin tab {
display: flex;
flex-direction: column;
.social-line {
flex: 0;
height: unset;
display: grid;
grid-template-columns: 1fr 1fr 80px;
}
.meta-data.html {
height: unset;
display: flex;
flex-direction: row;
gap: 0 8px;
flex: 1;
& > div {
display: flex;
flex-direction: column;
height: 100%;
flex: 1;
label {
flex: 0;
}
.editor {
flex: 1;
}
}
}
}

View File

@ -0,0 +1,108 @@
@use "sass:color";
@use "../../atoms/numbers";
@use "../../atoms/colours" as colour;
@mixin tab {
tr {
height: 24px;
margin: 0;
padding: 0;
}
td {
margin: 0;
padding: 0;
height: 24px;
}
$color: #05f;
.spell.rollable svg {
width: 24px;
height: 24px;
top: 1px;
z-index: 1;
position: relative;
.border {
fill: #0000;
}
.center {
fill: $color;
stroke: colour.$rollable-die-border-color;
}
.topleft {
fill: color.adjust($color, $lightness: numbers.$lighter_factor);
stroke: colour.$rollable-die-border-color;
}
.bottomleft {
fill: color.adjust($color, $lightness: numbers.$lightest_factor);
stroke: colour.$rollable-die-border-color;
}
.topright {
fill: color.adjust($color, $lightness: numbers.$darken_factor);
stroke: colour.$rollable-die-border-color;
}
.bottomright, .bottom {
fill: color.adjust($color, $lightness: numbers.$darkest_factor);
stroke: colour.$rollable-die-border-color;
}
}
.die-column {
width: 24px;
}
.clickable {
span {
position: relative;
z-index: 1;
}
}
tbody {
tr {
position: relative;
&::after {
content: '';
background-image: linear-gradient(to right, rgba(color.scale($color, $lightness: numbers.$zebra_light), numbers.$start_gradient), rgba(color.scale($color, $lightness: numbers.$zebra_light), numbers.$end_2_gradient));
border-top-right-radius: 8px;
border-bottom-right-radius: 8px;
position: absolute;
top: 2px;
left: 12px;
bottom: 2px;
right: 33%;
z-index: 0;
pointer-events: none;
}
&:nth-child(odd) {
&::after {
background-image: linear-gradient(to right, rgba(color.scale($color, $lightness: numbers.$zebra_dark), numbers.$start_gradient), rgba(color.scale($color, $lightness: numbers.$zebra_dark), numbers.$end_2_gradient));
}
}
}
}
.merkmal-list {
list-style: none;
margin: 0;
padding: 0;
text-indent: 0;
li {
display: inline-block;
padding: 0 4px;
}
}
}

View File

@ -1,20 +1,22 @@
@use "atoms/fonts";
@use "atoms/typography";
@use "atoms/svg";
@use "molecules/pill";
@use "molecules/rollable";
@use "molecules/lists";
@use "molecules/attributes";
@use "molecules/sidebar-elements";
@use "molecules/tabs";
@use "molecules/paperdoll";
@use "molecules/player-action";
@use "molecules/liturgy-banner";
@use "molecules/richtext-editor";
@use "organisms/character-sheet";
@use "organisms/group-sheet";
@use "molecules/tabs";
@use "organisms/equipment-sheet";
@use "molecules/paperdoll";
@use "organisms/creature-sheet";
@use "molecules/player-action";
@use "organisms/modify-liturgy";
@use "molecules/liturgy-banner";
@use "organisms/skill-sheet";
@use "organisms/active-effect-sheet";
@use "organisms/advantage-sheet";
@use "molecules/richtext-editor";

View File

@ -127,6 +127,14 @@
}
},
"Item": {
"Profession": {
"htmlFields": [
"description"
],
"booleanFields": [
"revealed"
]
},
"Equipment": {
"stringFields": [
"name",

View File

@ -3,7 +3,19 @@
{{!-- Sheet Header --}}
<header class="sheet-header">
{{!-- Header stuff goes here --}}
<div class="header-fields">
<div>
<input class="name" name="name" type="text" value="{{name}}" placeholder="Name"/>
<div class="rkp">
<span class="pill species">{{system.meta.spezies}}</span>
<span class="pill culture">{{system.meta.kultur}}</span>
{{#each professions}}
<span class="pill profession" {{#if isOwner}}data-action="openEmbeddedDocument"
data-item-id="{{this.id}}"{{/if}}>{{this.name}}</span>
{{/each}}
</div>
</div>
<div class="attributes {{#if this.colorfulDice}}colorfulDice{{/if}}">
{{#each attributes}}
{{> "systems/DSA_4-1/templates/ui/partial-attribute-button.hbs" this}}
@ -13,10 +25,8 @@
</header>
<div class="head-data">
<h1 class="charname {{#if owner}}secret-identity{{/if}}" {{#if owner}}title="{{originalName}}"{{/if}} ><input
name="name" type="text" value="{{name}}" placeholder="Name"/></h1>
<img class="profile-img" src="{{actor.img}}" data-edit="img" title="{{name}}"/>
<h2 class="sidebar-element header">Kampf Daten</h2>
<img class="profile-img" src="{{img}}" data-edit="img" title="{{name}}"/>
<div class="sidebar-element resource-bar">
<label>LeP: {{this.lep}}</label><span class="resource-fill lep" style="width: {{this.lepper}}%"></span>
@ -71,8 +81,6 @@
</div>
{{/each}}
<h2 class="sidebar-element header">Favouriten</h2>
</div>
{{!-- Sheet Tab Navigation --}}

View File

@ -1,85 +1,5 @@
<section class="tab {{tabs.skills.id}} {{tabs.skills.cssClass}}"
data-tab="{{tabs.skills.id}}"
data-group="{{tabs.skills.group}}">
<div class="talent-group">
<h2>Kampftalente</h2>
<ul>
{{#each skills.Kampf}}
<li>
{{> "systems/DSA_4-1/templates/ui/partial-rollable-weaponskill-button.hbs" this}}
</li>
{{/each}}
</ul>
</div>
<div class="talent-group">
<h2>Körperliche Talente</h2>
<ul>
<li>
{{#each skills.Körperlich}}
<li>
{{> "systems/DSA_4-1/templates/ui/partial-rollable-button.hbs" this}}
</li>
{{/each}}
</ul>
</div>
<div class="talent-group">
<h2>Gesellschaftliche Talente</h2>
<ul>
<li>
{{#each skills.Gesellschaft}}
<li>
{{> "systems/DSA_4-1/templates/ui/partial-rollable-button.hbs" this}}
</li>
{{/each}}
</ul>
</div>
<div class="talent-group">
<h2>Natur Talente</h2>
<ul>
<li>
{{#each skills.Natur}}
<li>
{{> "systems/DSA_4-1/templates/ui/partial-rollable-button.hbs" this}}
</li>
{{/each}}
</ul>
</div>
<div class="talent-group">
<h2>Wissenstalente</h2>
<ul>
<li>
{{#each skills.Wissen}}
<li>
{{> "systems/DSA_4-1/templates/ui/partial-rollable-button.hbs" this}}
</li>
{{/each}}
</ul>
</div>
<div class="talent-group">
<h2>Schriften & Sprachen</h2>
<ul>
<li>
{{#each skills.Schriften}}
<li>
{{> "systems/DSA_4-1/templates/ui/partial-rollable-language-button.hbs" this}}
</li>
{{/each}}
{{#each skills.Sprachen}}
<li>
{{> "systems/DSA_4-1/templates/ui/partial-rollable-language-button.hbs" this}}
</li>
{{/each}}
</ul>
</div>
<div class="talent-group">
<h2>Handwerkliche Talente</h2>
<ul>
<li>
{{#each skills.Handwerk}}
<li>
{{> "systems/DSA_4-1/templates/ui/partial-rollable-button.hbs" this}}
</li>
{{/each}}
</ul>
</div>
<section class="tab {{tabs.equipment.id}} {{tabs.skills.cssClass}}"
data-tab="{{tabs.equipment.id}}"
data-group="{{tabs.equipment.group}}">
To be done
</section>

View File

@ -4,32 +4,18 @@
<div class="meta-data">
<div><label>Spezies
<input type="text" name="system.meta.spezies" value="{{system.meta.spezies}}"/>
</label>
</div>
<div><label for="system.meta.kultur">Kultur</label>
<input type="text" name="system.meta.kultur"
value="{{system.meta.kultur}}"/>
</div>
<div><label for="system.meta.profession">Profession</label>
<input type="text" name="system.meta.profession"
value="{{system.meta.profession}}"/>
</div>
<div><label for="system.meta.geschlecht">Geschlecht</label>
<input type="text" name="system.meta.geschlecht"
value="{{system.meta.geschlecht}}"/>
</div>
<div class="double"><label>Sozialstatus</label>
<input type="text" name="system.meta.stand" value="{{system.meta.stand}}"/>
<input type="text" name="system.meta.titel" value="{{system.meta.titel}}"/>
</div>
<div class="meta-line">
<div><label for="system.meta.geschlecht">Geschlecht</label>
<input type="text" name="system.meta.geschlecht"
value="{{system.meta.geschlecht}}"/>
</div>
<div><label for="system.meta.groesse">Größe</label>
<input type="number" name="system.meta.groesse" value="{{system.meta.groesse}}"/>
</div>
<div><label for="system.meta.gewicht">Gewicht</label>
<input type="number" name="system.meta.gewicht" value="{{system.meta.gewicht}}"/>
<div><label for="system.meta.groesse">Größe</label>
<input type="number" name="system.meta.groesse" value="{{system.meta.groesse}}"/>
</div>
<div><label for="system.meta.gewicht">Gewicht</label>
<input type="number" name="system.meta.gewicht" value="{{system.meta.gewicht}}"/>
</div>
</div>
<div class="double"><label>Alter</label>
<input type="number" name="system.meta.groesse" value="{{system.meta.alter}}"/>
@ -37,13 +23,25 @@
</div>
</div>
<div class="meta-data html">
<div><label>Aussehen</label>
{{editor system.meta.aussehen target="system.meta.aussehen" button=true owner=owner
editable=editable}}
<div><label>Notizen</label>
<prose-mirror
name="system.meta.notizen"
button="false"
editable="{{editable}}"
toggled="true"
value="{{system.meta.notizen}}">
{{{system.meta.notizen}}}
</prose-mirror>
</div>
<div><label>Familie</label>
{{editor system.meta.familie target="system.meta.familie" button=true owner=owner
editable=editable}}
<div><label>Aussehen</label>
<prose-mirror
name="system.meta.aussehen"
button="false"
editable="{{editable}}"
toggled="true"
value="{{system.meta.aussehen}}">
{{{system.meta.aussehen}}}
</prose-mirror>
</div>
</div>
</section>

View File

@ -0,0 +1,40 @@
<section class="tab {{tabs.social.id}} {{tabs.social.cssClass}}"
data-tab="{{tabs.social.id}}"
data-group="{{tabs.social.group}}">
<div class="social-line">
<div><label>Stand</label>
<input type="text" name="system.meta.stand" value="{{system.meta.stand}}"/>
</div>
<div><label>Titel</label>
<input type="text" name="system.meta.titel" value="{{system.meta.titel}}"/>
</div>
<div><label>Sozialstatus</label>
<input type="text" name="system.attribute.so.aktuell" value="{{system.attribute.so.aktuell}}"/>
</div>
</div>
<div class="meta-data html">
<div><label>Verbindungen</label>
<prose-mirror
name="system.verbindungen"
button="false"
editable="{{editable}}"
toggled="true"
value="{{system.meta.verbindungen}}">
{{{system.meta.verbindungen}}}
</prose-mirror>
</div>
<div><label>Familie</label>
<prose-mirror
name="system.meta.familie"
button="false"
editable="{{editable}}"
toggled="true"
value="{{system.meta.familie}}">
{{{system.meta.familie}}}
</prose-mirror>
</div>
</div>
</section>