Adds Group Management

pull/48/head
macniel 2025-10-03 11:03:34 +02:00
parent 41045cb482
commit 691a811275
9 changed files with 360 additions and 4 deletions

View File

@ -7,6 +7,8 @@ import { VornachteileDataModel } from "./module/data/vornachteile.mjs";
import { Character } from "./module/documents/character.mjs"; import { Character } from "./module/documents/character.mjs";
import { CharacterSheet } from "./module/sheets/characterSheet.mjs"; import { CharacterSheet } from "./module/sheets/characterSheet.mjs";
import { VornachteilSheet } from "./module/sheets/vornachteilSheet.mjs"; import { VornachteilSheet } from "./module/sheets/vornachteilSheet.mjs";
import {GroupDataModel} from "./module/data/group.mjs";
import {GroupSheet} from "./module/sheets/groupSheet.mjs";
async function preloadHandlebarsTemplates() { async function preloadHandlebarsTemplates() {
return loadTemplates([ return loadTemplates([
@ -31,6 +33,7 @@ Hooks.once("init", () => {
// Configure System Data Models. // Configure System Data Models.
CONFIG.Actor.dataModels = { CONFIG.Actor.dataModels = {
character: PlayerCharacterDataModel, character: PlayerCharacterDataModel,
group: GroupDataModel
}; };
CONFIG.Item.dataModels = { CONFIG.Item.dataModels = {
@ -51,6 +54,11 @@ Hooks.once("init", () => {
makeDefault: true, makeDefault: true,
label: 'DSA41.CharacterLabels.Item' label: 'DSA41.CharacterLabels.Item'
}) })
Actors.registerSheet('dsa41.group', GroupSheet, {
types: ["group"],
makeDefault: true,
label : 'DSA41.GroupLabel.Item'
})
// Register sheet application classes // Register sheet application classes
Items.registerSheet('dsa41.skill', SkillSheet, { Items.registerSheet('dsa41.skill', SkillSheet, {
@ -69,11 +77,16 @@ Hooks.once("init", () => {
label: 'DSA41.VornachteilLabels.Item' label: 'DSA41.VornachteilLabels.Item'
}) })
return preloadHandlebarsTemplates(); return preloadHandlebarsTemplates();
}) })
Hooks.on('dropActorSheetData', (actor, sheet, data) => { Hooks.on('dropActorSheetData', (actor, sheet, data) => {
return CharacterSheet.onDroppedData(actor, sheet, data); if (actor.type === "character") {
return CharacterSheet.onDroppedData(actor, sheet, data);
} else {
return GroupSheet.onDroppedData(actor, sheet, data);
}
} ) } )
Hooks.once("ready", async function() { Hooks.once("ready", async function() {

View File

@ -0,0 +1,20 @@
const {
SchemaField, NumberField, StringField, EmbeddedDocumentField, DocumentIdField, ArrayField, ForeignDocumentField
} = foundry.data.fields;
export class GroupDataModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
return {
name: new StringField(),
inventory: new SchemaField({
quantity: new NumberField(),
item: new DocumentIdField(Item)
}),
characters: new ArrayField(
new DocumentIdField(Actor)
)
}
}
}

View File

@ -0,0 +1,12 @@
export class Group extends Actor {
/**
* @override
*/
prepareData() {
console.log("prepare", this);
super.prepareData();
}
}

View File

@ -0,0 +1,90 @@
export class GroupSheet extends ActorSheet {
/**@override */
static get defaultOptions() {
return foundry.utils.mergeObject(super.defaultOptions, {
classes: ['dsa41', 'sheet', 'actor', 'group'],
width: 520,
height: 480,
tabs: [
{
navSelector: '.sheet-tabs',
contentSelector: '.sheet-body',
initial: 'description',
},
],
});
}
/** @override */
async getData() {
const context = super.getData();
// Use a safe clone of the actor data for further operations.
const skillData = context.data;
// Add the actor's data to context.data for easier access, as well as flags.
context.system = skillData.system;
context.flags = skillData.flags;
context.characters = [];
for (const characterId of skillData.system.characters) {
const character = await game.actors.get(characterId)
context.characters.push(
{
img: character.img,
name: character.name,
attributes: [
{ name: "MU", value: character.system.attribute.mu.aktuell },
{ name: "KL", value: character.system.attribute.kl.aktuell },
{ name: "IN", value: character.system.attribute.in.aktuell },
{ name: "CH", value: character.system.attribute.ch.aktuell },
{ name: "FF", value: character.system.attribute.ff.aktuell },
{ name: "GE", value: character.system.attribute.ge.aktuell },
{ name: "KO", value: character.system.attribute.ko.aktuell },
{ name: "KK", value: character.system.attribute.kk.aktuell },
],
advantages: character.items.filter( (i) => i.type === "Advantage").map( (advantage) => {
return {
name: advantage.name,
id: advantage._id,
value: advantage.system.value,
}
}),
skills: character.items.filter( (i) => i.type === "Skill").map( (skill) => {
return {
name: skill.name,
taw: skill.system.taw,
id: skill._id
}
}),
isOwner: character.isOwner
}
)
}
console.log(context.characters)
return await context;
}
/** @override */
get template() {
return `systems/DSA_4-1/templates/actor/group-sheet.hbs`;
}
static async onDroppedData(group, sheet, data) {
if (data.type === "Actor") {
const uuid = await foundry.utils.parseUuid(data.uuid);
const character = await (game.actors.get(uuid.id))
await group.update({
system: {
characters: [
...group.system.characters,
character._id
]
}
})
ui.notifications.info(`${character.name} ist der Heldengruppe ${group.name} beigetreten`)
}
}
}

View File

@ -0,0 +1,160 @@
.dsa41.sheet.actor.group {
.window-content {
display: unset;
position: relative;
}
.sheet-header {
.sheet-name {
font-size: 24pt;
height: 48px;
}
}
.sheet-tabs {
position: absolute;
left: 0;
right: 0;
top: 27px;
height: 32px;
}
.sheet-body {
position: absolute;
top: 112px;
left: 2px;
bottom: 2px;
right: 2px;
div.tab {
height: 100%;
position: relative;
}
}
.characters-overview {
display: inline-flex;
overflow-x: auto;
height: 100%;
width: 100%;
.character {
width: 192px;
position: relative;
.header {
position: relative;
height: 80px;
overflow: hidden;
left: 0;
right: 0;
img {
position: absolute;
top: 0;
height: 80px;
width: 100%;
left: 0;
right: 0;
&::before {
}
}
span.name {
position: absolute;
bottom: 0;
left: 0;
right: 0;
text-align: center;
background-color: rgba(0, 0, 0, 0.5);
color: white;
}
}
.mini-attributes {
display: grid;
height: 24px;
grid-template-columns: repeat(8, 1fr);
.mini-attribute {
border-left: 1px solid black;
position: relative;
width: 24px;
&:first-of-type {
border-left: 0;
}
.value {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
line-height: 100%;
vertical-align: middle;
text-align: center;
display: block;
}
.name {
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 14px;
text-align: center;
display: block;
}
}
}
.fixedElements {
position: absolute;
overflow: scroll;
top: 102px;
bottom: 20px;
left: 0;
right: 0;
.inline-list {
list-style: none;
padding: 0;
display: block;
.mini-skill, .mini-advantage {
display: inline-block;
padding: 0 4px;
&:hover {
text-shadow: 0 0 10px rgb(255 0 0);
}
}
}
}
.owneroptions {
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 36px;
}
}
}
}

View File

@ -2,13 +2,14 @@
@use "./colours"; @use "./colours";
@use "./assets"; @use "./assets";
.dsa41.sheet.actor.character { .dsa41.sheet.actor {
nav.sheet-tabs.tabs { nav.sheet-tabs.tabs {
position: relative; position: relative;
display: flow; display: flow;
border-top: unset; border-top: unset;
border-bottom: unset;
a.item[data-tab] { a.item[data-tab] {
@ -43,4 +44,4 @@
} }
} }

View File

@ -3,4 +3,6 @@
@use "_attributes"; @use "_attributes";
@use "_sidebar-elements"; @use "_sidebar-elements";
@use "_character-sheet"; @use "_character-sheet";
@use "_group-sheet";
@use "_tabs"; @use "_tabs";

View File

@ -81,6 +81,9 @@
], ],
"documentTypes": { "documentTypes": {
"Actor": { "Actor": {
"group": {
},
"character": { "character": {
"numberFields": [ "numberFields": [
"groesse", "alter", "gewicht" "groesse", "alter", "gewicht"
@ -193,4 +196,4 @@
"url": "https://git.macniel.online/macniel/foundry-dsa41-game", "url": "https://git.macniel.online/macniel/foundry-dsa41-game",
"manifest": "https://git.macniel.online/macniel/foundry-dsa41-game/releases/download/{{VERSION}}/system.json", "manifest": "https://git.macniel.online/macniel/foundry-dsa41-game/releases/download/{{VERSION}}/system.json",
"download": "https://git.macniel.online/macniel/foundry-dsa41-game/releases/download/{{VERSION}}/release.zip" "download": "https://git.macniel.online/macniel/foundry-dsa41-game/releases/download/{{VERSION}}/release.zip"
} }

View File

@ -0,0 +1,55 @@
<form class="{{cssClass}} {{actor.type}} flexcol" autocomplete="off">
{{!-- Sheet Header --}}
<header class="sheet-header">
<input class="sheet-name" type="text" name="actor.name" value="{{actor.name}}" />
</header>
{{!-- Sheet Tab Navigation --}}
<nav class="sheet-tabs tabs" data-group="primary">
<a class="item" data-tab="characters">Charaktere</a>
<a class="item" data-tab="inventory">Inventar</a>
</nav>
{{!-- Sheet Body --}}
<section class="sheet-body">
<div class="tab characters" data-group="primary" data-tab="characters">
<div class="characters-overview">
{{#each characters}}
<div class="character">
<div class="header">
<img class="profile-img" src="{{this.img}}" style="object-fit: cover;" title="{{this.name}}" alt="{{this.name}}"/>
<span class="name">{{this.name}}</span>
</div>
<div class="mini-attributes">
{{#each this.attributes}}
<div class="mini-attribute">
<span class="value">{{this.value}}</span>
<span class="name">{{this.name}}</span>
</div>
{{/each}}
</div>
<div class="fixedElements">
<ul class="inline-list">
{{#each skills}}<li class="mini-skill clickable" data-id="{{this.id}}">{{this.name}}: {{this.taw}}</li>{{/each}}
</ul>
<ul class="inline-list">
{{#each advantages}}<li class="mini-advantage clickable" data-id="{{this.id}}">{{this.name}} {{#if this.value}}[{{this.value}}]{{/if}}</li>{{/each}}
</ul>
</div>
{{#if this.isOwner}}
<div class="owneroptions">
<button>Leave Group</button>
</div>
{{/if}}
</div>
{{/each}}
</div>
</div>
<div class="tab inventory" data-group="primary" data-tab="inventory">
</div>
</section>
</form>