diff --git a/package.json b/package.json
index eb43811b9..7dcbd4a19 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "gloomhavensecretariat",
- "version": "0.102.3",
+ "version": "0.102.4",
"license": "AGPL3",
"description": "Gloomhaven Secretariat is a Gloomhaven/Frosthaven Companion app.",
"homepage": "https://gloomhaven-secretariat.de",
@@ -101,7 +101,7 @@
"ng-in-viewport": "^16.1.0",
"rxjs": "~7.8.1",
"tslib": "^2.8.0",
- "uuid": "^10.0.0",
+ "uuid": "^11.0.1",
"zone.js": "~0.14.10"
},
"devDependencies": {
@@ -114,7 +114,7 @@
"@types/jasmine": "~5.1.4",
"@types/leaflet": "^1.9.14",
"@types/uuid": "^10.0.0",
- "electron": "^32.2.0",
+ "electron": "^33.0.2",
"electron-builder": "^25.1.8",
"http-server": "^14.1.1",
"husky": "^9.1.6",
diff --git a/src/app/game/model/data/Loot.ts b/src/app/game/model/data/Loot.ts
index d4b1b1c17..506b3d292 100644
--- a/src/app/game/model/data/Loot.ts
+++ b/src/app/game/model/data/Loot.ts
@@ -22,9 +22,11 @@ export enum LootType {
special2 = "special2"
}
-export const enhancableLootTypes: LootType[] = [LootType.lumber, LootType.metal, LootType.hide, LootType.arrowvine, LootType.axenut, LootType.corpsecap, LootType.flamefruit, LootType.rockroot, LootType.snowthistle, LootType.money];
+export const resourceLootTypes: LootType[] = [LootType.lumber, LootType.metal, LootType.hide, LootType.arrowvine, LootType.axenut, LootType.corpsecap, LootType.flamefruit, LootType.rockroot, LootType.snowthistle];
-export const appliableLootTypes: LootType[] = [LootType.money, LootType.lumber, LootType.metal, LootType.hide, LootType.arrowvine, LootType.axenut, LootType.corpsecap, LootType.flamefruit, LootType.rockroot, LootType.snowthistle, LootType.special1, LootType.special2, LootType.random_item];
+export const enhancableLootTypes: LootType[] = [...resourceLootTypes, LootType.money];
+
+export const appliableLootTypes: LootType[] = [...enhancableLootTypes, LootType.special1, LootType.special2, LootType.random_item];
export function getLootClass(type: LootType): LootClass {
diff --git a/src/app/ui/figures/party/party-sheet-dialog.ts b/src/app/ui/figures/party/party-sheet-dialog.ts
index 1e93d25a3..0fd15b3a2 100644
--- a/src/app/ui/figures/party/party-sheet-dialog.ts
+++ b/src/app/ui/figures/party/party-sheet-dialog.ts
@@ -1045,7 +1045,7 @@ export class PartySheetDialogComponent implements OnInit, OnDestroy {
openResources() {
this.dialog.open(PartyResourcesDialogComponent, {
- panelClass: ['dialog-invert'],
+ panelClass: ['dialog'],
});
}
diff --git a/src/app/ui/figures/party/resources/resources.html b/src/app/ui/figures/party/resources/resources.html
index 30a02a3b1..9acc41143 100644
--- a/src/app/ui/figures/party/resources/resources.html
+++ b/src/app/ui/figures/party/resources/resources.html
@@ -3,7 +3,9 @@
+
+
\ No newline at end of file
diff --git a/src/app/ui/figures/party/resources/resources.scss b/src/app/ui/figures/party/resources/resources.scss
index b35ce76ab..cf4d3d942 100644
--- a/src/app/ui/figures/party/resources/resources.scss
+++ b/src/app/ui/figures/party/resources/resources.scss
@@ -1,6 +1,7 @@
.resources-dialog {
position: relative;
+ color: var(--ghs-color-white);
table {
border-collapse: collapse;
@@ -15,14 +16,72 @@
border-bottom: calc(var(--ghs-unit) * 0.2 * var(--ghs-dialog-factor)) solid var(--ghs-color-darkgray);
}
+ th {
+ label {
+ cursor: pointer;
+ font-size: calc(var(--ghs-unit) * 2 * var(--ghs-text-factor));
+ display: flex;
+ justify-content: flex-end;
+ align-items: center;
+ }
+ }
+
tbody tr {
+
+ td,
+ th {
+ position: relative;
+ z-index: 1;
+
+ span,
+ input {
+ position: relative;
+ z-index: 2;
+ }
+
+ input {
+ width: calc(var(--ghs-unit) * 4 * var(--ghs-dialog-factor));
+ max-width: 100%;
+ text-align: center;
+ border: none;
+ outline: none;
+ }
+ }
+
&:nth-child(odd) {
- background-color: var(--ghs-color-lightgray);
+
+ td,
+ th {
+ &::before {
+ content: ' ';
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background-color: var(--ghs-color-darkgray);
+ opacity: 0.3;
+ z-index: 0;
+ }
+ }
}
&:hover {
- background-color: var(--ghs-color-yellow);
- opacity: 0.5;
+
+ td,
+ th {
+ &::before {
+ content: ' ';
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background-color: var(--ghs-color-yellow);
+ opacity: 0.5;
+ z-index: 0;
+ }
+ }
}
}
@@ -58,6 +117,35 @@
.ghs-svg {
width: calc(var(--ghs-unit) * 3 * var(--ghs-dialog-factor));
height: auto;
+ filter: var(--ghs-filter-white)
+ }
+ }
+
+ .buttons {
+ display: flex;
+ margin-top: calc(var(--ghs-unit) * 2 * var(--ghs-dialog-factor));
+ font-family: var(--ghs-font-title);
+ font-size: calc(var(--ghs-unit) * 3 * var(--ghs-dialog-factor));
+ justify-content: space-between;
+ align-items: center;
+
+ a {
+ cursor: pointer;
+ min-width: 33%;
+ display: flex;
+ justify-content: center;
+
+ &:hover {
+ opacity: 0.6;
+ }
+ }
+
+ .cancel {
+ color: var(--ghs-color-red);
+ }
+
+ .apply {
+ color: var(--ghs-color-green);
}
}
}
\ No newline at end of file
diff --git a/src/app/ui/figures/party/resources/resources.ts b/src/app/ui/figures/party/resources/resources.ts
index bc97b8bea..da2da5c0c 100644
--- a/src/app/ui/figures/party/resources/resources.ts
+++ b/src/app/ui/figures/party/resources/resources.ts
@@ -3,7 +3,8 @@ import { DialogRef } from "@angular/cdk/dialog";
import { Component, OnInit } from "@angular/core";
import { gameManager, GameManager } from "src/app/game/businesslogic/GameManager";
import { Character } from "src/app/game/model/Character";
-import { LootType } from "src/app/game/model/data/Loot";
+import { LootType, resourceLootTypes } from "src/app/game/model/data/Loot";
+import { Party } from "src/app/game/model/Party";
import { ghsDialogClosingHelper } from "src/app/ui/helper/Static";
@Component({
@@ -15,20 +16,70 @@ export class PartyResourcesDialogComponent implements OnInit {
gameManager: GameManager = gameManager;
+ party: Party = new Party();
characters: Character[] = [];
total: Partial> = {};
- lootColumns: LootType[] = [LootType.lumber, LootType.metal, LootType.hide, LootType.arrowvine, LootType.axenut, LootType.corpsecap, LootType.flamefruit, LootType.rockroot, LootType.snowthistle];;
+ totalGold: number = 0;
+ totalXP: number = 0;
+ lootColumns: LootType[] = resourceLootTypes;
+
+ edit: boolean = false;
+ edited: boolean = false;
constructor(private dialogRef: DialogRef) { }
ngOnInit(): void {
- this.characters = gameManager.game.figures.filter((figure) => figure instanceof Character).map((figure) => figure as Character);
+ this.party = JSON.parse(JSON.stringify(gameManager.game.party));
+ this.characters = gameManager.game.figures.filter((figure) => figure instanceof Character).map((figure) => JSON.parse(JSON.stringify(figure)));
+ this.update();
+ }
+
+ update() {
this.lootColumns.forEach((type) => {
this.total[type] = (gameManager.game.party.loot[type] || 0);
if (this.characters.length > 0) {
this.total[type] = (this.total[type] || 0) + this.characters.map((character) => character.progress.loot[type] || 0).reduce((a, b) => a + b);
}
})
+ if (this.characters.length) {
+ this.totalGold = this.characters.map((character) => character.progress.gold || 0).reduce((a, b) => a + b);
+ this.totalXP = this.characters.map((character) => character.progress.experience || 0).reduce((a, b) => a + b);
+ }
+ }
+
+ changeLoot(character: Character | undefined, type: LootType, event: any) {
+ if (character) {
+ character.progress.loot[type] = +event.target.value || undefined;
+ } else {
+ this.party.loot[type] = +event.target.value || undefined;
+ }
+ this.update();
+ this.edited = true;
+ }
+
+ changeGold(character: Character, event: any) {
+ character.progress.gold = +event.target.value;
+ this.update();
+ this.edited = true;
+ }
+
+ changeXP(character: Character, event: any) {
+ character.progress.experience = +event.target.value;
+ this.update();
+ this.edited = true;
+ }
+
+ apply() {
+ gameManager.stateManager.before("applyResourceChange");
+ gameManager.game.party.loot = this.party.loot;
+ gameManager.game.figures.filter((figure) => figure instanceof Character).forEach((figure) => {
+ const character = this.characters.find((character) => character.edition == figure.edition && character.name == figure.name);
+ if (character) {
+ figure.progress = character.progress;
+ }
+ })
+ gameManager.stateManager.after();
+ ghsDialogClosingHelper(this.dialogRef);
}
close() {
diff --git a/src/app/ui/header/menu/campaign/campaign.html b/src/app/ui/header/menu/campaign/campaign.html
index 29b1fff83..5b470dd00 100644
--- a/src/app/ui/header/menu/campaign/campaign.html
+++ b/src/app/ui/header/menu/campaign/campaign.html
@@ -29,19 +29,27 @@
-
+
-
+
+
+
-
+
-
-
-
0 && settingsManager.settings.characterSheet && !gameManager.bbRules()">
diff --git a/src/app/ui/header/menu/campaign/campaign.ts b/src/app/ui/header/menu/campaign/campaign.ts
index 3164f7062..a63c67aef 100644
--- a/src/app/ui/header/menu/campaign/campaign.ts
+++ b/src/app/ui/header/menu/campaign/campaign.ts
@@ -12,6 +12,7 @@ import { ItemsDialogComponent } from "src/app/ui/figures/items/dialog/items-dial
import { PartySheetDialogComponent } from "src/app/ui/figures/party/party-sheet-dialog";
import { WorldMapComponent } from "src/app/ui/figures/party/world-map/world-map";
import { ScenarioChartDialogComponent } from "../../../figures/party/scenario-chart/scenario-chart";
+import { PartyResourcesDialogComponent } from "src/app/ui/figures/party/resources/resources";
@Component({
@@ -159,6 +160,12 @@ export class CampaignMenuComponent implements OnInit {
this.close.emit();
}
+ openResources() {
+ this.dialog.open(PartyResourcesDialogComponent, {
+ panelClass: ['dialog'],
+ });
+ this.close.emit();
+ }
addParty() {
let party = new Party();
diff --git a/src/assets/locales/de.json b/src/assets/locales/de.json
index 720064ee8..bb5342ed7 100644
--- a/src/assets/locales/de.json
+++ b/src/assets/locales/de.json
@@ -37,6 +37,7 @@
"name": "Name für Kampagne {0}",
"reset": "Kampagne zurücksetzen"
},
+ "resources": "Ressourcen Übersicht",
"sheet": "Globaler Kampagnenbogen"
},
"cancel": "Abbrechen",
@@ -1016,6 +1017,8 @@
"summer": "Sommer",
"supply": {
".": "Versorgung von Frosthaven",
+ "apply": "Änderungen anwenden",
+ "edit": "Bearbeiten",
"total": "Insgesamt"
},
"totalDefense": "Gesamte Verteidigung",
diff --git a/src/assets/locales/en.json b/src/assets/locales/en.json
index e47200b35..689d27296 100644
--- a/src/assets/locales/en.json
+++ b/src/assets/locales/en.json
@@ -37,6 +37,7 @@
"name": "Name for Campaign {0}",
"reset": "Reset Campaign"
},
+ "resources": "Resource Overview Table",
"sheet": "Global Campaign Management Sheet",
"trials": {
".": "Trials",
@@ -1233,6 +1234,8 @@
"summer": "Summer",
"supply": {
".": "Frosthaven Supply",
+ "apply": "Apply changes",
+ "edit": "Edit",
"total": "Total"
},
"totalDefense": "Total Defense",