This commit is contained in:
Chris Chen 2025-11-05 15:21:42 -08:00
parent d20f2a37c4
commit 716e25f0ba
20 changed files with 502 additions and 53 deletions

View File

@ -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 },
] ]
}, },

View File

@ -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,

View File

@ -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">

View File

@ -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];

View File

@ -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> = {}

View File

@ -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>

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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>

View File

@ -0,0 +1,11 @@
:host {
display: block;
}
.float-right {
float: right;
}
kendo-grid {
height: 77vh;
}

View File

@ -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] || '';
}
}

View File

@ -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;

View File

@ -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>

View File

@ -0,0 +1,3 @@
:host ::ng-deep .k-editor-content .MD2Icon {
font-size: 30px;
}

View File

@ -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>
} }

View File

@ -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;
}
} }
} }

View File

@ -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}` : '')}` });
}
} }

View File

@ -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);
}
} }
} }

View File

@ -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;

View File

@ -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;
}