This commit is contained in:
Chris Chen 2025-11-04 22:14:55 -08:00
parent e5933104cc
commit 701c36112c
14 changed files with 315 additions and 265 deletions

View File

@ -25,6 +25,7 @@ export interface MD2MobInfo {
leaderImgUrl: string;
minionImgUrl: string;
mobLevelInfos: MD2MobLevelInfo[];
skills: MD2MobSkill[];
}
export interface MD2MobLevelInfo {
@ -40,17 +41,19 @@ export interface MD2MobLevelInfo {
actions: number;
attackInfo: MD2DiceSet;
defenceInfo: MD2DiceSet;
skills: MD2MobSkill[];
}
export interface MD2MobSkill {
id: string;
mobLevelInfoId: string;
seq: number;
level: number;
mobInfoId: string;
type: MobSkillType;
skillTarget: MobSkillTarget | null;
clawRoll: number;
skillRoll: number;
name: string;
skillCondition: string;
description: string;
uiDisplay?: boolean;
}

View File

@ -12,7 +12,10 @@ import { MD2DiceSet, MD2MobSkill } from "./massive-darkness2.db.model"
export enum MobSkillType {
Attack,
Defense,
Combat
Combat,
Passive,
ConditionalSkill,
ActiveSkill
}
export class MobSkill {
constructor(config: Partial<MobSkill> = {}) {

View File

@ -21,8 +21,9 @@
</div>
</div>
<div class="levels-section">
<h4>Mob Levels</h4>
<kendo-tabstrip tabPosition="top">
<kendo-tabstrip-tab title="Levels" [selected]="true">
<ng-template kendoTabContent>
<div class="levels-toolbar">
<button kendoButton (click)="addLevelHandler()" [primary]="true">
<span class="k-icon k-i-plus"></span> Add Level
@ -32,7 +33,8 @@
<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">
(save)="saveLevelHandler($event)" (remove)="removeLevelHandler($event)"
(dataStateChange)="levelsState = $event">
<kendo-grid-column field="level" title="Level" [width]="50">
<ng-template kendoGridCellTemplate let-dataItem>
@ -116,8 +118,8 @@
{{ 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 [(ngModel)]="dataItem.fixedLegendTreasure"
[name]="'fixedLegendTreasure_' + rowIndex" [min]="0" [decimals]="0" [format]="'n0'">
</kendo-numerictextbox>
</ng-template>
</kendo-grid-column>
@ -134,22 +136,22 @@
</ng-template>
</kendo-grid-column>
<kendo-grid-command-column title="Actions" [width]="250">
<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 kendoGridRemoveCommand>Remove</button>
<button kendoButton (click)="selectLevelInfo(dataItem)" [look]="'flat'">
<!-- <button kendoButton (click)="selectLevelInfo(dataItem)" [look]="'flat'">
View Skills
</button>
</button> -->
<button kendoGridSaveCommand>Save</button>
<button kendoGridCancelCommand>Cancel</button>
</ng-template>
</kendo-grid-command-column>
</kendo-grid>
</div>
<div class="skills-section" *ngIf="selectedLevelInfo">
<h4>Skills for Selected Level</h4>
</ng-template>
</kendo-tabstrip-tab>
<kendo-tabstrip-tab title="Skills">
<ng-template kendoTabContent>
<div class="skills-toolbar">
<button kendoButton (click)="addSkillHandler()" [primary]="true">
<span class="k-icon k-i-plus"></span> Add Skill
@ -160,6 +162,17 @@
[skip]="skillsState.skip" [sortable]="true" [filterable]="true" [pageable]="true" [height]="400"
(remove)="removeSkillHandler($event)" (dataStateChange)="skillsState = $event">
<kendo-grid-column field="seq" title="Seq" [width]="80">
<ng-template kendoGridCellTemplate let-dataItem>
{{ dataItem.seq }}
</ng-template>
</kendo-grid-column>
<kendo-grid-column field="level" title="Level" [width]="80">
<ng-template kendoGridCellTemplate let-dataItem>
{{ dataItem.level }}
</ng-template>
</kendo-grid-column>
<kendo-grid-column field="name" title="Name" [width]="150">
<ng-template kendoGridCellTemplate let-dataItem>
{{ dataItem.name }}
@ -178,32 +191,37 @@
</ng-template>
</kendo-grid-column>
<kendo-grid-column field="clawRoll" title="Claw Roll" [width]="100">
<ng-template kendoGridCellTemplate let-dataItem>
{{ dataItem.clawRoll }}
</ng-template>
</kendo-grid-column>
<kendo-grid-column field="skillRoll" title="Skill Roll" [width]="100">
<ng-template kendoGridCellTemplate let-dataItem>
{{ dataItem.skillRoll }}
</ng-template>
</kendo-grid-column>
<kendo-grid-column field="clawRoll" title="Claw Roll" [width]="100">
<ng-template kendoGridCellTemplate let-dataItem>
{{ dataItem.clawRoll }}
</ng-template>
</kendo-grid-column>
<kendo-grid-column field="description" title="Description" [width]="300">
<ng-template kendoGridCellTemplate let-dataItem>
<div *ngIf="dataItem.type == MobSkillType.ConditionalSkill" [innerHTML]="dataItem.skillCondition"></div>
<div [innerHTML]="dataItem.description"></div>
</ng-template>
</kendo-grid-column>
<kendo-grid-command-column title="Actions" [width]="200">
<kendo-grid-command-column title="Actions" [width]="133">
<ng-template kendoGridCellTemplate let-isNew="isNew" let-dataItem="dataItem" let-rowIndex="rowIndex">
<button kendoButton [primary]="true" (click)="editSkillHandler(dataItem)">Edit</button>
<button kendoGridRemoveCommand>Remove</button>
</ng-template>
</kendo-grid-command-column>
</kendo-grid>
</div>
</ng-template>
</kendo-tabstrip-tab>
</kendo-tabstrip>
</div>
<kendo-dialog-actions>

View File

@ -1,7 +1,7 @@
.k-dialog-content {
padding: 20px;
max-height: 80vh;
overflow-y: auto;
//overflow-y: auto;
}
.detail-container {
@ -54,4 +54,3 @@
.skills-toolbar {
margin-bottom: 10px;
}

View File

@ -16,6 +16,7 @@ import { MD2MobSkillEditorComponent } from '../md2-mob-skill-editor/md2-mob-skil
styleUrls: ['./md2-mob-info-detail.component.scss']
})
export class MD2MobInfoDetailComponent extends DialogContentBase implements OnInit {
MobSkillType = MobSkillType;
@Input() public mobInfo: MD2MobInfo;
@ViewChild('levelsGrid') levelsGrid: GridComponent;
@ViewChild('skillsGrid') skillsGrid: GridComponent;
@ -64,6 +65,7 @@ export class MD2MobInfoDetailComponent extends DialogContentBase implements OnIn
if (this.mobLevelInfos.length > 0) {
this.selectLevelInfo(this.mobLevelInfos[0]);
}
this.loadSkills();
}
}
@ -94,7 +96,7 @@ export class MD2MobInfoDetailComponent extends DialogContentBase implements OnIn
levelInfo.attackInfo = { blue: 0, green: 0, yellow: 0, orange: 0, red: 0, black: 0 };
}
this.selectedLevelInfo = levelInfo;
this.loadSkills(levelInfo);
this.loadSkills();
}
public editLevelHandler({ sender, rowIndex, dataItem }: any): void {
@ -150,8 +152,7 @@ export class MD2MobInfoDetailComponent extends DialogContentBase implements OnIn
: { 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 },
skills: [] // Don't copy skills, start with empty array
: { yellow: null, orange: null, red: null, blue: null, green: null, black: null }
};
} else {
// Default values if no levels exist
@ -167,8 +168,7 @@ export class MD2MobInfoDetailComponent extends DialogContentBase implements OnIn
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 },
skills: []
defenceInfo: { yellow: null, orange: null, red: null, blue: null, green: null, black: null }
};
}
@ -189,9 +189,6 @@ export class MD2MobInfoDetailComponent extends DialogContentBase implements OnIn
if (!dataItem.defenceInfo) {
dataItem.defenceInfo = { yellow: null, orange: null, red: null, blue: null, green: null, black: null };
}
if (!dataItem.skills) {
dataItem.skills = [];
}
this.isLoading = true;
this.mobLevelInfoService.createOrUpdate(dataItem).pipe(first()).subscribe(result => {
@ -209,7 +206,7 @@ export class MD2MobInfoDetailComponent extends DialogContentBase implements OnIn
// Update selected level if it's the one being edited
if (this.selectedLevelInfo?.id === result.id) {
this.selectedLevelInfo = result;
this.loadSkills(result);
this.loadSkills();
}
}
}
@ -237,7 +234,7 @@ export class MD2MobInfoDetailComponent extends DialogContentBase implements OnIn
// Clear selection if deleted level was selected
if (this.selectedLevelInfo?.id === dataItem.id) {
this.selectedLevelInfo = null;
this.skillsData = { data: [], total: 0 };
this.loadSkills();
}
}
this.isLoading = false;
@ -246,11 +243,16 @@ export class MD2MobInfoDetailComponent extends DialogContentBase implements OnIn
});
}
public loadSkills(levelInfo: MD2MobLevelInfo): void {
if (levelInfo && levelInfo.skills) {
public loadSkills(): void {
if (this.mobInfo && this.mobInfo.skills) {
// Filter skills by selected level if a level is selected
let filteredSkills = this.mobInfo.skills.sort((a, b) => a.seq - b.seq);
// if (this.selectedLevelInfo) {
// filteredSkills = this.mobInfo.skills.filter(s => s.level === this.selectedLevelInfo.level);
// }
this.skillsData = {
data: levelInfo.skills,
total: levelInfo.skills.length
data: filteredSkills,
total: filteredSkills.length
};
} else {
this.skillsData = { data: [], total: 0 };
@ -258,24 +260,40 @@ export class MD2MobInfoDetailComponent extends DialogContentBase implements OnIn
}
public addSkillHandler(): void {
if (!this.selectedLevelInfo) return;
if (!this.mobInfo) return;
// Get the last level info (highest level) if any exists
const lastLevel = this.mobInfo.skills.length > 0
? this.mobInfo.skills.reduce((prev, current) => (prev.seq > current.seq) ? prev : current)
: null;
let seq = 0;
let level = 1;
let type = MobSkillType.Combat;
if (lastLevel) {
seq = lastLevel.seq + 1;
level = lastLevel.level + 2;
type = lastLevel.type;
}
const newSkill: MD2MobSkill = {
id: this.generateId(),
mobLevelInfoId: this.selectedLevelInfo.id,
type: MobSkillType.Combat,
skillTarget: null,
seq: seq,
level: level,
mobInfoId: this.mobInfo.id,
type: type,
skillTarget: MobSkillTarget.Random,
clawRoll: 0,
skillRoll: 1,
name: '',
description: ''
name: 'Basic Skill',
skillCondition: '',
description: lastLevel?.description || ''
};
this.openSkillEditor(newSkill, true);
}
public editSkillHandler(dataItem: MD2MobSkill): void {
if (!this.selectedLevelInfo) return;
if (!this.mobInfo) return;
// Create a copy of the skill for editing
const skillCopy: MD2MobSkill = JSON.parse(JSON.stringify(dataItem));
@ -283,7 +301,7 @@ export class MD2MobInfoDetailComponent extends DialogContentBase implements OnIn
}
private openSkillEditor(skill: MD2MobSkill, isNew: boolean): void {
if (!this.selectedLevelInfo) return;
if (!this.mobInfo) return;
const dialogRef = this.dialogService.open({
title: isNew ? 'Add New Skill' : 'Edit Skill',
@ -295,7 +313,8 @@ export class MD2MobInfoDetailComponent extends DialogContentBase implements OnIn
const editor = dialogRef.content.instance;
editor.isAdding = isNew;
editor.data = skill;
editor.mobLevelInfoId = this.selectedLevelInfo.id;
editor.mobInfoId = this.mobInfo.id;
editor.selectedLevel = this.selectedLevelInfo?.level || 1;
// Force model re-initialization after data is set
setTimeout(() => {
@ -310,20 +329,20 @@ export class MD2MobInfoDetailComponent extends DialogContentBase implements OnIn
}
private handleSkillSaved(result: MD2MobSkill, isNew: boolean): void {
if (!this.selectedLevelInfo) return;
if (!this.mobInfo) return;
if (isNew) {
if (!this.selectedLevelInfo.skills) {
this.selectedLevelInfo.skills = [];
if (!this.mobInfo.skills) {
this.mobInfo.skills = [];
}
this.selectedLevelInfo.skills.push(result);
this.mobInfo.skills.push(result);
} else {
const index = this.selectedLevelInfo.skills?.findIndex(s => s.id === result.id);
if (index !== undefined && index !== -1 && this.selectedLevelInfo.skills) {
this.selectedLevelInfo.skills[index] = result;
const index = this.mobInfo.skills?.findIndex(s => s.id === result.id);
if (index !== undefined && index !== -1 && this.mobInfo.skills) {
this.mobInfo.skills[index] = result;
}
}
this.loadSkills(this.selectedLevelInfo);
this.loadSkills();
}
public saveSkillHandler({ dataItem, isNew }: any): void {
@ -332,18 +351,18 @@ export class MD2MobInfoDetailComponent extends DialogContentBase implements OnIn
}
public removeSkillHandler({ dataItem }: { dataItem: MD2MobSkill }): void {
if (!this.selectedLevelInfo) return;
if (!this.mobInfo) return;
this.msgBoxService.showConfirmDeleteBox().pipe(first()).subscribe(answer => {
if (answer === true) {
this.isLoading = true;
this.mobSkillService.delete(dataItem.id).pipe(first()).subscribe(result => {
if (this.selectedLevelInfo.skills) {
const index = this.selectedLevelInfo.skills.findIndex(s => s.id === dataItem.id);
if (this.mobInfo.skills) {
const index = this.mobInfo.skills.findIndex(s => s.id === dataItem.id);
if (index !== -1) {
this.selectedLevelInfo.skills.splice(index, 1);
this.mobInfo.skills.splice(index, 1);
}
this.loadSkills(this.selectedLevelInfo);
this.loadSkills();
}
this.isLoading = false;
});

View File

@ -47,7 +47,8 @@ export class MD2MobInfoEditorComponent extends DialogContentBase implements OnIn
from: fromValue,
leaderImgUrl: this.data?.leaderImgUrl || '',
minionImgUrl: this.data?.minionImgUrl || '',
mobLevelInfos: this.data?.mobLevelInfos || []
mobLevelInfos: this.data?.mobLevelInfos || [],
skills: this.data?.skills || []
};
// Set selected objects for dropdowns
@ -89,7 +90,8 @@ export class MD2MobInfoEditorComponent extends DialogContentBase implements OnIn
...this.model,
type: this.selectedMobType?.value ?? MobType.Mob,
from: this.selectedGameBundle?.value ?? GameBundle.CoreGame,
mobLevelInfos: this.data?.mobLevelInfos || []
mobLevelInfos: this.data?.mobLevelInfos || [],
skills: this.data?.skills || []
};
this.mobInfoService.createOrUpdate(mobInfo).pipe(first()).subscribe(result => {

View File

@ -9,35 +9,35 @@
</nb-card-header>
<nb-card-body>
<kendo-grid #grid [data]="gridData" [loading]="isLoading" [pageSize]="gridState.take" [skip]="gridState.skip"
[sortable]="true" [filterable]="true" [pageable]="true" [selectable]="true"
(dataStateChange)="gridState = $event; loadData()">
[group]="gridState.group" [sortable]="true" [filterable]="true" [pageable]="true" [selectable]="true"
[groupable]="true" (dataStateChange)="gridState = $event; loadData()">
<kendo-grid-toolbar>
<button kendoGridAddCommand>Add new</button>
</kendo-grid-toolbar>
<kendo-grid-column field="name" title="Name" width="200">
<kendo-grid-column field="name" title="Name" [width]="200">
</kendo-grid-column>
<kendo-grid-column field="type" title="Type" width="150">
<kendo-grid-column field="type" title="Type" [width]="150">
<ng-template kendoGridCellTemplate let-dataItem>
{{ getMobTypeName(dataItem.type) }}
</ng-template>
</kendo-grid-column>
<kendo-grid-column field="from" title="Game Bundle" width="150">
<kendo-grid-column field="from" title="Game Bundle" [width]="150">
<ng-template kendoGridCellTemplate let-dataItem>
{{ getGameBundleName(dataItem.from) }}
</ng-template>
</kendo-grid-column>
<kendo-grid-column field="leaderImgUrl" title="Leader Image" width="200">
<kendo-grid-column field="leaderImgUrl" title="Leader Image" [width]="200">
</kendo-grid-column>
<kendo-grid-column field="minionImgUrl" title="Minion Image" width="200">
<kendo-grid-column field="minionImgUrl" title="Minion Image" [width]="200">
</kendo-grid-column>
<kendo-grid-command-column title="Actions" width="250">
<kendo-grid-command-column title="Actions" [width]="250">
<ng-template kendoGridCellTemplate let-isNew="isNew" let-dataItem="dataItem" let-rowIndex="rowIndex">
<button kendoGridEditCommand [primary]="true">Edit</button>
<button kendoGridRemoveCommand>Remove</button>

View File

@ -22,11 +22,18 @@ export class MD2MobInfoMaintenanceComponent implements OnInit {
public gridState: State = {
skip: 0,
take: 10,
sort: [],
sort: [{
field: 'name',
dir: 'asc'
}],
filter: {
logic: 'and',
filters: []
}
},
group: [{
field: 'type',
dir: 'asc'
}]
};
public isLoading: boolean = false;
@ -45,7 +52,7 @@ export class MD2MobInfoMaintenanceComponent implements OnInit {
this.isLoading = true;
this.mobInfoService.getAll().pipe(first()).subscribe(result => {
this.gridData = {
data: result,
data: result.sort((a, b) => a.name.localeCompare(b.name)),
total: result.length
};
this.isLoading = false;

View File

@ -2,7 +2,23 @@
<form #form="ngForm" class="k-form">
<div class="row">
<div class="col-md-12">
<div class="col-md-3">
<div class="form-group">
<label class="k-label">Sequence</label>
<kendo-numerictextbox [(ngModel)]="model.seq" name="seq" [min]="0" [decimals]="0" [format]="'n0'">
</kendo-numerictextbox>
</div>
</div>
<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-6">
<div class="form-group">
<label class="k-label">Name</label>
<input kendoTextBox [(ngModel)]="model.name" name="name" class="k-input"
@ -28,20 +44,27 @@
</div>
<div class="col-md-3">
<div class="form-group">
<label class="k-label"><md2-icon icon="EnemyClaw"></md2-icon>Claw Roll</label>
<kendo-numerictextbox [(ngModel)]="model.clawRoll" name="clawRoll" [min]="0" [decimals]="0"
<label class="k-label"><md2-icon icon="EnemySkill"></md2-icon>Skill Roll</label>
<kendo-numerictextbox [(ngModel)]="model.skillRoll" name="skillRoll" [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="EnemySkill"></md2-icon>Skill Roll</label>
<kendo-numerictextbox [(ngModel)]="model.skillRoll" name="skillRoll" [min]="0" [decimals]="0"
<label class="k-label"><md2-icon icon="EnemyClaw"></md2-icon>Claw Roll</label>
<kendo-numerictextbox [(ngModel)]="model.clawRoll" name="clawRoll" [min]="0" [decimals]="0"
[format]="'n0'">
</kendo-numerictextbox>
</div>
</div>
<div class="col-md-12" *ngIf="selectedSkillType.value == MobSkillType.ConditionalSkill">
<div class="form-group">
<label class="k-label">Skill Condition</label>
<md2-html-editor [(ngModel)]="model.skillCondition" name="skillCondition"
class="htmlEditor"></md2-html-editor>
</div>
</div>
<div class="col-md-12">
<div class="form-group">
<label class="k-label">Description</label>

View File

@ -12,8 +12,10 @@ import { MD2MobSkillService } from '../../service/massive-darkness2.service';
styleUrls: ['./md2-mob-skill-editor.component.scss']
})
export class MD2MobSkillEditorComponent extends DialogContentBase implements OnInit {
MobSkillType = MobSkillType;
@Input() public data: MD2MobSkill;
@Input() public mobLevelInfoId: string;
@Input() public mobInfoId: string;
@Input() public selectedLevel: number = 1;
@Input() public isAdding: boolean = false;
@ViewChild('form') form: NgForm;
@ -43,12 +45,15 @@ export class MD2MobSkillEditorComponent extends DialogContentBase implements OnI
this.model = {
id: this.data?.id || '',
mobLevelInfoId: this.mobLevelInfoId || this.data?.mobLevelInfoId || '',
seq: this.data?.seq ?? 0,
level: this.data?.level ?? this.selectedLevel,
mobInfoId: this.mobInfoId || this.data?.mobInfoId || '',
type: typeValue,
skillTarget: targetValue,
clawRoll: this.data?.clawRoll ?? 0,
skillRoll: this.data?.skillRoll ?? 1,
name: this.data?.name || '',
skillCondition: this.data?.skillCondition || '',
description: this.data?.description || ''
};
@ -91,7 +96,8 @@ export class MD2MobSkillEditorComponent extends DialogContentBase implements OnI
...this.model,
type: this.selectedSkillType?.value ?? MobSkillType.Combat,
skillTarget: this.selectedSkillTarget?.value ?? null,
mobLevelInfoId: this.mobLevelInfoId || this.model.mobLevelInfoId
mobInfoId: this.mobInfoId || this.model.mobInfoId,
level: this.model.level || this.selectedLevel
};
this.mobSkillService.createOrUpdate(mobSkill).pipe(first()).subscribe(result => {

View File

@ -205,6 +205,12 @@ export class MD2Service {
private generateMob(mobName: string, level: number) {
let dbMobInfo = this.allMobInfos.find(m => m.name == mobName);
let levelInfo = dbMobInfo.mobLevelInfos.find(l => l.level <= level);
let skills = dbMobInfo.skills.filter(s => s.level <= level).sort((a, b) => b.level - a.level);
//Distinct by SkillType and Skill Name, take the one with the highest level
let mobInfo = new MobInfo({
name: dbMobInfo.name,
@ -213,8 +219,17 @@ export class MD2Service {
level: level,
rewardTokens: levelInfo.rewardTokens,
defenseInfo: levelInfo.defenceInfo,
skills: levelInfo.skills
skills: []
});
for (let i = 0; i < skills.length; i++) {
const skill = skills[i];
if (!mobInfo.skills.find(s => s.type == skill.type && s.name == skill.name)) {
mobInfo.skills.push(skill);
}
}
mobInfo.skills = mobInfo.skills.sort((a, b) => b.seq - a.seq);
mobInfo.leaderImgUrl = mobInfo.leaderImgUrl || MD2_IMG_URL(`/${GameBundle[dbMobInfo.from]}/Mobs/${mobInfo.name}/Leader.png`);
mobInfo.minionImgUrl = mobInfo.minionImgUrl || MD2_IMG_URL(`/${GameBundle[dbMobInfo.from]}/Mobs/${mobInfo.name}/Minion.png`);

View File

@ -57,5 +57,16 @@ export class ArrayUtils {
return array;
}
public static orderByThenBy<T>(
array: T[],
...criteria: ((a: T, b: T) => number)[]
): T[] {
return array.sort((a, b) => {
for (const compare of criteria) {
const result = compare(a, b);
if (result !== 0) return result;
}
return 0;
});
}
}

View File

@ -18589,62 +18589,6 @@ li:last-child .u-dot-line-v2::after, li:last-child
top: 2px;
}
/* HZ
------------------------------------*/
.nav-item > a,
.nav-item > .nav-link,
[class*="u-tab-link"]:not([class*="-icon"]) {
transition-property: color, background-color, border-color;
transition-duration: .2s;
transition-timing-function: ease-in;
}
[role="tablist"]:not([data-tabs-mobile-type="slide-up-down"]):not([data-tabs-mobile-type="accordion"]):not([data-scroll]) {
display: block;
}
[role="tablist"]:not([data-tabs-mobile-type="slide-up-down"]):not([data-tabs-mobile-type="accordion"]):not([data-scroll]) .nav-item {
display: inline-block;
}
[role="tablist"]:not([data-tabs-mobile-type="slide-up-down"]):not([data-tabs-mobile-type="accordion"]):not([data-scroll]) .js-tabs-mobile {
position: relative;
display: none;
}
[role="tablist"]:not([data-tabs-mobile-type="slide-up-down"]):not([data-tabs-mobile-type="accordion"]):not([data-scroll]) .js-tabs-mobile-control {
position: relative;
display: block;
}
[role="tablist"]:not([data-tabs-mobile-type="slide-up-down"]):not([data-tabs-mobile-type="accordion"]):not([data-scroll]) .js-tabs-mobile-control::after {
content: "";
position: absolute;
top: 50%;
right: 0;
display: block;
width: 0;
height: 0;
border-width: 5px 3.5px 0 3.5px;
border-style: solid;
border-color: #777 transparent transparent transparent;
margin-top: -1px;
}
[role="tablist"]:not([data-tabs-mobile-type="slide-up-down"]):not([data-tabs-mobile-type="accordion"]):not([data-scroll]) .js-tabs-mobile .nav-inner {
position: absolute;
top: calc(100% + 1px);
right: 0;
display: none;
background-color: #fff;
border: 1px solid;
padding-left: 0;
}
[role="tablist"]:not([data-tabs-mobile-type="slide-up-down"]):not([data-tabs-mobile-type="accordion"]):not([data-scroll]) .js-tabs-mobile .nav-inner .nav-item {
display: block;
white-space: nowrap;
}
[data-scroll]:not([data-tabs-mobile-type="slide-up-down"]):not([data-tabs-mobile-type="accordion"]) {
width: 100%;

View File

@ -31,7 +31,7 @@
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css" />
<link rel="stylesheet" href="./assets/home/css/styles.op-architecture.css">
<link href="https://unpkg.com/@progress/kendo-theme-fluent@12.2.0/dist/fluent-main.css" rel="stylesheet" />
<!-- <link href="https://unpkg.com/@progress/kendo-theme-fluent@12.2.0/dist/fluent-main.css" rel="stylesheet" /> -->
<!-- <link rel="stylesheet" href="./assets/home/css/">