Skip to content

Commit

Permalink
address #164, #635, #636
Browse files Browse the repository at this point in the history
  • Loading branch information
Lurkars committed Dec 16, 2024
1 parent 29979c3 commit 5cfd066
Show file tree
Hide file tree
Showing 12 changed files with 216 additions and 78 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "gloomhavensecretariat",
"version": "0.105.3",
"version": "0.105.4",
"license": "AGPL3",
"description": "Gloomhaven Secretariat is a Gloomhaven/Frosthaven Companion app.",
"homepage": "https://gloomhaven-secretariat.de",
Expand Down Expand Up @@ -128,4 +128,4 @@
"nodemon": "^3.1.7",
"typescript": "~5.5.4"
}
}
}
6 changes: 5 additions & 1 deletion src/app/game/businesslogic/CharacterManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,11 @@ export class CharacterManager {
}

removeCharacter(character: Character, retirement: boolean = false) {
this.game.figures.splice(this.game.figures.indexOf(character), 1);
const index = this.game.figures.indexOf(character);
if (index == -1) {
return;
}
this.game.figures.splice(index, 1);

if (retirement && settingsManager.settings.applyRetirement) {
gameManager.game.party.prosperity += gameManager.fhRules() ? 2 : 1;
Expand Down
20 changes: 14 additions & 6 deletions src/app/game/businesslogic/EntityManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ export class EntityManager {
entityCondition.highlight = false;

// apply Challenge #1487
if (gameManager.challengesManager.apply && gameManager.challengesManager.isActive(1487, 'fh') && entityCondition.types.indexOf(ConditionType.negative) && entityCondition.name != ConditionName.wound && entity instanceof Character && !this.isImmune(entity, entity, ConditionName.wound)) {
if (gameManager.challengesManager.apply && gameManager.challengesManager.isActive(1487, 'fh') && entityCondition.types.indexOf(ConditionType.negative) != -1 && entityCondition.name != ConditionName.wound && entity instanceof Character && !this.isImmune(entity, entity, ConditionName.wound)) {
this.addCondition(entity, figure, new Condition(ConditionName.wound));
}

Expand All @@ -395,7 +395,7 @@ export class EntityManager {
entity.entityConditions = entity.entityConditions.filter((entityCondition) => entityCondition.name != condition.name || entityCondition.permanent != permanent);

// apply Challenge #1525
if (gameManager.challengesManager.apply && gameManager.challengesManager.isActive(1525, 'fh') && condition.types.indexOf(ConditionType.negative) && entity instanceof MonsterEntity) {
if (gameManager.challengesManager.apply && gameManager.challengesManager.isActive(1525, 'fh') && condition.types.indexOf(ConditionType.negative) != -1 && entity instanceof MonsterEntity) {
this.addCondition(entity, figure, new Condition(ConditionName.strengthen));
}
}
Expand Down Expand Up @@ -547,21 +547,29 @@ export class EntityManager {
}
})

let challenge1524 = false;
let negativeCondition = false;

entity.entityConditions.forEach((entityCondition) => {
if (entityCondition.types.indexOf(ConditionType.expire) != -1) {
if (entityCondition.state == EntityConditionState.expire && !entityCondition.permanent) {
entityCondition.expired = true;
if (entityCondition.types.indexOf(ConditionType.negative) != -1) {
challenge1524 = true;
negativeCondition = true;
}
}
}
})

if (challenge1524 && figure instanceof Monster && !figure.isAlly && entity instanceof MonsterEntity && gameManager.challengesManager.isActive(1524, 'fh')) {
this.changeHealth(entity, figure, -1);
if (gameManager.challengesManager.apply && negativeCondition && figure instanceof Monster && !figure.isAlly && entity instanceof MonsterEntity) {
// apply Challenge #1524
if (gameManager.challengesManager.isActive(1524, 'fh')) {
this.changeHealth(entity, figure, -1);
}

// apply Challenge #1525
if (gameManager.challengesManager.isActive(1525, 'fh')) {
this.addCondition(entity, figure, new Condition(ConditionName.strengthen));
}
}
}

Expand Down
14 changes: 11 additions & 3 deletions src/app/ui/figures/character/sheet/character-sheet.html
Original file line number Diff line number Diff line change
Expand Up @@ -258,9 +258,12 @@
<input class="card-id" [value]="character.progress.personalQuest" type="text"
(change)="setPersonalQuest($event)">

<span *ngIf="!personalQuest" class="retired checkbox" [ngClass]="{'checked' : retired}"
(click)="toggleRetired()" [ghs-label]="'character.progress.retired'"
[ghs-label-attribute]="'title'"></span>
<label *ngIf="editable && !personalQuest" class="retire-button" ghs-pointer-input (singleClick)="retire()"
(doubleClick)="retire(true)" [ngClass]="{'disabled': !retireEnabled}">
<img class="ghs-svg" src="./assets/images/trophy.svg">
<span [ghs-label]="'character.progress.retirement'"></span>
</label>

<span *ngIf="personalQuest" class="personal-quest-name">
<span [ghs-label]="'data.personalQuest.' + personalQuest.cardId"></span>
<span *ngIf="personalQuest.altId">&nbsp;({{personalQuest.altId}})</span>
Expand Down Expand Up @@ -312,6 +315,11 @@
</div>
</div>

<label *ngIf="editable && personalQuest" class="retire-button" ghs-pointer-input (singleClick)="retire()"
(doubleClick)="retire(true)" [ngClass]="{'disabled': !retireEnabled}">
<img class="ghs-svg" src="./assets/images/trophy.svg">
<span [ghs-label]="'character.progress.retirement'"></span>
</label>
</div>
<div class="retirements" *ngIf="!gameManager.editionRules('jotl')">
<label><span [ghs-label]="'character.progress.retirements'"></span>:</label>
Expand Down
21 changes: 21 additions & 0 deletions src/app/ui/figures/character/sheet/character-sheet.scss
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,27 @@
margin-bottom: calc(var(--ghs-unit) * 1.5 * var(--ghs-dialog-factor));
border-top: calc(var(--ghs-unit) * 0.2 * var(--ghs-dialog-factor)) solid var(--ghs-color-black);
}

.retire-button {
cursor: pointer;
font-family: var(--ghs-font-normal);
font-size: calc(var(--ghs-unit) * 2.5 * var(--ghs-dialog-factor));
display: flex;
align-items: center;

&:hover {
opacity: 0.7;
}

&.disabled {
cursor: initial;
color: var(--ghs-color-gray);

.ghs-svg {
filter: var(--ghs-filter-gray);
}
}
}
}

.trial {
Expand Down
92 changes: 61 additions & 31 deletions src/app/ui/figures/character/sheet/character-sheet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { CharacterRetirementDialog } from "./retirement-dialog";


@Component({
standalone: false,
standalone: false,
selector: 'ghs-character-sheet',
templateUrl: 'character-sheet.html',
styleUrls: ['./character-sheet.scss'],
Expand All @@ -43,8 +43,8 @@ export class CharacterSheetComponent implements OnInit, AfterViewInit {
PerkType = PerkType;
LootType = LootType;
availablePerks: number = 0;
retired: boolean = false;
personalQuest: PersonalQuest | undefined;
retireEnabled: boolean = false;
hasAbilities: boolean = false;

goldTimeout: any = null;
Expand All @@ -60,7 +60,6 @@ export class CharacterSheetComponent implements OnInit, AfterViewInit {
constructor(private dialog: Dialog) { }

ngOnInit(): void {
this.retired = this.character.progress.retired;
if (this.character.identities && this.character.identities.length > 1 && settingsManager.settings.characterIdentities) {
this.titles = this.character.title.split('|');
if (this.titles.length < this.character.identities.length) {
Expand Down Expand Up @@ -116,6 +115,14 @@ export class CharacterSheetComponent implements OnInit, AfterViewInit {
}
}

if (!gameManager.game.scenario) {
if (this.personalQuest) {
this.retireEnabled = this.personalQuest.requirements.every((requirement, i) => this.character.progress.personalQuestProgress[i] >= EntityValueFunction(requirement.counter));
} else {
this.retireEnabled = true;
}
}

this.hasAbilities = gameManager.deckData(this.character, true).abilities.length > 0;

gameManager.uiChange.subscribe({
Expand All @@ -127,10 +134,16 @@ export class CharacterSheetComponent implements OnInit, AfterViewInit {
this.character.progress.perks[i] = 0;
}
}

if (this.personalQuest) {
this.retired = this.personalQuest.requirements.every((requirement, i) => this.character.progress.personalQuestProgress[i] >= EntityValueFunction(requirement.counter));

this.retireEnabled = false;
if (!gameManager.game.scenario) {
if (this.personalQuest) {
this.retireEnabled = this.personalQuest.requirements.every((requirement, i) => this.character.progress.personalQuestProgress[i] >= EntityValueFunction(requirement.counter));
} else {
this.retireEnabled = true;
}
}

}
})
}
Expand Down Expand Up @@ -167,23 +180,6 @@ export class CharacterSheetComponent implements OnInit, AfterViewInit {
gameManager.stateManager.after();
}


if (this.retired != this.character.progress.retired && this.editable) {
if (settingsManager.settings.applyRetirement && gameManager.game.party.campaignMode && this.retired) {
this.dialog.open(CharacterRetirementDialog, {
panelClass: ['dialog'],
data: this.character
});
} else {
gameManager.stateManager.before(this.character.progress.retired ? "setRetired" : "unsetRetired", gameManager.characterManager.characterName(this.character));
this.character.progress.retired = this.retired;
if (this.retired && gameManager.game.party.campaignMode) {
gameManager.game.party.retirements.push(this.character.toModel());
gameManager.characterManager.removeCharacter(this.character);
}
gameManager.stateManager.after();
}
}
}

titleChange() {
Expand All @@ -192,13 +188,6 @@ export class CharacterSheetComponent implements OnInit, AfterViewInit {
}
}

toggleRetired() {
this.retired = !this.retired;
if (this.standalone) {
this.applyValues();
}
}

ngAfterViewInit(): void {
if (this.titleInput) {
this.titleInput.nativeElement.value = this.character.title || settingsManager.getLabel('data.character.' + this.character.name.toLowerCase());
Expand Down Expand Up @@ -290,9 +279,11 @@ export class CharacterSheetComponent implements OnInit, AfterViewInit {
this.character.progress.personalQuest = event.target.value;
this.character.progress.personalQuestProgress = [];
this.personalQuest = gameManager.characterManager.personalQuestByCard(gameManager.currentEdition(), this.character.progress.personalQuest);
if (this.personalQuest && this.character.progress.personalQuest != this.personalQuest.cardId) {
if (this.personalQuest) {
this.character.progress.personalQuest = this.personalQuest.cardId;
this.retireEnabled = this.personalQuest.requirements.every((requirement, i) => this.character.progress.personalQuestProgress[i] >= EntityValueFunction(requirement.counter));
}

gameManager.stateManager.after();
}
}
Expand All @@ -318,6 +309,45 @@ export class CharacterSheetComponent implements OnInit, AfterViewInit {
gameManager.stateManager.before("setPQProgress", gameManager.characterManager.characterName(this.character), (index + 1), value);
this.character.progress.personalQuestProgress[index] = value;
gameManager.stateManager.after();

if (!gameManager.game.scenario) {
const retiredEnabled = this.retireEnabled;
if (this.personalQuest) {
this.retireEnabled = this.personalQuest.requirements.every((requirement, i) => this.character.progress.personalQuestProgress[i] >= EntityValueFunction(requirement.counter));
}

if (!retiredEnabled && this.retireEnabled && settingsManager.settings.applyRetirement && gameManager.game.party.campaignMode) {
this.retire(false, true);
}
}
}

retire(force: boolean = false, dialogOnly: boolean = false) {
if (force || this.retireEnabled) {
if (settingsManager.settings.applyRetirement && gameManager.game.party.campaignMode) {
this.dialog.open(CharacterRetirementDialog, {
panelClass: ['dialog'],
data: this.character
}).closed.subscribe({
next: (retired) => {
if (retired && this.dialogRef) {
ghsDialogClosingHelper(this.dialogRef);
}
}
});
} else if (!dialogOnly) {
if (this.dialogRef) {
ghsDialogClosingHelper(this.dialogRef);
}
gameManager.stateManager.before(this.character.progress.retired ? "setRetired" : "unsetRetired", gameManager.characterManager.characterName(this.character));
this.character.progress.retired = true;
if (gameManager.game.party.campaignMode) {
gameManager.game.party.retirements.push(this.character.toModel());
gameManager.characterManager.removeCharacter(this.character);
}
gameManager.stateManager.after();
}
}
}

personalQuestRequirementUnlocked(index: number): boolean {
Expand Down
2 changes: 1 addition & 1 deletion src/app/ui/figures/character/sheet/retirement-dialog.html
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
</div>
</div>

<div class="additional" *ngIf="gameManager.fhRules()">
<div class="additional" *ngIf="gameManager.fhRules() && hasResources">
<a (click)="moveResources()"><span [ghs-label]="'character.progress.retirement.moveSupply'"></span></a>
</div>

Expand Down
10 changes: 10 additions & 0 deletions src/app/ui/figures/character/sheet/retirement-dialog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { ScenarioData } from "src/app/game/model/data/ScenarioData";
import { ScenarioSummaryComponent } from "src/app/ui/footer/scenario/summary/scenario-summary";
import { ghsDialogClosingHelper } from "src/app/ui/helper/Static";
import { CharacterMoveResourcesDialog } from "./move-resources";
import { LootType, resourceLootTypes } from "src/app/game/model/data/Loot";

@Component({
standalone: false,
Expand All @@ -29,6 +30,8 @@ export class CharacterRetirementDialog {
additionalPQ: PersonalQuest | undefined;
additionalPQBuilding: BuildingData | undefined;

hasResources: boolean = false;

constructor(@Inject(DIALOG_DATA) public character: Character, private dialogRef: DialogRef, private dialog: Dialog) {
this.conclusion = gameManager.sectionData(this.character.edition).find((sectionData) => sectionData.retirement == this.character.name && sectionData.conclusion);
if (this.character.progress.personalQuest) {
Expand All @@ -38,6 +41,13 @@ export class CharacterRetirementDialog {
this.personalQuestBuilding = this.buildingsEnvelopeHelper(this.personalQuest.openEnvelope);
}
}

for(let key of Object.keys(this.character.progress.loot)) {
const loot : LootType = key as LootType;
if (resourceLootTypes.indexOf(loot) != -1 && this.character.progress.loot[loot]) {
this.hasResources = true;
}
}
}

openConclusion() {
Expand Down
15 changes: 15 additions & 0 deletions src/app/ui/figures/party/buildings/garden/garden.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,21 @@
<span class="value">{{resources[herb]}}</span>
</a>
</div>

<div class="sources">
<a class="source" (click)="selectSource(characters.length)"
[ngClass]="{'active': currentSource == characters.length, 'disabled' : !currentResources[characters.length]}">
<span [ghs-label]="'party.campaign.sheet.supply'"></span>:&nbsp;
<span class="value">{{currentResources[characters.length]}}</span>
</a>
<a class="source" (click)="selectSource(i)"
[ngClass]="{'active': currentSource == i, 'disabled' : !currentResources[i]}"
*ngFor="let character of characters; let i = index">
<img class="character-icon" [src]="character.iconUrl" />
<span class="value">{{currentResources[i]}}</span>
</a>
</div>

</div>

<div class="garden"
Expand Down
Loading

0 comments on commit 5cfd066

Please sign in to comment.