Update boss maint
This commit is contained in:
parent
a4391c84d0
commit
9ea2278dfb
@ -3,7 +3,7 @@
|
|||||||
<nb-card-body class="g-overflow-hidden">
|
<nb-card-body class="g-overflow-hidden">
|
||||||
<div class="row form-group">
|
<div class="row form-group">
|
||||||
<div class="col-md-5 g-height-700px">
|
<div class="col-md-5 g-height-700px">
|
||||||
<md2-mob-stand-info [mob]="boss.info" [mode]="mode"></md2-mob-stand-info>
|
<md2-mob-stand-info [mob]="boss" [mode]="mode"></md2-mob-stand-info>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-md-7">
|
<div class="col-md-7">
|
||||||
@ -17,11 +17,11 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
|
|
||||||
<md2-mob-attack-info [mob]="boss.info"></md2-mob-attack-info>
|
<md2-mob-attack-info [mob]="boss"></md2-mob-attack-info>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-8 MD2IconContainer-lg">
|
<div class="col-md-8 MD2IconContainer-lg">
|
||||||
|
|
||||||
<md2-mob-combat-info [mob]="boss.info"></md2-mob-combat-info>
|
<md2-mob-combat-info [mob]="boss"></md2-mob-combat-info>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -6,10 +6,11 @@ import { takeUntil } from 'rxjs/operators';
|
|||||||
import { MD2Service } from '../../../../services/MD2/md2.service';
|
import { MD2Service } from '../../../../services/MD2/md2.service';
|
||||||
import { MsgBoxService } from '../../../../services/msg-box.service';
|
import { MsgBoxService } from '../../../../services/msg-box.service';
|
||||||
import { StateService } from '../../../../services/state.service';
|
import { StateService } from '../../../../services/state.service';
|
||||||
import { MobDlgType, MD2Icon, MD2HeroInfo, RoundPhase } from '../../massive-darkness2.model';
|
import { MobDlgType, MD2Icon, MD2HeroInfo, RoundPhase, MobInfo } from '../../massive-darkness2.model';
|
||||||
import { MobSkill, IBossFight } from '../../massive-darkness2.model.boss';
|
import { MobSkill, IBossFight } from '../../massive-darkness2.model.boss';
|
||||||
import { MD2ComponentBase } from '../../MD2Base';
|
import { MD2ComponentBase } from '../../MD2Base';
|
||||||
import { SpawnMobDlgComponent } from '../../mobs/spawn-mob-dlg/spawn-mob-dlg.component';
|
import { SpawnMobDlgComponent } from '../../mobs/spawn-mob-dlg/spawn-mob-dlg.component';
|
||||||
|
import { MD2MobInfo, MD2MobSkill } from '../../massive-darkness2.db.model';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ngx-boss-activation',
|
selector: 'ngx-boss-activation',
|
||||||
@ -17,8 +18,8 @@ import { SpawnMobDlgComponent } from '../../mobs/spawn-mob-dlg/spawn-mob-dlg.com
|
|||||||
styleUrls: ['./boss-activation.component.scss']
|
styleUrls: ['./boss-activation.component.scss']
|
||||||
})
|
})
|
||||||
export class BossActivationComponent implements OnInit {
|
export class BossActivationComponent implements OnInit {
|
||||||
boss: IBossFight;
|
boss: MobInfo;
|
||||||
bossAction: MobSkill;
|
bossAction: MD2MobSkill;
|
||||||
currentAction: number;
|
currentAction: number;
|
||||||
allActions: number;
|
allActions: number;
|
||||||
MobDlgType = MobDlgType;
|
MobDlgType = MobDlgType;
|
||||||
|
|||||||
@ -8,17 +8,17 @@
|
|||||||
<div class="col-md-5">
|
<div class="col-md-5">
|
||||||
<!-- <img src="{{boss.standUrl}}" class="w-100 bossStandImg"> -->
|
<!-- <img src="{{boss.standUrl}}" class="w-100 bossStandImg"> -->
|
||||||
|
|
||||||
<md2-mob-stand-info [mob]="boss.info" [mode]="MobDlgType.PreView"></md2-mob-stand-info>
|
<md2-mob-stand-info [mob]="boss" [mode]="MobDlgType.PreView"></md2-mob-stand-info>
|
||||||
<!-- HP and Mana Bars -->
|
<!-- HP and Mana Bars -->
|
||||||
<div class="hero-stats-overlay">
|
<div class="hero-stats-overlay">
|
||||||
<div class="stat-bar-overlay hp-bar-overlay">
|
<div class="stat-bar-overlay hp-bar-overlay">
|
||||||
<div class="stat-bar-label-overlay">
|
<div class="stat-bar-label-overlay">
|
||||||
<md2-icon [icon]="MD2Icon.HP_Color" size="sm"></md2-icon>
|
<md2-icon [icon]="MD2Icon.HP_Color" size="sm"></md2-icon>
|
||||||
<span class="stat-value-overlay">{{boss.info.unitRemainHp}}/{{boss.info.hp}}</span>
|
<span class="stat-value-overlay">{{boss.unitRemainHp}}/{{boss.hp}}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="stat-progress-bar-overlay">
|
<div class="stat-progress-bar-overlay">
|
||||||
<div class="stat-progress-fill-overlay hp-fill-overlay"
|
<div class="stat-progress-fill-overlay hp-fill-overlay"
|
||||||
[style.width.%]="(boss.info.unitRemainHp / boss.info.hp) * 100">
|
[style.width.%]="(boss.unitRemainHp / boss.hp) * 100">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -27,26 +27,26 @@
|
|||||||
<div class="col-md-7">
|
<div class="col-md-7">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md">
|
<div class="col-md">
|
||||||
<adj-number-input name="mob{{boss.info.name}}" [(ngModel)]="boss.info.unitRemainHp" minimum="0"
|
<adj-number-input name="mob{{boss.name}}" [(ngModel)]="boss.unitRemainHp" minimum="0"
|
||||||
class="mb-3" title="Boss HP" (hitMinimum)="WIN()">
|
class="mb-3" title="Boss HP" (hitMinimum)="WIN()">
|
||||||
</adj-number-input>
|
</adj-number-input>
|
||||||
<md2-mob-attack-info [mob]="boss.info">
|
<md2-mob-attack-info [mob]="boss">
|
||||||
</md2-mob-attack-info>
|
</md2-mob-attack-info>
|
||||||
<md2-mob-def-info [mob]="boss.info"></md2-mob-def-info>
|
<md2-mob-def-info [mob]="boss"></md2-mob-def-info>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-9 h6" *ngIf="boss.extraRules">
|
<div class="col-md-9 bossSpecialRules" *ngIf="boss.bossFightProfile.specialRules">
|
||||||
<div [innerHtml]="boss.extraRules"></div>
|
<div [innerHtml]="boss.bossFightProfile.specialRules"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<md2-mob-combat-info [mob]="boss.info"></md2-mob-combat-info>
|
<md2-mob-combat-info [mob]="boss"></md2-mob-combat-info>
|
||||||
<!--
|
<!--
|
||||||
<button nbButton hero status="danger" size="small" (click)="attack(boss.info)">Attack It</button> -->
|
<button nbButton hero status="danger" size="small" (click)="attack(boss)">Attack It</button> -->
|
||||||
|
|
||||||
<!-- <label class="MD2Text mt-3" [innerHtml]="boss.info.combatSkill.skillName">
|
<!-- <label class="MD2Text mt-3" [innerHtml]="boss.combatSkill.skillName">
|
||||||
</label>
|
</label>
|
||||||
<label class="MD2Text" [innerHtml]="boss.info.combatInfo.skillDescription">
|
<label class="MD2Text" [innerHtml]="boss.combatInfo.skillDescription">
|
||||||
</label> -->
|
</label> -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@ -6,6 +6,11 @@ nb-card {
|
|||||||
max-height: 67vh;
|
max-height: 67vh;
|
||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
}
|
}
|
||||||
|
::ng-deep .bossSpecialRules {
|
||||||
|
.MD2Icon {
|
||||||
|
font-size: 30px;
|
||||||
|
}
|
||||||
|
}
|
||||||
// HP and Mana Bars Overlay
|
// HP and Mana Bars Overlay
|
||||||
.hero-stats-overlay {
|
.hero-stats-overlay {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|||||||
@ -39,7 +39,7 @@ export class BossFightComponent extends MD2ComponentBase {
|
|||||||
super.ngOnInit();
|
super.ngOnInit();
|
||||||
this.md2Service.heroAttackingSubject.pipe(takeUntil(this.destroy$)).subscribe(result => {
|
this.md2Service.heroAttackingSubject.pipe(takeUntil(this.destroy$)).subscribe(result => {
|
||||||
if (this.md2Service.info.isBossFight) {
|
if (this.md2Service.info.isBossFight) {
|
||||||
this.attack(this.boss.info);
|
this.attack(this.boss);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -49,7 +49,7 @@ export class BossFightComponent extends MD2ComponentBase {
|
|||||||
this.destroy$.complete();
|
this.destroy$.complete();
|
||||||
}
|
}
|
||||||
activate() {
|
activate() {
|
||||||
this.boss.activating();
|
this.md2Service.activateBoss();
|
||||||
}
|
}
|
||||||
WIN() {
|
WIN() {
|
||||||
this.msgBoxService.show('Win', { text: 'You Win the Boss Fight', icon: ADIcon.INFO });
|
this.msgBoxService.show('Win', { text: 'You Win the Boss Fight', icon: ADIcon.INFO });
|
||||||
@ -65,8 +65,8 @@ export class BossFightComponent extends MD2ComponentBase {
|
|||||||
if (mobResult) {
|
if (mobResult) {
|
||||||
let attackDamage = mobResult.uiWounds;
|
let attackDamage = mobResult.uiWounds;
|
||||||
if (attackDamage) {
|
if (attackDamage) {
|
||||||
this.boss.info.unitRemainHp -= attackDamage;
|
this.boss.unitRemainHp -= attackDamage;
|
||||||
if (this.boss.info.unitRemainHp <= 0) {
|
if (this.boss.unitRemainHp <= 0) {
|
||||||
this.WIN();
|
this.WIN();
|
||||||
}
|
}
|
||||||
this.cdRef.detectChanges();
|
this.cdRef.detectChanges();
|
||||||
|
|||||||
@ -270,16 +270,24 @@
|
|||||||
*ngIf="hero.uiActivating">
|
*ngIf="hero.uiActivating">
|
||||||
</adj-number-input>
|
</adj-number-input>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6">
|
<div class="col-6" *ngIf="hero.class==HeroClass.Berserker">
|
||||||
<adj-number-input name="heroRage" [(ngModel)]="hero.rage" minimum="0" maximum="7"
|
<adj-number-input name="heroRage" [(ngModel)]="hero.rage" minimum="0" maximum="7"
|
||||||
title="{{iconHtml(MD2Icon.Rage,'g-color-google-plus mr-1 g-font-size-18')}}Rage"
|
title="{{iconHtml(MD2Icon.Rage,'g-color-google-plus mr-1 g-font-size-18')}}Rage"
|
||||||
(blur)="heroUpdateDebounceTimer.resetTimer()" *ngIf="hero.class==HeroClass.Berserker">
|
(blur)="heroUpdateDebounceTimer.resetTimer()">
|
||||||
</adj-number-input>
|
</adj-number-input>
|
||||||
|
|
||||||
|
|
||||||
<adj-number-input name="heroCorruption" [(ngModel)]="hero.corruptionToken" minimum="0"
|
</div>
|
||||||
title="{{imgHtml('Tokens/CorruptToken.png','g-height-18')}} Corruption"
|
<div class="col-6" *ngIf="hero.uiShowExtraToken">
|
||||||
(blur)="heroUpdateDebounceTimer.resetTimer()" *ngIf="hero.uiShowCorruptionToken">
|
<adj-number-input name="heroExtraToken" [(ngModel)]="hero.extraToken" minimum="0"
|
||||||
|
title="{{hero.uiExtraTokenHtml}} {{hero.uiExtraTokenName}}"
|
||||||
|
(blur)="heroUpdateDebounceTimer.resetTimer()">
|
||||||
|
</adj-number-input>
|
||||||
|
</div>
|
||||||
|
<div class="col-6" *ngIf="hero.uiShowExtraToken2">
|
||||||
|
<adj-number-input name="heroExtraToken2" [(ngModel)]="hero.extraToken2" minimum="0"
|
||||||
|
title="{{hero.uiExtraTokenHtml2}} {{hero.uiExtraTokenName2}}"
|
||||||
|
(blur)="heroUpdateDebounceTimer.resetTimer()">
|
||||||
</adj-number-input>
|
</adj-number-input>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@ -73,6 +73,14 @@
|
|||||||
<span class="badge mr-1" *ngIf="hero.frozenToken">
|
<span class="badge mr-1" *ngIf="hero.frozenToken">
|
||||||
<md2-icon [icon]="MD2Icon.FrozenToken" size="sm"></md2-icon>{{hero.frozenToken}}
|
<md2-icon [icon]="MD2Icon.FrozenToken" size="sm"></md2-icon>{{hero.frozenToken}}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
|
<span class="badge mr-1" *ngIf="hero.extraToken">
|
||||||
|
<span [innerHtml]="hero.uiExtraTokenHtml"></span> {{hero.extraToken}}
|
||||||
|
</span>
|
||||||
|
<span class="badge mr-1" *ngIf="hero.extraToken2">
|
||||||
|
<span [innerHtml]="hero.uiExtraTokenHtml2"></span> {{hero.extraToken2}}
|
||||||
|
</span>
|
||||||
|
|
||||||
<span class="badge badge-success mr-1" *ngIf="hero.remainActions>0"
|
<span class="badge badge-success mr-1" *ngIf="hero.remainActions>0"
|
||||||
(click)="adjustHeroValue(hero,'remainActions')">Actions:
|
(click)="adjustHeroValue(hero,'remainActions')">Actions:
|
||||||
{{hero.remainActions}}</span>
|
{{hero.remainActions}}</span>
|
||||||
|
|||||||
@ -185,7 +185,7 @@ export class MassiveDarkness2Component extends MD2Base implements OnInit {
|
|||||||
|
|
||||||
public get round(): string {
|
public get round(): string {
|
||||||
if (this.md2Service.info.isBossFight) {
|
if (this.md2Service.info.isBossFight) {
|
||||||
return `Boss Fight ${NumberUtils.Ordinal(this.md2Service.info.boss.rounds)} Round`;
|
return `Boss Fight ${NumberUtils.Ordinal(this.md2Service.info.bossRound)} Round`;
|
||||||
} else {
|
} else {
|
||||||
return NumberUtils.Ordinal(this.md2Service.info.round) + ' Round';
|
return NumberUtils.Ordinal(this.md2Service.info.round) + ' Round';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,14 +8,17 @@ export enum MobSkillTarget {
|
|||||||
HighestHp = 70,
|
HighestHp = 70,
|
||||||
HighestMp = 80,
|
HighestMp = 80,
|
||||||
LowestLevel = 90,
|
LowestLevel = 90,
|
||||||
MostCorruption = 200,
|
MostExtraToken = 200,
|
||||||
LeastCorruption = 201
|
LeastExtraToken,
|
||||||
|
MostExtraToken2,
|
||||||
|
LeastExtraToken2
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum GameBundle {
|
export enum GameBundle {
|
||||||
CoreGame,
|
CoreGame,
|
||||||
HeavenFallen,
|
HeavenFallen,
|
||||||
Zombiecide
|
Zombiecide,
|
||||||
|
ZombiecideWhiteDeath
|
||||||
}
|
}
|
||||||
export interface MD2MobInfo {
|
export interface MD2MobInfo {
|
||||||
id: string;
|
id: string;
|
||||||
|
|||||||
@ -6,49 +6,60 @@ import { StringUtils } from "../../utilities/string-utils";
|
|||||||
import { GamePlayer } from "../games.model";
|
import { GamePlayer } from "../games.model";
|
||||||
import { MD2HeroInfo, AttackTarget, HeroClass } from "./massive-darkness2.model";
|
import { MD2HeroInfo, AttackTarget, HeroClass } from "./massive-darkness2.model";
|
||||||
import { MobSkill } from "./massive-darkness2.model.boss";
|
import { MobSkill } from "./massive-darkness2.model.boss";
|
||||||
|
import { MobSkillTarget } from "./massive-darkness2.db.model";
|
||||||
export class MD2Logic {
|
export class MD2Logic {
|
||||||
public static getTargetHeroByFilter(heros: MD2HeroInfo[], targetType: AttackTarget) {
|
public static getTargetHeroByFilter(heros: MD2HeroInfo[], targetType: MobSkillTarget) {
|
||||||
return this.getTargetHerosByFilter(heros, targetType, true)[0];
|
return this.getTargetHerosByFilter(heros, targetType, true)[0];
|
||||||
}
|
}
|
||||||
public static getTargetHerosByFilter(heros: MD2HeroInfo[], targetType: AttackTarget, onlyOne: boolean = false) {
|
public static getTargetHerosByFilter(heros: MD2HeroInfo[], targetType: MobSkillTarget, onlyOne: boolean = false) {
|
||||||
let beenAttackedHero = [] as MD2HeroInfo[];
|
let beenAttackedHero = [] as MD2HeroInfo[];
|
||||||
switch (targetType) {
|
switch (targetType) {
|
||||||
case AttackTarget.LeastHp:
|
case MobSkillTarget.LeastHp:
|
||||||
let lowestHp = Math.min(...heros.map(h => h.hp));
|
let lowestHp = Math.min(...heros.map(h => h.hp));
|
||||||
beenAttackedHero = heros.filter(h => h.hp == lowestHp);
|
beenAttackedHero = heros.filter(h => h.hp == lowestHp);
|
||||||
//this.otherAttackTarget = 'attacking the other <b>Lowest HP</b> hero.';
|
//this.otherAttackTarget = 'attacking the other <b>Lowest HP</b> hero.';
|
||||||
break;
|
break;
|
||||||
case AttackTarget.LeastMp:
|
case MobSkillTarget.LeastMp:
|
||||||
let lowestMp = Math.min(...heros.map(h => h.mp));
|
let lowestMp = Math.min(...heros.map(h => h.mp));
|
||||||
beenAttackedHero = heros.filter(h => h.hp == lowestMp);
|
beenAttackedHero = heros.filter(h => h.hp == lowestMp);
|
||||||
//this.otherAttackTarget = 'attacking the other <b>Lowest HP</b> hero.';
|
//this.otherAttackTarget = 'attacking the other <b>Lowest HP</b> hero.';
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AttackTarget.HighestHp:
|
case MobSkillTarget.HighestHp:
|
||||||
let highestHp = Math.max(...heros.map(h => h.hp));
|
let highestHp = Math.max(...heros.map(h => h.hp));
|
||||||
beenAttackedHero = heros.filter(h => h.hp == highestHp);
|
beenAttackedHero = heros.filter(h => h.hp == highestHp);
|
||||||
//this.otherAttackTarget = 'attacking the other <b>Highest HP</b> hero.';
|
//this.otherAttackTarget = 'attacking the other <b>Highest HP</b> hero.';
|
||||||
break;
|
break;
|
||||||
case AttackTarget.HighestMp:
|
case MobSkillTarget.HighestMp:
|
||||||
let highestMp = Math.max(...heros.map(h => h.mp));
|
let highestMp = Math.max(...heros.map(h => h.mp));
|
||||||
beenAttackedHero = heros.filter(h => h.mp == highestMp);
|
beenAttackedHero = heros.filter(h => h.mp == highestMp);
|
||||||
//this.otherAttackTarget = 'attacking the other <b>Highest Mp</b> hero.';
|
//this.otherAttackTarget = 'attacking the other <b>Highest Mp</b> hero.';
|
||||||
break;
|
break;
|
||||||
case AttackTarget.LowestLevel:
|
case MobSkillTarget.LowestLevel:
|
||||||
let lowestLevel = Math.max(...heros.map(h => h.level));
|
let lowestLevel = Math.max(...heros.map(h => h.level));
|
||||||
beenAttackedHero = heros.filter(h => h.level == lowestLevel);
|
beenAttackedHero = heros.filter(h => h.level == lowestLevel);
|
||||||
//this.otherAttackTarget = 'attacking the other <b>Lowest Level</b> hero.';
|
//this.otherAttackTarget = 'attacking the other <b>Lowest Level</b> hero.';
|
||||||
break;
|
break;
|
||||||
case AttackTarget.LeastCorruption:
|
case MobSkillTarget.LeastExtraToken:
|
||||||
|
|
||||||
let leastCor = Math.min(...heros.map(h => h.corruptionToken));
|
let leastExtraToken = Math.min(...heros.map(h => h.extraToken));
|
||||||
beenAttackedHero = heros.filter(h => h.corruptionToken == leastCor);
|
beenAttackedHero = heros.filter(h => h.extraToken == leastExtraToken);
|
||||||
break;
|
break;
|
||||||
case AttackTarget.MostCorruption:
|
case MobSkillTarget.MostExtraToken:
|
||||||
let mostCor = Math.max(...heros.map(h => h.corruptionToken));
|
let mostExtraToken = Math.max(...heros.map(h => h.extraToken));
|
||||||
beenAttackedHero = heros.filter(h => h.corruptionToken == mostCor);
|
beenAttackedHero = heros.filter(h => h.extraToken == mostExtraToken);
|
||||||
break;
|
break;
|
||||||
case AttackTarget.Random:
|
|
||||||
|
case MobSkillTarget.LeastExtraToken2:
|
||||||
|
|
||||||
|
let leastExtraToken2 = Math.min(...heros.map(h => h.extraToken2));
|
||||||
|
beenAttackedHero = heros.filter(h => h.extraToken2 == leastExtraToken2);
|
||||||
|
break;
|
||||||
|
case MobSkillTarget.MostExtraToken2:
|
||||||
|
let mostExtraToken2 = Math.max(...heros.map(h => h.extraToken2));
|
||||||
|
beenAttackedHero = heros.filter(h => h.extraToken2 == mostExtraToken2);
|
||||||
|
break;
|
||||||
|
case MobSkillTarget.Random:
|
||||||
default:
|
default:
|
||||||
beenAttackedHero = [heros[Math.round(Math.random() * (heros.length - 1))]];
|
beenAttackedHero = [heros[Math.round(Math.random() * (heros.length - 1))]];
|
||||||
//this.otherAttackTarget = 'Just act like normal.';
|
//this.otherAttackTarget = 'Just act like normal.';
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import { StringUtils } from "../../utilities/string-utils"
|
|||||||
import { BossActivationComponent } from "./boss-fight/boss-activation/boss-activation.component"
|
import { BossActivationComponent } from "./boss-fight/boss-activation/boss-activation.component"
|
||||||
import { TreasureType, AttackInfo, AttackType, MD2Icon, MD2HeroInfo, AttackTarget, MobInfo, MobType } from "./massive-darkness2.model"
|
import { TreasureType, AttackInfo, AttackType, MD2Icon, MD2HeroInfo, AttackTarget, MobInfo, MobType } from "./massive-darkness2.model"
|
||||||
import { RollingBlackDice } from "./massive-darkness2.model.dice"
|
import { RollingBlackDice } from "./massive-darkness2.model.dice"
|
||||||
import { MD2DiceSet, MD2MobSkill } from "./massive-darkness2.db.model"
|
import { MD2DiceSet, MD2MobSkill, MobSkillTarget } from "./massive-darkness2.db.model"
|
||||||
|
|
||||||
|
|
||||||
export enum MobSkillType {
|
export enum MobSkillType {
|
||||||
@ -156,14 +156,14 @@ export class BossMicheal extends BossFight {
|
|||||||
|
|
||||||
bossAction(): Observable<boolean> {
|
bossAction(): Observable<boolean> {
|
||||||
|
|
||||||
let actionResult = new RollingBlackDice().roll(this.actionBlackDice);
|
let actionResult = new RollingBlackDice().roll(2);
|
||||||
let actionHtml = '';
|
let actionHtml = '';
|
||||||
let beenAttackedHero = [] as MD2HeroInfo[];
|
let beenAttackedHero = [] as MD2HeroInfo[];
|
||||||
let bossAction: MobSkill;
|
let bossAction: MobSkill;
|
||||||
switch (actionResult.claws) {
|
switch (actionResult.claws) {
|
||||||
case 0:
|
case 0:
|
||||||
//Justice From Above
|
//Justice From Above
|
||||||
beenAttackedHero = this.md2Service.getTargetHerosByFilter(AttackTarget.MostCorruption, true);
|
beenAttackedHero = this.md2Service.getTargetHerosByFilter(MobSkillTarget.MostExtraToken, true);
|
||||||
bossAction = new MobSkill(
|
bossAction = new MobSkill(
|
||||||
{
|
{
|
||||||
name: 'Justice From Above',
|
name: 'Justice From Above',
|
||||||
@ -173,7 +173,7 @@ export class BossMicheal extends BossFight {
|
|||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
//Lance Dash
|
//Lance Dash
|
||||||
beenAttackedHero = this.md2Service.getTargetHerosByFilter(AttackTarget.LeastCorruption, true);
|
beenAttackedHero = this.md2Service.getTargetHerosByFilter(MobSkillTarget.LeastExtraToken, true);
|
||||||
bossAction = new MobSkill({
|
bossAction = new MobSkill({
|
||||||
name: 'Lance Dash',
|
name: 'Lance Dash',
|
||||||
description:
|
description:
|
||||||
@ -193,12 +193,13 @@ export class BossMicheal extends BossFight {
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return this.md2Service.dlgService.open(BossActivationComponent, { context: { boss: this, bossAction: bossAction, currentAction: this.activatedTimes, allActions: this.actions } }).onClose;
|
return null;
|
||||||
|
//return this.md2Service.dlgService.open(BossActivationComponent, { context: { boss: this, bossAction: bossAction, currentAction: this.activatedTimes, allActions: this.actions } }).onClose;
|
||||||
|
|
||||||
}
|
}
|
||||||
prepareForBossFight(): void {
|
prepareForBossFight(): void {
|
||||||
this.md2Service.heros.forEach(hero => {
|
this.md2Service.heros.forEach(hero => {
|
||||||
hero.uiShowCorruptionToken = true;
|
hero.uiShowExtraToken = true;
|
||||||
});
|
});
|
||||||
this.md2Service.msgBoxService.show('Prepare Boss Fight', {
|
this.md2Service.msgBoxService.show('Prepare Boss Fight', {
|
||||||
text: `<h6>Place ${this.md2Service.heros.length * 2} ${this.corruptionTokenHtml} on the Corruption Stone Zones (Shadow
|
text: `<h6>Place ${this.md2Service.heros.length * 2} ${this.corruptionTokenHtml} on the Corruption Stone Zones (Shadow
|
||||||
@ -282,7 +283,7 @@ export class BossReaper extends BossFight {
|
|||||||
switch (actionResult.claws) {
|
switch (actionResult.claws) {
|
||||||
case 0:
|
case 0:
|
||||||
//Justice From Above
|
//Justice From Above
|
||||||
beenAttackedHero = this.md2Service.getTargetHerosByFilter(AttackTarget.LeastMp, true);
|
beenAttackedHero = this.md2Service.getTargetHerosByFilter(MobSkillTarget.LeastMp, true);
|
||||||
bossAction = new MobSkill(
|
bossAction = new MobSkill(
|
||||||
{
|
{
|
||||||
name: 'Soul Drain',
|
name: 'Soul Drain',
|
||||||
@ -292,7 +293,7 @@ export class BossReaper extends BossFight {
|
|||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
//Lance Dash
|
//Lance Dash
|
||||||
beenAttackedHero = this.md2Service.getTargetHerosByFilter(AttackTarget.LeastCorruption, true);
|
beenAttackedHero = this.md2Service.getTargetHerosByFilter(MobSkillTarget.LeastExtraToken, true);
|
||||||
bossAction = new MobSkill({
|
bossAction = new MobSkill({
|
||||||
name: 'Time Ticking',
|
name: 'Time Ticking',
|
||||||
description:
|
description:
|
||||||
@ -313,7 +314,8 @@ export class BossReaper extends BossFight {
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return this.md2Service.dlgService.open(BossActivationComponent, { context: { boss: this, bossAction: bossAction, currentAction: this.activatedTimes, allActions: this.actions } }).onClose;
|
return null;
|
||||||
|
//return this.md2Service.dlgService.open(BossActivationComponent, { context: { boss: this, bossAction: bossAction, currentAction: this.activatedTimes, allActions: this.actions } }).onClose;
|
||||||
}
|
}
|
||||||
prepareForBossFight(): void {
|
prepareForBossFight(): void {
|
||||||
this.md2Service.msgBoxService.show('Prepare Boss Fight', {
|
this.md2Service.msgBoxService.show('Prepare Boss Fight', {
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import { ObjectUtils } from "../../utilities/object-utils";
|
|||||||
import { GamePlayer } from "../games.model";
|
import { GamePlayer } from "../games.model";
|
||||||
import { MD2Clone } from "./factorys/md2-clone";
|
import { MD2Clone } from "./factorys/md2-clone";
|
||||||
import { MobSkill } from "./massive-darkness2.model.boss";
|
import { MobSkill } from "./massive-darkness2.model.boss";
|
||||||
import { MD2DiceSet, MD2MobSkill } from "./massive-darkness2.db.model";
|
import { BossFightProfile, MD2DiceSet, MD2MobSkill } from "./massive-darkness2.db.model";
|
||||||
|
|
||||||
const MD2_IMG_URL = (id: string = null) => { return `${environment.apiUrl}/Files/Images/MD2/${(id ? `${encodeURI(id)}` : '')}` }
|
const MD2_IMG_URL = (id: string = null) => { return `${environment.apiUrl}/Files/Images/MD2/${(id ? `${encodeURI(id)}` : '')}` }
|
||||||
export enum MobDlgType {
|
export enum MobDlgType {
|
||||||
@ -333,12 +333,15 @@ export class MobInfo implements IDrawingItem {
|
|||||||
fireToken: number = 0;
|
fireToken: number = 0;
|
||||||
frozenToken: number = 0;
|
frozenToken: number = 0;
|
||||||
corruptionToken: number = 0;
|
corruptionToken: number = 0;
|
||||||
|
uiExtraTokenCount: number = 0;
|
||||||
|
uiExtraTokenCount2: number = 0;
|
||||||
uiWounds: number;
|
uiWounds: number;
|
||||||
uiFireTokens: number;
|
uiFireTokens: number;
|
||||||
uiFrozenTokens: number;
|
uiFrozenTokens: number;
|
||||||
uiCorruptionTokens: number;
|
uiCorruptionTokens: number;
|
||||||
uiAttackedBy: string;
|
uiAttackedBy: string;
|
||||||
extraRule: string;
|
extraRule: string;
|
||||||
|
bossFightProfile?: BossFightProfile;
|
||||||
get identifyName(): string {
|
get identifyName(): string {
|
||||||
return `${this.name}_${this.level}`;
|
return `${this.name}_${this.level}`;
|
||||||
}
|
}
|
||||||
@ -409,7 +412,8 @@ export class MD2HeroInfo {
|
|||||||
level: number = 1;
|
level: number = 1;
|
||||||
fireToken: number = 0;
|
fireToken: number = 0;
|
||||||
frozenToken: number = 0;
|
frozenToken: number = 0;
|
||||||
corruptionToken: number = 0;
|
extraToken: number = 0;
|
||||||
|
extraToken2: number = 0;
|
||||||
playerInfo: GamePlayer;
|
playerInfo: GamePlayer;
|
||||||
imgUrl: string;
|
imgUrl: string;
|
||||||
skillHtml: string;
|
skillHtml: string;
|
||||||
@ -417,7 +421,12 @@ export class MD2HeroInfo {
|
|||||||
remainActions: number = 3;
|
remainActions: number = 3;
|
||||||
rage: number = 0;
|
rage: number = 0;
|
||||||
uiActivating = false;
|
uiActivating = false;
|
||||||
uiShowCorruptionToken = false;
|
uiExtraTokenHtml: string = '';
|
||||||
|
uiExtraTokenHtml2: string = '';
|
||||||
|
uiExtraTokenName: string = '';
|
||||||
|
uiExtraTokenName2: string = '';
|
||||||
|
uiShowExtraToken = false;
|
||||||
|
uiShowExtraToken2 = false;
|
||||||
uiBossFight = false;
|
uiBossFight = false;
|
||||||
uiShowAttackBtn = false;
|
uiShowAttackBtn = false;
|
||||||
|
|
||||||
|
|||||||
@ -145,46 +145,6 @@ export class MD2HtmlEditorComponent implements ControlValueAccessor, AfterViewIn
|
|||||||
}).result.subscribe((html: string) => {
|
}).result.subscribe((html: string) => {
|
||||||
if (html && this.editor) {
|
if (html && this.editor) {
|
||||||
this.insertAfterSelection(html, true);
|
this.insertAfterSelection(html, true);
|
||||||
return;
|
|
||||||
// Insert the HTML content at the current cursor position
|
|
||||||
// Use ProseMirror's dispatch method to insert content at cursor
|
|
||||||
const view = this.editor.view;
|
|
||||||
if (view && view.state) {
|
|
||||||
try {
|
|
||||||
// Parse the HTML content
|
|
||||||
const dom = document.createElement('div');
|
|
||||||
dom.innerHTML = html;
|
|
||||||
|
|
||||||
// Use ProseMirror's DOMParser to parse HTML
|
|
||||||
// Access it from the view's state
|
|
||||||
const pmState = view.state;
|
|
||||||
|
|
||||||
// Use the editor's exec method or manual dispatch
|
|
||||||
if ((this.editor as any).exec) {
|
|
||||||
// Try using exec with 'insertHTML' command if available
|
|
||||||
try {
|
|
||||||
(this.editor as any).exec('insertHTML', html);
|
|
||||||
} catch (e) {
|
|
||||||
throw new Error('insertHTML not supported');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new Error('exec method not available');
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.error('Error inserting HTML:', e);
|
|
||||||
// Fallback: append to the end
|
|
||||||
const currentValue = this.editor.value || '';
|
|
||||||
const newValue = currentValue + ' ' + html;
|
|
||||||
this.value = newValue;
|
|
||||||
this.onChange(newValue);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Fallback: append to the end
|
|
||||||
const currentValue = this.editor.value || '';
|
|
||||||
const newValue = currentValue + ' ' + html;
|
|
||||||
this.value = newValue;
|
|
||||||
this.onChange(newValue);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -445,7 +405,7 @@ export const rbjTagNodeSpec: NodeSpec = {
|
|||||||
"span",
|
"span",
|
||||||
{
|
{
|
||||||
class: classValue,
|
class: classValue,
|
||||||
// "rbj-tag-id": node.attrs["rbj-tag-id"],
|
"md2-icon": md2IconText,
|
||||||
// "tag-marker": node.attrs["tag-marker"],
|
// "tag-marker": node.attrs["tag-marker"],
|
||||||
// "tag-value": node.attrs["tag-value"],
|
// "tag-value": node.attrs["tag-value"],
|
||||||
// "tag-preview": node.attrs["tag-preview"],
|
// "tag-preview": node.attrs["tag-preview"],
|
||||||
|
|||||||
@ -37,7 +37,7 @@ import { MD2Service } from '../../../services/MD2/md2.service';
|
|||||||
gap: 10px;
|
gap: 10px;
|
||||||
max-height: 400px;
|
max-height: 400px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
width:400px;
|
//width:400px;
|
||||||
}
|
}
|
||||||
.icon-item {
|
.icon-item {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|||||||
@ -2,7 +2,28 @@
|
|||||||
<kendo-tabstrip tabPosition="top">
|
<kendo-tabstrip tabPosition="top">
|
||||||
<kendo-tabstrip-tab title="Boss Fight Info" [selected]="true">
|
<kendo-tabstrip-tab title="Boss Fight Info" [selected]="true">
|
||||||
<ng-template kendoTabContent>
|
<ng-template kendoTabContent>
|
||||||
<form class="k-form" style="padding: 20px;">
|
<form class="k-form" style="padding: 5px;">
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="k-label g-cursor-pointer"
|
||||||
|
(click)="showInsertMD2Icon('extraTokenHtml')">Extra Token Name<span
|
||||||
|
class="tokenIconDiv" [innerHTML]="model.extraTokenHtml"></span></label>
|
||||||
|
<input kendoTextBox [(ngModel)]="model.extraTokenName" name="extraTokenName"
|
||||||
|
class="k-input" placeholder="Enter extra token name" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="k-label g-cursor-pointer"
|
||||||
|
(click)="showInsertMD2Icon('extraTokenHtml2')">Extra Token Name 2<span
|
||||||
|
class="tokenIconDiv" [innerHTML]="model.extraTokenHtml2"></span></label>
|
||||||
|
<input kendoTextBox [(ngModel)]="model.extraTokenName2" name="extraTokenName2"
|
||||||
|
class="k-input" placeholder="Enter extra token name 2" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@ -33,39 +54,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-6">
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="k-label">Extra Token Name</label>
|
|
||||||
<input kendoTextBox [(ngModel)]="model.extraTokenName" name="extraTokenName"
|
|
||||||
class="k-input" placeholder="Enter extra token name" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="k-label">Extra Token HTML</label>
|
|
||||||
<md2-html-editor [(ngModel)]="model.extraTokenHtml" name="extraTokenHtml"
|
|
||||||
class="htmlEditor"></md2-html-editor>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-6">
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="k-label">Extra Token Name 2</label>
|
|
||||||
<input kendoTextBox [(ngModel)]="model.extraTokenName2" name="extraTokenName2"
|
|
||||||
class="k-input" placeholder="Enter extra token name 2" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="k-label">Extra Token HTML 2</label>
|
|
||||||
<md2-html-editor [(ngModel)]="model.extraTokenHtml2" name="extraTokenHtml2"
|
|
||||||
class="htmlEditor"></md2-html-editor>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
</form>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</kendo-tabstrip-tab>
|
</kendo-tabstrip-tab>
|
||||||
@ -81,8 +70,8 @@
|
|||||||
|
|
||||||
<kendo-grid #phaseBuffsGrid [data]="phaseBuffsData" [loading]="isLoading"
|
<kendo-grid #phaseBuffsGrid [data]="phaseBuffsData" [loading]="isLoading"
|
||||||
[pageSize]="phaseBuffsState.take" [skip]="phaseBuffsState.skip" [sortable]="true"
|
[pageSize]="phaseBuffsState.take" [skip]="phaseBuffsState.skip" [sortable]="true"
|
||||||
[filterable]="true" [pageable]="true" [height]="400"
|
[filterable]="true" [pageable]="true" [height]="400" (remove)="removePhaseBuffHandler($event)"
|
||||||
(remove)="removePhaseBuffHandler($event)" (dataStateChange)="phaseBuffsState = $event; loadPhaseBuffs()">
|
(dataStateChange)="phaseBuffsState = $event; loadPhaseBuffs()">
|
||||||
|
|
||||||
<kendo-grid-column field="phase" title="Phase" [width]="80">
|
<kendo-grid-column field="phase" title="Phase" [width]="80">
|
||||||
<ng-template kendoGridCellTemplate let-dataItem>
|
<ng-template kendoGridCellTemplate let-dataItem>
|
||||||
@ -116,7 +105,8 @@
|
|||||||
|
|
||||||
<kendo-grid-column field="extraBuffDescription" title="Extra Buff Description" [width]="300">
|
<kendo-grid-column field="extraBuffDescription" title="Extra Buff Description" [width]="300">
|
||||||
<ng-template kendoGridCellTemplate let-dataItem>
|
<ng-template kendoGridCellTemplate let-dataItem>
|
||||||
<div *ngIf="dataItem.enableExtraBuffDescription" [innerHTML]="dataItem.extraBuffDescription">
|
<div *ngIf="dataItem.enableExtraBuffDescription"
|
||||||
|
[innerHTML]="dataItem.extraBuffDescription">
|
||||||
</div>
|
</div>
|
||||||
<span *ngIf="!dataItem.enableExtraBuffDescription">-</span>
|
<span *ngIf="!dataItem.enableExtraBuffDescription">-</span>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
@ -125,7 +115,8 @@
|
|||||||
<kendo-grid-command-column title="Actions" [width]="133">
|
<kendo-grid-command-column title="Actions" [width]="133">
|
||||||
<ng-template kendoGridCellTemplate let-isNew="isNew" let-dataItem="dataItem"
|
<ng-template kendoGridCellTemplate let-isNew="isNew" let-dataItem="dataItem"
|
||||||
let-rowIndex="rowIndex">
|
let-rowIndex="rowIndex">
|
||||||
<button kendoButton [primary]="true" (click)="editPhaseBuffHandler(dataItem)">Edit</button>
|
<button kendoButton [primary]="true"
|
||||||
|
(click)="editPhaseBuffHandler(dataItem)">Edit</button>
|
||||||
<button kendoGridRemoveCommand>Remove</button>
|
<button kendoGridRemoveCommand>Remove</button>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</kendo-grid-command-column>
|
</kendo-grid-command-column>
|
||||||
@ -141,4 +132,4 @@
|
|||||||
<button kendoButton [primary]="true" (click)="save()" [disabled]="!isValid || processing">
|
<button kendoButton [primary]="true" (click)="save()" [disabled]="!isValid || processing">
|
||||||
{{ processing ? 'Saving...' : 'Save' }}
|
{{ processing ? 'Saving...' : 'Save' }}
|
||||||
</button>
|
</button>
|
||||||
</kendo-dialog-actions>
|
</kendo-dialog-actions>
|
||||||
@ -1 +1,10 @@
|
|||||||
// Boss Fight Editor styles
|
// Boss Fight Editor styles
|
||||||
|
.tokenIconDiv {
|
||||||
|
margin-left: 5px;
|
||||||
|
font-size: 30px;
|
||||||
|
img {
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import { MobSkillType } from '../../massive-darkness2.model.boss';
|
|||||||
import { MD2BossFightProfileService, MD2PhaseBuffService } from '../../service/massive-darkness2.service';
|
import { MD2BossFightProfileService, MD2PhaseBuffService } from '../../service/massive-darkness2.service';
|
||||||
import { MsgBoxService } from '../../../../services/msg-box.service';
|
import { MsgBoxService } from '../../../../services/msg-box.service';
|
||||||
import { MD2PhaseBuffEditorComponent } from '../md2-phase-buff-editor/md2-phase-buff-editor.component';
|
import { MD2PhaseBuffEditorComponent } from '../md2-phase-buff-editor/md2-phase-buff-editor.component';
|
||||||
|
import { MD2IconPickerDlgComponent } from '../../md2-html-editor/md2-icon-picker-dlg.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ngx-md2-boss-fight-editor',
|
selector: 'ngx-md2-boss-fight-editor',
|
||||||
@ -192,7 +193,20 @@ export class MD2BossFightEditorComponent extends DialogContentBase implements On
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
showInsertMD2Icon(attributeName: string) {
|
||||||
|
this.dialogService.open({
|
||||||
|
title: 'Select MD2 Icon',
|
||||||
|
content: MD2IconPickerDlgComponent,
|
||||||
|
width: '800px',
|
||||||
|
height: 600
|
||||||
|
}).result.subscribe((html: string) => {
|
||||||
|
if (html && typeof html === 'string') {
|
||||||
|
this.model[attributeName] = html;
|
||||||
|
} else {
|
||||||
|
this.model[attributeName] = '';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
public get isValid(): boolean {
|
public get isValid(): boolean {
|
||||||
if (!this.model) {
|
if (!this.model) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -11,7 +11,8 @@
|
|||||||
<kendo-grid #grid [data]="gridData" [loading]="isLoading" [pageSize]="gridState.take" [skip]="gridState.skip"
|
<kendo-grid #grid [data]="gridData" [loading]="isLoading" [pageSize]="gridState.take" [skip]="gridState.skip"
|
||||||
[group]="gridState.group" [filter]="gridState.filter" [sort]="gridState.sort" [sortable]="true"
|
[group]="gridState.group" [filter]="gridState.filter" [sort]="gridState.sort" [sortable]="true"
|
||||||
[filterable]="true" [pageable]="true" [selectable]="true" [groupable]="true"
|
[filterable]="true" [pageable]="true" [selectable]="true" [groupable]="true"
|
||||||
(dataStateChange)="gridState = $event; processGridData()">
|
(dataStateChange)="gridState = $event; processGridData()" (edit)="editHandler($event)"
|
||||||
|
(remove)="removeHandler($event)" (add)="addHandler()">
|
||||||
|
|
||||||
<kendo-grid-toolbar>
|
<kendo-grid-toolbar>
|
||||||
<button kendoGridAddCommand>Add new</button>
|
<button kendoGridAddCommand>Add new</button>
|
||||||
|
|||||||
@ -31,6 +31,7 @@ export class MD2InitService {
|
|||||||
this.mobInfoService.getAll().pipe(first()).subscribe(result => {
|
this.mobInfoService.getAll().pipe(first()).subscribe(result => {
|
||||||
this.md2Service.mobInfos = result.filter(m => m.type == MobType.Mob);
|
this.md2Service.mobInfos = result.filter(m => m.type == MobType.Mob);
|
||||||
this.md2Service.roamingMobInfos = result.filter(m => m.type == MobType.RoamingMonster);
|
this.md2Service.roamingMobInfos = result.filter(m => m.type == MobType.RoamingMonster);
|
||||||
|
this.md2Service.bossInfos = result.filter(m => m.type == MobType.Boss);
|
||||||
for (let i = 0; i < result.length; i++) {
|
for (let i = 0; i < result.length; i++) {
|
||||||
const mobInfo = result[i];
|
const mobInfo = result[i];
|
||||||
for (let j = 0; j < mobInfo.mobLevelInfos.length; j++) {
|
for (let j = 0; j < mobInfo.mobLevelInfos.length; j++) {
|
||||||
|
|||||||
@ -2,8 +2,8 @@ import { Injectable } from '@angular/core';
|
|||||||
import { AttackInfo, AttackTarget, CoreGameDarknessPhaseRule, DrawingBag, DrawingItem, HeroClass, IDarknessPhaseRule, MD2EnemyPhaseSpecialInfo, MD2EnemyPhaseSpecialRule, MD2HeroInfo, MD2Icon, MD2Rules, MobInfo, MobType, RoundPhase, TreasureItem, TreasureType } from '../../games/massive-darkness2/massive-darkness2.model';
|
import { AttackInfo, AttackTarget, CoreGameDarknessPhaseRule, DrawingBag, DrawingItem, HeroClass, IDarknessPhaseRule, MD2EnemyPhaseSpecialInfo, MD2EnemyPhaseSpecialRule, MD2HeroInfo, MD2Icon, MD2Rules, MobInfo, MobType, RoundPhase, TreasureItem, TreasureType } from '../../games/massive-darkness2/massive-darkness2.model';
|
||||||
import { first, map, reduce } from "rxjs/operators";
|
import { first, map, reduce } from "rxjs/operators";
|
||||||
import { NbDialogService, NbThemeService } from '@nebular/theme';
|
import { NbDialogService, NbThemeService } from '@nebular/theme';
|
||||||
import { Subject } from 'rxjs';
|
import { Observable, Subject } from 'rxjs';
|
||||||
import { BossMicheal, BossReaper, IBossFight } from '../../games/massive-darkness2/massive-darkness2.model.boss';
|
import { BossFight, MobSkillType } from '../../games/massive-darkness2/massive-darkness2.model.boss';
|
||||||
import { ADIcon, MessageBoxConfig } from '../../ui/alert-dlg/alert-dlg.model';
|
import { ADIcon, MessageBoxConfig } from '../../ui/alert-dlg/alert-dlg.model';
|
||||||
import { NumberUtils } from '../../utilities/number-utils';
|
import { NumberUtils } from '../../utilities/number-utils';
|
||||||
import { StringUtils } from '../../utilities/string-utils';
|
import { StringUtils } from '../../utilities/string-utils';
|
||||||
@ -16,8 +16,10 @@ import { MD2Logic } from '../../games/massive-darkness2/massive-darkness2.logic'
|
|||||||
import { MD2InitService } from './md2-init.service';
|
import { MD2InitService } from './md2-init.service';
|
||||||
import { ArrayUtils } from '../../utilities/array-utils';
|
import { ArrayUtils } from '../../utilities/array-utils';
|
||||||
import { DropDownOption } from '../../entity/dropDownOption';
|
import { DropDownOption } from '../../entity/dropDownOption';
|
||||||
import { GameBundle, MD2DiceSet, MD2MobInfo } from '../../games/massive-darkness2/massive-darkness2.db.model';
|
import { GameBundle, MD2DiceSet, MD2MobInfo, MD2MobSkill, MobSkillTarget } from '../../games/massive-darkness2/massive-darkness2.db.model';
|
||||||
import { environment } from '../../../environments/environment';
|
import { environment } from '../../../environments/environment';
|
||||||
|
import { RollingBlackDice } from '../../games/massive-darkness2/massive-darkness2.model.dice';
|
||||||
|
import { BossActivationComponent } from '../../games/massive-darkness2/boss-fight/boss-activation/boss-activation.component';
|
||||||
|
|
||||||
|
|
||||||
const MD2_IMG_URL = (id: string = null) => { return `${environment.apiUrl}/Files/Images/MD2/Mobs${(id ? `${encodeURI(id)}` : '')}` };
|
const MD2_IMG_URL = (id: string = null) => { return `${environment.apiUrl}/Files/Images/MD2/Mobs${(id ? `${encodeURI(id)}` : '')}` };
|
||||||
@ -32,6 +34,7 @@ export class MD2Service {
|
|||||||
public specialRule: MD2EnemyPhaseSpecialInfo;
|
public specialRule: MD2EnemyPhaseSpecialInfo;
|
||||||
public info: MD2GameInfo;
|
public info: MD2GameInfo;
|
||||||
public playerHero: MD2HeroInfo;
|
public playerHero: MD2HeroInfo;
|
||||||
|
public bossInfos: MD2MobInfo[] = [];
|
||||||
public mobInfos: MD2MobInfo[] = [];
|
public mobInfos: MD2MobInfo[] = [];
|
||||||
public roamingMobInfos: MD2MobInfo[] = [];
|
public roamingMobInfos: MD2MobInfo[] = [];
|
||||||
public mobDeck: DrawingBag<MobInfo>;
|
public mobDeck: DrawingBag<MobInfo>;
|
||||||
@ -134,8 +137,8 @@ export class MD2Service {
|
|||||||
this.msgBoxService.show(`${NumberUtils.Ordinal(this.info.round)} Hero Phase`, { icon: ADIcon.INFO });
|
this.msgBoxService.show(`${NumberUtils.Ordinal(this.info.round)} Hero Phase`, { icon: ADIcon.INFO });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.info.boss.darknessPhase();
|
this.bossDarknessPhase();
|
||||||
this.msgBoxService.show(`Boss Fight - ${NumberUtils.Ordinal(this.info.boss.rounds)} Hero Phase`, { icon: ADIcon.INFO });
|
this.msgBoxService.show(`Boss Fight - ${NumberUtils.Ordinal(this.info.bossRound)} Hero Phase`, { icon: ADIcon.INFO });
|
||||||
}
|
}
|
||||||
|
|
||||||
//this.runNextPhase();
|
//this.runNextPhase();
|
||||||
@ -221,15 +224,15 @@ export class MD2Service {
|
|||||||
mobInfo.skills = mobInfo.skills.sort((a, b) => b.seq - a.seq);
|
mobInfo.skills = mobInfo.skills.sort((a, b) => b.seq - a.seq);
|
||||||
switch (dbMobInfo.type) {
|
switch (dbMobInfo.type) {
|
||||||
case MobType.Mob:
|
case MobType.Mob:
|
||||||
mobInfo.leaderImgUrl = mobInfo.leaderImgUrl || MD2_IMG_URL(`/${GameBundle[dbMobInfo.from]}/Mobs/${mobInfo.name}/Leader.png`);
|
mobInfo.leaderImgUrl = !!mobInfo.leaderImgUrl ? MD2_IMG_URL(mobInfo.leaderImgUrl) : MD2_IMG_URL(`/${GameBundle[dbMobInfo.from]}/Mobs/${mobInfo.name}/Leader.png`);
|
||||||
mobInfo.minionImgUrl = mobInfo.minionImgUrl || MD2_IMG_URL(`/${GameBundle[dbMobInfo.from]}/Mobs/${mobInfo.name}/Minion.png`);
|
mobInfo.minionImgUrl = !!mobInfo.minionImgUrl ? MD2_IMG_URL(mobInfo.minionImgUrl) : MD2_IMG_URL(`/${GameBundle[dbMobInfo.from]}/Mobs/${mobInfo.name}/Minion.png`);
|
||||||
break;
|
break;
|
||||||
case MobType.RoamingMonster:
|
case MobType.RoamingMonster:
|
||||||
mobInfo.leaderImgUrl = mobInfo.leaderImgUrl || MD2_IMG_URL(`/${GameBundle[dbMobInfo.from]}/RoamingMonsters/${mobInfo.name}/Stand.png`);
|
mobInfo.leaderImgUrl = !!mobInfo.leaderImgUrl ? MD2_IMG_URL(mobInfo.leaderImgUrl) : MD2_IMG_URL(`/${GameBundle[dbMobInfo.from]}/RoamingMonsters/${mobInfo.name}/Stand.png`);
|
||||||
mobInfo.minionImgUrl = null;
|
mobInfo.minionImgUrl = null;
|
||||||
break;
|
break;
|
||||||
case MobType.Boss:
|
case MobType.Boss:
|
||||||
mobInfo.leaderImgUrl = mobInfo.leaderImgUrl || MD2_IMG_URL(`/Boss/${mobInfo.name}-Stand.png`);
|
mobInfo.leaderImgUrl = !!mobInfo.leaderImgUrl ? MD2_IMG_URL(mobInfo.leaderImgUrl) : MD2_IMG_URL(`/Boss/${mobInfo.name}-Stand.png`);
|
||||||
mobInfo.minionImgUrl = null;
|
mobInfo.minionImgUrl = null;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -297,34 +300,58 @@ export class MD2Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public enterBossFight() {
|
public enterBossFight() {
|
||||||
|
|
||||||
this.msgBoxService.showInputbox('Boss Fight', 'Choose the boss', {
|
this.msgBoxService.showInputbox('Boss Fight', 'Choose the boss', {
|
||||||
inputType: 'dropdown',
|
inputType: 'dropdown',
|
||||||
dropDownOptions: [new DropDownOption('The Reaper', 'The Reaper'), new DropDownOption('Michael - The Corrupted Archangel', 'Michael - The Corrupted Archangel')]
|
dropDownOptions: this.bossInfos.map(b => new DropDownOption(b.id, b.name))
|
||||||
}).pipe(first()).subscribe(result => {
|
}).pipe(first()).subscribe(result => {
|
||||||
if (result) {
|
if (result) {
|
||||||
this.info.mobs = [];
|
this.info.mobs = [];
|
||||||
this.info.roamingMonsters = [];
|
this.info.roamingMonsters = [];
|
||||||
|
let bossInfo = this.bossInfos.find(b => b.id == result);
|
||||||
|
this.info.boss = new MobInfo(bossInfo);
|
||||||
|
|
||||||
if (result == 'The Reaper') {
|
this.info.boss.leaderImgUrl = !!this.info.boss.leaderImgUrl ? this.imgUrl(this.info.boss.leaderImgUrl) : this.imgUrl(`/Boss/${this.info.boss.name}-Stand.png`);
|
||||||
this.info.boss = new BossReaper(this);
|
|
||||||
} else {
|
let bossLevelInfo = bossInfo.mobLevelInfos.sort((a, b) => b.level - a.level)
|
||||||
this.info.boss = new BossMicheal(this);
|
.find(l => l.level <= Math.max(...this.info.heros.map(h => h.level)));
|
||||||
|
if (bossLevelInfo) {
|
||||||
|
this.info.boss.hp = bossLevelInfo.hpPerHero * this.info.heros.length;
|
||||||
|
this.info.boss.unitRemainHp = this.info.boss.hp;
|
||||||
|
this.info.boss.actions = bossLevelInfo.actions;
|
||||||
|
this.info.boss.attackInfos = [this.getAttackInfo(bossLevelInfo.attackInfo)];
|
||||||
|
let altAttackInfo = bossLevelInfo.alterAttackInfo;
|
||||||
|
if (altAttackInfo
|
||||||
|
&& (altAttackInfo.black > 0 || altAttackInfo.blue > 0 || altAttackInfo.green > 0 || altAttackInfo.orange > 0 || altAttackInfo.red > 0 || altAttackInfo.yellow > 0)
|
||||||
|
) {
|
||||||
|
this.info.boss.attackInfos.push(this.getAttackInfo(altAttackInfo));
|
||||||
|
}
|
||||||
|
this.info.boss.defenseInfo = bossLevelInfo.defenceInfo;
|
||||||
}
|
}
|
||||||
this.info.roamingMonsters = [];
|
this.info.roamingMonsters = [];
|
||||||
this.info.mobs = [];
|
this.info.mobs = [];
|
||||||
this.info.isBossFight = true;
|
this.info.isBossFight = true;
|
||||||
this.info.isBossFight = true;
|
|
||||||
this.info.boss.info.hp = this.info.boss.info.hpPerHero * this.info.heros.length;
|
|
||||||
this.info.boss.info.unitRemainHp = this.info.boss.info.hp;
|
|
||||||
this.refreshUI$.next();
|
this.refreshUI$.next();
|
||||||
this.info.boss.prepareForBossFight();
|
this.prepareForBossFight();
|
||||||
this.levelUpPhase(false);
|
this.levelUpPhase(false);
|
||||||
|
|
||||||
|
//Reset all heroes
|
||||||
|
let extraTokenName = this.info.boss.bossFightProfile.extraTokenName;
|
||||||
|
let extraTokenHtml = this.info.boss.bossFightProfile.extraTokenHtml;
|
||||||
|
let extraTokenName2 = this.info.boss.bossFightProfile.extraTokenName2;
|
||||||
|
let extraTokenHtml2 = this.info.boss.bossFightProfile.extraTokenHtml2;
|
||||||
this.heros.forEach(hero => {
|
this.heros.forEach(hero => {
|
||||||
hero.hp = hero.hpMaximum;
|
hero.hp = hero.hpMaximum;
|
||||||
hero.mp = hero.mpMaximum;
|
hero.mp = hero.mpMaximum;
|
||||||
hero.remainActions = 3;
|
hero.remainActions = 3;
|
||||||
hero.uiActivating = false;
|
hero.uiActivating = false;
|
||||||
hero.uiBossFight = true;
|
hero.uiBossFight = true;
|
||||||
|
hero.uiExtraTokenHtml = extraTokenHtml;
|
||||||
|
hero.uiExtraTokenName = extraTokenName;
|
||||||
|
hero.uiShowExtraToken = !!extraTokenName;
|
||||||
|
hero.uiShowExtraToken2 = !!extraTokenName2;
|
||||||
|
hero.uiExtraTokenHtml2 = extraTokenHtml2;
|
||||||
|
hero.uiExtraTokenName2 = extraTokenName2;
|
||||||
});
|
});
|
||||||
this.broadcastGameInfo();
|
this.broadcastGameInfo();
|
||||||
}
|
}
|
||||||
@ -332,9 +359,6 @@ export class MD2Service {
|
|||||||
});
|
});
|
||||||
//this.sendMsgboxMsg
|
//this.sendMsgboxMsg
|
||||||
}
|
}
|
||||||
public activateBoss() {
|
|
||||||
this.info.boss.activating();
|
|
||||||
}
|
|
||||||
public fileList(folderPath: string) {
|
public fileList(folderPath: string) {
|
||||||
return this.fileService.FileList('Images/MD2/' + folderPath);
|
return this.fileService.FileList('Images/MD2/' + folderPath);
|
||||||
}
|
}
|
||||||
@ -439,7 +463,7 @@ export class MD2Service {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public getTargetHerosByFilter(targetType: AttackTarget, onlyOne: boolean = false) {
|
public getTargetHerosByFilter(targetType: MobSkillTarget, onlyOne: boolean = false) {
|
||||||
return MD2Logic.getTargetHerosByFilter(this.info.heros, targetType, onlyOne);
|
return MD2Logic.getTargetHerosByFilter(this.info.heros, targetType, onlyOne);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -505,39 +529,39 @@ export class MD2Service {
|
|||||||
return `<span md2-icon='${String.fromCharCode(65 + icon)}' class='MD2Icon dice ${MD2Icon[icon].replace('Dice', '')} ${cssClass}'></span>`;
|
return `<span md2-icon='${String.fromCharCode(65 + icon)}' class='MD2Icon dice ${MD2Icon[icon].replace('Dice', '')} ${cssClass}'></span>`;
|
||||||
} else {
|
} else {
|
||||||
if (!cssClass) {
|
if (!cssClass) {
|
||||||
cssClass = 'g-height-25 mr-1';
|
cssClass = 'MD2IconImg g-height-25 mr-1';
|
||||||
}
|
}
|
||||||
//image based icons
|
//image based icons
|
||||||
switch (icon) {
|
switch (icon) {
|
||||||
|
|
||||||
case MD2Icon.HP_Color:
|
case MD2Icon.HP_Color:
|
||||||
return this.imgHtml('HeartIcon.png', cssClass);
|
return this.imgHtml('HeartIcon.png', cssClass, 'HP');
|
||||||
case MD2Icon.Mana_Color:
|
case MD2Icon.Mana_Color:
|
||||||
return this.imgHtml('ManaIcon.png', cssClass);
|
return this.imgHtml('ManaIcon.png', cssClass, 'Mana');
|
||||||
case MD2Icon.CorruptToken:
|
case MD2Icon.CorruptToken:
|
||||||
return this.imgHtml('Tokens/CorruptToken.png', cssClass);
|
return this.imgHtml('Tokens/CorruptToken.png', cssClass, 'Corruption Token');
|
||||||
case MD2Icon.TimeToken:
|
case MD2Icon.TimeToken:
|
||||||
return this.imgHtml('Tokens/TimeToken.png', cssClass);
|
return this.imgHtml('Tokens/TimeToken.png', cssClass, 'Time Token');
|
||||||
case MD2Icon.FireToken:
|
case MD2Icon.FireToken:
|
||||||
return this.imgHtml('Tokens/FireToken.png', cssClass);
|
return this.imgHtml('Tokens/FireToken.png', cssClass, 'Fire Token');
|
||||||
case MD2Icon.FrozenToken:
|
case MD2Icon.FrozenToken:
|
||||||
return this.imgHtml('Tokens/FrozenToken.png', cssClass);
|
return this.imgHtml('Tokens/FrozenToken.png', cssClass, 'Frozen Token');
|
||||||
case MD2Icon.TreasureToken:
|
case MD2Icon.TreasureToken:
|
||||||
return this.imgHtml('TreasureToken/Cover.png', cssClass);
|
return this.imgHtml('TreasureToken/Cover.png', cssClass, 'Treasure Token');
|
||||||
case MD2Icon.TreasureToken_Common:
|
case MD2Icon.TreasureToken_Common:
|
||||||
return this.imgHtml('TreasureToken/Common.png', cssClass);
|
return this.imgHtml('TreasureToken/Common.png', cssClass, 'Common Treasure Token');
|
||||||
case MD2Icon.TreasureToken_Rare:
|
case MD2Icon.TreasureToken_Rare:
|
||||||
return this.imgHtml('TreasureToken/Rare.png', cssClass);
|
return this.imgHtml('TreasureToken/Rare.png', cssClass, 'Rare Treasure Token');
|
||||||
case MD2Icon.TreasureToken_Epic:
|
case MD2Icon.TreasureToken_Epic:
|
||||||
return this.imgHtml('TreasureToken/Epic.png', cssClass);
|
return this.imgHtml('TreasureToken/Epic.png', cssClass, 'Epic Treasure Token');
|
||||||
case MD2Icon.TreasureToken_Legendary:
|
case MD2Icon.TreasureToken_Legendary:
|
||||||
return this.imgHtml('TreasureToken/Legendary.png', cssClass);
|
return this.imgHtml('TreasureToken/Legendary.png', cssClass, 'Legendary Treasure Token');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public imgHtml(imgPath: string, cssClass = 'g-height-25 mr-1') {
|
public imgHtml(imgPath: string, cssClass = 'g-height-25 mr-1', imgTitle = '') {
|
||||||
return `<img src='${this.imgUrl(imgPath)}' class='${cssClass}'>`;
|
return `<img src='${this.imgUrl(imgPath)}' class='${cssClass}' title='${imgTitle}'>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
public imgUrl(imgPath: string) {
|
public imgUrl(imgPath: string) {
|
||||||
@ -619,14 +643,7 @@ export class MD2Service {
|
|||||||
}
|
}
|
||||||
public broadcastGameInfo() {
|
public broadcastGameInfo() {
|
||||||
let parameters = {};
|
let parameters = {};
|
||||||
if (this.info.boss) {
|
|
||||||
this.info.boss.md2Service = undefined;
|
|
||||||
}
|
|
||||||
parameters['gameInfo'] = JSON.stringify(this.info);
|
parameters['gameInfo'] = JSON.stringify(this.info);
|
||||||
|
|
||||||
if (this.info.boss) {
|
|
||||||
this.info.boss.md2Service = this;
|
|
||||||
}
|
|
||||||
this.broadcastMessage('GameRoom', 'update', parameters);
|
this.broadcastMessage('GameRoom', 'update', parameters);
|
||||||
}
|
}
|
||||||
broadcastFetchGameInfo() {
|
broadcastFetchGameInfo() {
|
||||||
@ -650,8 +667,191 @@ export class MD2Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// #endregion Public Methods (27)
|
// #endregion Public Methods (27)
|
||||||
|
|
||||||
|
//#region Boss Fight
|
||||||
|
private bossActivatedTimes: number = 0;
|
||||||
|
activateBoss(): boolean {
|
||||||
|
this.bossActivatedTimes = this.info.boss.actions;
|
||||||
|
this.runBossAction();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
runBossAction() {
|
||||||
|
this.bossAction().pipe(first()).subscribe(result => {
|
||||||
|
this.bossActivatedTimes--;
|
||||||
|
if (this.bossActivatedTimes) {
|
||||||
|
this.runBossAction();
|
||||||
|
} else {
|
||||||
|
if (false == this.heros.some(h => h.remainActions > 0)) {
|
||||||
|
this.darknessPhase();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bossAction(): Observable<boolean> {
|
||||||
|
let actionBlackDice = 2;
|
||||||
|
let actionResult = new RollingBlackDice().roll(actionBlackDice);
|
||||||
|
let actionHtml = '';
|
||||||
|
let beenAttackedHero = [] as MD2HeroInfo[];
|
||||||
|
let bossAction: MD2MobSkill;
|
||||||
|
bossAction = this.info.boss.skills.find(s => s.type == MobSkillType.ActiveSkill && s.skillRoll == actionResult.claws);
|
||||||
|
|
||||||
|
return this.dlgService.open(BossActivationComponent, { context: { boss: this.info.boss, bossAction: bossAction, currentAction: this.bossActivatedTimes, allActions: this.info.boss.actions } }).onClose;
|
||||||
|
|
||||||
|
}
|
||||||
|
prepareForBossFight(): void {
|
||||||
|
this.heros.forEach(hero => {
|
||||||
|
hero.uiShowExtraToken = !!this.info.boss.bossFightProfile.extraTokenName;
|
||||||
|
hero.uiShowExtraToken2 = !!this.info.boss.bossFightProfile.extraTokenName2;
|
||||||
|
});
|
||||||
|
//init boss first round buff
|
||||||
|
this.bossDarknessPhase();
|
||||||
|
let prerequisiteHtml = this.info.boss.bossFightProfile.prerequisite;
|
||||||
|
//Detect prerequisiteHtml is empty or not,like <p></p>
|
||||||
|
if (prerequisiteHtml.trim() == '<p></p>') {
|
||||||
|
prerequisiteHtml = '';
|
||||||
|
}
|
||||||
|
if (prerequisiteHtml) {
|
||||||
|
prerequisiteHtml = this.skillParse(prerequisiteHtml, MobSkillTarget.Random);
|
||||||
|
this.msgBoxService.show('Prepare Boss Fight', {
|
||||||
|
text: prerequisiteHtml
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
bossDarknessPhase(): void {
|
||||||
|
this.info.bossRound++;
|
||||||
|
let roundBuff = this.info.boss.bossFightProfile.phaseBuffs.find(p => p.phase == this.info.bossRound);
|
||||||
|
if (roundBuff) {
|
||||||
|
this.info.boss.actions += roundBuff.extraAction || 0;
|
||||||
|
for (let i = 0; i < this.info.boss.attackInfos.length; i++) {
|
||||||
|
this.info.boss.attackInfos[i].black += roundBuff.extraAttackDice.black || 0;
|
||||||
|
this.info.boss.attackInfos[i].yellow += roundBuff.extraAttackDice.yellow || 0;
|
||||||
|
this.info.boss.attackInfos[i].orange += roundBuff.extraAttackDice.orange || 0;
|
||||||
|
this.info.boss.attackInfos[i].red += roundBuff.extraAttackDice.red || 0;
|
||||||
|
}
|
||||||
|
this.info.boss.defenseInfo.black += roundBuff.extraDefenceDice.black || 0;
|
||||||
|
this.info.boss.defenseInfo.yellow += roundBuff.extraDefenceDice.yellow || 0;
|
||||||
|
this.info.boss.defenseInfo.orange += roundBuff.extraDefenceDice.orange || 0;
|
||||||
|
this.info.boss.defenseInfo.red += roundBuff.extraDefenceDice.red || 0;
|
||||||
|
this.info.boss.hp += roundBuff.extraHp || 0;
|
||||||
|
this.info.boss.unitRemainHp += roundBuff.extraHp || 0;
|
||||||
|
this.info.boss.uiExtraTokenCount += roundBuff.extraTokenCount || 0;
|
||||||
|
this.info.boss.uiExtraTokenCount2 += roundBuff.extraTokenCount2 || 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
//#endregion Boss Fight
|
||||||
|
|
||||||
|
public skillParse(skillHtmlContent: string, targetRule: MobSkillTarget, onlyOneTarget: boolean = true) {
|
||||||
|
let targetHeros = MD2Logic.getTargetHerosByFilter(this.info.heros, targetRule, onlyOneTarget);
|
||||||
|
//if the skillHtmlContent contains ${Expression} replace it with the expression result
|
||||||
|
//Example: ${1+1} will be replaced with 2
|
||||||
|
//bossExtraTokenCount will be replaced with this.info.boss.uiExtraTokenCount
|
||||||
|
//bossExtraTokenCount2 will be replaced with this.info.boss.uiExtraTokenCount2
|
||||||
|
//targetHero.level will be replaced with the hero level
|
||||||
|
//targetHero.hp will be replaced with the hero hp
|
||||||
|
//targetHero.mp will be replaced with the hero mp
|
||||||
|
//targetHero.ap will be replaced with the hero ap
|
||||||
|
//targetHero.fireToken will be replaced with the hero fire token
|
||||||
|
//targetHero.frozenToken will be replaced with the hero frozen token
|
||||||
|
//targetHero.uiExtraTokenCount will be replaced with the hero extra token count
|
||||||
|
//targetHero.uiExtraTokenCount2 will be replaced with the hero extra token count2
|
||||||
|
|
||||||
|
//For example:
|
||||||
|
//${targetHero.level+bossExtraTokenCount} will be replaced with the number
|
||||||
|
//then calculate the result and replace the ${Expression} with the result
|
||||||
|
//Example: ${1+1} will be replaced with 2
|
||||||
|
//${3-1}
|
||||||
|
//${2*3}
|
||||||
|
//${2/3}
|
||||||
|
//${2%3}
|
||||||
|
|
||||||
|
|
||||||
|
// No target heroes found, still process boss tokens
|
||||||
|
let result = skillHtmlContent;
|
||||||
|
|
||||||
|
result = result.replace(/\bheroes.length\b/g, String(this.info?.heros?.length || 0));
|
||||||
|
|
||||||
|
if (result.includes('boss.') && this.info?.boss) {
|
||||||
|
// Replace boss tokens even if no heroes
|
||||||
|
result = result.replace(/\bboss.ExtraTokenCount\b/g, String(this.info?.boss?.uiExtraTokenCount || 0));
|
||||||
|
result = result.replace(/\bboss.ExtraTokenCount2\b/g, String(this.info?.boss?.uiExtraTokenCount2 || 0));
|
||||||
|
}
|
||||||
|
// Evaluate remaining expressions (if any numbers remain)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (result.includes('targetHero') && targetHeros && targetHeros.length > 0) {
|
||||||
|
|
||||||
|
// Use the first hero as targetHero for replacements
|
||||||
|
const targetHero = targetHeros[0];
|
||||||
|
let result = skillHtmlContent;
|
||||||
|
|
||||||
|
// Replace targetHero properties
|
||||||
|
result = result.replace(/\btargetHero\.name\b/g, String(targetHero?.heroFullName || 0));
|
||||||
|
result = result.replace(/\btargetHero\.level\b/g, String(targetHero?.level || 0));
|
||||||
|
result = result.replace(/\btargetHero\.hp\b/g, String(targetHero?.hp || 0));
|
||||||
|
result = result.replace(/\btargetHero\.mp\b/g, String(targetHero?.mp || 0));
|
||||||
|
result = result.replace(/\btargetHero\.ap\b/g, String(targetHero?.ap || 0));
|
||||||
|
result = result.replace(/\btargetHero\.fireToken\b/g, String(targetHero?.fireToken || 0));
|
||||||
|
result = result.replace(/\btargetHero\.frozenToken\b/g, String(targetHero?.frozenToken || 0));
|
||||||
|
// Map uiExtraTokenCount to extraToken and uiExtraTokenCount2 to extraToken2
|
||||||
|
result = result.replace(/\btargetHero\.uiExtraTokenCount\b/g, String(targetHero?.extraToken || 0));
|
||||||
|
result = result.replace(/\btargetHero\.uiExtraTokenCount2\b/g, String(targetHero?.extraToken2 || 0));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Evaluate expressions in ${...} format
|
||||||
|
result = this.evaluateExpressions(result);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private evaluateExpressions(content: string): string {
|
||||||
|
// Match ${expression} pattern
|
||||||
|
const expressionPattern = /\$\{([^}]+)\}/g;
|
||||||
|
|
||||||
|
return content.replace(expressionPattern, (match, expression) => {
|
||||||
|
try {
|
||||||
|
const sanitizedExpression = expression.trim();
|
||||||
|
|
||||||
|
// After placeholder replacement, expression should only contain numbers, operators, and spaces
|
||||||
|
// Check if expression still contains letters (variables that weren't replaced)
|
||||||
|
if (/[a-zA-Z_]/.test(sanitizedExpression)) {
|
||||||
|
// Variables weren't replaced, return original match
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate expression contains only safe mathematical characters
|
||||||
|
// Allow: numbers, decimal points, operators (+, -, *, /, %), parentheses, and spaces
|
||||||
|
if (!/^[0-9+\-*/().%\s]+$/.test(sanitizedExpression)) {
|
||||||
|
// Contains unsafe characters, return original
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Evaluate the expression safely using Function constructor
|
||||||
|
// This is safer than eval() as it runs in strict mode
|
||||||
|
const result = Function('"use strict"; return (' + sanitizedExpression + ')')();
|
||||||
|
|
||||||
|
// Check if result is a valid number
|
||||||
|
if (typeof result === 'number' && !isNaN(result) && isFinite(result)) {
|
||||||
|
return String(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invalid result, return original match
|
||||||
|
return match;
|
||||||
|
} catch (error) {
|
||||||
|
// If evaluation fails for any reason, return the original match
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class MD2GameInfo {
|
export class MD2GameInfo {
|
||||||
@ -666,8 +866,8 @@ export class MD2GameInfo {
|
|||||||
|
|
||||||
this.mobs = this.mobs.map(m => new MobInfo(m));
|
this.mobs = this.mobs.map(m => new MobInfo(m));
|
||||||
this.roamingMonsters = this.roamingMonsters.map(m => new MobInfo(m));
|
this.roamingMonsters = this.roamingMonsters.map(m => new MobInfo(m));
|
||||||
if (this.boss && this.boss.info) {
|
if (this.boss) {
|
||||||
this.boss.info = new MobInfo(this.boss.info);
|
this.boss = new MobInfo(this.boss);
|
||||||
}
|
}
|
||||||
this.heros = this.heros.map(h => new MD2HeroInfo(h));
|
this.heros = this.heros.map(h => new MD2HeroInfo(h));
|
||||||
}
|
}
|
||||||
@ -679,7 +879,8 @@ export class MD2GameInfo {
|
|||||||
public heros: MD2HeroInfo[] = [];
|
public heros: MD2HeroInfo[] = [];
|
||||||
public disconnectedHeroes: MD2HeroInfo[] = [];
|
public disconnectedHeroes: MD2HeroInfo[] = [];
|
||||||
public round = 1;
|
public round = 1;
|
||||||
|
public bossRound = 0;
|
||||||
public roundPhase: RoundPhase = RoundPhase.HeroPhase;
|
public roundPhase: RoundPhase = RoundPhase.HeroPhase;
|
||||||
public showAttackBtn: boolean = false;
|
public showAttackBtn: boolean = false;
|
||||||
public boss: IBossFight;
|
public boss: MobInfo;
|
||||||
}
|
}
|
||||||
@ -30,3 +30,7 @@ a,
|
|||||||
input {
|
input {
|
||||||
touch-action: manipulation;
|
touch-action: manipulation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
k-editor-content p {
|
||||||
|
line-height: 1rem;
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user