2025-11-15 15:10:48 -08:00

241 lines
8.4 KiB
TypeScript

import { ChangeDetectorRef, Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { NbDialogRef } from '@nebular/theme';
import { concatMap, find, defaultIfEmpty, first, map, switchMap } from 'rxjs/operators';
import { FileService } from '../../../../services/file.service';
import { MD2Service } from '../../../../services/MD2/md2.service';
import { MsgBoxService } from '../../../../services/msg-box.service';
import { StateService } from '../../../../services/state.service';
import { StringUtils } from '../../../../utilities/string-utils';
import { AttackInfo, AttackTarget, AttackType, MD2HeroInfo, MD2Icon, MobDlgType, MobInfo, MobType } from '../../massive-darkness2.model';
import { MD2ComponentBase } from '../../MD2Base';
import { ADButtons, ADIcon } from '../../../../ui/alert-dlg/alert-dlg.model';
import { MobSkillType } from '../../massive-darkness2.model.boss';
import { Observable, from, of } from 'rxjs';
import { MD2MobSkill, MobSkillTarget } from '../../massive-darkness2.db.model';
import { MD2Logic } from '../../massive-darkness2.logic';
type SkillResolutionResult = { result: boolean; skill: MD2MobSkill | null };
@Component({
selector: 'ngx-spawn-mob-dlg',
templateUrl: './spawn-mob-dlg.component.html',
styleUrls: ['./spawn-mob-dlg.component.scss']
})
export class SpawnMobDlgComponent extends MD2ComponentBase implements OnInit {
MobDlgType = MobDlgType;
MobType = MobType;
mode: MobDlgType;
cardTitle: string;
title: string;
titleHtml: string;
MD2Icon = MD2Icon;
mob: MobInfo;
actionInfoHtml: string;
beenAttackedHero = null as MD2HeroInfo;
attackTarget: string;
otherAttackTarget: string;
constructor(
private dlgRef: NbDialogRef<SpawnMobDlgComponent>,
private msgBoxService: MsgBoxService,
public md2Service: MD2Service,
protected stateService: StateService,
protected route: ActivatedRoute,
protected cdRef: ChangeDetectorRef,
) {
super(md2Service, stateService, route, cdRef);
}
activeSkill: MD2MobSkill = null;;
ngOnInit(): void {
//this.mob = new MobInfo(this.mob);
if (this.mode == MobDlgType.Spawn && this.mob.type == MobType.Mob) {
this.mob.attackInfos = [new AttackInfo(MD2Icon.Melee), new AttackInfo(MD2Icon.Range), new AttackInfo(MD2Icon.Magic)];
} else if (this.mode == MobDlgType.Activating) {
if (this.mob.skills) {
//this.mobActivate(this.mob, this.md2Service.info.heros);
//this.mob.activateFunction(this.mob, this.md2Service.msgBoxService, this.md2Service.info.heros);
this.mobActivate(this.mob, this.md2Service.info.heros).pipe(first()).subscribe(result => {
if (result && result.skill) {
this.activeSkill = result.skill;
//this.actionInfoHtml = `<h4>${result.skill.name}</h4><div>${result.skill.description}</div>`;
}
if (this.mob.type == MobType.Mob) {
this.mob.actions = 2;
} else {
if (result && result.skill) {
this.mob.actions = 1;
} else {
this.mob.actions = 2;
this.activeSkill = { name: 'Normal Action', description: `${this.mob.name} Gains 2 Actions.` } as MD2MobSkill;
//this.actionInfoHtml = `${this.mob.name} Gains 2 Actions.`;
}
}
});
}
}
this.mob.uiWounds = 0;
this.mob.uiFrozenTokens = 0;
this.mob.uiFrozenTokens = 0;
this.initTitleHtml();
}
mobActivate(mob: MobInfo, heros: MD2HeroInfo[]): Observable<SkillResolutionResult> {
switch (mob.type) {
case MobType.Mob:
return of({ result: false, skill: null } as SkillResolutionResult);
case MobType.RoamingMonster:
if (!mob.skills || mob.skills.length === 0) {
return of({ result: false, skill: null } as SkillResolutionResult);
}
const orderedSkills = mob.skills
.filter(s => [MobSkillType.ConditionalSkill, MobSkillType.OtherWiseSkill].includes(s.type))
.sort((a, b) => (a.seq ?? Number.MAX_SAFE_INTEGER) - (b.seq ?? Number.MAX_SAFE_INTEGER));
if (orderedSkills.length === 0) {
return of({ result: false, skill: null } as SkillResolutionResult);
}
return from(orderedSkills).pipe(
concatMap(skill => this.resolveSkillPrompt(skill)),
find(resolution => resolution.result === true),
defaultIfEmpty({ result: false, skill: null } as SkillResolutionResult)
);
case MobType.Boss:
default:
return of({ result: false, skill: null } as SkillResolutionResult);
}
}
private resolveSkillPrompt(skill: MD2MobSkill): Observable<SkillResolutionResult> {
if (skill.type === MobSkillType.OtherWiseSkill) {
return of({ result: true, skill } as SkillResolutionResult);
}
const title = 'Resolve Skill?';
const prompt = skill.skillCondition;
return this.msgBoxService.show(title, {
text: prompt,
icon: ADIcon.QUESTION,
buttons: ADButtons.YesNo
}).pipe(
map(answer => ({ result: !!answer, skill } as SkillResolutionResult))
);
}
submit() {
if (this.mode == MobDlgType.Spawn) {
this.mob.attackInfos = this.mob.attackInfos.filter(a => a.yellow > 0 || a.orange > 0 || a.red > 0);
}
switch (this.mode) {
case MobDlgType.Spawn:
this.mob.attackInfos = this.mob.attackInfos.filter(a => a.yellow > 0 || a.orange > 0 || a.red > 0);
break;
case MobDlgType.Activating:
break;
case MobDlgType.BeenAttacked:
break;
case MobDlgType.PreView:
default:
break;
}
this.md2Service.info.showAttackBtn = false;
this.md2Service.refreshUI$.next();
this.dlgRef.close(this.mob);
}
cancel() {
this.dlgRef.close();
}
initTitleHtml() {
this.cardTitle = MobType[this.mob.type];
let htmlText = '';
if (this.mode == MobDlgType.Spawn) {
htmlText = `${this.mob.description} Shows Up`;
} else if (this.mode == MobDlgType.Activating) {
let targetType = null as MobSkillTarget;
let randomAttack = Math.random() * MobSkillTarget.HighestLevel;
const values = Object.values(MobSkillTarget);
const stringKeys = Object
.keys(MobSkillTarget)
.filter((v) => isNaN(Number(v)))
for (let i = 0; i < stringKeys.length; i++) {
const element = MobSkillTarget[stringKeys[i]];
if (element >= randomAttack) {
targetType = element;
break;
}
}
this.beenAttackedHero = MD2Logic.getTargetHeroByFilter(this.md2Service.heros, targetType);
switch (targetType) {
case MobSkillTarget.LeastHp:
this.otherAttackTarget = 'attacking the other <b>Lowest HP</b> hero.';
break;
case MobSkillTarget.HighestHp:
this.otherAttackTarget = 'attacking the other <b>Highest HP</b> hero.';
break;
case MobSkillTarget.HighestMp:
this.otherAttackTarget = 'attacking the other <b>Highest Mana</b> hero.';
break;
case MobSkillTarget.LowestLevel:
this.otherAttackTarget = 'attacking the other <b>Lowest Level</b> hero.';
break;
case MobSkillTarget.HighestLevel:
this.otherAttackTarget = 'attacking the other <b>Highest Level</b> hero.';
break;
case MobSkillTarget.Random:
default:
this.otherAttackTarget = 'Just act like normal.';
break;
}
//let attackedHeros = StringUtils.makeCommaSeparatedString(this.beenAttackedHero.map(h => this.md2Service.heroFullName(h)), true, true);
this.attackTarget = `Attacking <b>${this.beenAttackedHero.heroFullName}</b> first if possible, otherwise ${this.otherAttackTarget}`;
htmlText = `${this.title}`;
} else {
htmlText = `${this.mob.description}`;
}
this.titleHtml = htmlText;
}
public get headerStatus(): string {
switch (this.mode) {
case MobDlgType.Spawn:
return 'warning';
break;
case MobDlgType.Activating:
return 'danger';
break;
case MobDlgType.BeenAttacked:
return 'info';
break;
case MobDlgType.PreView:
default:
return '';
break;
}
}
public get submitBtnText(): string {
switch (this.mode) {
case MobDlgType.Activating:
return 'Next';
break;
case MobDlgType.BeenAttacked:
return 'Attack!!';
break;
case MobDlgType.PreView:
case MobDlgType.Spawn:
default:
return 'Close';
}
}
}