From 2ef9968920f9d9e2d40c03038831d455ee029000 Mon Sep 17 00:00:00 2001 From: Chris Chen Date: Wed, 12 Nov 2025 18:22:33 -0800 Subject: [PATCH] WIP --- src/app/games/massive-darkness2/MD2Base.ts | 80 +++++++----- .../hero-dashboard.component.html | 5 +- .../hero-dashboard.component.ts | 17 ++- .../massive-darkness2.component.html | 13 +- .../massive-darkness2.component.ts | 10 +- .../massive-darkness2.model.ts | 4 + .../mob-combat-info.component.html | 7 +- .../spawn-mob-dlg.component.html | 16 ++- .../spawn-mob-dlg.component.scss | 119 ++++++++++++++++++ .../spawn-mob-dlg/spawn-mob-dlg.component.ts | 6 +- src/app/services/MD2/md2-broadcast.service.ts | 10 +- src/app/services/MD2/md2.service.ts | 2 +- src/app/services/login-user.service.ts | 4 +- src/app/services/signal-r.service.ts | 4 +- src/environments/environment.ts | 2 +- 15 files changed, 238 insertions(+), 61 deletions(-) diff --git a/src/app/games/massive-darkness2/MD2Base.ts b/src/app/games/massive-darkness2/MD2Base.ts index af6e15c..b80c3cf 100644 --- a/src/app/games/massive-darkness2/MD2Base.ts +++ b/src/app/games/massive-darkness2/MD2Base.ts @@ -7,6 +7,7 @@ import { SignalRMessage } from "../../services/signal-r.service"; import { StateService } from "../../services/state.service"; import { ADIcon, MessageBoxConfig } from "../../ui/alert-dlg/alert-dlg.model"; import { MD2HeroInfo, MD2Icon, MobInfo, RoundPhase } from "./massive-darkness2.model"; +import { LoginUserService } from "../../services/login-user.service"; @Injectable() export abstract class MD2Base { @@ -95,38 +96,7 @@ export abstract class MD2Base { this.md2Service.heros.push(heroInfo); break; case 'update': - let exitingHero = this.md2Service.heros.find(h => h.playerInfo.signalRClientId == heroInfo.playerInfo.signalRClientId); - if (exitingHero) { - let activateBoss = exitingHero.uiActivating && !heroInfo.uiActivating; - - this.md2Service.heros[this.md2Service.heros.indexOf(exitingHero)] = heroInfo; - if (this.isHeroDashboard && this.md2Service.stateService.playerHero.playerInfo.tabId == heroInfo.playerInfo.tabId) { - this.md2Service.stateService.playerHero = heroInfo; - } - if (!this.isHeroDashboard && this.md2Service.info.isBossFight && activateBoss) { - this.md2Service.activateBoss(); - } - } else { - this.md2Service.heros.push(heroInfo); - } - if (!this.isHeroDashboard) { - if (this.gameInfo.roundPhase == RoundPhase.HeroPhase) { - if (!this.md2Service.heros.some(h => h.remainActions > 0) && !this.md2Service.heros.some(h => h.uiActivating)) { - if (!this.md2Service.info.isBossFight) { - if (this.md2Service.mobs.length > 0 || this.md2Service.roamingMonsters.length > 0) { - this.md2Service.msgBoxService.show('Enemy Phase', { icon: ADIcon.WARNING }).pipe(first()).subscribe(result => { - this.md2Service.runNextPhase(); - }); - } else { - this.md2Service.runNextPhase(); - } - } - - - } - } - } - + this.updateHeroInfo(heroInfo); //Object.assign(heroInfo, exitingHero); break; case 'updateMyHero': @@ -140,6 +110,18 @@ export abstract class MD2Base { } this.detectChanges(); break; + case 'heroes': + switch (message.actionName) { + case 'updateAll': + let allHeroes = (JSON.parse(message.parameters['heros']) as MD2HeroInfo[]).map(h => new MD2HeroInfo(h)); + //Remove heroes that are not in the list + this.md2Service.info.heros = this.md2Service.heros.filter(h => !allHeroes.some(h2 => h2.playerInfo.tabId == h.playerInfo.tabId)); + allHeroes.forEach(heroInfo => { + this.updateHeroInfo(heroInfo); + }); + break; + } + break; case 'GameRoom': switch (message.actionName) { case 'Leaving': @@ -229,6 +211,40 @@ export abstract class MD2Base { break; } } + updateHeroInfo(heroInfo: MD2HeroInfo) { + let exitingHero = this.md2Service.heros.find(h => h.playerInfo.signalRClientId == heroInfo.playerInfo.signalRClientId); + if (exitingHero) { + let activateBoss = exitingHero.uiActivating && !heroInfo.uiActivating; + + this.md2Service.heros[this.md2Service.heros.indexOf(exitingHero)] = heroInfo; + //My hero update + if (this.isHeroDashboard && this.md2Service.loginUserService.sessionTabId == heroInfo.playerInfo.tabId) { + this.md2Service.stateService.playerHero = heroInfo; + } + if (!this.isHeroDashboard && this.md2Service.info.isBossFight && activateBoss) { + this.md2Service.activateBoss(); + } + } else { + this.md2Service.heros.push(heroInfo); + } + if (!this.isHeroDashboard) { + if (this.gameInfo.roundPhase == RoundPhase.HeroPhase) { + if (!this.md2Service.heros.some(h => h.remainActions > 0) && !this.md2Service.heros.some(h => h.uiActivating)) { + if (!this.md2Service.info.isBossFight) { + if (this.md2Service.mobs.length > 0 || this.md2Service.roamingMonsters.length > 0) { + this.md2Service.msgBoxService.show('Enemy Phase', { icon: ADIcon.WARNING }).pipe(first()).subscribe(result => { + this.md2Service.runNextPhase(); + }); + } else { + this.md2Service.runNextPhase(); + } + } + + + } + } + } + } abstract heroAction(hero: MD2HeroInfo, action: string); } diff --git a/src/app/games/massive-darkness2/hero-dashboard/hero-dashboard.component.html b/src/app/games/massive-darkness2/hero-dashboard/hero-dashboard.component.html index a1c0b48..7d874f4 100644 --- a/src/app/games/massive-darkness2/hero-dashboard/hero-dashboard.component.html +++ b/src/app/games/massive-darkness2/hero-dashboard/hero-dashboard.component.html @@ -126,9 +126,10 @@
-
Abilities
+
Abilities
-
Shadow Abilities
+
+ Shadow Abilities
diff --git a/src/app/games/massive-darkness2/hero-dashboard/hero-dashboard.component.ts b/src/app/games/massive-darkness2/hero-dashboard/hero-dashboard.component.ts index 4221ded..66445fc 100644 --- a/src/app/games/massive-darkness2/hero-dashboard/hero-dashboard.component.ts +++ b/src/app/games/massive-darkness2/hero-dashboard/hero-dashboard.component.ts @@ -55,6 +55,10 @@ export class HeroDashboardComponent extends MD2Base implements OnInit { new DropDownOption(HeroClass.Wizard, 'Wizard'), new DropDownOption(HeroClass.Shaman, 'Shaman'), new DropDownOption(HeroClass.Druid, 'Druid'), + new DropDownOption(HeroClass.Necromancer, 'Necromancer'), + new DropDownOption(HeroClass.Monk, 'Monk'), + new DropDownOption(HeroClass.Thinker, 'Thinker'), + new DropDownOption(HeroClass.Bard, 'Bard'), ]; heros = [] as MD2HeroInfo[]; heroProfiles: MD2HeroProfile[] = []; @@ -100,6 +104,7 @@ export class HeroDashboardComponent extends MD2Base implements OnInit { } initHero() { this.gameRoomService.gameRoomId = this.roomId; + this.gameRoomService.joinGameRoom(this.roomId); if (!this.md2Service.heros.some(h => h.playerInfo.signalRClientId == this.stateService.loginUserService.userAccess.signalRSessionId)) { this.msgBoxService.showInputbox('Select Hero Class', '', { dropDownOptions: this.classOptions, inputType: 'dropdown' }) @@ -156,12 +161,18 @@ export class HeroDashboardComponent extends MD2Base implements OnInit { selectCurrentHero() { if (this.currentSelectingHero) { this.md2Service.playerJoin(this.currentSelectingHero); + this.md2Service.broadcastService.broadcastMyHeroInfo(); this.isSelectingHero = false; this.detectChanges(); - this.gameRoomService.joinGameRoom(this.roomId); } } - + showSkills(type: string) { + if (type == 'abilities') { + this.msgBoxService.show('Abilities', { text: this.currentSelectingHero.skillHtml }); + } else { + this.msgBoxService.show('Shadow Abilities', { text: this.currentSelectingHero.shadowSkillHtml }); + } + } nextHero() { this.currentHeroIndex++; if (this.currentHeroIndex >= this.heros.length) { @@ -189,7 +200,7 @@ export class HeroDashboardComponent extends MD2Base implements OnInit { } openDoor() { this.md2Service.broadcastService.broadcastHeroAction('openDoor'); - this.showMoveAction = false; + //this.showMoveAction = false; this.detectChanges(); } moveAction() { diff --git a/src/app/games/massive-darkness2/massive-darkness2.component.html b/src/app/games/massive-darkness2/massive-darkness2.component.html index 9f92ff7..2922952 100644 --- a/src/app/games/massive-darkness2/massive-darkness2.component.html +++ b/src/app/games/massive-darkness2/massive-darkness2.component.html @@ -63,19 +63,20 @@ HP: {{hero.hp}}/{{hero.hpMaximum}} Mana: {{hero.mp}}/{{hero.mpMaximum}} Exp: {{hero.exp}} - - {{hero.fireToken}} + + {{hero.fireToken}} - - {{hero.frozenToken}} + + {{hero.frozenToken}} Actions: {{hero.remainActions}} Inactive Activating - + + X +
diff --git a/src/app/games/massive-darkness2/massive-darkness2.component.ts b/src/app/games/massive-darkness2/massive-darkness2.component.ts index 5ae0385..dedfd99 100644 --- a/src/app/games/massive-darkness2/massive-darkness2.component.ts +++ b/src/app/games/massive-darkness2/massive-darkness2.component.ts @@ -5,7 +5,7 @@ import { MsgBoxService } from '../../services/msg-box.service'; import { ArrayUtils } from '../../utilities/array-utils'; import { ObjectUtils } from '../../utilities/object-utils'; import { first, map, take, takeUntil } from 'rxjs/operators'; -import { TreasureType, DrawingBag, DrawingItem, HeroClass, MD2HeroInfo, RoundPhase, MobInfo, MobDlgType } from './massive-darkness2.model'; +import { TreasureType, DrawingBag, DrawingItem, HeroClass, MD2HeroInfo, RoundPhase, MobInfo, MobDlgType, MD2Icon } from './massive-darkness2.model'; import { MD2Service } from '../../services/MD2/md2.service'; import { GameRoomService } from '../../services/game-room.service'; import { MD2Base } from './MD2Base'; @@ -25,6 +25,7 @@ import { NumberUtils } from '../../utilities/number-utils'; changeDetection: ChangeDetectionStrategy.OnPush }) export class MassiveDarkness2Component extends MD2Base implements OnInit { + MD2Icon = MD2Icon; HeroClass = HeroClass; constructor( private fileService: FileService, @@ -148,7 +149,12 @@ export class MassiveDarkness2Component extends MD2Base implements OnInit { this.md2Service.broadcastService.broadcastAllHeroInfoToAll(); } removeHero(hero) { - this.md2Service.info.heros.splice(this.md2Service.info.heros.indexOf(hero)); + this.msgBoxService.showConfirmDeleteBox().pipe(first()).subscribe(result => { + if (result) { + this.md2Service.info.heros.splice(this.md2Service.info.heros.indexOf(hero)); + this.cdRef.detectChanges(); + } + }); } diff --git a/src/app/games/massive-darkness2/massive-darkness2.model.ts b/src/app/games/massive-darkness2/massive-darkness2.model.ts index a96dd9b..601231d 100644 --- a/src/app/games/massive-darkness2/massive-darkness2.model.ts +++ b/src/app/games/massive-darkness2/massive-darkness2.model.ts @@ -37,6 +37,10 @@ export enum HeroClass { Shaman, Paladin, Druid, + Necromancer, + Monk, + Thinker, + Bard } export enum MobType { Mob, diff --git a/src/app/games/massive-darkness2/mobs/mob-detail-info/mob-combat-info/mob-combat-info.component.html b/src/app/games/massive-darkness2/mobs/mob-detail-info/mob-combat-info/mob-combat-info.component.html index 64da57e..f8939d8 100644 --- a/src/app/games/massive-darkness2/mobs/mob-detail-info/mob-combat-info/mob-combat-info.component.html +++ b/src/app/games/massive-darkness2/mobs/mob-detail-info/mob-combat-info/mob-combat-info.component.html @@ -20,13 +20,12 @@ {{skillTriggerHtml}} --> -
-
+ +
- -
+
\ No newline at end of file diff --git a/src/app/games/massive-darkness2/mobs/spawn-mob-dlg/spawn-mob-dlg.component.html b/src/app/games/massive-darkness2/mobs/spawn-mob-dlg/spawn-mob-dlg.component.html index fa2205f..836d360 100644 --- a/src/app/games/massive-darkness2/mobs/spawn-mob-dlg/spawn-mob-dlg.component.html +++ b/src/app/games/massive-darkness2/mobs/spawn-mob-dlg/spawn-mob-dlg.component.html @@ -10,10 +10,22 @@
-
diff --git a/src/app/games/massive-darkness2/mobs/spawn-mob-dlg/spawn-mob-dlg.component.scss b/src/app/games/massive-darkness2/mobs/spawn-mob-dlg/spawn-mob-dlg.component.scss index e3beee8..528b514 100644 --- a/src/app/games/massive-darkness2/mobs/spawn-mob-dlg/spawn-mob-dlg.component.scss +++ b/src/app/games/massive-darkness2/mobs/spawn-mob-dlg/spawn-mob-dlg.component.scss @@ -2,3 +2,122 @@ width: 885px; height: 95vh !important; } +.skill-card { + border-radius: 16px; + overflow: hidden; + position: relative; + border: 1px solid #252a34; + background: radial-gradient(120% 180% at 50% -40%, rgba(217, 143, 43, 0.08), transparent 60%), + linear-gradient(180deg, rgba(255, 255, 255, 0.04), rgba(255, 255, 255, 0.01)), #14161b; + transition: + transform 0.12s ease, + box-shadow 0.25s ease, + filter 0.2s ease; + margin-top: -130px; + z-index: 1; + width: 96%; +} +.skill-card::before { + content: ""; + position: absolute; + inset: 0; + pointer-events: none; + border-radius: 16px; + padding: 1px; + background: linear-gradient( + 180deg, + rgba(246, 230, 185, 0.6), + rgba(176, 136, 46, 0.35) 55%, + rgba(246, 230, 185, 0.6) + ); + -webkit-mask: + linear-gradient(#000 0 0) content-box, + linear-gradient(#000 0 0); + -webkit-mask-composite: xor; + mask-composite: exclude; +} +.skill-card[open] { + box-shadow: + 0 0 0 2px rgba(217, 143, 43, 0.25), + 0 12px 28px rgba(0, 0, 0, 0.6); +} + +summary { + list-style: none; + cursor: pointer; + position: relative; + display: grid; + grid-template-columns: 1fr auto; + align-items: center; + gap: 0.75rem; + padding: 6px 1rem; + background: linear-gradient(180deg, rgba(255, 255, 255, 0.04), rgba(255, 255, 255, 0)); +} +summary::-webkit-details-marker { + display: none; +} +summary:hover { + filter: saturate(1.08); + box-shadow: + 0 0 0 2px rgba(155, 28, 28, 0.25), + 0 0 18px rgba(217, 143, 43, 0.18) inset; +} +summary:focus-visible { + outline: 2px solid #d98f2b; + outline-offset: 2px; + box-shadow: 0 0 18px rgba(217, 143, 43, 0.35); +} + +.skill-name { + margin: 0; + font-size: 2rem; + letter-spacing: 0.04em; + background: linear-gradient(180deg, #f6e6b9, #b0882e 50%, #f6e6b9); + -webkit-background-clip: text; + background-clip: text; + color: transparent; + font-family: "DwarvenAxeBBW00-Regular", sans-serif !important; +} +.rarity { + font-size: 0.75rem; + text-transform: uppercase; + letter-spacing: 0.12em; + padding: 0.25rem 0.5rem; + border-radius: 999px; + border: 1px solid rgba(240, 217, 154, 0.45); + background: linear-gradient(180deg, rgba(255, 255, 255, 0.08), rgba(255, 255, 255, 0.02)); + color: #e8e5de; +} +.rarity.legendary { + border-color: rgba(217, 143, 43, 0.6); + box-shadow: inset 0 0 10px rgba(217, 143, 43, 0.25); +} +.rarity.epic { + border-color: rgba(155, 28, 28, 0.6); + box-shadow: inset 0 0 10px rgba(155, 28, 28, 0.3); +} +.rarity.rare { + border-color: rgba(148, 164, 58, 0.6); + box-shadow: inset 0 0 10px rgba(148, 164, 58, 0.28); +} +::ng-deep { + .skill-body { + padding: 0 1rem 1rem; + color: #cfcab7; + } + .skill-body p { + margin: 0.6rem 0 0.4rem; + color: #ddd6bf; + } + .skill-body ul { + margin: 0.25rem 0 0; + padding-left: 1.1rem; + } + .skill-body li { + margin: 0.25rem 0; + color: #a7a196; + } + .skill-body strong { + color: #efe7cf; + } +} diff --git a/src/app/games/massive-darkness2/mobs/spawn-mob-dlg/spawn-mob-dlg.component.ts b/src/app/games/massive-darkness2/mobs/spawn-mob-dlg/spawn-mob-dlg.component.ts index da0812a..bc3f16f 100644 --- a/src/app/games/massive-darkness2/mobs/spawn-mob-dlg/spawn-mob-dlg.component.ts +++ b/src/app/games/massive-darkness2/mobs/spawn-mob-dlg/spawn-mob-dlg.component.ts @@ -66,7 +66,7 @@ export class SpawnMobDlgComponent extends MD2ComponentBase implements OnInit { this.mob.actions = 1; } else { this.mob.actions = 2; - this.activeSkill = { name: 'Normal Action', description: '${this.mob.name} Gains 2 Actions.' } as MD2MobSkill; + this.activeSkill = { name: 'Normal Action', description: `${this.mob.name} Gains 2 Actions.` } as MD2MobSkill; //this.actionInfoHtml = `${this.mob.name} Gains 2 Actions.`; } } @@ -113,8 +113,8 @@ export class SpawnMobDlgComponent extends MD2ComponentBase implements OnInit { return of({ result: true, skill } as SkillResolutionResult); } - const title = skill.name || 'Resolve Skill?'; - const prompt = skill.skillCondition || skill.description || 'Resolve this skill?'; + const title = 'Resolve Skill?'; + const prompt = skill.skillCondition; return this.msgBoxService.show(title, { text: prompt, diff --git a/src/app/services/MD2/md2-broadcast.service.ts b/src/app/services/MD2/md2-broadcast.service.ts index 0b13772..222db78 100644 --- a/src/app/services/MD2/md2-broadcast.service.ts +++ b/src/app/services/MD2/md2-broadcast.service.ts @@ -26,8 +26,14 @@ export class MD2BroadcastService { return this.stateService.playerHero; } public broadcastAllHeroInfoToAll() { - this.stateService.info.heros.forEach(element => { - this.broadcastHeroInfoToAll(element); + let message = { + receiver: { isGroup: true, sessionId: this.gameRoomService.gameRoomId } as SignalRSession, + from: { isGroup: false, sessionId: this.loginUserService.userAccess.signalRSessionId }, + actionType: 'heroes', + actionName: 'updateAll', + } as SignalRMessage; + message.parameters = { heros: JSON.stringify(this.stateService.info.heros) }; + this.gameRoomService.sendMessage(message).pipe(first()).subscribe(result => { }); this.broadcastMobsInfo(); } diff --git a/src/app/services/MD2/md2.service.ts b/src/app/services/MD2/md2.service.ts index 7e80815..39de9be 100644 --- a/src/app/services/MD2/md2.service.ts +++ b/src/app/services/MD2/md2.service.ts @@ -73,7 +73,7 @@ export class MD2Service { public fileService: FileService, public msgBoxService: MsgBoxService, private gameRoomService: GameRoomService, - private loginUserService: LoginUserService, + public loginUserService: LoginUserService, public stateService: MD2StateService, public signalRService: SignalRService, public dlgService: NbDialogService, diff --git a/src/app/services/login-user.service.ts b/src/app/services/login-user.service.ts index deb4530..87b49b2 100644 --- a/src/app/services/login-user.service.ts +++ b/src/app/services/login-user.service.ts @@ -18,10 +18,10 @@ export class LoginUserService { } public get sessionTabId(): string { - return sessionStorage.getItem('tabId'); + return localStorage.getItem('tabId'); } public set sessionTabId(v: string) { - sessionStorage.setItem('tabId', v); + localStorage.setItem('tabId', v); } } diff --git a/src/app/services/signal-r.service.ts b/src/app/services/signal-r.service.ts index abaa2a9..156b055 100644 --- a/src/app/services/signal-r.service.ts +++ b/src/app/services/signal-r.service.ts @@ -42,7 +42,9 @@ export class SignalRService { } public startSignalRConnection(gameRoomId: string = '') { - this.loginUserService.sessionTabId = UuidUtils.generate(); + if (!this.loginUserService.sessionTabId) { + this.loginUserService.sessionTabId = UuidUtils.generate(); + } const tree = this.router.createUrlTree([], { queryParams: { diff --git a/src/environments/environment.ts b/src/environments/environment.ts index c198d5a..fe5d828 100644 --- a/src/environments/environment.ts +++ b/src/environments/environment.ts @@ -13,7 +13,7 @@ const urls = [ 'https://api.golife.love' ]; const LINE_CLIENT_ID = '1657422139'; -const dockerDebug = urls[0]; +const dockerDebug = urls[2]; export const environment = { production: false, apiUrl: dockerDebug,