WIP
This commit is contained in:
parent
701c36112c
commit
d20f2a37c4
7
.hintrc
7
.hintrc
@ -9,5 +9,10 @@
|
||||
"image-alt": "off"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"browserslist": [
|
||||
"defaults",
|
||||
"not ie 11",
|
||||
"not ie <= 11"
|
||||
]
|
||||
}
|
||||
@ -49,6 +49,7 @@ import { MD2MobInfoMaintenanceComponent } from './massive-darkness2/md2-mob-info
|
||||
import { MD2MobInfoEditorComponent } from './massive-darkness2/md2-mob-info-maintenance/md2-mob-info-editor/md2-mob-info-editor.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 { MD2MobLevelEditorComponent } from './massive-darkness2/md2-mob-info-maintenance/md2-mob-level-editor/md2-mob-level-editor.component';
|
||||
|
||||
|
||||
@NgModule({
|
||||
@ -82,7 +83,8 @@ import { MD2MobSkillEditorComponent } from './massive-darkness2/md2-mob-info-mai
|
||||
MD2MobInfoMaintenanceComponent,
|
||||
MD2MobInfoEditorComponent,
|
||||
MD2MobInfoDetailComponent,
|
||||
MD2MobSkillEditorComponent
|
||||
MD2MobSkillEditorComponent,
|
||||
MD2MobLevelEditorComponent
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
|
||||
@ -40,6 +40,7 @@ export interface MD2MobLevelInfo {
|
||||
hpPerHero: number;
|
||||
actions: number;
|
||||
attackInfo: MD2DiceSet;
|
||||
alterAttackInfo?: MD2DiceSet;
|
||||
defenceInfo: MD2DiceSet;
|
||||
}
|
||||
|
||||
@ -59,6 +60,7 @@ export interface MD2MobSkill {
|
||||
}
|
||||
|
||||
export interface MD2DiceSet {
|
||||
type: MobSkillType;
|
||||
yellow: number | null;
|
||||
orange: number | null;
|
||||
red: number | null;
|
||||
|
||||
@ -15,7 +15,10 @@ export enum MobSkillType {
|
||||
Combat,
|
||||
Passive,
|
||||
ConditionalSkill,
|
||||
ActiveSkill
|
||||
ActiveSkill,
|
||||
MeleeAttack = 15,
|
||||
RangeAttack,
|
||||
MagicAttack,
|
||||
}
|
||||
export class MobSkill {
|
||||
constructor(config: Partial<MobSkill> = {}) {
|
||||
|
||||
@ -23,6 +23,7 @@ export enum RoundPhase {
|
||||
BossActivation
|
||||
}
|
||||
export enum TreasureType {
|
||||
Cover,
|
||||
Common,
|
||||
Rare,
|
||||
Epic,
|
||||
@ -72,9 +73,17 @@ export enum MD2Icon {
|
||||
Rage,
|
||||
RedDice,
|
||||
BlueDice,
|
||||
GreenDice,
|
||||
YellowDice,
|
||||
OrangeDice,
|
||||
BlackDice
|
||||
BlackDice,
|
||||
//Below are image based icons
|
||||
TreasureToken = 300,
|
||||
TreasureToken_Common,
|
||||
TreasureToken_Rare,
|
||||
TreasureToken_Epic,
|
||||
TreasureToken_Legendary,
|
||||
|
||||
}
|
||||
export enum AttackTarget {
|
||||
Random = 40,
|
||||
|
||||
@ -1 +1,5 @@
|
||||
@if(isImageIcon) {
|
||||
<img [src]="imgUrl" class="{{sizeClass}} mx-2">
|
||||
} @else {
|
||||
<span [innerHtml]="iconHtml" class="{{sizeClass}} mx-2"></span>
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { MD2Icon } from '../massive-darkness2.model';
|
||||
import { MD2Icon, TreasureType } from '../massive-darkness2.model';
|
||||
import { MD2StateService } from '../../../services/MD2/md2-state.service';
|
||||
|
||||
@Component({
|
||||
@ -10,7 +10,8 @@ import { MD2StateService } from '../../../services/MD2/md2-state.service';
|
||||
export class MD2IconComponent implements OnInit {
|
||||
|
||||
@Input() iconClass: string = 'mr-1';
|
||||
|
||||
isImageIcon: boolean = false;
|
||||
imgUrl: string;
|
||||
iconHtml: string;
|
||||
private _icon: string | MD2Icon;
|
||||
|
||||
@ -27,7 +28,7 @@ export class MD2IconComponent implements OnInit {
|
||||
v = MD2Icon[key as keyof typeof MD2Icon];
|
||||
}
|
||||
}
|
||||
this.iconHtml = this.md2StateService.iconHtml(v as MD2Icon);
|
||||
this.initIcon(v as MD2Icon);
|
||||
}
|
||||
if (this.isMD2Icon(v)) {
|
||||
this.iconName = MD2Icon[v].toLowerCase();
|
||||
@ -48,20 +49,46 @@ export class MD2IconComponent implements OnInit {
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
private initIcon(icon: MD2Icon): void {
|
||||
if (icon < MD2Icon.TreasureToken) {
|
||||
this.isImageIcon = false;
|
||||
this.iconHtml = this.md2StateService.iconHtml(icon);
|
||||
} else {
|
||||
this.isImageIcon = true;
|
||||
switch (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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public get sizeClass(): string {
|
||||
switch (this.size) {
|
||||
case 'sm':
|
||||
return 'g-font-size-18'
|
||||
return this.isImageIcon ? 'g-width-25 img-fluid' : 'g-font-size-18'
|
||||
break;
|
||||
case 'med':
|
||||
return 'g-font-size-30'
|
||||
return this.isImageIcon ? 'g-width-35 img-fluid' : 'g-font-size-30'
|
||||
break;
|
||||
case 'lg':
|
||||
return 'g-font-size-50'
|
||||
return this.isImageIcon ? 'g-width-50 img-fluid' : 'g-font-size-50'
|
||||
break;
|
||||
|
||||
default:
|
||||
return 'g-font-size-' + this.size;
|
||||
return this.isImageIcon ? 'g-width-20 img-fluid' : 'g-font-size-' + this.size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -32,19 +32,12 @@
|
||||
|
||||
<kendo-grid #levelsGrid [data]="mobLevelInfos" [loading]="isLoading" [pageSize]="levelsState.take"
|
||||
[skip]="levelsState.skip" [sortable]="true" [filterable]="true" [pageable]="true" [height]="300"
|
||||
kendoGridTemplateEditing (edit)="editLevelHandler($event)" (cancel)="cancelLevelHandler($event)"
|
||||
(save)="saveLevelHandler($event)" (remove)="removeLevelHandler($event)"
|
||||
(dataStateChange)="levelsState = $event">
|
||||
(remove)="removeLevelHandler($event)" (dataStateChange)="levelsState = $event">
|
||||
|
||||
<kendo-grid-column field="level" title="Level" [width]="50">
|
||||
<ng-template kendoGridCellTemplate let-dataItem>
|
||||
{{ dataItem.level }}
|
||||
</ng-template>
|
||||
<ng-template kendoGridEditTemplate let-dataItem="dataItem" let-rowIndex="rowIndex">
|
||||
<kendo-numerictextbox [(ngModel)]="dataItem.level" [name]="'level_' + rowIndex" [min]="1" [decimals]="0"
|
||||
[format]="'n0'">
|
||||
</kendo-numerictextbox>
|
||||
</ng-template>
|
||||
</kendo-grid-column>
|
||||
|
||||
<!-- <kendo-grid-column field="fixedHp" title="HP" [width]="80">
|
||||
@ -62,11 +55,6 @@
|
||||
<ng-template kendoGridCellTemplate let-dataItem>
|
||||
{{ dataItem.hpPerHero }}
|
||||
</ng-template>
|
||||
<ng-template kendoGridEditTemplate let-dataItem="dataItem" let-rowIndex="rowIndex">
|
||||
<kendo-numerictextbox [(ngModel)]="dataItem.hpPerHero" [name]="'hpPerHero_' + rowIndex" [min]="0"
|
||||
[decimals]="0" [format]="'n0'">
|
||||
</kendo-numerictextbox>
|
||||
</ng-template>
|
||||
</kendo-grid-column>
|
||||
|
||||
<!-- <kendo-grid-column field="actions" title="Actions" [width]="100">
|
||||
@ -84,67 +72,37 @@
|
||||
<ng-template kendoGridCellTemplate let-dataItem>
|
||||
{{ dataItem.rewardTokens }}
|
||||
</ng-template>
|
||||
<ng-template kendoGridEditTemplate let-dataItem="dataItem" let-rowIndex="rowIndex">
|
||||
<kendo-numerictextbox [(ngModel)]="dataItem.rewardTokens" [name]="'rewardTokens_' + rowIndex" [min]="0"
|
||||
[decimals]="0" [format]="'n0'">
|
||||
</kendo-numerictextbox>
|
||||
</ng-template>
|
||||
</kendo-grid-column>
|
||||
|
||||
<kendo-grid-column field="fixedRareTreasure" title="Rare Treasure" [width]="80">
|
||||
<ng-template kendoGridCellTemplate let-dataItem>
|
||||
{{ dataItem.fixedRareTreasure }}
|
||||
</ng-template>
|
||||
<ng-template kendoGridEditTemplate let-dataItem="dataItem" let-rowIndex="rowIndex">
|
||||
<kendo-numerictextbox [(ngModel)]="dataItem.fixedRareTreasure" [name]="'fixedRareTreasure_' + rowIndex"
|
||||
[min]="0" [decimals]="0" [format]="'n0'">
|
||||
</kendo-numerictextbox>
|
||||
</ng-template>
|
||||
</kendo-grid-column>
|
||||
|
||||
<kendo-grid-column field="fixedEpicTreasure" title="Epic Treasure" [width]="80">
|
||||
<ng-template kendoGridCellTemplate let-dataItem>
|
||||
{{ dataItem.fixedEpicTreasure }}
|
||||
</ng-template>
|
||||
<ng-template kendoGridEditTemplate let-dataItem="dataItem" let-rowIndex="rowIndex">
|
||||
<kendo-numerictextbox [(ngModel)]="dataItem.fixedEpicTreasure" [name]="'fixedEpicTreasure_' + rowIndex"
|
||||
[min]="0" [decimals]="0" [format]="'n0'">
|
||||
</kendo-numerictextbox>
|
||||
</ng-template>
|
||||
</kendo-grid-column>
|
||||
|
||||
<kendo-grid-column field="fixedLegendTreasure" title="Legend Treasure" [width]="60">
|
||||
<ng-template kendoGridCellTemplate let-dataItem>
|
||||
{{ dataItem.fixedLegendTreasure }}
|
||||
</ng-template>
|
||||
<ng-template kendoGridEditTemplate let-dataItem="dataItem" let-rowIndex="rowIndex">
|
||||
<kendo-numerictextbox [(ngModel)]="dataItem.fixedLegendTreasure"
|
||||
[name]="'fixedLegendTreasure_' + rowIndex" [min]="0" [decimals]="0" [format]="'n0'">
|
||||
</kendo-numerictextbox>
|
||||
</ng-template>
|
||||
</kendo-grid-column>
|
||||
<!-- result.defenceInfo.blue
|
||||
result.defenceInfo.green -->
|
||||
<kendo-grid-column field="defenceInfo.blue" title="Blue Dice" [width]="60">
|
||||
<ng-template kendoGridCellTemplate let-dataItem>
|
||||
{{ dataItem.defenceInfo.blue }}
|
||||
</ng-template>
|
||||
<ng-template kendoGridEditTemplate let-dataItem="dataItem" let-rowIndex="rowIndex">
|
||||
<kendo-numerictextbox [(ngModel)]="dataItem.defenceInfo.blue" [name]="'defenceInfo.blue_' + rowIndex"
|
||||
[min]="0" [decimals]="0" [format]="'n0'">
|
||||
</kendo-numerictextbox>
|
||||
{{ dataItem.defenceInfo?.blue }}
|
||||
</ng-template>
|
||||
</kendo-grid-column>
|
||||
|
||||
<kendo-grid-command-column title="Actions" [width]="133">
|
||||
<ng-template kendoGridCellTemplate let-isNew="isNew" let-dataItem="dataItem" let-rowIndex="rowIndex">
|
||||
<button kendoGridEditCommand [primary]="true">Edit</button>
|
||||
<button kendoButton [primary]="true" (click)="editLevelHandler(dataItem)">Edit</button>
|
||||
<button kendoGridRemoveCommand>Remove</button>
|
||||
<!-- <button kendoButton (click)="selectLevelInfo(dataItem)" [look]="'flat'">
|
||||
View Skills
|
||||
</button> -->
|
||||
<button kendoGridSaveCommand>Save</button>
|
||||
<button kendoGridCancelCommand>Cancel</button>
|
||||
</ng-template>
|
||||
</kendo-grid-command-column>
|
||||
</kendo-grid>
|
||||
|
||||
@ -20,7 +20,7 @@
|
||||
}
|
||||
|
||||
.info-grid {
|
||||
display: grid;
|
||||
display: grd;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
@ -9,6 +9,7 @@ import { MobSkillType } from '../../massive-darkness2.model.boss';
|
||||
import { MD2MobLevelInfoService, MD2MobSkillService } from '../../service/massive-darkness2.service';
|
||||
import { MsgBoxService } from '../../../../services/msg-box.service';
|
||||
import { MD2MobSkillEditorComponent } from '../md2-mob-skill-editor/md2-mob-skill-editor.component';
|
||||
import { MD2MobLevelEditorComponent } from '../md2-mob-level-editor/md2-mob-level-editor.component';
|
||||
|
||||
@Component({
|
||||
selector: 'ngx-md2-mob-info-detail',
|
||||
@ -90,28 +91,25 @@ export class MD2MobInfoDetailComponent extends DialogContentBase implements OnIn
|
||||
|
||||
public selectLevelInfo(levelInfo: MD2MobLevelInfo): void {
|
||||
if (levelInfo.defenceInfo == null) {
|
||||
levelInfo.defenceInfo = { blue: 0, green: 0, yellow: 0, orange: 0, red: 0, black: 0 };
|
||||
levelInfo.defenceInfo = { type: MobSkillType.Defense, blue: 0, green: 0, yellow: 0, orange: 0, red: 0, black: 0 };
|
||||
}
|
||||
if (levelInfo.attackInfo == null) {
|
||||
levelInfo.attackInfo = { blue: 0, green: 0, yellow: 0, orange: 0, red: 0, black: 0 };
|
||||
levelInfo.attackInfo = { type: MobSkillType.Attack, blue: 0, green: 0, yellow: 0, orange: 0, red: 0, black: 0 };
|
||||
}
|
||||
this.selectedLevelInfo = levelInfo;
|
||||
this.loadSkills();
|
||||
}
|
||||
|
||||
public editLevelHandler({ sender, rowIndex, dataItem }: any): void {
|
||||
// The template-driven editing directive handles edit mode automatically
|
||||
// This handler is here to ensure the grid enters edit mode
|
||||
// The grid should already be in edit mode from the directive, but we ensure it
|
||||
}
|
||||
public editLevelHandler(dataItem: MD2MobLevelInfo): void {
|
||||
if (!this.mobInfo) return;
|
||||
|
||||
public cancelLevelHandler({ sender, rowIndex }: any): void {
|
||||
// Cancel editing - template-driven editing handles this automatically
|
||||
sender.closeRow(rowIndex);
|
||||
// Create a copy of the level info for editing
|
||||
const levelCopy: MD2MobLevelInfo = JSON.parse(JSON.stringify(dataItem));
|
||||
this.openLevelEditor(levelCopy, false);
|
||||
}
|
||||
|
||||
public addLevelHandler(): void {
|
||||
if (!this.mobInfo || !this.levelsGrid) return;
|
||||
if (!this.mobInfo) return;
|
||||
|
||||
// Get the last level info (highest level) if any exists
|
||||
const lastLevel = this.mobLevelInfos.length > 0
|
||||
@ -121,16 +119,8 @@ export class MD2MobInfoDetailComponent extends DialogContentBase implements OnIn
|
||||
// Calculate the next level number
|
||||
const nextLevel = lastLevel ? lastLevel.level + 2 : 1;
|
||||
let rewardTokens = 0;
|
||||
let actions = 1;
|
||||
|
||||
switch (nextLevel) {
|
||||
case 1:
|
||||
case 3:
|
||||
rewardTokens = 1;
|
||||
break;
|
||||
case 5:
|
||||
rewardTokens = 2;
|
||||
break;
|
||||
}
|
||||
|
||||
let newLevel: MD2MobLevelInfo;
|
||||
|
||||
@ -144,15 +134,15 @@ export class MD2MobInfoDetailComponent extends DialogContentBase implements OnIn
|
||||
fixedRareTreasure: lastLevel.fixedRareTreasure ?? 0,
|
||||
fixedEpicTreasure: lastLevel.fixedEpicTreasure ?? 0,
|
||||
fixedLegendTreasure: lastLevel.fixedLegendTreasure ?? 0,
|
||||
fixedHp: lastLevel.fixedHp ?? 1,
|
||||
fixedHp: lastLevel.fixedHp ?? 0,
|
||||
hpPerHero: lastLevel.hpPerHero ?? 0,
|
||||
actions: lastLevel.actions ?? 1,
|
||||
actions: lastLevel.actions ?? actions,
|
||||
attackInfo: lastLevel.attackInfo
|
||||
? { ...lastLevel.attackInfo }
|
||||
: { yellow: null, orange: null, red: null, blue: null, green: null, black: null },
|
||||
: { type: MobSkillType.Attack, yellow: null, orange: null, red: null, blue: null, green: null, black: null },
|
||||
defenceInfo: lastLevel.defenceInfo
|
||||
? { ...lastLevel.defenceInfo }
|
||||
: { yellow: null, orange: null, red: null, blue: null, green: null, black: null }
|
||||
: { type: MobSkillType.Defense, yellow: null, orange: null, red: null, blue: null, green: null, black: null }
|
||||
};
|
||||
} else {
|
||||
// Default values if no levels exist
|
||||
@ -164,42 +154,91 @@ export class MD2MobInfoDetailComponent extends DialogContentBase implements OnIn
|
||||
fixedRareTreasure: 0,
|
||||
fixedEpicTreasure: 0,
|
||||
fixedLegendTreasure: 0,
|
||||
fixedHp: 1,
|
||||
fixedHp: 0,
|
||||
hpPerHero: 0,
|
||||
actions: 1,
|
||||
attackInfo: { yellow: null, orange: null, red: null, blue: null, green: null, black: null },
|
||||
defenceInfo: { yellow: null, orange: null, red: null, blue: null, green: null, black: null }
|
||||
actions: actions,
|
||||
attackInfo: { type: MobSkillType.Attack, yellow: null, orange: null, red: null, blue: null, green: null, black: null },
|
||||
defenceInfo: { type: MobSkillType.Defense, yellow: null, orange: null, red: null, blue: null, green: null, black: null }
|
||||
};
|
||||
}
|
||||
|
||||
// Use grid's addRow method to properly add a new row in edit mode
|
||||
this.levelsGrid.addRow(newLevel);
|
||||
switch (this.mobInfo.type) {
|
||||
case MobType.Mob:
|
||||
newLevel.actions = 2;
|
||||
|
||||
switch (nextLevel) {
|
||||
case 1:
|
||||
case 3:
|
||||
newLevel.rewardTokens = 1;
|
||||
break;
|
||||
case 5:
|
||||
newLevel.rewardTokens = 2;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case MobType.Boss:
|
||||
newLevel.actions = 1;
|
||||
break;
|
||||
case MobType.RoamingMonster:
|
||||
newLevel.actions = 1;
|
||||
|
||||
switch (nextLevel) {
|
||||
case 1:
|
||||
newLevel.rewardTokens = 2;
|
||||
newLevel.fixedRareTreasure = 1;
|
||||
break;
|
||||
case 3:
|
||||
newLevel.rewardTokens = 2;
|
||||
newLevel.fixedEpicTreasure = 1;
|
||||
break;
|
||||
case 5:
|
||||
newLevel.rewardTokens = 0;
|
||||
newLevel.fixedEpicTreasure = 3;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
this.openLevelEditor(newLevel, true);
|
||||
}
|
||||
|
||||
public saveLevelHandler({ dataItem, isNew }: any): void {
|
||||
private openLevelEditor(level: MD2MobLevelInfo, isNew: boolean): void {
|
||||
if (!this.mobInfo) return;
|
||||
|
||||
const dialogRef = this.dialogService.open({
|
||||
title: isNew ? 'Add New Level' : 'Edit Level',
|
||||
content: MD2MobLevelEditorComponent,
|
||||
width: '80vw',
|
||||
height: 700
|
||||
});
|
||||
|
||||
const editor = dialogRef.content.instance as MD2MobLevelEditorComponent;
|
||||
editor.isAdding = isNew;
|
||||
editor.data = level;
|
||||
editor.mobInfoId = this.mobInfo.id;
|
||||
editor.mobType = this.mobInfo.type;
|
||||
|
||||
// Force model re-initialization after data is set
|
||||
setTimeout(() => {
|
||||
editor.initializeModel();
|
||||
}, 0);
|
||||
|
||||
dialogRef.result.subscribe(result => {
|
||||
if (result && typeof result === 'object' && 'id' in result) {
|
||||
this.handleLevelSaved(result as MD2MobLevelInfo, isNew);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private handleLevelSaved(result: MD2MobLevelInfo, isNew: boolean): void {
|
||||
if (!this.mobInfo) return;
|
||||
|
||||
if (isNew) {
|
||||
dataItem.id = this.generateLevelId();
|
||||
dataItem.mobInfoId = this.mobInfo?.id;
|
||||
if (!this.mobInfo.mobLevelInfos) {
|
||||
this.mobInfo.mobLevelInfos = [];
|
||||
}
|
||||
|
||||
// Ensure required objects exist
|
||||
if (!dataItem.attackInfo) {
|
||||
dataItem.attackInfo = { yellow: null, orange: null, red: null, blue: null, green: null, black: null };
|
||||
}
|
||||
if (!dataItem.defenceInfo) {
|
||||
dataItem.defenceInfo = { yellow: null, orange: null, red: null, blue: null, green: null, black: null };
|
||||
}
|
||||
|
||||
this.isLoading = true;
|
||||
this.mobLevelInfoService.createOrUpdate(dataItem).pipe(first()).subscribe(result => {
|
||||
this.isLoading = false;
|
||||
if (isNew) {
|
||||
// For new items, add to the array
|
||||
|
||||
result.attackInfo.black = 0;
|
||||
this.mobLevelInfos.push(result);
|
||||
} else {
|
||||
// For existing items, update in the array
|
||||
const index = this.mobLevelInfos.findIndex(l => l.id === result.id);
|
||||
if (index !== -1) {
|
||||
this.mobLevelInfos[index] = result;
|
||||
@ -210,17 +249,6 @@ export class MD2MobInfoDetailComponent extends DialogContentBase implements OnIn
|
||||
}
|
||||
}
|
||||
}
|
||||
// Close the edit row after saving
|
||||
if (this.levelsGrid) {
|
||||
const rowIndex = this.mobLevelInfos.findIndex(l => l.id === result.id);
|
||||
if (rowIndex !== -1) {
|
||||
this.levelsGrid.closeRow(rowIndex);
|
||||
}
|
||||
}
|
||||
}, error => {
|
||||
this.isLoading = false;
|
||||
console.error('Error saving level info:', error);
|
||||
});
|
||||
}
|
||||
|
||||
public removeLevelHandler({ dataItem }: { dataItem: MD2MobLevelInfo }): void {
|
||||
|
||||
@ -9,8 +9,9 @@
|
||||
</nb-card-header>
|
||||
<nb-card-body>
|
||||
<kendo-grid #grid [data]="gridData" [loading]="isLoading" [pageSize]="gridState.take" [skip]="gridState.skip"
|
||||
[group]="gridState.group" [sortable]="true" [filterable]="true" [pageable]="true" [selectable]="true"
|
||||
[groupable]="true" (dataStateChange)="gridState = $event; loadData()">
|
||||
[group]="gridState.group" [filter]="gridState.filter" [sort]="gridState.sort" [sortable]="true"
|
||||
[filterable]="true" [pageable]="true" [selectable]="true" [groupable]="true"
|
||||
(dataStateChange)="gridState = $event; processGridData()">
|
||||
|
||||
<kendo-grid-toolbar>
|
||||
<button kendoGridAddCommand>Add new</button>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||
import { GridComponent, GridDataResult } from '@progress/kendo-angular-grid';
|
||||
import { State } from '@progress/kendo-data-query';
|
||||
import { State, process } from '@progress/kendo-data-query';
|
||||
import { first } from 'rxjs/operators';
|
||||
import { MD2MobInfo, GameBundle } from '../massive-darkness2.db.model';
|
||||
import { MobType } from '../massive-darkness2.model';
|
||||
@ -19,6 +19,7 @@ export class MD2MobInfoMaintenanceComponent implements OnInit {
|
||||
@ViewChild('grid') grid: GridComponent;
|
||||
|
||||
public gridData: GridDataResult = { data: [], total: 0 };
|
||||
private allData: MD2MobInfo[] = [];
|
||||
public gridState: State = {
|
||||
skip: 0,
|
||||
take: 10,
|
||||
@ -51,14 +52,30 @@ export class MD2MobInfoMaintenanceComponent implements OnInit {
|
||||
public loadData(): void {
|
||||
this.isLoading = true;
|
||||
this.mobInfoService.getAll().pipe(first()).subscribe(result => {
|
||||
this.gridData = {
|
||||
data: result.sort((a, b) => a.name.localeCompare(b.name)),
|
||||
total: result.length
|
||||
};
|
||||
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 = {} as MD2MobInfo;
|
||||
const dialogRef = this.dialogService.open({
|
||||
|
||||
@ -0,0 +1,168 @@
|
||||
<div class="k-dialog-content">
|
||||
<form #form="ngForm" class="k-form">
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<div class="form-group">
|
||||
<label class="k-label">Level *</label>
|
||||
<kendo-numerictextbox [(ngModel)]="model.level" name="level" [min]="1" [decimals]="0"
|
||||
[format]="'n0'">
|
||||
</kendo-numerictextbox>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-3">
|
||||
<div class="form-group">
|
||||
<label class="k-label">
|
||||
<md2-icon [icon]="MD2Icon.HP"></md2-icon>
|
||||
{{mobType==MobType.Mob?'HP/Unit':'HP/Hero'}}
|
||||
</label>
|
||||
<kendo-numerictextbox [(ngModel)]="model.hpPerHero" name="hpPerHero" [min]="0" [decimals]="0"
|
||||
[format]="'n0'">
|
||||
</kendo-numerictextbox>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-3">
|
||||
<div class="form-group">
|
||||
<label class="k-label">
|
||||
<md2-icon [icon]="MD2Icon.TreasureToken"></md2-icon>Reward Tokens</label>
|
||||
<kendo-numerictextbox [(ngModel)]="model.rewardTokens" name="rewardTokens" [min]="0" [decimals]="0"
|
||||
[format]="'n0'">
|
||||
</kendo-numerictextbox>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-3">
|
||||
<div class="form-group">
|
||||
<label class="k-label">Fixed HP</label>
|
||||
<kendo-numerictextbox [(ngModel)]="model.fixedHp" name="fixedHp" [min]="0" [decimals]="0"
|
||||
[format]="'n0'">
|
||||
</kendo-numerictextbox>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-3">
|
||||
<div class="form-group">
|
||||
<label class="k-label">
|
||||
<md2-icon [icon]="MD2Icon.TreasureToken_Rare"></md2-icon>Rare Treasure</label>
|
||||
<kendo-numerictextbox [(ngModel)]="model.fixedRareTreasure" name="fixedRareTreasure" [min]="0"
|
||||
[decimals]="0" [format]="'n0'">
|
||||
</kendo-numerictextbox>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-3">
|
||||
<div class="form-group">
|
||||
<label class="k-label">
|
||||
<md2-icon [icon]="MD2Icon.TreasureToken_Epic"></md2-icon>Epic Treasure</label>
|
||||
<kendo-numerictextbox [(ngModel)]="model.fixedEpicTreasure" name="fixedEpicTreasure" [min]="0"
|
||||
[decimals]="0" [format]="'n0'">
|
||||
</kendo-numerictextbox>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-3">
|
||||
<div class="form-group">
|
||||
<label class="k-label">
|
||||
<md2-icon [icon]="MD2Icon.TreasureToken_Legendary"></md2-icon>Legend Treasure</label>
|
||||
<kendo-numerictextbox [(ngModel)]="model.fixedLegendTreasure" name="fixedLegendTreasure" [min]="0"
|
||||
[decimals]="0" [format]="'n0'">
|
||||
</kendo-numerictextbox>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-3">
|
||||
<div class="form-group">
|
||||
<label class="k-label">Actions</label>
|
||||
<kendo-numerictextbox [(ngModel)]="model.actions" name="actions" [min]="0" [decimals]="0"
|
||||
[format]="'n0'">
|
||||
</kendo-numerictextbox>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h5>Defense Info</h5>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<div class="form-group">
|
||||
<label class="k-label">
|
||||
<md2-icon [icon]="MD2Icon.BlueDice"></md2-icon>Blue Dice</label>
|
||||
<kendo-numerictextbox [(ngModel)]="model.defenceInfo.blue" name="defenceInfo.blue" [min]="0"
|
||||
[decimals]="0" [format]="'n0'">
|
||||
</kendo-numerictextbox>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<div class="form-group">
|
||||
<label class="k-label">
|
||||
<md2-icon [icon]="MD2Icon.GreenDice"></md2-icon>Green Dice</label>
|
||||
<kendo-numerictextbox [(ngModel)]="model.defenceInfo.green" name="defenceInfo.green" [min]="0"
|
||||
[decimals]="0" [format]="'n0'">
|
||||
</kendo-numerictextbox>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<div class="form-group">
|
||||
<label class="k-label">
|
||||
<md2-icon [icon]="MD2Icon.BlackDice"></md2-icon>Black Dice</label>
|
||||
<kendo-numerictextbox [(ngModel)]="model.defenceInfo.black" name="defenceInfo.black" [min]="0"
|
||||
[decimals]="0" [format]="'n0'">
|
||||
</kendo-numerictextbox>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row" *ngIf="mobType!=MobType.Mob">
|
||||
<div class="col-md-12">
|
||||
<h5>Attack Info</h5>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<div class="form-group">
|
||||
<label class="k-label">
|
||||
<md2-icon [icon]="MD2Icon.YellowDice"></md2-icon>Yellow Dice</label>
|
||||
<kendo-numerictextbox [(ngModel)]="model.attackInfo.yellow" name="attackInfo.yellow" [min]="0"
|
||||
[decimals]="0" [format]="'n0'">
|
||||
</kendo-numerictextbox>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<div class="form-group">
|
||||
<label class="k-label">
|
||||
<md2-icon [icon]="MD2Icon.OrangeDice"></md2-icon>Orange Dice</label>
|
||||
<kendo-numerictextbox [(ngModel)]="model.attackInfo.orange" name="attackInfo.orange" [min]="0"
|
||||
[decimals]="0" [format]="'n0'">
|
||||
</kendo-numerictextbox>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<div class="form-group">
|
||||
<label class="k-label">
|
||||
<md2-icon [icon]="MD2Icon.RedDice"></md2-icon>Red Dice</label>
|
||||
<kendo-numerictextbox [(ngModel)]="model.attackInfo.red" name="attackInfo.red" [min]="0"
|
||||
[decimals]="0" [format]="'n0'">
|
||||
</kendo-numerictextbox>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<div class="form-group">
|
||||
<label class="k-label">
|
||||
<md2-icon [icon]="MD2Icon.BlackDice"></md2-icon>Black Dice</label>
|
||||
<kendo-numerictextbox [(ngModel)]="model.attackInfo.black" name="attackInfo.black" [min]="0"
|
||||
[decimals]="0" [format]="'n0'">
|
||||
</kendo-numerictextbox>
|
||||
</div>
|
||||
</div>
|
||||
</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,22 @@
|
||||
.k-dialog-content {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.k-form {
|
||||
.form-group {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.k-label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
h5 {
|
||||
margin-top: 20px;
|
||||
margin-bottom: 15px;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,94 @@
|
||||
import { Component, Input, OnInit, ChangeDetectorRef } from '@angular/core';
|
||||
import { DialogRef, DialogContentBase } from '@progress/kendo-angular-dialog';
|
||||
import { first } from 'rxjs/operators';
|
||||
import { MD2MobLevelInfo } from '../../massive-darkness2.db.model';
|
||||
import { MobSkillType } from '../../massive-darkness2.model.boss';
|
||||
import { MD2MobLevelInfoService } from '../../service/massive-darkness2.service';
|
||||
import { MD2Icon, MobType } from '../../massive-darkness2.model';
|
||||
|
||||
@Component({
|
||||
selector: 'ngx-md2-mob-level-editor',
|
||||
templateUrl: './md2-mob-level-editor.component.html',
|
||||
styleUrls: ['./md2-mob-level-editor.component.scss']
|
||||
})
|
||||
export class MD2MobLevelEditorComponent extends DialogContentBase implements OnInit {
|
||||
MobType = MobType;
|
||||
MD2Icon = MD2Icon;
|
||||
MobSkillType = MobSkillType;
|
||||
@Input() public data: MD2MobLevelInfo;
|
||||
@Input() public mobType: MobType;
|
||||
@Input() public mobInfoId: string;
|
||||
@Input() public isAdding: boolean = false;
|
||||
|
||||
public model: MD2MobLevelInfo;
|
||||
public processing: boolean = false;
|
||||
|
||||
constructor(
|
||||
public dialog: DialogRef,
|
||||
private mobLevelInfoService: MD2MobLevelInfoService,
|
||||
private cdr: ChangeDetectorRef
|
||||
) {
|
||||
super(dialog);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.initializeModel();
|
||||
}
|
||||
|
||||
public initializeModel(): void {
|
||||
this.model = {
|
||||
id: this.data?.id || '',
|
||||
level: this.data?.level ?? 1,
|
||||
mobInfoId: this.mobInfoId || this.data?.mobInfoId || '',
|
||||
rewardTokens: this.data?.rewardTokens ?? 0,
|
||||
fixedRareTreasure: this.data?.fixedRareTreasure ?? 0,
|
||||
fixedEpicTreasure: this.data?.fixedEpicTreasure ?? 0,
|
||||
fixedLegendTreasure: this.data?.fixedLegendTreasure ?? 0,
|
||||
fixedHp: this.data?.fixedHp ?? 1,
|
||||
hpPerHero: this.data?.hpPerHero ?? 0,
|
||||
actions: this.data?.actions ?? 1,
|
||||
attackInfo: this.data?.attackInfo
|
||||
? { ...this.data.attackInfo }
|
||||
: { type: MobSkillType.Attack, yellow: null, orange: null, red: null, blue: null, green: null, black: null },
|
||||
defenceInfo: this.data?.defenceInfo
|
||||
? { ...this.data.defenceInfo }
|
||||
: { type: MobSkillType.Defense, yellow: null, orange: null, red: null, blue: null, green: null, black: null }
|
||||
};
|
||||
|
||||
this.cdr.detectChanges();
|
||||
}
|
||||
|
||||
public close(): void {
|
||||
this.dialog.close();
|
||||
}
|
||||
|
||||
public save(): void {
|
||||
if (!this.processing) {
|
||||
this.processing = true;
|
||||
|
||||
// Ensure required objects exist
|
||||
if (!this.model.attackInfo) {
|
||||
this.model.attackInfo = { type: MobSkillType.Attack, yellow: null, orange: null, red: null, blue: null, green: null, black: null };
|
||||
}
|
||||
if (!this.model.defenceInfo) {
|
||||
this.model.defenceInfo = { type: MobSkillType.Defense, yellow: null, orange: null, red: null, blue: null, green: null, black: null };
|
||||
}
|
||||
|
||||
this.mobLevelInfoService.createOrUpdate(this.model).pipe(first()).subscribe(result => {
|
||||
this.processing = false;
|
||||
this.dialog.close(result);
|
||||
}, error => {
|
||||
this.processing = false;
|
||||
console.error('Error saving mob level info:', error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public get isValid(): boolean {
|
||||
if (!this.model) {
|
||||
return false;
|
||||
}
|
||||
return this.model.level > 0 && this.model.mobInfoId !== '';
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,7 +15,6 @@ body {
|
||||
color: #7d7d8f;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-moz-font-feature-settings: "liga", "kern";
|
||||
text-rendering: optimizelegibility;
|
||||
background-color: #fff;
|
||||
overflow-x: hidden;
|
||||
|
||||
@ -128,6 +128,12 @@
|
||||
}
|
||||
color: #ffc107 !important;
|
||||
}
|
||||
&.diceGreen {
|
||||
&::before {
|
||||
content: "U";
|
||||
}
|
||||
color: #3df33d !important;
|
||||
}
|
||||
&.diceOrange {
|
||||
&::before {
|
||||
content: "U";
|
||||
@ -163,6 +169,9 @@
|
||||
&.Red {
|
||||
color: crimson !important;
|
||||
}
|
||||
&.Green {
|
||||
color: #3df33d !important;
|
||||
}
|
||||
&::before {
|
||||
content: "U";
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user