685 lines
25 KiB
TypeScript
685 lines
25 KiB
TypeScript
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 { first, map, reduce } from "rxjs/operators";
|
|
import { NbDialogService, NbThemeService } from '@nebular/theme';
|
|
import { Subject } from 'rxjs';
|
|
import { BossMicheal, BossReaper, IBossFight } from '../../games/massive-darkness2/massive-darkness2.model.boss';
|
|
import { ADIcon, MessageBoxConfig } from '../../ui/alert-dlg/alert-dlg.model';
|
|
import { NumberUtils } from '../../utilities/number-utils';
|
|
import { StringUtils } from '../../utilities/string-utils';
|
|
import { FileService } from '../file.service';
|
|
import { GameRoomService } from '../game-room.service';
|
|
import { LoginUserService } from '../login-user.service';
|
|
import { MsgBoxService } from '../msg-box.service';
|
|
import { SignalRService, SignalRClient, SignalRMessage } from '../signal-r.service';
|
|
import { MD2Logic } from '../../games/massive-darkness2/massive-darkness2.logic';
|
|
import { MD2InitService } from './md2-init.service';
|
|
import { ArrayUtils } from '../../utilities/array-utils';
|
|
import { DropDownOption } from '../../entity/dropDownOption';
|
|
import { GameBundle, MD2DiceSet, MD2MobInfo } from '../../games/massive-darkness2/massive-darkness2.db.model';
|
|
import { environment } from '../../../environments/environment';
|
|
|
|
|
|
const MD2_IMG_URL = (id: string = null) => { return `${environment.apiUrl}/Files/Images/MD2/Mobs${(id ? `${encodeURI(id)}` : '')}` };
|
|
@Injectable({
|
|
providedIn: 'root'
|
|
})
|
|
export class MD2Service {
|
|
// #region Properties (24)
|
|
|
|
private _highestPlayerLevel: number = 1;
|
|
private _playerAmount: number = 2;
|
|
public specialRule: MD2EnemyPhaseSpecialInfo;
|
|
public info: MD2GameInfo;
|
|
public playerHero: MD2HeroInfo;
|
|
public mobInfos: MD2MobInfo[] = [];
|
|
public roamingMobInfos: MD2MobInfo[] = [];
|
|
public mobDeck: DrawingBag<MobInfo>;
|
|
public roamingMobDeck: DrawingBag<MobInfo>;
|
|
public treasureBag: DrawingBag<TreasureItem> = new DrawingBag<TreasureItem>();
|
|
|
|
public darknessPhaseRule: IDarknessPhaseRule;
|
|
public enemyPhaseMobs: MobInfo[];
|
|
public enemyPhaseSubject = new Subject<MobInfo>();
|
|
public initialized = false;
|
|
public mobBeenKilledSubject = new Subject<MobInfo>();
|
|
|
|
public refreshUI$: Subject<void> = new Subject<void>();
|
|
public refreshTreasureBagSubject = new Subject<DrawingBag<TreasureItem>>();
|
|
|
|
public heroAttackingSubject = new Subject<MD2HeroInfo>();
|
|
|
|
|
|
public get heros() {
|
|
return this.info.heros;
|
|
}
|
|
public get roamingMonsters() {
|
|
return this.info.roamingMonsters;
|
|
}
|
|
public get mobs() {
|
|
return this.info.mobs;
|
|
}
|
|
public get allRoamingMonsterInfos() {
|
|
return this.roamingMobInfos;
|
|
}
|
|
public get allMobInfos() {
|
|
return this.mobInfos;
|
|
}
|
|
|
|
// #endregion Properties (24)
|
|
|
|
// #region Constructors (1)
|
|
constructor(
|
|
public fileService: FileService,
|
|
public msgBoxService: MsgBoxService,
|
|
public gameRoomService: GameRoomService,
|
|
public loginUserService: LoginUserService,
|
|
public signalRService: SignalRService,
|
|
public dlgService: NbDialogService,
|
|
public themeService: NbThemeService
|
|
) {
|
|
this.darknessPhaseRule = new CoreGameDarknessPhaseRule();
|
|
this.info = new MD2GameInfo();
|
|
this.darknessPhaseRule.addTreasureToken.subscribe(treasureType => {
|
|
this.addTreasure(treasureType, 1);
|
|
});
|
|
this.specialRule = new MD2EnemyPhaseSpecialInfo();
|
|
}
|
|
|
|
// #endregion Constructors (1)
|
|
// #region Public Getters And Setters (5)
|
|
|
|
public get highestPlayerLevel(): number {
|
|
if (this.heros.length > 0) {
|
|
return Math.max(...this.heros.map(h => h.level));
|
|
} else {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
public get playerAmount(): number {
|
|
if (this.heros.length > 0) {
|
|
return this.heros.length;
|
|
} else {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
public get currentActivateHero(): MD2HeroInfo {
|
|
return this.info.heros.find(h => h.uiActivating);
|
|
}
|
|
|
|
|
|
|
|
|
|
// #endregion Public Getters And Setters (5)
|
|
|
|
// #region Public Methods (27)
|
|
|
|
|
|
public addTreasure(type: TreasureType, amount: number = 1) {
|
|
this.treasureBag.AddItem(new TreasureItem(type, amount));
|
|
this.refreshTreasureBagSubject.next(this.treasureBag);
|
|
}
|
|
|
|
public darknessPhase() {
|
|
this.heros.forEach(hero => {
|
|
hero.remainActions = 3;
|
|
this.broadcastHeroInfoToOwner(hero);
|
|
});
|
|
this.info.roundPhase = RoundPhase.HeroPhase;
|
|
if (!this.info.isBossFight) {
|
|
this.info.round++;
|
|
if (this.darknessPhaseRule.runDarknessPhase()) {
|
|
this.msgBoxService.show(`${NumberUtils.Ordinal(this.info.round)} Hero Phase`, { icon: ADIcon.INFO });
|
|
}
|
|
} else {
|
|
this.info.boss.darknessPhase();
|
|
this.msgBoxService.show(`Boss Fight - ${NumberUtils.Ordinal(this.info.boss.rounds)} Hero Phase`, { icon: ADIcon.INFO });
|
|
}
|
|
|
|
//this.runNextPhase();
|
|
}
|
|
|
|
public spawnMob(isRoamingMonster: boolean, mobName: string = null) {
|
|
let mobDeck = null as DrawingBag<MobInfo>;
|
|
let level = 1;
|
|
if (this.highestPlayerLevel < 3) {
|
|
} else if (this.highestPlayerLevel < 5) {
|
|
level = 3;
|
|
} else {
|
|
level = 5;
|
|
}
|
|
if (isRoamingMonster) {
|
|
mobDeck = this.roamingMobDeck;
|
|
} else {
|
|
mobDeck = this.mobDeck;
|
|
}
|
|
|
|
if (mobDeck.drawingItems.filter(m => (m as MobInfo).level == level)
|
|
.map(d => d.drawingWeight).reduce((a, b) => a + b, 0) == 0) {
|
|
mobDeck.RestoreRemoveItems();
|
|
}
|
|
|
|
let newSpawnMob = null as MobInfo;
|
|
|
|
if (mobName) {
|
|
newSpawnMob = new MobInfo(mobDeck.DrawAndRemove(1, m => m.level == level && m.name == mobName)[0]);
|
|
} else {
|
|
newSpawnMob = new MobInfo(mobDeck.DrawAndRemove(1, m => m.level == level)[0]);
|
|
}
|
|
|
|
let exitingMob = isRoamingMonster ? this.roamingMonsters.find(m => m.name == newSpawnMob.name) : this.mobs.find(m => m.name == newSpawnMob.name);
|
|
|
|
if (exitingMob) {
|
|
exitingMob.level = newSpawnMob.level;
|
|
exitingMob.hp = newSpawnMob.hp;
|
|
exitingMob.imageUrl = newSpawnMob.imageUrl;
|
|
exitingMob.attackInfos = newSpawnMob.attackInfos;
|
|
exitingMob.defenseInfo = newSpawnMob.defenseInfo;
|
|
exitingMob.skills = newSpawnMob.skills;
|
|
} else {
|
|
if (isRoamingMonster) {
|
|
newSpawnMob = this.generateMob(isRoamingMonster, newSpawnMob.name, level);
|
|
this.roamingMonsters.push(newSpawnMob);
|
|
} else {
|
|
newSpawnMob = this.generateMob(isRoamingMonster, newSpawnMob.name, level);
|
|
this.mobs.push(newSpawnMob);
|
|
}
|
|
|
|
newSpawnMob.carriedTreasure = this.treasureBag.DrawAndRemove(newSpawnMob.rewardTokens);
|
|
|
|
this.refreshTreasureBagSubject.next(this.treasureBag);
|
|
}
|
|
newSpawnMob.imageUrl = this.mobImage(newSpawnMob.name, newSpawnMob.level, isRoamingMonster);
|
|
|
|
return { exitingMob, mob: newSpawnMob };
|
|
}
|
|
private generateMob(isRoamingMonster: boolean, mobName: string, level: number) {
|
|
let dbMobInfo = isRoamingMonster ? this.allRoamingMonsterInfos.find(m => m.name == mobName) : this.allMobInfos.find(m => m.name == mobName);
|
|
let levelInfo = dbMobInfo.mobLevelInfos.find(l => l.level <= level);
|
|
let skills = dbMobInfo.skills.filter(s => s.level <= level).sort((a, b) => b.seq - a.seq);
|
|
//Distinct by SkillType and Skill Name, take the one with the highest level
|
|
|
|
let mobInfo = new MobInfo({
|
|
name: dbMobInfo.name,
|
|
hp: levelInfo.hpPerHero,
|
|
hpPerHero: levelInfo.hpPerHero,
|
|
level: level,
|
|
rewardTokens: levelInfo.rewardTokens,
|
|
defenseInfo: levelInfo.defenceInfo,
|
|
type: dbMobInfo.type,
|
|
skills: []
|
|
});
|
|
|
|
for (let i = 0; i < skills.length; i++) {
|
|
const skill = skills[i];
|
|
if (!mobInfo.skills.find(s => s.type == skill.type && s.name == skill.name)) {
|
|
mobInfo.skills.push(skill);
|
|
}
|
|
}
|
|
mobInfo.skills = mobInfo.skills.sort((a, b) => b.seq - a.seq);
|
|
switch (dbMobInfo.type) {
|
|
case MobType.Mob:
|
|
mobInfo.leaderImgUrl = 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`);
|
|
break;
|
|
case MobType.RoamingMonster:
|
|
mobInfo.leaderImgUrl = mobInfo.leaderImgUrl || MD2_IMG_URL(`/${GameBundle[dbMobInfo.from]}/RoamingMonsters/${mobInfo.name}/Stand.png`);
|
|
mobInfo.minionImgUrl = null;
|
|
break;
|
|
case MobType.Boss:
|
|
mobInfo.leaderImgUrl = mobInfo.leaderImgUrl || MD2_IMG_URL(`/Boss/${mobInfo.name}-Stand.png`);
|
|
mobInfo.minionImgUrl = null;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
mobInfo.fixedCarriedTreasure = [];
|
|
levelInfo.fixedRareTreasure > 0 && mobInfo.fixedCarriedTreasure.push(new TreasureItem(TreasureType.Rare, levelInfo.fixedRareTreasure));
|
|
levelInfo.fixedEpicTreasure > 0 && mobInfo.fixedCarriedTreasure.push(new TreasureItem(TreasureType.Epic, levelInfo.fixedEpicTreasure));
|
|
levelInfo.fixedLegendTreasure > 0 && mobInfo.fixedCarriedTreasure.push(new TreasureItem(TreasureType.Legendary, levelInfo.fixedLegendTreasure));
|
|
|
|
|
|
switch (dbMobInfo.type) {
|
|
case MobType.Mob:
|
|
//Maybe add more mobs later
|
|
mobInfo.mobAmount = this.playerAmount + 1;
|
|
break;
|
|
case MobType.RoamingMonster:
|
|
case MobType.Boss:
|
|
mobInfo.hp = levelInfo.hpPerHero * this.playerAmount;
|
|
mobInfo.unitRemainHp = mobInfo.hp;
|
|
mobInfo.mobAmount = 0;
|
|
mobInfo.attackInfos = [this.getAttackInfo(levelInfo.attackInfo)];
|
|
let altAttackInfo = levelInfo.alterAttackInfo;
|
|
if (altAttackInfo
|
|
&& (altAttackInfo.black > 0 || altAttackInfo.blue > 0 || altAttackInfo.green > 0 || altAttackInfo.orange > 0 || altAttackInfo.red > 0 || altAttackInfo.yellow > 0)
|
|
) {
|
|
mobInfo.attackInfos.push(this.getAttackInfo(altAttackInfo));
|
|
}
|
|
break;
|
|
}
|
|
return mobInfo;
|
|
}
|
|
private getAttackInfo(attackInfo: MD2DiceSet): AttackInfo {
|
|
return new AttackInfo(attackInfo.type as unknown as MD2Icon, attackInfo.yellow, attackInfo.orange, attackInfo.red, attackInfo.black);
|
|
}
|
|
public enemyPhase(triggerSpecialRule: boolean = true) {
|
|
//this.msgBoxService
|
|
//Draw a special rule
|
|
|
|
this.enemyPhaseMobs = this.roamingMonsters.concat(this.mobs);
|
|
|
|
if (this.mobs.length > 0 && triggerSpecialRule) {
|
|
let specialRuleDrawingBag = new DrawingBag<MD2EnemyPhaseSpecialRule>(this.specialRule.specialRules);
|
|
let specialRule = specialRuleDrawingBag.Draw(1)[0];
|
|
this.specialRule.specialRule = specialRule;
|
|
if (specialRule.description) {
|
|
this.themeService.changeTheme('dark');
|
|
this.msgBoxService.show(specialRule.title, { text: specialRule.description, icon: ADIcon.WARNING })
|
|
.pipe(first()).subscribe(result => {
|
|
this.enemyPhase(false);
|
|
});
|
|
return;
|
|
} else {
|
|
this.specialRule.specialRule = null;
|
|
}
|
|
}
|
|
|
|
if (this.enemyPhaseMobs.length > 0) {
|
|
this.enemyPhaseMobs = ArrayUtils.Shuffle(this.enemyPhaseMobs);
|
|
//this.showEnemyPhaseAction();
|
|
this.enemyPhaseSubject.next(this.enemyPhaseMobs[0]);
|
|
} else {
|
|
this.runNextPhase();
|
|
}
|
|
}
|
|
|
|
public enterBossFight() {
|
|
this.msgBoxService.showInputbox('Boss Fight', 'Choose the boss', {
|
|
inputType: 'dropdown',
|
|
dropDownOptions: [new DropDownOption('The Reaper', 'The Reaper'), new DropDownOption('Michael - The Corrupted Archangel', 'Michael - The Corrupted Archangel')]
|
|
}).pipe(first()).subscribe(result => {
|
|
if (result) {
|
|
this.info.mobs = [];
|
|
this.info.roamingMonsters = [];
|
|
|
|
if (result == 'The Reaper') {
|
|
this.info.boss = new BossReaper(this);
|
|
} else {
|
|
this.info.boss = new BossMicheal(this);
|
|
}
|
|
this.info.roamingMonsters = [];
|
|
this.info.mobs = [];
|
|
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.info.boss.prepareForBossFight();
|
|
this.levelUpPhase(false);
|
|
this.heros.forEach(hero => {
|
|
hero.hp = hero.hpMaximum;
|
|
hero.mp = hero.mpMaximum;
|
|
hero.remainActions = 3;
|
|
hero.uiActivating = false;
|
|
hero.uiBossFight = true;
|
|
});
|
|
this.broadcastGameInfo();
|
|
}
|
|
|
|
});
|
|
//this.sendMsgboxMsg
|
|
}
|
|
public activateBoss() {
|
|
this.info.boss.activating();
|
|
}
|
|
public fileList(folderPath: string) {
|
|
return this.fileService.FileList('Images/MD2/' + folderPath);
|
|
}
|
|
|
|
public heroFullName(hero: MD2HeroInfo) {
|
|
return MD2Logic.heroFullName(hero);
|
|
}
|
|
|
|
public levelUpPhase(runNextPhase: boolean = true) {
|
|
for (let i = 0; i < this.heros.length; i++) {
|
|
const hero = this.heros[i];
|
|
let levelUpInfo = MD2Rules.checkCoreGameLevelup(hero.level, hero.exp);
|
|
while (levelUpInfo != null) {
|
|
hero.level = levelUpInfo.level;
|
|
hero.hp += levelUpInfo.extraHp;
|
|
hero.hpMaximum += levelUpInfo.extraHp;
|
|
hero.mp += levelUpInfo.extraMp;
|
|
hero.mpMaximum += levelUpInfo.extraMp;
|
|
hero.exp = levelUpInfo.currentExp;
|
|
this.broadcastHeroInfoToOwner(hero);
|
|
this.sendMsgboxMsg(hero.playerInfo.signalRClientId, { title: `Level Up Lv.${hero.level}`, text: 'Please do a skill level up!', icon: ADIcon.INFO });
|
|
levelUpInfo = MD2Rules.checkCoreGameLevelup(hero.level, hero.exp);
|
|
}
|
|
}
|
|
this.refreshUI$.next();
|
|
if (runNextPhase) {
|
|
this.runNextPhase();
|
|
}
|
|
}
|
|
|
|
public mobImage(name: string, level: number, isRoamingMonsters: boolean) {
|
|
if (level < 3) {
|
|
level = 1;
|
|
} else if (level < 5) {
|
|
level = 2;
|
|
} else {
|
|
level = 3;
|
|
}
|
|
if (isRoamingMonsters) {
|
|
return this.imgUrl(`Mobs/CoreGame/RoamingMonsters/${name}/${level}.png`);
|
|
} else {
|
|
return this.imgUrl(`Mobs/CoreGame/Mobs/${name}/${level}.png`);
|
|
}
|
|
}
|
|
|
|
public playerJoin(hero: MD2HeroInfo) {
|
|
hero.playerInfo = this.gameRoomService.currentPlayer();
|
|
hero.level = 1;
|
|
hero.hp = hero.hpMaximum;
|
|
hero.mp = hero.mpMaximum;
|
|
hero.exp = 0;
|
|
this.playerHero = hero;
|
|
// let message = {
|
|
// receiver: { isGroup: true, sessionId: this.gameRoomService.gameRoomId } as SignalRSession,
|
|
// from: { isGroup: false, sessionId: this.loginUserService.userAccess.signalRSessionId },
|
|
// actionType: 'hero',
|
|
// actionName: 'join',
|
|
|
|
// } as SignalRMessage;
|
|
// message.parameters = { hero: JSON.stringify(hero) };
|
|
// this.gameRoomService.sendMessage(message).pipe(first()).subscribe(result => {
|
|
// });
|
|
}
|
|
|
|
|
|
public runNextPhase() {
|
|
this.info.roundPhase++;
|
|
switch (this.info.roundPhase) {
|
|
case RoundPhase.HeroPhase:
|
|
//HeroPhase will be handled in the darkness phase
|
|
// this.heros.forEach(hero => {
|
|
// hero.remainActions = 3;
|
|
// this.broadcastHeroInfoToOwner(hero);
|
|
// });
|
|
break;
|
|
case RoundPhase.EnemyPhase:
|
|
this.enemyPhase();
|
|
break;
|
|
case RoundPhase.LevelUpPhase:
|
|
this.levelUpPhase();
|
|
break;
|
|
case RoundPhase.DarknessPhase:
|
|
this.darknessPhase();
|
|
this.themeService.changeTheme('default');
|
|
break;
|
|
default: break;
|
|
}
|
|
let parameters = {};
|
|
parameters['phase'] = this.info.roundPhase;
|
|
this.broadcastMessage('roundPhase', '', parameters);
|
|
}
|
|
|
|
public sendMsgboxMsg(playerSessionId: string, msg: Partial<MessageBoxConfig>) {
|
|
let message = {
|
|
receiver: { isGroup: false, connectionId: playerSessionId } as SignalRClient,
|
|
from: { isGroup: false, connectionId: this.loginUserService.userAccess.signalRConnectionId },
|
|
actionType: 'message',
|
|
actionName: 'popup',
|
|
} as SignalRMessage;
|
|
message.parameters = { msg: JSON.stringify(msg) };
|
|
this.gameRoomService.sendMessage(message).pipe(first()).subscribe(result => {
|
|
});
|
|
}
|
|
|
|
public getTargetHerosByFilter(targetType: AttackTarget, onlyOne: boolean = false) {
|
|
return MD2Logic.getTargetHerosByFilter(this.info.heros, targetType, onlyOne);
|
|
}
|
|
|
|
public getTargetHerosHtml(beenAttackedHero: MD2HeroInfo[]) {
|
|
return MD2Logic.getTargetHerosHtml(beenAttackedHero);
|
|
}
|
|
|
|
public drawingHealFountain() {
|
|
let result = new DrawingBag<DrawingItem>([new DrawingItem('Heal Fountain', '3 HP', '', 2), new DrawingItem('Heal Fountain', '4 HP', '', 1), new DrawingItem('Heal Fountain', 'Full HP', '', 1)])
|
|
.Draw(1)[0];
|
|
switch (result.description) {
|
|
case '3 HP':
|
|
this.currentActivateHero.hp = Math.min(this.currentActivateHero.hp + 3, this.currentActivateHero.hpMaximum);
|
|
break;
|
|
case '4 HP':
|
|
this.currentActivateHero.hp = Math.min(this.currentActivateHero.hp + 4, this.currentActivateHero.hpMaximum);
|
|
break;
|
|
case 'Full HP':
|
|
this.currentActivateHero.hp = this.currentActivateHero.hpMaximum;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
this.broadcastHeroInfoToAll(this.currentActivateHero, true);
|
|
//this.broadcastHeroInfoToOwner(this.currentActivateHero);
|
|
this.msgBoxService.show(
|
|
this.imgHtml('/Fountain/Cover.png', '')
|
|
, { text: `${this.currentActivateHero.heroFullName} Recovered ${result.description}.` });
|
|
}
|
|
|
|
public openTreasureChest() {
|
|
let result = new DrawingBag<DrawingItem>([
|
|
new DrawingItem('Common', `${this.treasureImageHtml(TreasureType.Common)} x 2`, '', 10),
|
|
new DrawingItem('Open Treasure Chest', `${this.treasureImageHtml(TreasureType.Rare)} x 2`, '', 5),
|
|
])
|
|
.Draw(1)[0];
|
|
|
|
this.msgBoxService.show(
|
|
this.imgHtml('/TreasureChest/SmallTresureChest.jpg', ''), { text: `${this.currentActivateHero.heroFullName} gets ${result.description}.` });
|
|
}
|
|
public openGreatTreasureChest() {
|
|
let result = new DrawingBag<DrawingItem>([
|
|
new DrawingItem('Common', `${this.treasureImageHtml(TreasureType.Rare)} x 3`, '', 3),
|
|
new DrawingItem('Open Treasure Chest', `${this.treasureImageHtml(TreasureType.Epic)} x 3`, '', 1),
|
|
]).Draw(1)[0];
|
|
|
|
this.msgBoxService.show(
|
|
this.imgHtml('/TreasureChest/BigTresureChest.png', ''), { text: `${this.currentActivateHero.heroFullName} gets ${result.description}.` });
|
|
}
|
|
|
|
public iconHtml(icon: MD2Icon, cssClass = '') {
|
|
|
|
|
|
if (icon == MD2Icon.Fire) {
|
|
cssClass += ' g-color-google-plus ';
|
|
}
|
|
if (icon == MD2Icon.Frost || icon == MD2Icon.Mana) {
|
|
cssClass += ' g-color-aqua ';
|
|
}
|
|
if (icon < MD2Icon.RedDice) {
|
|
return `<span md2-icon='${String.fromCharCode(65 + icon)}' class='MD2Icon ${cssClass}'>${String.fromCharCode(65 + icon)}</span>`
|
|
} else if (icon < MD2Icon.TreasureToken) {
|
|
return `<span md2-icon='${String.fromCharCode(65 + icon)}' class='MD2Icon dice ${MD2Icon[icon].replace('Dice', '')} ${cssClass}'></span>`;
|
|
} else {
|
|
if (!cssClass) {
|
|
cssClass = 'g-height-25 mr-1';
|
|
}
|
|
//image based icons
|
|
switch (icon) {
|
|
|
|
case MD2Icon.HP_Color:
|
|
return this.imgHtml('HeartIcon.png', cssClass);
|
|
case MD2Icon.Mana_Color:
|
|
return this.imgHtml('ManaIcon.png', cssClass);
|
|
case MD2Icon.CorruptToken:
|
|
return this.imgHtml('Tokens/CorruptToken.png', cssClass);
|
|
case MD2Icon.TimeToken:
|
|
return this.imgHtml('Tokens/TimeToken.png', cssClass);
|
|
case MD2Icon.FireToken:
|
|
return this.imgHtml('Tokens/FireToken.png', cssClass);
|
|
case MD2Icon.FrozenToken:
|
|
return this.imgHtml('Tokens/FrozenToken.png', cssClass);
|
|
case MD2Icon.TreasureToken:
|
|
return this.imgHtml('TreasureToken/Cover.png', cssClass);
|
|
case MD2Icon.TreasureToken_Common:
|
|
return this.imgHtml('TreasureToken/Common.png', cssClass);
|
|
case MD2Icon.TreasureToken_Rare:
|
|
return this.imgHtml('TreasureToken/Rare.png', cssClass);
|
|
case MD2Icon.TreasureToken_Epic:
|
|
return this.imgHtml('TreasureToken/Epic.png', cssClass);
|
|
case MD2Icon.TreasureToken_Legendary:
|
|
return this.imgHtml('TreasureToken/Legendary.png', cssClass);
|
|
}
|
|
}
|
|
}
|
|
|
|
public imgHtml(imgPath: string, cssClass = 'g-height-25 mr-1') {
|
|
return `<img src='${this.imgUrl(imgPath)}' class='${cssClass}'>`;
|
|
}
|
|
|
|
public imgUrl(imgPath: string) {
|
|
return this.fileService.ImageUrl('MD2/' + imgPath);
|
|
}
|
|
public treasureImage(type: TreasureType) {
|
|
return this.imgUrl(`TreasureToken/${TreasureType[type]}.png`);
|
|
}
|
|
public treasureImageHtml(type: TreasureType) {
|
|
return this.imgHtml(`TreasureToken/${TreasureType[type]}.png`, 'g-height-40 mr-1');
|
|
}
|
|
|
|
public broadcastAllHeroInfoToAll() {
|
|
let message = {
|
|
receiver: { isGroup: true, connectionId: this.gameRoomService.gameRoomId } as SignalRClient,
|
|
from: { isGroup: false, connectionId: this.loginUserService.userAccess.signalRConnectionId },
|
|
actionType: 'heroes',
|
|
actionName: 'updateAll',
|
|
} as SignalRMessage;
|
|
message.parameters = { heros: JSON.stringify(this.info.heros) };
|
|
this.gameRoomService.sendMessage(message).pipe(first()).subscribe(result => {
|
|
});
|
|
this.broadcastMobsInfo();
|
|
}
|
|
|
|
public broadcastHeroAction(action: string, extraValue: any = null) {
|
|
let parameters = {};
|
|
parameters['tabId'] = this.loginUserService.sessionTabId;
|
|
parameters['extraValue'] = JSON.stringify(extraValue);
|
|
this.broadcastMessage('heroAction', action, parameters);
|
|
}
|
|
|
|
public broadcastHeroInfoToAll(hero: MD2HeroInfo, fromDashboard: boolean = false) {
|
|
let message = {
|
|
receiver: { isGroup: true, connectionId: this.gameRoomService.gameRoomId } as SignalRClient,
|
|
from: { isGroup: fromDashboard, connectionId: fromDashboard ? this.gameRoomService.gameRoomId : hero.playerInfo.signalRClientId },
|
|
actionType: 'hero',
|
|
actionName: 'update',
|
|
} as SignalRMessage;
|
|
message.parameters = { hero: JSON.stringify(hero) };
|
|
this.gameRoomService.sendMessage(message).pipe(first()).subscribe(result => {
|
|
});
|
|
}
|
|
|
|
public broadcastHeroInfoToOwner(hero: MD2HeroInfo) {
|
|
let message = {
|
|
receiver: { isGroup: false, connectionId: hero.playerInfo.signalRClientId } as SignalRClient,
|
|
from: { isGroup: true, connectionId: this.gameRoomService.gameRoomId },
|
|
actionType: 'hero',
|
|
actionName: 'updateMyHero',
|
|
} as SignalRMessage;
|
|
message.parameters = { hero: JSON.stringify(hero) };
|
|
this.gameRoomService.sendMessage(message).pipe(first()).subscribe(result => {
|
|
});
|
|
}
|
|
|
|
/**
|
|
* `sessionId` = null means broadcast to all
|
|
*/
|
|
public broadcastMessage(actionType: string,
|
|
actionName: string,
|
|
parameters: { [key: string]: string; } = {},
|
|
sessionId: string = null) {
|
|
let message = {
|
|
receiver: { isGroup: !sessionId, connectionId: sessionId } as SignalRClient,
|
|
from: { isGroup: false, connectionId: this.loginUserService.userAccess.signalRConnectionId },
|
|
actionType: actionType,
|
|
actionName: actionName,
|
|
parameters: parameters
|
|
} as SignalRMessage;
|
|
|
|
if (sessionId == null) {
|
|
message.receiver = { isGroup: true, connectionId: this.gameRoomService.gameRoomId } as SignalRClient
|
|
} else {
|
|
message.receiver = { isGroup: false, connectionId: this.gameRoomService.gameRoomId } as SignalRClient
|
|
}
|
|
this.gameRoomService.sendMessage(message).pipe(first()).subscribe(result => {
|
|
});
|
|
}
|
|
public broadcastGameInfo() {
|
|
let parameters = {};
|
|
if (this.info.boss) {
|
|
this.info.boss.md2Service = undefined;
|
|
}
|
|
parameters['gameInfo'] = JSON.stringify(this.info);
|
|
|
|
if (this.info.boss) {
|
|
this.info.boss.md2Service = this;
|
|
}
|
|
this.broadcastMessage('GameRoom', 'update', parameters);
|
|
}
|
|
broadcastFetchGameInfo() {
|
|
this.broadcastMessage('GameRoom', 'getGameInfo', {});
|
|
}
|
|
public broadcastRoundPhase() {
|
|
let parameters = {};
|
|
parameters['phase'] = JSON.stringify(this.info.roundPhase);
|
|
this.broadcastMessage('GameRoom', 'phase', parameters);
|
|
}
|
|
|
|
public broadcastMobsInfo() {
|
|
let parameters = {};
|
|
parameters['roamingMonsters'] = JSON.stringify(this.info.roamingMonsters);
|
|
parameters['mobs'] = JSON.stringify(this.info.mobs);
|
|
this.broadcastMessage('mobs', 'update', parameters);
|
|
}
|
|
|
|
public broadcastMyHeroInfo() {
|
|
this.broadcastHeroInfoToAll(this.playerHero);
|
|
}
|
|
|
|
|
|
// #endregion Public Methods (27)
|
|
|
|
}
|
|
|
|
export class MD2GameInfo {
|
|
/**
|
|
*
|
|
*/
|
|
constructor(
|
|
config: Partial<MD2GameInfo> = undefined
|
|
) {
|
|
if (config) {
|
|
Object.assign(this, config);
|
|
|
|
this.mobs = this.mobs.map(m => new MobInfo(m));
|
|
this.roamingMonsters = this.roamingMonsters.map(m => new MobInfo(m));
|
|
if (this.boss && this.boss.info) {
|
|
this.boss.info = new MobInfo(this.boss.info);
|
|
}
|
|
this.heros = this.heros.map(h => new MD2HeroInfo(h));
|
|
}
|
|
|
|
}
|
|
public isBossFight: boolean = false;
|
|
public mobs: MobInfo[] = [];
|
|
public roamingMonsters: MobInfo[] = [];
|
|
public heros: MD2HeroInfo[] = [];
|
|
public disconnectedHeroes: MD2HeroInfo[] = [];
|
|
public round = 1;
|
|
public roundPhase: RoundPhase = RoundPhase.HeroPhase;
|
|
public showAttackBtn: boolean = false;
|
|
public boss: IBossFight;
|
|
} |