From 3976a5460e0f7cf618dec209c8c0791f37883f33 Mon Sep 17 00:00:00 2001 From: Lurkars Date: Sun, 30 Jul 2023 21:59:27 +0200 Subject: [PATCH] address #160, #315, #346, small other improvements and fixes --- package-lock.json | 4 +- package.json | 2 +- src/app/app.component.ts | 6 + .../game/businesslogic/CharacterManager.ts | 10 +- src/app/game/businesslogic/EntityManager.ts | 45 +++++- src/app/game/businesslogic/RoundManager.ts | 10 +- src/app/game/businesslogic/SettingsManager.ts | 5 + src/app/game/businesslogic/StateManager.ts | 1 + src/app/game/model/Settings.ts | 1 + .../character/cards/initiative-dialog.ts | 8 +- src/app/ui/figures/character/character.html | 10 +- src/app/ui/figures/character/character.scss | 43 ++++- src/app/ui/figures/character/character.ts | 15 +- .../figures/character/fullview/fullview.html | 4 +- .../character/sheet/character-sheet.ts | 10 ++ src/app/ui/figures/conditions/conditions.ts | 29 +--- .../entities-menu/entities-menu-dialog.html | 52 ++++-- .../entities-menu/entities-menu-dialog.scss | 70 +++++++-- .../entities-menu/entities-menu-dialog.ts | 148 +++++++++++++----- .../figures/entity-menu/entity-menu-dialog.ts | 5 +- src/app/ui/header/menu/settings/settings.html | 13 ++ src/app/ui/header/menu/settings/settings.ts | 10 ++ src/assets/locales/de.json | 4 + src/assets/locales/en.json | 4 + src/styles.scss | 11 +- 25 files changed, 392 insertions(+), 128 deletions(-) diff --git a/package-lock.json b/package-lock.json index c5b4ff5f6..75352c1ac 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "gloomhavensecretariat", - "version": "0.70.3", + "version": "0.70.4", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "gloomhavensecretariat", - "version": "0.70.3", + "version": "0.70.4", "license": "AGPL3", "dependencies": { "@angular/animations": "^16.1.7", diff --git a/package.json b/package.json index 756337eb7..977f3dcb2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gloomhavensecretariat", - "version": "0.70.3", + "version": "0.70.4", "license": "AGPL3", "description": "Gloomhaven Secretariat is a Gloomhaven Companion app.", "homepage": "https://gloomhaven-secretariat.de", diff --git a/src/app/app.component.ts b/src/app/app.component.ts index cb51646da..8691b4dea 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -40,6 +40,12 @@ export class AppComponent implements OnInit { document.body.classList.remove('modern'); this.meta.updateTag({ name: 'theme-color', content: '#936658' }); } + + if (settingsManager.settings.portraitMode) { + document.body.classList.add('portrait-mode'); + } else { + document.body.classList.remove('portrait-mode'); + } } applyAnimations() { diff --git a/src/app/game/businesslogic/CharacterManager.ts b/src/app/game/businesslogic/CharacterManager.ts index e2ea79dfb..b96c9e43d 100644 --- a/src/app/game/businesslogic/CharacterManager.ts +++ b/src/app/game/businesslogic/CharacterManager.ts @@ -254,18 +254,20 @@ export class CharacterManager { character.level = level; - if (character.health == character.maxHealth) { - character.health = character.stat.health; - } + const adjustHealth = character.health == character.maxHealth; character.maxHealth = character.stat.health; + if (character.name == 'shackles' && character.edition == 'fh' && character.progress.perks[11] == 2) { + character.maxHealth += 5; + } + if (character.progress.equippedItems.find((identifier) => identifier.edition == 'fh' && identifier.name == '3')) { character.maxHealth += 1; character.health += 1; } - if (character.health > character.maxHealth) { + if (character.health > character.maxHealth || adjustHealth) { character.health = character.maxHealth; } diff --git a/src/app/game/businesslogic/EntityManager.ts b/src/app/game/businesslogic/EntityManager.ts index 83c93cd06..26fe52d0c 100644 --- a/src/app/game/businesslogic/EntityManager.ts +++ b/src/app/game/businesslogic/EntityManager.ts @@ -181,22 +181,51 @@ export class EntityManager { return entity.entityConditions.filter((value) => (!value.expired || expiredIndicator && value.types.indexOf(ConditionType.expiredIndicator) != -1) && (hidden || value.types.indexOf(ConditionType.hidden) == -1)); } - isImmune(monster: Monster, entity: MonsterEntity, conditionName: ConditionName): boolean { - const stat = monster.stats.find((monsterStat) => monsterStat.level == entity.level && monsterStat.type == entity.type); + isImmune(entity: Entity, figure: Figure, conditionName: ConditionName): boolean { + let immune: boolean = false; + if (figure instanceof Monster && entity instanceof MonsterEntity) { + const stat = figure.stats.find((monsterStat) => monsterStat.level == entity.level && monsterStat.type == entity.type); + immune = stat != undefined && stat.immunities != undefined && stat.immunities.indexOf(conditionName as string) != -1; + } else if (figure instanceof Character) { + let immunities: ConditionName[] = []; + if (figure.progress.equippedItems.find((identifier) => identifier.edition == 'gh' && identifier.name == '38')) { + immunities.push(ConditionName.stun, ConditionName.muddle); + } + if (figure.progress.equippedItems.find((identifier) => identifier.edition == 'gh' && identifier.name == '52')) { + immunities.push(ConditionName.poison, ConditionName.wound); + } + if (figure.progress.equippedItems.find((identifier) => identifier.edition == 'gh' && identifier.name == '103')) { + immunities.push(ConditionName.poison, ConditionName.wound); + } + if (figure.progress.equippedItems.find((identifier) => identifier.edition == 'cs' && identifier.name == '57')) { + immunities.push(ConditionName.muddle); + } + if (figure.progress.equippedItems.find((identifier) => identifier.edition == 'fh' && identifier.name == '138')) { + immunities.push(ConditionName.disarm, ConditionName.stun, ConditionName.muddle); + } + + if (figure.name == 'blinkblade' && figure.edition == 'fh' && figure.progress.perks[10]) { + immunities.push(ConditionName.immobilize); + } else if (figure.name == 'coral' && figure.edition == 'fh' && figure.progress.perks[7]) { + immunities.push(ConditionName.impair); + } else if (figure.name == 'prism' && figure.edition == 'fh' && figure.progress.perks[9]) { + immunities.push(ConditionName.wound); + } - let immune = stat != undefined && stat.immunities != undefined && stat.immunities.indexOf(conditionName as string) != -1; + immune = immunities.indexOf(conditionName) != -1; + } if (!immune) { if (conditionName == ConditionName.wound_x) { - return this.isImmune(monster, entity, ConditionName.wound); + return this.isImmune(entity, figure, ConditionName.wound); } else if (conditionName == ConditionName.poison_x) { - return this.isImmune(monster, entity, ConditionName.poison); + return this.isImmune(entity, figure, ConditionName.poison); } else if (conditionName == ConditionName.rupture) { - return this.isImmune(monster, entity, ConditionName.wound); + return this.isImmune(entity, figure, ConditionName.wound); } else if (conditionName == ConditionName.infect) { - return this.isImmune(monster, entity, ConditionName.poison); + return this.isImmune(entity, figure, ConditionName.poison); } else if (conditionName == ConditionName.chill) { - return this.isImmune(monster, entity, ConditionName.immobilize) || this.isImmune(monster, entity, ConditionName.muddle); + return this.isImmune(entity, figure, ConditionName.immobilize) || this.isImmune(entity, figure, ConditionName.muddle); } } diff --git a/src/app/game/businesslogic/RoundManager.ts b/src/app/game/businesslogic/RoundManager.ts index cf2d6eab7..741d57102 100644 --- a/src/app/game/businesslogic/RoundManager.ts +++ b/src/app/game/businesslogic/RoundManager.ts @@ -310,8 +310,14 @@ export class RoundManager { if (figure instanceof Character && settingsManager.settings.applyLongRest && figure.longRest && (skipSummons || !figure.summons.some((summon) => summon.active))) { if (figure.health < figure.maxHealth || figure.entityConditions.find((entityCondition) => !entityCondition.expired && entityCondition.types.indexOf(ConditionType.clearHeal) != -1 && !entityCondition.permanent)) { - figure.health += 2; - gameManager.entityManager.addCondition(figure, new Condition(ConditionName.heal, 2), figure.active || false, figure.off || false); + let heal = 2; + + if (figure.name == 'lightning' && figure.edition == 'fh-crossover' && figure.progress.perks[9]) { + heal += 1; + } + + figure.health += heal; + gameManager.entityManager.addCondition(figure, new Condition(ConditionName.heal, heal), figure.active || false, figure.off || false); gameManager.entityManager.applyCondition(figure, ConditionName.heal, true); } } diff --git a/src/app/game/businesslogic/SettingsManager.ts b/src/app/game/businesslogic/SettingsManager.ts index 5e837ccad..5f294dc80 100644 --- a/src/app/game/businesslogic/SettingsManager.ts +++ b/src/app/game/businesslogic/SettingsManager.ts @@ -474,6 +474,11 @@ export class SettingsManager { this.storeSettings(); } + setPortraitMode(portraitMode: boolean) { + this.settings.portraitMode = portraitMode; + this.storeSettings(); + } + setPressDoubleClick(pressDoubleClick: boolean) { this.settings.pressDoubleClick = pressDoubleClick; this.storeSettings(); diff --git a/src/app/game/businesslogic/StateManager.ts b/src/app/game/businesslogic/StateManager.ts index f2f719b2f..09bd50c84 100644 --- a/src/app/game/businesslogic/StateManager.ts +++ b/src/app/game/businesslogic/StateManager.ts @@ -271,6 +271,7 @@ export class StateManager { settings.fhStyle = settingsManager.settings.fhStyle; settings.fontsize = settingsManager.settings.fontsize; settings.fullscreen = settingsManager.settings.fullscreen; + settings.portraitMode = settingsManager.settings.portraitMode; settings.pressDoubleClick = settingsManager.settings.pressDoubleClick; settings.serverAutoconnect = settingsManager.settings.serverAutoconnect; settings.serverPassword = settingsManager.settings.serverPassword; diff --git a/src/app/game/model/Settings.ts b/src/app/game/model/Settings.ts index 903610514..0377c05db 100644 --- a/src/app/game/model/Settings.ts +++ b/src/app/game/model/Settings.ts @@ -67,6 +67,7 @@ export class Settings { locale: string = "en"; lootDeck: boolean = true; maxUndo: number = 100; + portraitMode: boolean = true; monsters: boolean = true; moveElements: boolean = true; partySheet: boolean = true; diff --git a/src/app/ui/figures/character/cards/initiative-dialog.ts b/src/app/ui/figures/character/cards/initiative-dialog.ts index 0dd976682..c129b47c5 100644 --- a/src/app/ui/figures/character/cards/initiative-dialog.ts +++ b/src/app/ui/figures/character/cards/initiative-dialog.ts @@ -74,13 +74,6 @@ export class CharacterInitiativeDialogComponent { setInitiative(initiative: number) { if (((gameManager.game.state == GameState.draw || !settingsManager.settings.initiativeRequired) && initiative >= 0 || initiative > 0) && initiative < 100 && initiative != this.figure.initiative) { this.figure.initiative = initiative; - if (this.character) { - if (initiative == 99 && !this.character.longRest) { - this.character.longRest = true; - } else { - this.character.longRest = false; - } - } if (this.character) { this.character.initiativeVisible = true; } @@ -99,6 +92,7 @@ export class CharacterInitiativeDialogComponent { this.character.longRest = true; } else { this.setInitiative(99); + this.character.longRest = true; if (gameManager.game.state == GameState.next) { gameManager.sortFigures(this.character); } diff --git a/src/app/ui/figures/character/character.html b/src/app/ui/figures/character/character.html index 9b7f68b82..05ab4dd5c 100644 --- a/src/app/ui/figures/character/character.html +++ b/src/app/ui/figures/character/character.html @@ -1,10 +1,12 @@
+ [ngClass]="{'empty' : summonCount == 0, 'off' : character.off || character.exhausted || character.health <= 0 }"> - - + + + -
+
diff --git a/src/app/ui/figures/character/character.scss b/src/app/ui/figures/character/character.scss index 4a32465b1..fb29c57f4 100644 --- a/src/app/ui/figures/character/character.scss +++ b/src/app/ui/figures/character/character.scss @@ -115,18 +115,32 @@ height: 100%; } - .icon { + .entities-menu { + cursor: pointer; + position: relative; display: block; - width: calc(var(--ghs-unit) * 6); + width: auto; height: calc(var(--ghs-unit) * 6); margin-right: calc(var(--ghs-unit) * 1); - img { - width: 100%; - height: auto; + img.icon { + height: 100%; + width: auto; filter: var(--ghs-filter-shadow); } + img.menu { + position: absolute; + top: 50%; + left: calc(var(--ghs-unit) * -4); + transform: translateY(-50%); + opacity: 0.5; + width: calc(var(--ghs-unit) * 3.7 * var(--ghs-text-factor)); + height: auto; + filter: var(--ghs-filter-darkgray); + opacity: 0.5; + } + &:not(.empty) { opacity: 1; transform: translate(0%, 0%); @@ -137,6 +151,25 @@ max-width: 0; transform: translate(0%, 100%); } + + &.disabled { + cursor: initial; + pointer-events: none; + + img.menu { + display: none; + } + } + + &:hover { + img.icon { + opacity: 0.5; + } + + img.menu { + opacity: 1; + } + } } .summons { diff --git a/src/app/ui/figures/character/character.ts b/src/app/ui/figures/character/character.ts index 3517f238b..96fc01fae 100644 --- a/src/app/ui/figures/character/character.ts +++ b/src/app/ui/figures/character/character.ts @@ -21,6 +21,7 @@ import { Subscription } from 'rxjs'; import { CharacterBattleGoalsDialog } from '../battlegoal/dialog/battlegoal-dialog'; import { ItemsCharacterDialogComponent } from '../items/character/items-character-dialog'; import { ItemsDialogComponent } from '../items/dialog/items-dialog'; +import { EntitiesMenuDialogComponent } from '../entities-menu/entities-menu-dialog'; @Component({ selector: 'ghs-character', @@ -51,7 +52,7 @@ export class CharacterComponent implements OnInit, OnDestroy { maxHp: number = 0; token: number = 0; - emptySummons: boolean = true; + summonCount: number = 0; activeConditions: EntityCondition[] = []; constructor(private dialog: Dialog, private overlay: Overlay) { } @@ -70,7 +71,7 @@ export class CharacterComponent implements OnInit, OnDestroy { } update(): void { - this.emptySummons = this.character.summons.length == 0 || this.character.summons.every((summon) => !gameManager.entityManager.isAlive(summon)); + this.summonCount = this.character.summons.filter((summon) => gameManager.entityManager.isAlive(summon)).length; this.activeConditions = gameManager.entityManager.activeConditions(this.character); } @@ -288,6 +289,16 @@ export class CharacterComponent implements OnInit, OnDestroy { // } } + openEntitiesMenu(event: any) { + this.dialog.open(EntitiesMenuDialogComponent, { + panelClass: 'dialog', + data: { + character: this.character + }, + positionStrategy: this.overlay.position().flexibleConnectedTo(event.target).withPositions(ghsDefaultDialogPositions()) + }); + } + openSummonDialog(event: any): void { this.dialog.open(CharacterSummonDialog, { panelClass: 'dialog', diff --git a/src/app/ui/figures/character/fullview/fullview.html b/src/app/ui/figures/character/fullview/fullview.html index 24e2ed4a9..2725edfcb 100644 --- a/src/app/ui/figures/character/fullview/fullview.html +++ b/src/app/ui/figures/character/fullview/fullview.html @@ -1,8 +1,8 @@
+ [ngClass]="{'empty' : summonCount == 0, 'off' : character.off || character.exhausted || character.health <= 0 }"> - +
diff --git a/src/app/ui/figures/character/sheet/character-sheet.ts b/src/app/ui/figures/character/sheet/character-sheet.ts index bd0da7d5e..f7cc6dace 100644 --- a/src/app/ui/figures/character/sheet/character-sheet.ts +++ b/src/app/ui/figures/character/sheet/character-sheet.ts @@ -347,6 +347,16 @@ export class CharacterSheetComponent implements OnInit, AfterViewInit { } this.character.mergeAttackModifierDeck(gameManager.attackModifierManager.buildCharacterAttackModifierDeck(this.character)); gameManager.attackModifierManager.shuffleModifiers(this.character.attackModifierDeck); + + if (this.character.name == 'shackles' && this.character.edition == 'fh' && index == 11) { + if (this.character.progress.perks[index] == 2) { + this.character.maxHealth += 5; + } else { + this.character.maxHealth -= 5; + } + this.character.health = this.character.maxHealth; + } + gameManager.stateManager.after(); } } diff --git a/src/app/ui/figures/conditions/conditions.ts b/src/app/ui/figures/conditions/conditions.ts index 79f60e5c1..784e826a0 100644 --- a/src/app/ui/figures/conditions/conditions.ts +++ b/src/app/ui/figures/conditions/conditions.ts @@ -124,33 +124,14 @@ export class ConditionsComponent implements OnInit { } isImmune(conditionName: ConditionName): boolean { - - if (this.figure instanceof Character) { - let immunities: ConditionName[] = []; - if (this.figure.progress.equippedItems.find((identifier) => identifier.edition == 'gh' && identifier.name == '38')) { - immunities.push(ConditionName.stun, ConditionName.muddle); - } - if (this.figure.progress.equippedItems.find((identifier) => identifier.edition == 'gh' && identifier.name == '52')) { - immunities.push(ConditionName.poison, ConditionName.wound); - } - if (this.figure.progress.equippedItems.find((identifier) => identifier.edition == 'gh' && identifier.name == '103')) { - immunities.push(ConditionName.poison, ConditionName.wound); - } - if (this.figure.progress.equippedItems.find((identifier) => identifier.edition == 'cs' && identifier.name == '57')) { - immunities.push(ConditionName.muddle); - } - if (this.figure.progress.equippedItems.find((identifier) => identifier.edition == 'fh' && identifier.name == '138')) { - immunities.push(ConditionName.disarm, ConditionName.stun, ConditionName.muddle); - } - - return immunities.indexOf(conditionName) != -1; - } - if (this.figure instanceof Monster) { if (!(this.entity instanceof MonsterEntity)) { - return this.entities.every((entity) => this.figure instanceof Monster && entity instanceof MonsterEntity && gameManager.entityManager.isImmune(this.figure, entity, conditionName)); + return this.entities.every((entity) => this.figure instanceof Monster && entity instanceof MonsterEntity && gameManager.entityManager.isImmune(entity, this.figure, conditionName)); + } else { + return gameManager.entityManager.isImmune(this.entity, this.figure, conditionName); } - return gameManager.entityManager.isImmune(this.figure, this.entity, conditionName); + } else if (this.figure instanceof Character && this.entity instanceof Character) { + return gameManager.entityManager.isImmune(this.entity, this.figure, conditionName); } return false; diff --git a/src/app/ui/figures/entities-menu/entities-menu-dialog.html b/src/app/ui/figures/entities-menu/entities-menu-dialog.html index a9cd55940..ae2152861 100644 --- a/src/app/ui/figures/entities-menu/entities-menu-dialog.html +++ b/src/app/ui/figures/entities-menu/entities-menu-dialog.html @@ -1,17 +1,33 @@
-
- -   -   -   +
+ +   +   +  
+ + + {{gameManager.characterManager.characterName(character,true)}} + +
-
{{entity.number}}
+ +
{{entity.number}}
+
+ + + + - + {{gameManager.toSummon(entity).number}} + +
+
@@ -32,8 +48,11 @@
- + + +
@@ -41,9 +60,20 @@ + + + + + + {{maxHealth | ghsValueSign}} + + + +
- + diff --git a/src/app/ui/figures/entities-menu/entities-menu-dialog.scss b/src/app/ui/figures/entities-menu/entities-menu-dialog.scss index 9993788b3..1459cf811 100644 --- a/src/app/ui/figures/entities-menu/entities-menu-dialog.scss +++ b/src/app/ui/figures/entities-menu/entities-menu-dialog.scss @@ -24,19 +24,11 @@ height: calc(var(--ghs-unit) * 4.5 * var(--ghs-dialog-factor)); width: auto; } - - .character-icon { - cursor: pointer; - - &:hover { - opacity: 0.4; - } - } } .entities { - + display: flex; justify-content: center; align-items: center; @@ -81,6 +73,52 @@ opacity: 0.7; border-color: var(--ghs-color-gray); } + + .summon-image { + position: relative; + width: calc(var(--ghs-unit) * 4); + height: calc(var(--ghs-unit) * 4); + transition: top 500ms ease-out, left 500ms ease-out; + + &.new::before { + content: " "; + display: block; + position: absolute; + width: calc(var(--ghs-unit) * 4); + height: calc(var(--ghs-unit) * 4); + background-image: url('~/src/assets/images/summons/minus.svg'); + background-size: cover; + z-index: 2; + } + + img { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 1; + } + + .summon-number { + position: absolute; + display: flex; + justify-content: center; + align-items: center; + top: 0; + left: calc(var(--ghs-unit) * -0.1); + height: calc(var(--ghs-unit) * 4); + width: calc(var(--ghs-unit) * 2); + font-family: var(--ghs-font-title); + font-size: calc(var(--ghs-unit) * 2.5); + color: var(--ghs-color-white); + background-color: var(--ghs-color-darkgray); + border-top-left-radius: calc(var(--ghs-unit) * 4); + border-bottom-left-radius: calc(var(--ghs-unit) * 4); + z-index: 3; + opacity: 0.9; + } + } } } @@ -88,6 +126,20 @@ display: grid; grid-template-columns: repeat(3, calc(var(--ghs-unit) * 7 * var(--ghs-dialog-factor))); align-content: space-between; + + .max-health-container { + position: relative; + display: flex; + align-items: center; + justify-content: space-evenly; + grid-column: 2 span; + width: calc(var(--ghs-unit) * 14 * var(--ghs-dialog-factor)); + + img { + height: calc(var(--ghs-unit) * 3 * var(--ghs-dialog-factor)); + width: auto; + } + } } .ghs-svg { diff --git a/src/app/ui/figures/entities-menu/entities-menu-dialog.ts b/src/app/ui/figures/entities-menu/entities-menu-dialog.ts index f97836b1a..b8be63a1e 100644 --- a/src/app/ui/figures/entities-menu/entities-menu-dialog.ts +++ b/src/app/ui/figures/entities-menu/entities-menu-dialog.ts @@ -9,6 +9,8 @@ import { MonsterEntity } from "src/app/game/model/MonsterEntity"; import { MonsterType } from "src/app/game/model/data/MonsterType"; import { ghsValueSign } from "../../helper/Static"; import { EntityValueFunction } from "src/app/game/model/Entity"; +import { Summon, SummonState } from "src/app/game/model/Summon"; +import { Character } from "src/app/game/model/Character"; @Component({ selector: 'ghs-entities-menu-dialog', @@ -21,16 +23,28 @@ export class EntitiesMenuDialogComponent { settingsManager: SettingsManager = settingsManager; health: number = 0; + maxHealth: number = 0; ConditionName = ConditionName; ConditionType = ConditionType; MonsterType = MonsterType; - entities: MonsterEntity[]; - allEntities: MonsterEntity[]; + entities: (MonsterEntity | Summon)[]; + allEntities: (MonsterEntity | Summon)[] = []; entityConditions: EntityCondition[] = []; + monster: Monster | undefined; + character: Character | undefined; - constructor(@Inject(DIALOG_DATA) public data: { monster: Monster, type: MonsterType | undefined }, private dialogRef: DialogRef) { - this.allEntities = data.monster.entities.filter((entity) => !data.type || entity.type == data.type); + SummonState = SummonState; + EntityValueFunction = EntityValueFunction; + + constructor(@Inject(DIALOG_DATA) public data: { monster: Monster, character: Character, type: MonsterType | undefined }, private dialogRef: DialogRef) { + if (this.data.monster) { + this.monster = this.data.monster; + this.allEntities = this.monster.entities.filter((entity) => !data.type || entity.type == data.type); + } else if (this.data.character) { + this.character = this.data.character; + this.allEntities = this.character.summons; + } this.dialogRef.closed.subscribe({ next: (forced) => { if (!forced) { @@ -56,7 +70,7 @@ export class EntitiesMenuDialogComponent { }) } - toggleEntity(entity: MonsterEntity) { + toggleEntity(entity: MonsterEntity | Summon) { if (this.entities.indexOf(entity) == -1) { this.entities.push(entity); } else { @@ -69,35 +83,45 @@ export class EntitiesMenuDialogComponent { this.health += value; } + changeMaxHealth(value: number) { + this.maxHealth += value; + } + + toggleType() { - const normalStat = this.data.monster.stats.find((stat) => { - return stat.level == this.data.monster.level && stat.type == MonsterType.normal; - }); - const eliteStat = this.data.monster.stats.find((stat) => { - return stat.level == this.data.monster.level && stat.type == MonsterType.elite; - }); - if (normalStat && eliteStat) { - gameManager.stateManager.before("toggleTypeAll", "data.monster." + this.data.monster.name); - this.entities.forEach((entity) => { - if (gameManager.entityManager.isAlive(entity)) { - entity.type = entity.type == MonsterType.elite ? MonsterType.normal : MonsterType.elite; - entity.maxHealth = EntityValueFunction(entity.type == MonsterType.normal ? normalStat.health : eliteStat.health, this.data.monster.level) - if (entity.health > entity.maxHealth) { - entity.health = entity.maxHealth; - } else if (entity.health < entity.maxHealth && entity.health == EntityValueFunction(entity.type == MonsterType.normal ? eliteStat.health : normalStat.health, this.data.monster.level)) { - entity.health = entity.maxHealth; - } - } + if (this.monster) { + const normalStat = this.monster.stats.find((stat) => { + return this.monster && stat.level == this.monster.level && stat.type == MonsterType.normal; }); - gameManager.stateManager.after(); - } else { - console.warn("Missing stats!", this.data.monster); + const eliteStat = this.monster.stats.find((stat) => { + return this.monster && stat.level == this.monster.level && stat.type == MonsterType.elite; + }); + if (normalStat && eliteStat) { + gameManager.stateManager.before("toggleTypeAll", "monster." + this.monster.name); + this.entities.forEach((entity) => { + if (this.monster && gameManager.entityManager.isAlive(entity) && entity instanceof MonsterEntity) { + entity.type = entity.type == MonsterType.elite ? MonsterType.normal : MonsterType.elite; + entity.maxHealth = EntityValueFunction(entity.type == MonsterType.normal ? normalStat.health : eliteStat.health, this.monster.level) + if (entity.health > entity.maxHealth) { + entity.health = entity.maxHealth; + } else if (entity.health < entity.maxHealth && entity.health == EntityValueFunction(entity.type == MonsterType.normal ? eliteStat.health : normalStat.health, this.monster.level)) { + entity.health = entity.maxHealth; + } + } + }); + gameManager.stateManager.after(); + } else { + console.warn("Missing stats!", this.monster); + } } } toggleDead() { - gameManager.stateManager.before("monsterDead", "data.monster." + this.data.monster.name, this.data.type ? 'monster.' + this.data.type + ' ' : ''); - + if (this.monster) { + gameManager.stateManager.before("monsterDead", "monster." + this.monster.name, this.data.type ? 'monster.' + this.data.type + ' ' : ''); + } else if (this.character) { + gameManager.stateManager.before("summonsDead", "data." + this.character.name); + } this.entities.forEach((entity) => { entity.dead = true; }); @@ -105,13 +129,17 @@ export class EntitiesMenuDialogComponent { setTimeout(() => { this.entities.forEach((entity) => { if (gameManager.game.state == GameState.draw || entity.entityConditions.length == 0 || entity.entityConditions.every((entityCondition) => entityCondition.types.indexOf(ConditionType.turn) == -1 && entityCondition.types.indexOf(ConditionType.apply) == -1)) { - gameManager.monsterManager.removeMonsterEntity(this.data.monster, entity); + if (this.monster && entity instanceof MonsterEntity) { + gameManager.monsterManager.removeMonsterEntity(this.monster, entity); + } else if (this.character && entity instanceof Summon) { + gameManager.characterManager.removeSummon(this.character, entity); + } } }); if (this.entities.every((monsterEntity) => !gameManager.entityManager.isAlive(monsterEntity))) { - if (this.data.monster.active) { - gameManager.roundManager.toggleFigure(this.data.monster); + if (this.monster && this.monster.active) { + gameManager.roundManager.toggleFigure(this.monster); } } @@ -123,13 +151,19 @@ export class EntitiesMenuDialogComponent { close(): void { this.entityConditions.filter((entityCondition) => entityCondition.state == EntityConditionState.new || entityCondition.state == EntityConditionState.removed).forEach((entityCondition) => { - gameManager.stateManager.before(...gameManager.entityManager.undoInfos(undefined, this.data.monster, entityCondition.state == EntityConditionState.removed ? "removeCondition" : "addCondition"), "game.condition." + entityCondition.name, this.data.type ? 'monster.' + this.data.type + ' ' : ''); + if (this.monster) { + gameManager.stateManager.before(...gameManager.entityManager.undoInfos(undefined, this.monster, entityCondition.state == EntityConditionState.removed ? "removeCondition" : "addCondition"), "game.condition." + entityCondition.name, this.data.type ? 'monster.' + this.data.type + ' ' : ''); + } else if (this.character) { + gameManager.stateManager.before(...gameManager.entityManager.undoInfos(undefined, this.character, entityCondition.state == EntityConditionState.removed ? "removeConditionSummons" : "addConditionSummons"), "game.condition." + entityCondition.name); + } this.entities.forEach((entity) => { entityCondition.expired = entityCondition.state == EntityConditionState.new; if (entityCondition.state == EntityConditionState.removed) { gameManager.entityManager.removeCondition(entity, entityCondition); - } else if (!gameManager.entityManager.isImmune(this.data.monster, entity, entityCondition.name)) { - gameManager.entityManager.addCondition(entity, entityCondition, this.data.monster.active, this.data.monster.off); + } else if (this.monster && !gameManager.entityManager.isImmune(entity, this.monster, entityCondition.name)) { + gameManager.entityManager.addCondition(entity, entityCondition, this.monster.active, this.monster.off); + } else if (this.character) { + gameManager.entityManager.addCondition(entity, entityCondition, entity.active, this.character.off); } }) gameManager.stateManager.after(); @@ -137,7 +171,13 @@ export class EntitiesMenuDialogComponent { this.entityConditions.forEach((condition) => { if (this.entities.find((entity) => entity.entityConditions.find((entityCondition) => entityCondition.name == condition.name && !entityCondition.expired && entityCondition.value != condition.value))) { - gameManager.stateManager.before(...gameManager.entityManager.undoInfos(undefined, this.data.monster, "setConditionValue"), "game.condition." + condition.name, "" + condition.value, this.data.type ? 'monster.' + this.data.type + ' ' : ''); + + if (this.monster) { + gameManager.stateManager.before(...gameManager.entityManager.undoInfos(undefined, this.monster, "setConditionValue"), "game.condition." + condition.name, "" + condition.value, this.data.type ? 'monster.' + this.data.type + ' ' : ''); + } else if (this.character) { + gameManager.stateManager.before(...gameManager.entityManager.undoInfos(undefined, this.character, "setConditionValueSummons"), "game.condition." + condition.name, "" + condition.value); + } + this.entities.forEach((entity) => { const entityCondition = entity.entityConditions.find((entityCondition) => entityCondition.name == condition.name && !entityCondition.expired); if (entityCondition && entityCondition.value != condition.value) { @@ -149,8 +189,12 @@ export class EntitiesMenuDialogComponent { }) if (this.health != 0) { - gameManager.stateManager.before("changeMonsterHP", "data.monster." + this.data.monster.name, ghsValueSign(this.health), this.data.type ? 'monster.' + this.data.type + ' ' : ''); - let deadEntities: MonsterEntity[] = []; + if (this.monster) { + gameManager.stateManager.before("changeMonsterHP", "monster." + this.monster.name, ghsValueSign(this.health), this.data.type ? 'monster.' + this.data.type + ' ' : ''); + } else if (this.character) { + gameManager.stateManager.before("changeSummonsHP", "character." + this.character.name, ghsValueSign(this.health)); + } + let deadEntities: (MonsterEntity | Summon)[] = []; this.entities.forEach((entity) => { if (this.health != 0) { gameManager.entityManager.changeHealth(entity, this.health); @@ -168,13 +212,17 @@ export class EntitiesMenuDialogComponent { setTimeout(() => { deadEntities.forEach((entity) => { if (entity.dead) { - gameManager.monsterManager.removeMonsterEntity(this.data.monster, entity); + if (this.monster && entity instanceof MonsterEntity) { + gameManager.monsterManager.removeMonsterEntity(this.monster, entity); + } else if (this.character && entity instanceof Summon) { + gameManager.characterManager.removeSummon(this.character, entity); + } } }) if (this.entities.every((monsterEntity) => !gameManager.entityManager.isAlive(monsterEntity))) { - if (this.data.monster.active) { - gameManager.roundManager.toggleFigure(this.data.monster); + if (this.monster && this.monster.active) { + gameManager.roundManager.toggleFigure(this.monster); } } @@ -184,6 +232,26 @@ export class EntitiesMenuDialogComponent { gameManager.stateManager.after(); } } + + if (this.maxHealth != 0) { + if (this.monster) { + gameManager.stateManager.before("changeMonsterMaxHP", "monster." + this.monster.name, ghsValueSign(this.health), this.data.type ? 'monster.' + this.data.type + ' ' : ''); + } else if (this.character) { + gameManager.stateManager.before("changeSummonsMaxHP", "character." + this.character.name, ghsValueSign(this.health)); + } + + this.entities.forEach((entity) => { + if (entity.health == entity.maxHealth) { + entity.health += this.maxHealth; + } + entity.maxHealth += this.maxHealth; + if (entity.health > entity.maxHealth) { + entity.health = entity.maxHealth; + } + }) + + gameManager.stateManager.after(); + } } } \ No newline at end of file diff --git a/src/app/ui/figures/entity-menu/entity-menu-dialog.ts b/src/app/ui/figures/entity-menu/entity-menu-dialog.ts index b76becb9e..cbdcb6840 100644 --- a/src/app/ui/figures/entity-menu/entity-menu-dialog.ts +++ b/src/app/ui/figures/entity-menu/entity-menu-dialog.ts @@ -415,10 +415,9 @@ export class EntityMenuDialogComponent { } } - isImmune(conditionName: ConditionName): boolean { - if (this.data.figure instanceof Monster && this.data.entity instanceof MonsterEntity) { - return gameManager.entityManager.isImmune(this.data.figure, this.data.entity, conditionName); + if (this.data.entity) { + return gameManager.entityManager.isImmune(this.data.entity, this.data.figure, conditionName); } return false; } diff --git a/src/app/ui/header/menu/settings/settings.html b/src/app/ui/header/menu/settings/settings.html index 77cbf320e..38c6c1387 100644 --- a/src/app/ui/header/menu/settings/settings.html +++ b/src/app/ui/header/menu/settings/settings.html @@ -987,6 +987,19 @@
+
+
+ + + + + +
+