WIP
This commit is contained in:
parent
d20f2a37c4
commit
716e25f0ba
@ -6,6 +6,7 @@ import { GamesComponent } from './games.component';
|
|||||||
import { HeroDashboardComponent } from './massive-darkness2/hero-dashboard/hero-dashboard.component';
|
import { HeroDashboardComponent } from './massive-darkness2/hero-dashboard/hero-dashboard.component';
|
||||||
import { MassiveDarkness2Component } from './massive-darkness2/massive-darkness2.component';
|
import { MassiveDarkness2Component } from './massive-darkness2/massive-darkness2.component';
|
||||||
import { MD2MobInfoMaintenanceComponent } from './massive-darkness2/md2-mob-info-maintenance/md2-mob-info-maintenance.component';
|
import { MD2MobInfoMaintenanceComponent } from './massive-darkness2/md2-mob-info-maintenance/md2-mob-info-maintenance.component';
|
||||||
|
import { MD2HeroProfileMaintenanceComponent } from './massive-darkness2/md2-hero-profile-maintenance/md2-hero-profile-maintenance.component';
|
||||||
export class GameRoomMenuConfig {
|
export class GameRoomMenuConfig {
|
||||||
public static HostMenu: NbMenuItem[] = [
|
public static HostMenu: NbMenuItem[] = [
|
||||||
|
|
||||||
@ -49,6 +50,7 @@ const routes: Routes = [
|
|||||||
{ path: 'MD2', component: MassiveDarkness2Component },
|
{ path: 'MD2', component: MassiveDarkness2Component },
|
||||||
{ path: 'MD2_Hero/:roomId', component: HeroDashboardComponent },
|
{ path: 'MD2_Hero/:roomId', component: HeroDashboardComponent },
|
||||||
{ path: 'MD2MobInfo', component: MD2MobInfoMaintenanceComponent },
|
{ path: 'MD2MobInfo', component: MD2MobInfoMaintenanceComponent },
|
||||||
|
{ path: 'MD2HeroProfile', component: MD2HeroProfileMaintenanceComponent },
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@ -50,6 +50,8 @@ import { MD2MobInfoEditorComponent } from './massive-darkness2/md2-mob-info-main
|
|||||||
import { MD2MobInfoDetailComponent } from './massive-darkness2/md2-mob-info-maintenance/md2-mob-info-detail/md2-mob-info-detail.component';
|
import { MD2MobInfoDetailComponent } from './massive-darkness2/md2-mob-info-maintenance/md2-mob-info-detail/md2-mob-info-detail.component';
|
||||||
import { MD2MobSkillEditorComponent } from './massive-darkness2/md2-mob-info-maintenance/md2-mob-skill-editor/md2-mob-skill-editor.component';
|
import { MD2MobSkillEditorComponent } from './massive-darkness2/md2-mob-info-maintenance/md2-mob-skill-editor/md2-mob-skill-editor.component';
|
||||||
import { MD2MobLevelEditorComponent } from './massive-darkness2/md2-mob-info-maintenance/md2-mob-level-editor/md2-mob-level-editor.component';
|
import { MD2MobLevelEditorComponent } from './massive-darkness2/md2-mob-info-maintenance/md2-mob-level-editor/md2-mob-level-editor.component';
|
||||||
|
import { MD2HeroProfileMaintenanceComponent } from './massive-darkness2/md2-hero-profile-maintenance/md2-hero-profile-maintenance.component';
|
||||||
|
import { MD2HeroProfileEditorComponent } from './massive-darkness2/md2-hero-profile-maintenance/md2-hero-profile-editor/md2-hero-profile-editor.component';
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
@ -84,7 +86,9 @@ import { MD2MobLevelEditorComponent } from './massive-darkness2/md2-mob-info-mai
|
|||||||
MD2MobInfoEditorComponent,
|
MD2MobInfoEditorComponent,
|
||||||
MD2MobInfoDetailComponent,
|
MD2MobInfoDetailComponent,
|
||||||
MD2MobSkillEditorComponent,
|
MD2MobSkillEditorComponent,
|
||||||
MD2MobLevelEditorComponent
|
MD2MobLevelEditorComponent,
|
||||||
|
MD2HeroProfileMaintenanceComponent,
|
||||||
|
MD2HeroProfileEditorComponent
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
|
|||||||
@ -10,7 +10,19 @@
|
|||||||
<div class="tp-box g-height-300 g-height-350--sm g-height-500--md" [@flipState]="flip">
|
<div class="tp-box g-height-300 g-height-350--sm g-height-500--md" [@flipState]="flip">
|
||||||
<div class="tp-box__side tp-box__front ">
|
<div class="tp-box__side tp-box__front ">
|
||||||
|
|
||||||
<img class="MD2HeroCard " src="{{hero.imgUrl}}" (click)="toggleFlip()">
|
<div class="row">
|
||||||
|
<div class="col-6">
|
||||||
|
<!-- show hero stand image -->
|
||||||
|
<img src="{{imgUrl('Heros/'+className+'.jpg')}}" (click)="toggleFlip()">
|
||||||
|
</div>
|
||||||
|
<div class="col-6">
|
||||||
|
<!-- show skill html -->
|
||||||
|
<div [innerHTML]="hero.skillHtml"></div>
|
||||||
|
<!-- show shadow skill html -->
|
||||||
|
<div [innerHTML]="hero.shadowSkillHtml"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- <img class="MD2HeroCard " src="{{imgUrl('Heros/'+className+'.jpg')}}" (click)="toggleFlip()"> -->
|
||||||
|
|
||||||
<div class="d-none d-sm-block">
|
<div class="d-none d-sm-block">
|
||||||
<div *ngIf="hero.uiActivating&&hero.remainActions>0">
|
<div *ngIf="hero.uiActivating&&hero.remainActions>0">
|
||||||
|
|||||||
@ -11,8 +11,9 @@ import { ADButtonColor, ADButtons } from '../../../ui/alert-dlg/alert-dlg.model'
|
|||||||
import { ArrayUtils } from '../../../utilities/array-utils';
|
import { ArrayUtils } from '../../../utilities/array-utils';
|
||||||
import { StringUtils } from '../../../utilities/string-utils';
|
import { StringUtils } from '../../../utilities/string-utils';
|
||||||
import { DebounceTimer } from '../../../utilities/timer-utils';
|
import { DebounceTimer } from '../../../utilities/timer-utils';
|
||||||
import { HeroClass, MD2HeroInfo, MD2Icon } from '../massive-darkness2.model';
|
import { HeroClass, MD2HeroInfo, MD2HeroProfile, MD2Icon } from '../massive-darkness2.model';
|
||||||
import { MD2Base } from '../MD2Base';
|
import { MD2Base } from '../MD2Base';
|
||||||
|
import { MD2HeroProfileService } from '../service/massive-darkness2.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ngx-hero-dashboard',
|
selector: 'ngx-hero-dashboard',
|
||||||
@ -55,16 +56,7 @@ export class HeroDashboardComponent extends MD2Base implements OnInit {
|
|||||||
new DropDownOption(HeroClass.Druid, 'Druid'),
|
new DropDownOption(HeroClass.Druid, 'Druid'),
|
||||||
];
|
];
|
||||||
heros = [] as MD2HeroInfo[];
|
heros = [] as MD2HeroInfo[];
|
||||||
wizards: MD2HeroInfo[] = [
|
heroProfiles: MD2HeroProfile[] = [];
|
||||||
new MD2HeroInfo({ name: 'Ajax', mpMaximum: 6, hpMaximum: 4, skillHtml: '', shadowSkillHtml: '' }),
|
|
||||||
new MD2HeroInfo({ name: 'Baldric', mpMaximum: 5, hpMaximum: 4, skillHtml: '', shadowSkillHtml: '' }),
|
|
||||||
new MD2HeroInfo({ name: 'Ego', mpMaximum: 5, hpMaximum: 6, skillHtml: '', shadowSkillHtml: '' }),
|
|
||||||
new MD2HeroInfo({ name: 'Elias', mpMaximum: 6, hpMaximum: 5, skillHtml: '', shadowSkillHtml: '' }),
|
|
||||||
new MD2HeroInfo({ name: 'Megan', mpMaximum: 5, hpMaximum: 5, skillHtml: '', shadowSkillHtml: '' }),
|
|
||||||
new MD2HeroInfo({ name: 'Moira', mpMaximum: 6, hpMaximum: 5, skillHtml: '', shadowSkillHtml: '' }),
|
|
||||||
new MD2HeroInfo({ name: 'Myriam', mpMaximum: 7, hpMaximum: 4, skillHtml: '', shadowSkillHtml: '' }),
|
|
||||||
new MD2HeroInfo({ name: 'Valdis', mpMaximum: 6, hpMaximum: 4, skillHtml: '', shadowSkillHtml: '' })
|
|
||||||
]
|
|
||||||
|
|
||||||
public get hero() {
|
public get hero() {
|
||||||
return this.md2Service.playerHero;
|
return this.md2Service.playerHero;
|
||||||
@ -73,6 +65,7 @@ export class HeroDashboardComponent extends MD2Base implements OnInit {
|
|||||||
constructor(
|
constructor(
|
||||||
private gameRoomService: GameRoomService,
|
private gameRoomService: GameRoomService,
|
||||||
public md2Service: MD2Service,
|
public md2Service: MD2Service,
|
||||||
|
private heroProfileService: MD2HeroProfileService,
|
||||||
protected stateService: StateService,
|
protected stateService: StateService,
|
||||||
protected route: ActivatedRoute,
|
protected route: ActivatedRoute,
|
||||||
protected cdRef: ChangeDetectorRef,
|
protected cdRef: ChangeDetectorRef,
|
||||||
@ -100,6 +93,7 @@ export class HeroDashboardComponent extends MD2Base implements OnInit {
|
|||||||
initHero() {
|
initHero() {
|
||||||
this.gameRoomService.gameRoomId = this.roomId;
|
this.gameRoomService.gameRoomId = this.roomId;
|
||||||
if (!this.md2Service.heros.some(h => h.playerInfo.signalRClientId == this.stateService.loginUserService.userAccess.signalRSessionId)) {
|
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' })
|
this.msgBoxService.showInputbox('Select Hero Class', '', { dropDownOptions: this.classOptions, inputType: 'dropdown' })
|
||||||
.pipe(first()).subscribe(heroClass => {
|
.pipe(first()).subscribe(heroClass => {
|
||||||
if (heroClass != null) {
|
if (heroClass != null) {
|
||||||
@ -124,21 +118,24 @@ export class HeroDashboardComponent extends MD2Base implements OnInit {
|
|||||||
initClassHeroList(heroClass: HeroClass) {
|
initClassHeroList(heroClass: HeroClass) {
|
||||||
this.heros = [];
|
this.heros = [];
|
||||||
this.className = HeroClass[heroClass];
|
this.className = HeroClass[heroClass];
|
||||||
this.fileList(`Heros/${this.className}`).pipe(first()).subscribe(fileNames => {
|
this.heroProfileService.getAll().pipe(first()).subscribe(result => {
|
||||||
for (let i = 0; i < fileNames.length; i++) {
|
|
||||||
const heroNames = fileNames[i].split('.')[0].split('-');
|
|
||||||
|
|
||||||
|
this.heroProfiles = result;
|
||||||
|
for (let i = 0; i < this.heroProfiles.length; i++) {
|
||||||
|
const heroProfile = this.heroProfiles[i];
|
||||||
this.heros.push(new MD2HeroInfo({
|
this.heros.push(new MD2HeroInfo({
|
||||||
name: heroNames[0].replace('/', ''),
|
name: heroProfile.title,
|
||||||
mpMaximum: Number.parseInt(heroNames[1]),
|
mpMaximum: heroProfile.mana,
|
||||||
hpMaximum: Number.parseInt(heroNames[2]),
|
hpMaximum: heroProfile.hp,
|
||||||
imgUrl: this.imgUrl(`Heros/${this.className}/${fileNames[i]}`),
|
skillHtml: heroProfile.skillHtml,
|
||||||
|
shadowSkillHtml: heroProfile.shadowSkillHtml,
|
||||||
class: heroClass
|
class: heroClass
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
this.heros = ArrayUtils.Shuffle(this.heros);//.sort((a, b) => StringUtils.compareSemVer(a.name, b.name));
|
this.heros = ArrayUtils.Shuffle(this.heros);//.sort((a, b) => StringUtils.compareSemVer(a.name, b.name));
|
||||||
this.showHeroList(heroClass, 0);
|
this.showHeroList(heroClass, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
showHeroList(heroClass: HeroClass, index: number) {
|
showHeroList(heroClass: HeroClass, index: number) {
|
||||||
let className = HeroClass[heroClass];
|
let className = HeroClass[heroClass];
|
||||||
|
|||||||
@ -83,6 +83,12 @@ export enum MD2Icon {
|
|||||||
TreasureToken_Rare,
|
TreasureToken_Rare,
|
||||||
TreasureToken_Epic,
|
TreasureToken_Epic,
|
||||||
TreasureToken_Legendary,
|
TreasureToken_Legendary,
|
||||||
|
HP_Color,
|
||||||
|
Mana_Color,
|
||||||
|
CorruptToken,
|
||||||
|
TimeToken,
|
||||||
|
FireToken,
|
||||||
|
FrozenToken
|
||||||
|
|
||||||
}
|
}
|
||||||
export enum AttackTarget {
|
export enum AttackTarget {
|
||||||
@ -374,7 +380,15 @@ export class MobInfo implements IDrawingItem {
|
|||||||
public actionSubject: Subject<string>;
|
public actionSubject: Subject<string>;
|
||||||
public activateFunction?: (mob: MobInfo, msgBoxService: MsgBoxService, heros: MD2HeroInfo[]) => void;
|
public activateFunction?: (mob: MobInfo, msgBoxService: MsgBoxService, heros: MD2HeroInfo[]) => void;
|
||||||
}
|
}
|
||||||
|
export interface MD2HeroProfile {
|
||||||
|
id: string;
|
||||||
|
heroClass: HeroClass;
|
||||||
|
title: string;
|
||||||
|
hp: number;
|
||||||
|
mana: number;
|
||||||
|
skillHtml: string;
|
||||||
|
shadowSkillHtml: string;
|
||||||
|
}
|
||||||
export class MD2HeroInfo {
|
export class MD2HeroInfo {
|
||||||
constructor(
|
constructor(
|
||||||
config: Partial<MD2HeroInfo> = {}
|
config: Partial<MD2HeroInfo> = {}
|
||||||
|
|||||||
@ -0,0 +1,55 @@
|
|||||||
|
<div class="k-dialog-content">
|
||||||
|
<form #form="ngForm">
|
||||||
|
<div class="row form-group">
|
||||||
|
<div class="col-md-4">
|
||||||
|
|
||||||
|
<label class="k-label">Hero Class *</label>
|
||||||
|
<kendo-dropdownlist [(ngModel)]="selectedHeroClass" name="heroClass" [data]="heroClasses"
|
||||||
|
[valueField]="'value'" [textField]="'text'"
|
||||||
|
[defaultItem]="{ value: null, text: 'Select hero class...' }">
|
||||||
|
</kendo-dropdownlist>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
|
||||||
|
<label class="k-label">Title</label>
|
||||||
|
<input kendoTextBox [(ngModel)]="model.title" name="title" class="k-input"
|
||||||
|
placeholder="Enter hero profile title" />
|
||||||
|
</div>
|
||||||
|
<div class="col-md-2">
|
||||||
|
|
||||||
|
<label class="k-label">Mana</label>
|
||||||
|
<kendo-numerictextbox [(ngModel)]="model.mana" name="mana" [format]="'n0'" [min]="0" [max]="100"
|
||||||
|
class="k-input" placeholder="Enter mana value">
|
||||||
|
</kendo-numerictextbox>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-2">
|
||||||
|
|
||||||
|
<label class="k-label">HP</label>
|
||||||
|
<kendo-numerictextbox [(ngModel)]="model.hp" name="hP" [format]="'n0'" [min]="0" [max]="100"
|
||||||
|
class="k-input" placeholder="Enter HP value">
|
||||||
|
</kendo-numerictextbox>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="k-label">Skill HTML</label>
|
||||||
|
|
||||||
|
<md2-html-editor [(ngModel)]="model.skillHtml" name="skillHtml" class="htmlEditor"></md2-html-editor>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="k-label">Shadow Skill HTML</label>
|
||||||
|
<md2-html-editor [(ngModel)]="model.shadowSkillHtml" name="shadowSkillHtml"
|
||||||
|
class="htmlEditor"></md2-html-editor>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<kendo-dialog-actions>
|
||||||
|
<button kendoButton (click)="close()">Cancel</button>
|
||||||
|
<button kendoButton [primary]="true" (click)="save()" [disabled]="!isValid || processing">
|
||||||
|
{{ processing ? 'Saving...' : 'Save' }}
|
||||||
|
</button>
|
||||||
|
</kendo-dialog-actions>
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
:host {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.k-form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.k-form-field {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.k-label {
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.k-form-error {
|
||||||
|
color: #f31700;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,98 @@
|
|||||||
|
import { Component, Input, OnInit, ViewChild, ChangeDetectorRef } from '@angular/core';
|
||||||
|
import { DialogRef, DialogContentBase } from '@progress/kendo-angular-dialog';
|
||||||
|
import { NgForm } from '@angular/forms';
|
||||||
|
import { first } from 'rxjs/operators';
|
||||||
|
import { MD2HeroProfile, HeroClass } from '../../massive-darkness2.model';
|
||||||
|
import { MD2HeroProfileService } from '../../service/massive-darkness2.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ngx-md2-hero-profile-editor',
|
||||||
|
templateUrl: './md2-hero-profile-editor.component.html',
|
||||||
|
styleUrls: ['./md2-hero-profile-editor.component.scss']
|
||||||
|
})
|
||||||
|
export class MD2HeroProfileEditorComponent extends DialogContentBase implements OnInit {
|
||||||
|
@Input() public data: MD2HeroProfile;
|
||||||
|
@Input() public isAdding: boolean = false;
|
||||||
|
@ViewChild('form') form: NgForm;
|
||||||
|
|
||||||
|
public model: MD2HeroProfile;
|
||||||
|
public processing: boolean = false;
|
||||||
|
public heroClasses: Array<{ value: HeroClass; text: string }> = [];
|
||||||
|
public selectedHeroClass: { value: HeroClass; text: string } | null = null;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public dialog: DialogRef,
|
||||||
|
private heroProfileService: MD2HeroProfileService,
|
||||||
|
private cdr: ChangeDetectorRef
|
||||||
|
) {
|
||||||
|
super(dialog);
|
||||||
|
this.initializeEnums();
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.initializeModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
public initializeModel(): void {
|
||||||
|
const classValue = this.data?.heroClass !== undefined && this.data?.heroClass !== null ? this.data.heroClass : HeroClass.Berserker;
|
||||||
|
|
||||||
|
this.model = {
|
||||||
|
id: this.data?.id || '',
|
||||||
|
heroClass: classValue,
|
||||||
|
title: this.data?.title || '',
|
||||||
|
hp: this.data?.hp || 0,
|
||||||
|
mana: this.data?.mana || 0,
|
||||||
|
skillHtml: this.data?.skillHtml || '',
|
||||||
|
shadowSkillHtml: this.data?.shadowSkillHtml || ''
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set selected object for dropdown
|
||||||
|
this.selectedHeroClass = this.heroClasses.find(c => c.value === classValue) || this.heroClasses[0] || null;
|
||||||
|
|
||||||
|
this.cdr.detectChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
private initializeEnums(): void {
|
||||||
|
// Initialize HeroClass options
|
||||||
|
Object.keys(HeroClass).filter(key => isNaN(Number(key))).forEach(key => {
|
||||||
|
this.heroClasses.push({
|
||||||
|
value: HeroClass[key] as HeroClass,
|
||||||
|
text: key
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public close(): void {
|
||||||
|
this.dialog.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public save(): void {
|
||||||
|
if (this.model.title && !this.processing) {
|
||||||
|
this.processing = true;
|
||||||
|
|
||||||
|
// Extract enum value from selected object
|
||||||
|
const heroProfile: MD2HeroProfile = {
|
||||||
|
...this.model,
|
||||||
|
heroClass: this.selectedHeroClass?.value ?? HeroClass.Berserker
|
||||||
|
};
|
||||||
|
|
||||||
|
this.heroProfileService.createOrUpdate(heroProfile).pipe(first()).subscribe(result => {
|
||||||
|
this.processing = false;
|
||||||
|
this.dialog.close(result);
|
||||||
|
}, error => {
|
||||||
|
this.processing = false;
|
||||||
|
console.error('Error saving hero profile:', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public get isValid(): boolean {
|
||||||
|
if (!this.model) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const titleValid = true;// this.model.title && this.model.title.trim().length > 0;
|
||||||
|
const classValid = this.selectedHeroClass !== null && this.selectedHeroClass !== undefined;
|
||||||
|
return titleValid && classValid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,57 @@
|
|||||||
|
<nb-card>
|
||||||
|
<nb-card-header>
|
||||||
|
<h4>MD2 Hero Profile Maintenance</h4>
|
||||||
|
<button class="float-right" kendoButton (click)="addHandler()" [primary]="true">
|
||||||
|
<span class="k-icon k-i-plus"></span> Add New
|
||||||
|
</button>
|
||||||
|
|
||||||
|
</nb-card-header>
|
||||||
|
<nb-card-body>
|
||||||
|
<kendo-grid #grid [data]="gridData" [loading]="isLoading" [pageSize]="gridState.take" [skip]="gridState.skip"
|
||||||
|
[group]="gridState.group" [filter]="gridState.filter" [sort]="gridState.sort" [sortable]="true"
|
||||||
|
[filterable]="true" [pageable]="true" [selectable]="true" [groupable]="true"
|
||||||
|
(dataStateChange)="gridState = $event; processGridData()" (edit)="editHandler($event)"
|
||||||
|
(remove)="removeHandler($event)" (add)="addHandler()">
|
||||||
|
|
||||||
|
<kendo-grid-toolbar>
|
||||||
|
<button kendoGridAddCommand>Add new</button>
|
||||||
|
</kendo-grid-toolbar>
|
||||||
|
|
||||||
|
<kendo-grid-column field="title" title="Title" [width]="150">
|
||||||
|
</kendo-grid-column>
|
||||||
|
|
||||||
|
<kendo-grid-column field="heroClass" title="Hero Class" [width]="60">
|
||||||
|
<ng-template kendoGridCellTemplate let-dataItem>
|
||||||
|
{{ getHeroClassName(dataItem.heroClass) }}
|
||||||
|
</ng-template>
|
||||||
|
<ng-template kendoGridGroupHeaderTemplate let-value="value">
|
||||||
|
{{ getHeroClassName(value) }}
|
||||||
|
</ng-template>
|
||||||
|
</kendo-grid-column>
|
||||||
|
|
||||||
|
<kendo-grid-column field="hP" title="HP" [width]="80">
|
||||||
|
<ng-template kendoGridCellTemplate let-dataItem>
|
||||||
|
<md2-icon [icon]="MD2Icon.Mana_Color" size="sm"></md2-icon> {{ dataItem.mana }}
|
||||||
|
<md2-icon [icon]="MD2Icon.HP_Color" size="sm"></md2-icon> {{ dataItem.hp }}
|
||||||
|
</ng-template>
|
||||||
|
</kendo-grid-column>
|
||||||
|
|
||||||
|
<kendo-grid-column field="skill" title="Skill" [width]="500">
|
||||||
|
<ng-template kendoGridCellTemplate let-dataItem>
|
||||||
|
<div [innerHTML]="dataItem.skillHtml"></div>
|
||||||
|
<div>
|
||||||
|
<md2-icon [icon]="MD2Icon.Shadow" size="sm"></md2-icon> <b>Shadow:</b>
|
||||||
|
<div [innerHTML]="dataItem.shadowSkillHtml"></div>
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
</kendo-grid-column>
|
||||||
|
|
||||||
|
<kendo-grid-command-column title="Actions" [width]="140">
|
||||||
|
<ng-template kendoGridCellTemplate let-isNew="isNew" let-dataItem="dataItem" let-rowIndex="rowIndex">
|
||||||
|
<button kendoGridEditCommand [primary]="true">Edit</button>
|
||||||
|
<button kendoGridRemoveCommand>Remove</button>
|
||||||
|
</ng-template>
|
||||||
|
</kendo-grid-command-column>
|
||||||
|
</kendo-grid>
|
||||||
|
</nb-card-body>
|
||||||
|
</nb-card>
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
:host {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.float-right {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
kendo-grid {
|
||||||
|
height: 77vh;
|
||||||
|
}
|
||||||
@ -0,0 +1,143 @@
|
|||||||
|
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||||
|
import { GridComponent, GridDataResult } from '@progress/kendo-angular-grid';
|
||||||
|
import { State, process } from '@progress/kendo-data-query';
|
||||||
|
import { first } from 'rxjs/operators';
|
||||||
|
import { MD2HeroProfile, HeroClass, MD2Icon } from '../massive-darkness2.model';
|
||||||
|
import { MD2HeroProfileService } from '../service/massive-darkness2.service';
|
||||||
|
import { MD2HeroProfileEditorComponent } from './md2-hero-profile-editor/md2-hero-profile-editor.component';
|
||||||
|
import { DialogService } from '@progress/kendo-angular-dialog';
|
||||||
|
import { MsgBoxService } from '../../../services/msg-box.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ngx-md2-hero-profile-maintenance',
|
||||||
|
templateUrl: './md2-hero-profile-maintenance.component.html',
|
||||||
|
styleUrls: ['./md2-hero-profile-maintenance.component.scss']
|
||||||
|
})
|
||||||
|
export class MD2HeroProfileMaintenanceComponent implements OnInit {
|
||||||
|
@ViewChild('grid') grid: GridComponent;
|
||||||
|
MD2Icon = MD2Icon;
|
||||||
|
public gridData: GridDataResult = { data: [], total: 0 };
|
||||||
|
private allData: MD2HeroProfile[] = [];
|
||||||
|
private lastSelectedHeroClass: HeroClass;
|
||||||
|
public gridState: State = {
|
||||||
|
skip: 0,
|
||||||
|
take: 10,
|
||||||
|
sort: [{
|
||||||
|
field: 'title',
|
||||||
|
dir: 'asc'
|
||||||
|
}],
|
||||||
|
filter: {
|
||||||
|
logic: 'and',
|
||||||
|
filters: []
|
||||||
|
},
|
||||||
|
group: [{
|
||||||
|
field: 'heroClass',
|
||||||
|
dir: 'asc'
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
public isLoading: boolean = false;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private heroProfileService: MD2HeroProfileService,
|
||||||
|
private dialogService: DialogService,
|
||||||
|
private msgBoxService: MsgBoxService
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.loadData();
|
||||||
|
}
|
||||||
|
|
||||||
|
public loadData(): void {
|
||||||
|
this.isLoading = true;
|
||||||
|
this.heroProfileService.getAll().pipe(first()).subscribe(result => {
|
||||||
|
this.allData = result;
|
||||||
|
this.processGridData();
|
||||||
|
this.isLoading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public processGridData(): void {
|
||||||
|
// Normalize filter state to handle null/undefined/empty filters
|
||||||
|
let normalizedFilter: { logic: 'and' | 'or'; filters: any[] } = { logic: 'and', filters: [] };
|
||||||
|
if (this.gridState.filter) {
|
||||||
|
const filters = this.gridState.filter.filters || [];
|
||||||
|
if (filters.length > 0) {
|
||||||
|
normalizedFilter = this.gridState.filter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const normalizedState: State = {
|
||||||
|
...this.gridState,
|
||||||
|
filter: normalizedFilter
|
||||||
|
};
|
||||||
|
|
||||||
|
this.gridData = process(this.allData, normalizedState);
|
||||||
|
}
|
||||||
|
|
||||||
|
public addHandler(): void {
|
||||||
|
const editorData = { heroClass: this.lastSelectedHeroClass || HeroClass.Berserker } as MD2HeroProfile;
|
||||||
|
const dialogRef = this.dialogService.open({
|
||||||
|
title: 'Add New Hero Profile',
|
||||||
|
content: MD2HeroProfileEditorComponent,
|
||||||
|
width: '90vw',
|
||||||
|
height: 600
|
||||||
|
});
|
||||||
|
|
||||||
|
const editor = dialogRef.content.instance;
|
||||||
|
editor.isAdding = true;
|
||||||
|
editor.data = editorData;
|
||||||
|
|
||||||
|
// Force model re-initialization after data is set
|
||||||
|
setTimeout(() => {
|
||||||
|
editor.initializeModel();
|
||||||
|
}, 0);
|
||||||
|
|
||||||
|
dialogRef.result.subscribe((result: MD2HeroProfile) => {
|
||||||
|
if (result) {
|
||||||
|
this.lastSelectedHeroClass = result.heroClass;
|
||||||
|
this.loadData();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public editHandler({ dataItem }: { dataItem: MD2HeroProfile }): void {
|
||||||
|
const dialogRef = this.dialogService.open({
|
||||||
|
title: 'Edit Hero Profile',
|
||||||
|
content: MD2HeroProfileEditorComponent,
|
||||||
|
width: '90vw',
|
||||||
|
height: 600
|
||||||
|
});
|
||||||
|
|
||||||
|
const editor = dialogRef.content.instance;
|
||||||
|
editor.isAdding = false;
|
||||||
|
editor.data = JSON.parse(JSON.stringify(dataItem));
|
||||||
|
|
||||||
|
// Force model re-initialization after data is set
|
||||||
|
setTimeout(() => {
|
||||||
|
editor.initializeModel();
|
||||||
|
}, 0);
|
||||||
|
|
||||||
|
dialogRef.result.subscribe(result => {
|
||||||
|
if (result) {
|
||||||
|
this.loadData();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public removeHandler({ dataItem }: { dataItem: MD2HeroProfile }): void {
|
||||||
|
this.msgBoxService.showConfirmDeleteBox().pipe(first()).subscribe(answer => {
|
||||||
|
if (answer === true) {
|
||||||
|
this.isLoading = true;
|
||||||
|
this.heroProfileService.delete(dataItem.id).pipe(first()).subscribe(result => {
|
||||||
|
this.loadData();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public getHeroClassName(heroClass: HeroClass): string {
|
||||||
|
return HeroClass[heroClass] || '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -27,7 +27,7 @@ export class MD2HeroSelectComponent implements ControlValueAccessor, Validator {
|
|||||||
readonly: boolean = false;
|
readonly: boolean = false;
|
||||||
isRequired: boolean = false;
|
isRequired: boolean = false;
|
||||||
heroOptions: DropDownOption[];
|
heroOptions: DropDownOption[];
|
||||||
@Input() id?= '';
|
@Input() id? = '';
|
||||||
@Input() name = '';
|
@Input() name = '';
|
||||||
@Input() data: MD2HeroInfo;
|
@Input() data: MD2HeroInfo;
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
<kendo-editor [value]="value" (valueChange)="onChange($event)" (blur)="onTouched()" [disabled]="disabled"
|
<kendo-editor [value]="value" (valueChange)="onChange($event)" (blur)="onTouched()" [disabled]="disabled"
|
||||||
[schema]="messageTemplateSchema" [iframe]="false" class="h-100">
|
[schema]="messageTemplateSchema" [iframe]="false" class="h-100">
|
||||||
<kendo-toolbar>
|
<kendo-toolbar>
|
||||||
|
<!-- Custom MD2 Icon button -->
|
||||||
|
<kendo-toolbar-button text="Insert Icon" (click)="showInsertMD2Icon()"></kendo-toolbar-button>
|
||||||
<!-- Standard editing tools -->
|
<!-- Standard editing tools -->
|
||||||
<kendo-toolbar-buttongroup>
|
<kendo-toolbar-buttongroup>
|
||||||
<kendo-toolbar-button kendoEditorBoldButton></kendo-toolbar-button>
|
<kendo-toolbar-button kendoEditorBoldButton></kendo-toolbar-button>
|
||||||
@ -8,10 +10,6 @@
|
|||||||
<kendo-toolbar-button kendoEditorUnderlineButton></kendo-toolbar-button>
|
<kendo-toolbar-button kendoEditorUnderlineButton></kendo-toolbar-button>
|
||||||
<kendo-toolbar-button kendoEditorStrikethroughButton></kendo-toolbar-button>
|
<kendo-toolbar-button kendoEditorStrikethroughButton></kendo-toolbar-button>
|
||||||
</kendo-toolbar-buttongroup>
|
</kendo-toolbar-buttongroup>
|
||||||
<kendo-toolbar-buttongroup>
|
|
||||||
<kendo-toolbar-button kendoEditorSubscriptButton></kendo-toolbar-button>
|
|
||||||
<kendo-toolbar-button kendoEditorSuperscriptButton></kendo-toolbar-button>
|
|
||||||
</kendo-toolbar-buttongroup>
|
|
||||||
<kendo-toolbar-buttongroup>
|
<kendo-toolbar-buttongroup>
|
||||||
<kendo-toolbar-button kendoEditorAlignLeftButton></kendo-toolbar-button>
|
<kendo-toolbar-button kendoEditorAlignLeftButton></kendo-toolbar-button>
|
||||||
<kendo-toolbar-button kendoEditorAlignCenterButton></kendo-toolbar-button>
|
<kendo-toolbar-button kendoEditorAlignCenterButton></kendo-toolbar-button>
|
||||||
@ -30,21 +28,13 @@
|
|||||||
<kendo-toolbar-button kendoEditorIndentButton></kendo-toolbar-button>
|
<kendo-toolbar-button kendoEditorIndentButton></kendo-toolbar-button>
|
||||||
<kendo-toolbar-button kendoEditorOutdentButton></kendo-toolbar-button>
|
<kendo-toolbar-button kendoEditorOutdentButton></kendo-toolbar-button>
|
||||||
</kendo-toolbar-buttongroup>
|
</kendo-toolbar-buttongroup>
|
||||||
<kendo-toolbar-button kendoEditorBlockquoteButton></kendo-toolbar-button>
|
|
||||||
<kendo-toolbar-button kendoEditorSelectAllButton></kendo-toolbar-button>
|
|
||||||
<kendo-toolbar-buttongroup>
|
<kendo-toolbar-buttongroup>
|
||||||
<kendo-toolbar-button kendoEditorUndoButton></kendo-toolbar-button>
|
<kendo-toolbar-button kendoEditorUndoButton></kendo-toolbar-button>
|
||||||
<kendo-toolbar-button kendoEditorRedoButton></kendo-toolbar-button>
|
<kendo-toolbar-button kendoEditorRedoButton></kendo-toolbar-button>
|
||||||
</kendo-toolbar-buttongroup>
|
</kendo-toolbar-buttongroup>
|
||||||
<kendo-toolbar-buttongroup>
|
|
||||||
<kendo-toolbar-button kendoEditorCreateLinkButton></kendo-toolbar-button>
|
|
||||||
<kendo-toolbar-button kendoEditorUnlinkButton></kendo-toolbar-button>
|
|
||||||
</kendo-toolbar-buttongroup>
|
|
||||||
<kendo-toolbar-button kendoEditorInsertFileButton></kendo-toolbar-button>
|
<kendo-toolbar-button kendoEditorInsertFileButton></kendo-toolbar-button>
|
||||||
<kendo-toolbar-button kendoEditorInsertImageButton></kendo-toolbar-button>
|
<kendo-toolbar-button kendoEditorInsertImageButton></kendo-toolbar-button>
|
||||||
<kendo-toolbar-button kendoEditorViewSourceButton></kendo-toolbar-button>
|
<kendo-toolbar-button kendoEditorViewSourceButton></kendo-toolbar-button>
|
||||||
<kendo-toolbar-button kendoEditorCleanFormattingButton></kendo-toolbar-button>
|
<kendo-toolbar-button kendoEditorCleanFormattingButton></kendo-toolbar-button>
|
||||||
<!-- Custom MD2 Icon button -->
|
|
||||||
<kendo-toolbar-button text="Insert Icon" (click)="showInsertMD2Icon()"></kendo-toolbar-button>
|
|
||||||
</kendo-toolbar>
|
</kendo-toolbar>
|
||||||
</kendo-editor>
|
</kendo-editor>
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
:host ::ng-deep .k-editor-content .MD2Icon {
|
||||||
|
font-size: 30px;
|
||||||
|
}
|
||||||
@ -1,5 +1,5 @@
|
|||||||
@if(isImageIcon) {
|
@if(isImageIcon) {
|
||||||
<img [src]="imgUrl" class="{{sizeClass}} mx-2">
|
<span [innerHTML]="imgUrl" class="{{sizeClass}} mx-2"></span>
|
||||||
} @else {
|
} @else {
|
||||||
<span [innerHtml]="iconHtml" class="{{sizeClass}} mx-2"></span>
|
<span [innerHtml]="iconHtml" class="{{sizeClass}} mx-2"></span>
|
||||||
}
|
}
|
||||||
@ -55,23 +55,8 @@ export class MD2IconComponent implements OnInit {
|
|||||||
this.iconHtml = this.md2StateService.iconHtml(icon);
|
this.iconHtml = this.md2StateService.iconHtml(icon);
|
||||||
} else {
|
} else {
|
||||||
this.isImageIcon = true;
|
this.isImageIcon = true;
|
||||||
switch (icon) {
|
this.imgUrl = this.md2StateService.iconHtml(icon);
|
||||||
case MD2Icon.TreasureToken:
|
|
||||||
this.imgUrl = this.md2StateService.treasureImage(TreasureType.Cover);
|
|
||||||
break;
|
|
||||||
case MD2Icon.TreasureToken_Common:
|
|
||||||
this.imgUrl = this.md2StateService.treasureImageHtml(TreasureType.Common);
|
|
||||||
break;
|
|
||||||
case MD2Icon.TreasureToken_Rare:
|
|
||||||
this.imgUrl = this.md2StateService.treasureImage(TreasureType.Rare);
|
|
||||||
break;
|
|
||||||
case MD2Icon.TreasureToken_Epic:
|
|
||||||
this.imgUrl = this.md2StateService.treasureImage(TreasureType.Epic);
|
|
||||||
break;
|
|
||||||
case MD2Icon.TreasureToken_Legendary:
|
|
||||||
this.imgUrl = this.md2StateService.treasureImage(TreasureType.Legendary);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import { Injectable } from '@angular/core';
|
|||||||
import { CrudService } from '../../../services/crudServices/crud.service';
|
import { CrudService } from '../../../services/crudServices/crud.service';
|
||||||
import { MD2MobInfo, MD2MobLevelInfo, MD2MobSkill } from '../massive-darkness2.db.model';
|
import { MD2MobInfo, MD2MobLevelInfo, MD2MobSkill } from '../massive-darkness2.db.model';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { MD2HeroProfile } from '../massive-darkness2.model';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
@ -34,4 +35,16 @@ export class MD2MobSkillService extends CrudService<MD2MobSkill> {
|
|||||||
super(http, (action: string = null) => { return `MD2MobSkill${(action ? `/${action}` : '')}` });
|
super(http, (action: string = null) => { return `MD2MobSkill${(action ? `/${action}` : '')}` });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class MD2HeroProfileService extends CrudService<MD2HeroProfile> {
|
||||||
|
|
||||||
|
constructor(http: HttpClient) {
|
||||||
|
super(http, (action: string = null) => { return `MD2HeroProfile${(action ? `/${action}` : '')}` });
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -34,8 +34,38 @@ export class MD2StateService {
|
|||||||
}
|
}
|
||||||
if (icon < MD2Icon.RedDice) {
|
if (icon < MD2Icon.RedDice) {
|
||||||
return `<span md2-icon='${String.fromCharCode(65 + icon)}' class='MD2Icon ${cssClass}'>${String.fromCharCode(65 + icon)}</span>`
|
return `<span md2-icon='${String.fromCharCode(65 + icon)}' class='MD2Icon ${cssClass}'>${String.fromCharCode(65 + icon)}</span>`
|
||||||
} else {
|
} else if (icon < MD2Icon.TreasureToken) {
|
||||||
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 {
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -39,6 +39,12 @@
|
|||||||
line-height: 50px;
|
line-height: 50px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.shadow-skill {
|
||||||
|
::before {
|
||||||
|
font-family: "Massive Darkness 2", sans-serif !important;
|
||||||
|
content: "D";
|
||||||
|
}
|
||||||
|
}
|
||||||
.MD2Icon {
|
.MD2Icon {
|
||||||
font-family: "Massive Darkness 2", sans-serif !important;
|
font-family: "Massive Darkness 2", sans-serif !important;
|
||||||
//font-size: 20px;
|
//font-size: 20px;
|
||||||
|
|||||||
@ -20,3 +20,7 @@ nb-card {
|
|||||||
max-width: 96vw;
|
max-width: 96vw;
|
||||||
max-height: 96vh;
|
max-height: 96vh;
|
||||||
}
|
}
|
||||||
|
p {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user