This commit is contained in:
Chris Chen 2025-11-04 18:13:43 -08:00
parent 46ec236ed5
commit e5933104cc
18 changed files with 262 additions and 357 deletions

13
.hintrc Normal file
View File

@ -0,0 +1,13 @@
{
"extends": [
"development"
],
"hints": {
"axe/text-alternatives": [
"default",
{
"image-alt": "off"
}
]
}
}

View File

@ -1,222 +0,0 @@
import { environment } from "../../../../../environments/environment";
import { DefenseInfo, IMobFactory, MD2Icon, MobInfo } from "../../massive-darkness2.model";
import { MobSkill, MobSkillType } from "../../massive-darkness2.model.boss";
const MD2_IMG_URL = (id: string = null) => { return `${environment.apiUrl}/Files/Images/MD2/Mobs${(id ? `${encodeURI(id)}` : '')}` }
const CORE_GAME_MOB_LEVEL = [
{ name: 'Gargoyles', level: 1, hp: 2, rewardTokens: 1, defBlue: 1 },
{ name: 'Gargoyles', level: 3, hp: 3, rewardTokens: 1, defBlue: 2 },
{ name: 'Gargoyles', level: 5, hp: 6, rewardTokens: 2, defBlue: 3 },
{ name: 'Demons', level: 1, hp: 3, rewardTokens: 1, defBlue: 1 },
{ name: 'Demons', level: 3, hp: 4, rewardTokens: 1, defBlue: 2 },
{ name: 'Demons', level: 5, hp: 6, rewardTokens: 2, defBlue: 4 },
{ name: 'Undead', level: 1, hp: 4, rewardTokens: 1, defBlue: 1 },
{ name: 'Undead', level: 3, hp: 5, rewardTokens: 1, defBlue: 1 },
{ name: 'Undead', level: 5, hp: 8, rewardTokens: 2, defBlue: 1 },
{ name: 'Fire Entities', level: 1, hp: 3, rewardTokens: 1, defBlue: 1 },
{ name: 'Fire Entities', level: 3, hp: 4, rewardTokens: 1, defBlue: 2 },
{ name: 'Fire Entities', level: 5, hp: 7, rewardTokens: 2, defBlue: 3 },
{ name: 'Fallen Angels', level: 1, hp: 2, rewardTokens: 1, defBlue: 2 },
{ name: 'Fallen Angels', level: 3, hp: 3, rewardTokens: 1, defBlue: 3 },
{ name: 'Fallen Angels', level: 5, hp: 5, rewardTokens: 2, defBlue: 5 },
{ name: 'Infernal Imps', level: 1, hp: 3, rewardTokens: 1, defBlue: 1 },
{ name: 'Infernal Imps', level: 3, hp: 4, rewardTokens: 1, defBlue: 1 },
{ name: 'Infernal Imps', level: 5, hp: 5, rewardTokens: 2, defBlue: 3 },
{ name: 'Skeletons', level: 1, hp: 2, rewardTokens: 1, defBlue: 1 },
{ name: 'Skeletons', level: 3, hp: 3, rewardTokens: 1, defBlue: 2 },
{ name: 'Skeletons', level: 5, hp: 5, rewardTokens: 2, defBlue: 4 },
{ name: 'Satyrs', level: 1, hp: 3, rewardTokens: 1, defBlue: 1 },
{ name: 'Satyrs', level: 3, hp: 4, rewardTokens: 1, defBlue: 2 },
{ name: 'Satyrs', level: 5, hp: 6, rewardTokens: 2, defBlue: 4 }]
export abstract class MobFactory implements IMobFactory {
abstract mobName: string;
abstract generate(level: number): MobInfo
protected mob: MobInfo;
protected loadLevelInfo(mobName: string, level: number) {
let levelInfo = CORE_GAME_MOB_LEVEL.find(m => m.name == mobName && level >= m.level);
this.mob = new MobInfo({
name: mobName, hp: levelInfo.hp, level: level, rewardTokens: levelInfo.rewardTokens,
defenseInfo: new DefenseInfo(levelInfo.defBlue)
});
this.mob.leaderImgUrl = MD2_IMG_URL(`/CoreGame/Mobs/${this.mob.name}/Leader.png`);
this.mob.minionImgUrl = MD2_IMG_URL(`/CoreGame/Mobs/${this.mob.name}/Minion.png`);
}
iconHtml(icon: MD2Icon, cssClass = 'g-font-size-24') {
if (icon == MD2Icon.Fire) {
cssClass += ' g-color-google-plus ';
}
if (icon == MD2Icon.Frost || icon == MD2Icon.Mana) {
cssClass += ' g-color-aqua ';
}
if (icon < MD2Icon.RedDice) {
return `<span class='MD2Icon ${cssClass}'>${String.fromCharCode(65 + icon)}</span>`
}
else {
return `<span class='MD2Icon dice ${MD2Icon[icon].replace('Dice', '')} ${cssClass}'></span>`;
}
}
}
export class MobDemonsFactory extends MobFactory {
mobName: string = 'Demons';
generate(level: number): MobInfo {
this.loadLevelInfo('Demons', level);
this.mob.combatSkill = new MobSkill(
{
description: `Attacking or defending Hero discards 1 ${this.iconHtml(MD2Icon.Mana)}`
}
)
return this.mob;
}
}
export class MobFallenAngelFactory extends MobFactory {
mobName: string = 'Fallen Angels';
generate(level: number): MobInfo {
this.loadLevelInfo('Fallen Angels', level);
this.mob.combatSkill = new MobSkill(
{
description: `Defender -${level == 1 ? 1 : 2} ${this.iconHtml(MD2Icon.Defense)}`,
type: MobSkillType.Attack
}
)
return this.mob;
}
}
export class MobFireEntitiesFactory extends MobFactory {
mobName: string = 'Fire Entities';
generate(level: number): MobInfo {
this.loadLevelInfo('Fire Entities', level);
this.mob.combatSkill = new MobSkill(
{
description: `Add 1 ${this.iconHtml(MD2Icon.Fire)} to the attacking or defending Hero.`,
type: MobSkillType.Combat
}
)
return this.mob;
}
}
export class MobGargoylesFactory extends MobFactory {
mobName: string = 'Gargoyles';
generate(level: number): MobInfo {
this.loadLevelInfo('Gargoyles', level);
this.mob.combatSkill = new MobSkill(
{
description: `+ ${level < 5 ? 1 : 2} ${this.iconHtml(MD2Icon.Defense)}`,
type: MobSkillType.Defense
}
)
return this.mob;
}
}
export class MobInfernalImpsFactory extends MobFactory {
mobName: string = 'Infernal Imps';
generate(level: number): MobInfo {
this.loadLevelInfo('Infernal Imps', level);
let damage = 1;
switch (level) {
case 1:
case 2:
damage = 1;
break;
case 3:
case 4:
damage = 2;
break;
case 5:
damage = 3;
break;
default:
damage = 1;
break;
}
this.mob.combatSkill = new MobSkill(
{
description: `Kill 1 Imp, then deal ${damage} Wound to each Hero in the attacker's Zone(once per roll).`,
type: MobSkillType.Defense
}
)
return this.mob;
}
}
export class MobSatyrsFactory extends MobFactory {
mobName: string = 'Satyrs';
generate(level: number): MobInfo {
this.loadLevelInfo('Satyrs', level);
this.mob.combatSkill = new MobSkill(
{
description: `+ ${level < 3 ? 1 : 2} ${this.iconHtml(MD2Icon.Attack)}`,
type: MobSkillType.Attack
}
)
return this.mob;
}
}
export class MobSkeletonsFactory extends MobFactory {
mobName: string = 'Skeletons';
generate(level: number): MobInfo {
this.loadLevelInfo('Skeletons', level);
this.mob.combatSkill = new MobSkill(
{
description: `Add 1 minion to this Mob(if possible) unless the Hero discards ${level < 5 ? 1 : 2} ${this.iconHtml(MD2Icon.Mana)}.`,
type: MobSkillType.Defense,
skillRoll: 2
}
)
return this.mob;
}
}
export class MobUndeadFactory extends MobFactory {
mobName: string = 'Undead';
generate(level: number): MobInfo {
this.loadLevelInfo('Undead', level);
let skillDesc = '';
if (level < 3) {
skillDesc = `+1 ${this.iconHtml(MD2Icon.YellowDice)}`;
} else if (level < 5) {
skillDesc = `+2 ${this.iconHtml(MD2Icon.YellowDice)}`;
} else {
skillDesc = `+1 ${this.iconHtml(MD2Icon.YellowDice)} 1 ${this.iconHtml(MD2Icon.OrangeDice)}`;
}
skillDesc += ' and this Mob takes 2 wounds';
this.mob.combatSkill = new MobSkill(
{
description: skillDesc,
type: MobSkillType.Attack
}
)
this.mob.drawingWeight = 1;
return this.mob;
}
}
export const CoreGameMobFactories = [
new MobDemonsFactory(),
new MobFallenAngelFactory(),
new MobFireEntitiesFactory(),
new MobGargoylesFactory(),
new MobInfernalImpsFactory(),
new MobSatyrsFactory(),
new MobSkeletonsFactory(),
new MobUndeadFactory(),
];

View File

@ -3,8 +3,9 @@ import { first, map } from "rxjs/operators";
import { environment } from "../../../../../environments/environment"; import { environment } from "../../../../../environments/environment";
import { ADButtons, ADIcon } from "../../../../ui/alert-dlg/alert-dlg.model"; import { ADButtons, ADIcon } from "../../../../ui/alert-dlg/alert-dlg.model";
import { MD2Logic } from "../../massive-darkness2.logic"; import { MD2Logic } from "../../massive-darkness2.logic";
import { AttackInfo, AttackTarget, DefenseInfo, IMobFactory, MD2Icon, MobInfo, MobType, TreasureItem, TreasureType } from "../../massive-darkness2.model"; import { AttackInfo, AttackTarget, IMobFactory, MD2Icon, MobInfo, MobType, TreasureItem, TreasureType } from "../../massive-darkness2.model";
import { MobSkill, MobSkillType } from "../../massive-darkness2.model.boss"; import { MobSkillType } from "../../massive-darkness2.model.boss";
import { MD2DiceSet, MD2MobSkill } from "../../massive-darkness2.db.model";
const MD2_IMG_URL = (id: string = null) => { return `${environment.apiUrl}/Files/Images/MD2/Mobs${(id ? `${encodeURI(id)}` : '')}` } const MD2_IMG_URL = (id: string = null) => { return `${environment.apiUrl}/Files/Images/MD2/Mobs${(id ? `${encodeURI(id)}` : '')}` }
const CORE_GAME_MOB_LEVEL = [ const CORE_GAME_MOB_LEVEL = [
@ -13,68 +14,68 @@ const CORE_GAME_MOB_LEVEL = [
name: 'Andra', level: 1, hp: 5, name: 'Andra', level: 1, hp: 5,
attackInfos: [new AttackInfo(MD2Icon.Melee, 1, 0, 0, 1), new AttackInfo(MD2Icon.Range, 1, 0, 0, 1)], attackInfos: [new AttackInfo(MD2Icon.Melee, 1, 0, 0, 1), new AttackInfo(MD2Icon.Range, 1, 0, 0, 1)],
defenseInfo: new DefenseInfo(2, 1), defenseInfo: { blue: 2, black: 1 } as MD2DiceSet,
}), }),
new MobInfo({ new MobInfo({
name: 'Andra', level: 3, hp: 7, name: 'Andra', level: 3, hp: 7,
attackInfos: [new AttackInfo(MD2Icon.Melee, 1, 1, 0, 1), new AttackInfo(MD2Icon.Range, 1, 1, 0, 1)], attackInfos: [new AttackInfo(MD2Icon.Melee, 1, 1, 0, 1), new AttackInfo(MD2Icon.Range, 1, 1, 0, 1)],
defenseInfo: new DefenseInfo(3, 1), defenseInfo: { blue: 3, black: 1 } as MD2DiceSet,
}), }),
new MobInfo({ new MobInfo({
name: 'Andra', level: 5, hp: 5, name: 'Andra', level: 5, hp: 5,
attackInfos: [new AttackInfo(MD2Icon.Melee, 1, 2, 0, 1), new AttackInfo(MD2Icon.Range, 1, 2, 0, 1)], attackInfos: [new AttackInfo(MD2Icon.Melee, 1, 2, 0, 1), new AttackInfo(MD2Icon.Range, 1, 2, 0, 1)],
defenseInfo: new DefenseInfo(5, 1), defenseInfo: { blue: 5, black: 1 } as MD2DiceSet,
}), }),
new MobInfo({ new MobInfo({
name: 'Ytheria, Undead Queen', level: 1, hp: 4, name: 'Ytheria, Undead Queen', level: 1, hp: 4,
attackInfos: [new AttackInfo(MD2Icon.Melee, 1), new AttackInfo(MD2Icon.Range, 2, 0, 0, 1)], attackInfos: [new AttackInfo(MD2Icon.Melee, 1), new AttackInfo(MD2Icon.Range, 2, 0, 0, 1)],
defenseInfo: new DefenseInfo(1, 1), defenseInfo: { blue: 1, black: 1 } as MD2DiceSet,
}), }),
new MobInfo({ new MobInfo({
name: 'Ytheria, Undead Queen', level: 3, hp: 6, name: 'Ytheria, Undead Queen', level: 3, hp: 6,
attackInfos: [new AttackInfo(MD2Icon.Melee, 0, 1), new AttackInfo(MD2Icon.Range, 1, 1, 0, 1)], attackInfos: [new AttackInfo(MD2Icon.Melee, 0, 1), new AttackInfo(MD2Icon.Range, 1, 1, 0, 1)],
defenseInfo: new DefenseInfo(2, 1), defenseInfo: { blue: 2, black: 1 } as MD2DiceSet,
}), }),
new MobInfo({ new MobInfo({
name: 'Ytheria, Undead Queen', level: 5, hp: 8, name: 'Ytheria, Undead Queen', level: 5, hp: 8,
attackInfos: [new AttackInfo(MD2Icon.Melee, 2, 1), new AttackInfo(MD2Icon.Range, 2, 1, 0, 1)], attackInfos: [new AttackInfo(MD2Icon.Melee, 2, 1), new AttackInfo(MD2Icon.Range, 2, 1, 0, 1)],
defenseInfo: new DefenseInfo(4, 1), defenseInfo: { blue: 4, black: 1 } as MD2DiceSet,
}), }),
new MobInfo({ new MobInfo({
name: 'Lyidan, Incubus Lord', level: 1, hp: 7, name: 'Lyidan, Incubus Lord', level: 1, hp: 7,
attackInfos: [new AttackInfo(MD2Icon.Melee, 0, 1, 0, 2)], attackInfos: [new AttackInfo(MD2Icon.Melee, 0, 1, 0, 2)],
defenseInfo: new DefenseInfo(2, 1), defenseInfo: { blue: 2, black: 1 } as MD2DiceSet,
}), }),
new MobInfo({ new MobInfo({
name: 'Lyidan, Incubus Lord', level: 3, hp: 10, name: 'Lyidan, Incubus Lord', level: 3, hp: 10,
attackInfos: [new AttackInfo(MD2Icon.Melee, 0, 2, 0, 1)], attackInfos: [new AttackInfo(MD2Icon.Melee, 0, 2, 0, 1)],
defenseInfo: new DefenseInfo(2, 1), defenseInfo: { blue: 2, black: 1 } as MD2DiceSet,
}), }),
new MobInfo({ new MobInfo({
name: 'Lyidan, Incubus Lord', level: 5, hp: 12, name: 'Lyidan, Incubus Lord', level: 5, hp: 12,
attackInfos: [new AttackInfo(MD2Icon.Melee, 2, 2, 0, 1)], attackInfos: [new AttackInfo(MD2Icon.Melee, 2, 2, 0, 1)],
defenseInfo: new DefenseInfo(4, 1), defenseInfo: { blue: 4, black: 1 } as MD2DiceSet,
}), }),
new MobInfo({ new MobInfo({
name: 'The Ghoul', level: 1, hp: 5, name: 'The Ghoul', level: 1, hp: 5,
attackInfos: [new AttackInfo(MD2Icon.Melee, 0, 1, 0, 1)], attackInfos: [new AttackInfo(MD2Icon.Melee, 0, 1, 0, 1)],
defenseInfo: new DefenseInfo(2, 1), defenseInfo: { blue: 2, black: 1 } as MD2DiceSet,
}), }),
new MobInfo({ new MobInfo({
name: 'The Ghoul', level: 3, hp: 8, name: 'The Ghoul', level: 3, hp: 8,
attackInfos: [new AttackInfo(MD2Icon.Melee, 0, 2, 0, 2)], attackInfos: [new AttackInfo(MD2Icon.Melee, 0, 2, 0, 2)],
defenseInfo: new DefenseInfo(3, 1), defenseInfo: { blue: 3, black: 1 } as MD2DiceSet,
}), }),
new MobInfo({ new MobInfo({
name: 'The Ghoul', level: 5, hp: 10, name: 'The Ghoul', level: 5, hp: 10,
attackInfos: [new AttackInfo(MD2Icon.Melee, 0, 3, 0, 3)], attackInfos: [new AttackInfo(MD2Icon.Melee, 0, 3, 0, 3)],
defenseInfo: new DefenseInfo(4, 1), defenseInfo: { blue: 4, black: 1 } as MD2DiceSet,
}), }),
@ -83,21 +84,21 @@ const CORE_GAME_MOB_LEVEL = [
attackInfos: [ attackInfos: [
new AttackInfo(MD2Icon.Magic, 0, 1, 0, 2), new AttackInfo(MD2Icon.Magic, 0, 1, 0, 2),
], ],
defenseInfo: new DefenseInfo(2, 1), defenseInfo: { blue: 2, black: 1 } as MD2DiceSet,
}), }),
new MobInfo({ new MobInfo({
name: 'Balrog', level: 3, hp: 8, name: 'Balrog', level: 3, hp: 8,
attackInfos: [ attackInfos: [
new AttackInfo(MD2Icon.Magic, 0, 2, 0, 2), new AttackInfo(MD2Icon.Magic, 0, 2, 0, 2),
], ],
defenseInfo: new DefenseInfo(3, 1), defenseInfo: { blue: 3, black: 1 } as MD2DiceSet,
}), }),
new MobInfo({ new MobInfo({
name: 'Balrog', level: 5, hp: 10, name: 'Balrog', level: 5, hp: 10,
attackInfos: [ attackInfos: [
new AttackInfo(MD2Icon.Magic, 0, 3, 0, 2), new AttackInfo(MD2Icon.Magic, 0, 3, 0, 2),
], ],
defenseInfo: new DefenseInfo(4, 1), defenseInfo: { blue: 4, black: 1 } as MD2DiceSet,
}), }),
] ]
@ -194,12 +195,13 @@ export class RMUndeadQueenFactory extends CoreGameRMFactory {
});; });;
} }
this.mob.combatSkill = new MobSkill( this.mob.skills = [
{ {
description: `Add 1 Minion to each Mob in the Dungeon, if possible.`, description: `Add 1 Minion to each Mob in the Dungeon, if possible.`,
type: MobSkillType.Attack type: MobSkillType.Attack,
}
) skillRoll: 1
} as MD2MobSkill];
return this.mob; return this.mob;
} }
} }
@ -249,12 +251,12 @@ export class RMAndraFactory extends CoreGameRMFactory {
}); });
} }
this.mob.combatSkill = new MobSkill( this.mob.skills = [
{ {
description: `Deal ${damage} wound to another Hero with the lowest HP in LoS`, description: `Deal ${damage} wound to another Hero with the lowest HP in LoS`,
type: MobSkillType.Combat type: MobSkillType.Combat,
} skillRoll: 1
) } as MD2MobSkill];
return this.mob; return this.mob;
} }
} }
@ -293,12 +295,12 @@ export class RMTheGhoulFactory extends CoreGameRMFactory {
}); });
} }
this.mob.combatSkill = new MobSkill( this.mob.skills = [
{ {
description: `Move the closest <b>Mob with minion</b> 1 Zone toward The Ghoul.`, description: `Move the closest <b>Mob with minion</b> 1 Zone toward The Ghoul.`,
type: MobSkillType.Combat type: MobSkillType.Combat,
} skillRoll: 1
) } as MD2MobSkill];
return this.mob; return this.mob;
} }
} }
@ -340,12 +342,12 @@ export class RMLyidanIncubusLordFactory extends CoreGameRMFactory {
}); });
} }
this.mob.combatSkill = new MobSkill( this.mob.skills = [
{ {
description: `After combat, resolve all ${this.iconHtml(MD2Icon.Fire)} on the defending Hero(once per combat).`, description: `After combat, resolve all ${this.iconHtml(MD2Icon.Fire)} on the defending Hero(once per combat).`,
type: MobSkillType.Attack type: MobSkillType.Attack,
} skillRoll: 1
) } as MD2MobSkill];
return this.mob; return this.mob;
} }
} }
@ -376,12 +378,12 @@ export class RMBalrogFactory extends CoreGameRMFactory {
} }
} }
this.mob.combatSkill = new MobSkill( this.mob.skills = [
{ {
description: `The Hero takes 1 ${this.iconHtml(MD2Icon.Fire)}`, description: `The Hero takes 1 ${this.iconHtml(MD2Icon.Fire)}`,
type: MobSkillType.Combat type: MobSkillType.Combat,
} skillRoll: 1
) } as MD2MobSkill];
return this.mob; return this.mob;
} }
} }

View File

@ -15,7 +15,6 @@
</div> </div>
--> -->
<md2-html-editor></md2-html-editor>
<div class="col-12 col-md-5"> <div class="col-12 col-md-5">
<nb-card> <nb-card>

View File

@ -52,6 +52,7 @@ export interface MD2MobSkill {
skillRoll: number; skillRoll: number;
name: string; name: string;
description: string; description: string;
uiDisplay?: boolean;
} }
export interface MD2DiceSet { export interface MD2DiceSet {

View File

@ -4,8 +4,9 @@ import { first } from "rxjs/operators"
import { MD2Service } from "../../services/MD2/md2.service" import { MD2Service } from "../../services/MD2/md2.service"
import { StringUtils } from "../../utilities/string-utils" import { StringUtils } from "../../utilities/string-utils"
import { BossActivationComponent } from "./boss-fight/boss-activation/boss-activation.component" import { BossActivationComponent } from "./boss-fight/boss-activation/boss-activation.component"
import { TreasureType, AttackInfo, DefenseInfo, AttackType, MD2Icon, MD2HeroInfo, AttackTarget, MobInfo, MobType } from "./massive-darkness2.model" import { TreasureType, AttackInfo, AttackType, MD2Icon, MD2HeroInfo, AttackTarget, MobInfo, MobType } from "./massive-darkness2.model"
import { RollingBlackDice } from "./massive-darkness2.model.dice" import { RollingBlackDice } from "./massive-darkness2.model.dice"
import { MD2DiceSet, MD2MobSkill } from "./massive-darkness2.db.model"
export enum MobSkillType { export enum MobSkillType {
@ -110,14 +111,18 @@ export class BossMicheal extends BossFight {
type: MobType.Boss, type: MobType.Boss,
hpPerHero: 15, hpPerHero: 15,
level: 10, level: 10,
combatSkill: new MobSkill(
{
name: `Combat 1 ${this.md2Service.stateService.iconHtml(MD2Icon.EnemySkill)}`,
description: `Deal 1 Wound for each ${this.corruptionTokenHtml} on the attacking or defending Hero. Discard the tokens afterwards(once per combat).`
}),
imageUrl: md2Service.stateService.imgUrl('/Boss/Michael.png') imageUrl: md2Service.stateService.imgUrl('/Boss/Michael.png')
}); });
this.info.defenseInfo = new DefenseInfo(5, 1); if (!this.info.skills) {
this.info.skills = [];
}
this.info.skills.push({
name: `Combat 1 ${this.md2Service.stateService.iconHtml(MD2Icon.EnemySkill)}`,
description: `Deal 1 Wound for each ${this.corruptionTokenHtml} on the attacking or defending Hero. Discard the tokens afterwards(once per combat).`,
type: MobSkillType.Combat,
skillRoll: 1
} as MD2MobSkill);
this.info.defenseInfo = { blue: 5, black: 1 } as MD2DiceSet;
this.info.attackInfos = [new AttackInfo(MD2Icon.Melee, 2, 2, 0, 1)]; this.info.attackInfos = [new AttackInfo(MD2Icon.Melee, 2, 2, 0, 1)];
this.actions = 1; this.actions = 1;
this.actionBlackDice = 2; this.actionBlackDice = 2;
@ -233,15 +238,17 @@ export class BossReaper extends BossFight {
type: MobType.Boss, type: MobType.Boss,
hpPerHero: 25, hpPerHero: 25,
level: 10, level: 10,
combatSkill: new MobSkill(
{
description: `If the Hero has no ${this.md2Service.stateService.iconHtml(MD2Icon.Mana)}, they take 1 ${this.md2Service.stateService.iconHtml(MD2Icon.Frost)}`,
type: MobSkillType.Attack,
}),
imageUrl: md2Service.stateService.imgUrl('/Boss/The Reaper-Stand.png') imageUrl: md2Service.stateService.imgUrl('/Boss/The Reaper-Stand.png')
}); });
this.info.defenseInfo = new DefenseInfo(4, 3); if (!this.info.skills) {
this.info.skills = [];
}
this.info.skills.push({
description: `If the Hero has no ${this.md2Service.stateService.iconHtml(MD2Icon.Mana)}, they take 1 ${this.md2Service.stateService.iconHtml(MD2Icon.Frost)}`,
type: MobSkillType.Attack,
skillRoll: 1
} as MD2MobSkill);
this.info.defenseInfo = { blue: 4, black: 3 } as MD2DiceSet;
this.info.attackInfos = [new AttackInfo(MD2Icon.Melee, 1, 2, 0, 3)]; this.info.attackInfos = [new AttackInfo(MD2Icon.Melee, 1, 2, 0, 3)];
this.actions = 1; this.actions = 1;
this.actionBlackDice = 2; this.actionBlackDice = 2;

View File

@ -5,6 +5,7 @@ import { ObjectUtils } from "../../utilities/object-utils";
import { GamePlayer } from "../games.model"; import { GamePlayer } from "../games.model";
import { MD2Clone } from "./factorys/md2-clone"; import { MD2Clone } from "./factorys/md2-clone";
import { MobSkill } from "./massive-darkness2.model.boss"; import { MobSkill } from "./massive-darkness2.model.boss";
import { MD2DiceSet, MD2MobSkill } from "./massive-darkness2.db.model";
const MD2_IMG_URL = (id: string = null) => { return `${environment.apiUrl}/Files/Images/MD2/${(id ? `${encodeURI(id)}` : '')}` } const MD2_IMG_URL = (id: string = null) => { return `${environment.apiUrl}/Files/Images/MD2/${(id ? `${encodeURI(id)}` : '')}` }
export enum MobDlgType { export enum MobDlgType {
@ -110,14 +111,7 @@ export class AttackInfo {
yellow: number yellow: number
black: number black: number
} }
export class DefenseInfo {
constructor(blue: number, black: number = 0) {
this.blue = blue
this.black = black
}
blue: number
black: number
}
export class MD2LevelUpReward { export class MD2LevelUpReward {
constructor(config: Partial<MD2LevelUpReward>) { constructor(config: Partial<MD2LevelUpReward>) {
Object.assign(this, config); Object.assign(this, config);
@ -311,10 +305,11 @@ export class MobInfo implements IDrawingItem {
fixedCarriedTreasure: TreasureItem[]; fixedCarriedTreasure: TreasureItem[];
unitRemainHp: number; unitRemainHp: number;
attackInfos: AttackInfo[]; attackInfos: AttackInfo[];
defenseInfo: DefenseInfo; defenseInfo: MD2DiceSet;
skills: MD2MobSkill[];
actions: number = 0; actions: number = 0;
activateDescription: string; activateDescription: string;
combatSkill: MobSkill
fireToken: number = 0; fireToken: number = 0;
frozenToken: number = 0; frozenToken: number = 0;

View File

@ -1 +1 @@
<span [innerHtml]="iconHtml" class="g-font-size-20 g-line-height-0 mx-2"></span> <span [innerHtml]="iconHtml" class="{{sizeClass}} mx-2"></span>

View File

@ -15,11 +15,17 @@ export class MD2IconComponent implements OnInit {
private _icon: string | MD2Icon; private _icon: string | MD2Icon;
@Input() public set icon(v: string | MD2Icon) { @Input() public set icon(v: string | MD2Icon) {
if (v !== undefined) {
if (this._icon != v) { if (this._icon != v) {
this._icon = v; this._icon = v;
//if it's string, convert it to MD2Icon //if it's string, convert it to MD2Icon
if (typeof v === 'string') { if (typeof v === 'string') {
v = MD2Icon[v]; const key = Object.keys(MD2Icon).find(
k => k.toLowerCase() === v.toString().toLowerCase()
);
if (key) {
v = MD2Icon[key as keyof typeof MD2Icon];
}
} }
this.iconHtml = this.md2StateService.iconHtml(v as MD2Icon); this.iconHtml = this.md2StateService.iconHtml(v as MD2Icon);
} }
@ -30,6 +36,8 @@ export class MD2IconComponent implements OnInit {
} }
} }
}
isMD2Icon(icon: MD2Icon | string): icon is MD2Icon { isMD2Icon(icon: MD2Icon | string): icon is MD2Icon {
return Number.isInteger(icon); return Number.isInteger(icon);
} }

View File

@ -111,11 +111,55 @@ export class MD2MobInfoDetailComponent extends DialogContentBase implements OnIn
public addLevelHandler(): void { public addLevelHandler(): void {
if (!this.mobInfo || !this.levelsGrid) return; if (!this.mobInfo || !this.levelsGrid) return;
const newLevel: MD2MobLevelInfo = { // Get the last level info (highest level) if any exists
const lastLevel = this.mobLevelInfos.length > 0
? this.mobLevelInfos.reduce((prev, current) => (prev.level > current.level) ? prev : current)
: null;
// Calculate the next level number
const nextLevel = lastLevel ? lastLevel.level + 2 : 1;
let rewardTokens = 0;
switch (nextLevel) {
case 1:
case 3:
rewardTokens = 1;
break;
case 5:
rewardTokens = 2;
break;
}
let newLevel: MD2MobLevelInfo;
if (lastLevel) {
// Copy the last level's info as initial values
newLevel = {
id: this.generateLevelId(), id: this.generateLevelId(),
level: this.mobLevelInfos.length + 1, level: nextLevel,
mobInfoId: this.mobInfo.id, mobInfoId: this.mobInfo.id,
rewardTokens: 0, rewardTokens: rewardTokens,
fixedRareTreasure: lastLevel.fixedRareTreasure ?? 0,
fixedEpicTreasure: lastLevel.fixedEpicTreasure ?? 0,
fixedLegendTreasure: lastLevel.fixedLegendTreasure ?? 0,
fixedHp: lastLevel.fixedHp ?? 1,
hpPerHero: lastLevel.hpPerHero ?? 0,
actions: lastLevel.actions ?? 1,
attackInfo: lastLevel.attackInfo
? { ...lastLevel.attackInfo }
: { 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
};
} else {
// Default values if no levels exist
newLevel = {
id: this.generateLevelId(),
level: nextLevel,
mobInfoId: this.mobInfo.id,
rewardTokens: rewardTokens,
fixedRareTreasure: 0, fixedRareTreasure: 0,
fixedEpicTreasure: 0, fixedEpicTreasure: 0,
fixedLegendTreasure: 0, fixedLegendTreasure: 0,
@ -126,6 +170,7 @@ export class MD2MobInfoDetailComponent extends DialogContentBase implements OnIn
defenceInfo: { 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: [] skills: []
}; };
}
// Use grid's addRow method to properly add a new row in edit mode // Use grid's addRow method to properly add a new row in edit mode
this.levelsGrid.addRow(newLevel); this.levelsGrid.addRow(newLevel);

View File

@ -15,10 +15,18 @@
</span> </span>
</div> </div>
</div> </div>
<div class='form-group' *ngIf="showSkill"> <div class='form-group'>
<label for='' class='MD2text g-font-size-22 label mb-2'> <!-- <label for='' class='MD2text g-font-size-22 label mb-2'>
<md2-icon icon="blackDice" size="lg"></md2-icon> {{skillTriggerHtml}} <md2-icon icon="enemySkill" size="md"> <md2-icon icon="blackDice" size="lg"></md2-icon> {{skillTriggerHtml}} <md2-icon icon="enemySkill" size="md">
</md2-icon> </md2-icon>
</label> -->
<div *ngFor="let skill of mob.skills" class=" g-brd-bottom--dashed g-brd-gray-light-v2">
<div *ngIf="skill.uiDisplay">
<label for='' class='MD2text g-font-size-22 label mb-2'>
{{MobSkillType[skill.type]}} {{skill.skillRoll}} <md2-icon icon="enemySkill" size="md"></md2-icon>
</label> </label>
<div class='g-font-size-20 skillDesc MD2text' [innerHtml]="mob.combatSkill.description"></div> <div class='g-font-size-20 skillDesc MD2text' [innerHtml]="skill.description"></div>
</div>
</div>
</div> </div>

View File

@ -23,6 +23,9 @@
font-size: 45px; font-size: 45px;
} }
} }
.skillDesc .MD2Icon {
font-size: 45px; //override the style of the skillDesc class and sub elements
:host ::ng-deep .skillDesc .MD2Icon {
font-size: 30px;
} }

View File

@ -8,7 +8,7 @@ import { MobSkillType } from '../../../massive-darkness2.model.boss';
styleUrls: ['./mob-combat-info.component.scss'] styleUrls: ['./mob-combat-info.component.scss']
}) })
export class MobCombatInfoComponent implements OnInit { export class MobCombatInfoComponent implements OnInit {
MobSkillType = MobSkillType;
MD2Icon = MD2Icon; MD2Icon = MD2Icon;
private _mob: MobInfo; private _mob: MobInfo;
public get mob(): MobInfo { public get mob(): MobInfo {
@ -28,23 +28,23 @@ export class MobCombatInfoComponent implements OnInit {
constructor() { } constructor() { }
ngOnInit(): void { ngOnInit(): void {
if (this.mob.combatSkill) { if (this.mob.skills && this.mob.skills.length > 0) {
this.mob.skills.forEach(element => {
switch (this.mode) { switch (this.mode) {
case MobDlgType.Activating: case MobDlgType.Activating:
this.showSkill = [MobSkillType.Combat, MobSkillType.Attack].includes(this.mob.combatSkill.type); element.uiDisplay = [MobSkillType.Combat, MobSkillType.Attack].includes(element.type);
break; break;
case MobDlgType.BeenAttacked: case MobDlgType.BeenAttacked:
this.showSkill = [MobSkillType.Combat, MobSkillType.Defense].includes(this.mob.combatSkill.type); element.uiDisplay = [MobSkillType.Combat, MobSkillType.Defense].includes(element.type);
break; break;
case MobDlgType.PreView: case MobDlgType.PreView:
this.showSkill = true; element.uiDisplay = true;
break; break;
case MobDlgType.Spawn: case MobDlgType.Spawn:
default: element.uiDisplay = false;
this.showSkill = false;
break; break;
} }
this.skillTriggerHtml = `${MobSkillType[this.mob.combatSkill.type]} ${this.mob.combatSkill.skillRoll} ` });
} }
this.showBlackDice = this.mob.type == MobType.Mob && (this.mode == MobDlgType.Activating || this.mode == MobDlgType.BeenAttacked) && this.mob.minionAmount > 0;; this.showBlackDice = this.mob.type == MobType.Mob && (this.mode == MobDlgType.Activating || this.mode == MobDlgType.BeenAttacked) && this.mob.minionAmount > 0;;

View File

@ -11,7 +11,6 @@ import { StateService } from '../../../services/state.service';
import { ADIcon } from '../../../ui/alert-dlg/alert-dlg.model'; import { ADIcon } from '../../../ui/alert-dlg/alert-dlg.model';
import { NumberUtils } from '../../../utilities/number-utils'; import { NumberUtils } from '../../../utilities/number-utils';
import { StringUtils } from '../../../utilities/string-utils'; import { StringUtils } from '../../../utilities/string-utils';
import { CoreGameMobFactories } from '../factorys/mobs/CoreGame';
import { CoreGameRMFactories } from '../factorys/roamingMonsters/CoreGame'; import { CoreGameRMFactories } from '../factorys/roamingMonsters/CoreGame';
import { DrawingBag, DrawingItem, MD2Icon, MobDlgType, MobInfo, TreasureType } from '../massive-darkness2.model'; import { DrawingBag, DrawingItem, MD2Icon, MobDlgType, MobInfo, TreasureType } from '../massive-darkness2.model';
import { MD2Base, MD2ComponentBase } from '../MD2Base'; import { MD2Base, MD2ComponentBase } from '../MD2Base';
@ -90,7 +89,7 @@ export class MobsComponent extends MD2ComponentBase implements OnInit {
} }
spawnSpecificMob() { spawnSpecificMob() {
let mobOptions = this.isRoamingMonster ? CoreGameRMFactories.map(f => new DropDownOption(f.mobName, f.mobName)) : CoreGameMobFactories.map(f => new DropDownOption(f.mobName, f.mobName)); let mobOptions = this.isRoamingMonster ? CoreGameRMFactories.map(f => new DropDownOption(f.mobName, f.mobName)) : this.md2Service.allMobInfos.map(f => new DropDownOption(f.name, f.name));
this.msgBoxService.showInputbox('Spawn', '', { inputType: 'dropdown', dropDownOptions: mobOptions }).pipe(first()).subscribe(mobName => { this.msgBoxService.showInputbox('Spawn', '', { inputType: 'dropdown', dropDownOptions: mobOptions }).pipe(first()).subscribe(mobName => {
if (mobName) { if (mobName) {

View File

@ -1,8 +1,9 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { CoreGameMobFactories } from '../../games/massive-darkness2/factorys/mobs/CoreGame';
import { CoreGameRMFactories } from '../../games/massive-darkness2/factorys/roamingMonsters/CoreGame'; import { CoreGameRMFactories } from '../../games/massive-darkness2/factorys/roamingMonsters/CoreGame';
import { DrawingBag, MobInfo, TreasureItem, TreasureType } from '../../games/massive-darkness2/massive-darkness2.model'; import { DrawingBag, MobInfo, TreasureItem, TreasureType } from '../../games/massive-darkness2/massive-darkness2.model';
import { MD2StateService } from './md2-state.service'; import { MD2StateService } from './md2-state.service';
import { MD2MobInfoService } from '../../games/massive-darkness2/service/massive-darkness2.service';
import { first } from 'rxjs/operators';
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
@ -10,7 +11,8 @@ import { MD2StateService } from './md2-state.service';
export class MD2InitService { export class MD2InitService {
constructor( constructor(
private stateService: MD2StateService private stateService: MD2StateService,
private mobInfoService: MD2MobInfoService,
) { } ) { }
public initMobDecks() { public initMobDecks() {
@ -31,11 +33,26 @@ export class MD2InitService {
} }
private initCoreGameMobs() { private initCoreGameMobs() {
CoreGameMobFactories.forEach(factory => { // CoreGameMobFactories.forEach(factory => {
for (let i = 1; i <= 5; i++) { // for (let i = 1; i <= 5; i++) {
this.stateService.mobDeck.AddItem(new MobInfo({ name: factory.mobName, level: i, drawingWeight: 1 })); // this.stateService.mobDeck.AddItem(new MobInfo({ name: factory.mobName, level: i, drawingWeight: 1 }));
i++; // i++;
// }
// });
this.mobInfoService.getAll().pipe(first()).subscribe(result => {
this.stateService.mobInfos = result;
for (let i = 0; i < result.length; i++) {
const mobInfo = result[i];
for (let j = 0; j < mobInfo.mobLevelInfos.length; j++) {
const levelInfo = mobInfo.mobLevelInfos[j];
this.stateService.mobDeck.AddItem(new MobInfo({ name: mobInfo.name, level: levelInfo.level, drawingWeight: 1 }));
} }
}
// result.forEach(mobInfo => {
// this.stateService.mobDeck.AddItem(new MobInfo({ name: mobInfo.name, level: mobInfo.level, drawingWeight: 1 }));
// });
}); });
} }

View File

@ -2,6 +2,7 @@ import { Injectable } from '@angular/core';
import { DrawingBag, MD2HeroInfo, MD2Icon, MobInfo, TreasureItem, TreasureType } from '../../games/massive-darkness2/massive-darkness2.model'; import { DrawingBag, MD2HeroInfo, MD2Icon, MobInfo, TreasureItem, TreasureType } from '../../games/massive-darkness2/massive-darkness2.model';
import { FileService } from '../file.service'; import { FileService } from '../file.service';
import { MD2GameInfo } from './md2.service'; import { MD2GameInfo } from './md2.service';
import { MD2MobInfo } from '../../games/massive-darkness2/massive-darkness2.db.model';
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
@ -13,6 +14,7 @@ export class MD2StateService {
public info: MD2GameInfo; public info: MD2GameInfo;
public playerHero: MD2HeroInfo; public playerHero: MD2HeroInfo;
public mobInfos: MD2MobInfo[] = [];
public mobDeck: DrawingBag<MobInfo>; public mobDeck: DrawingBag<MobInfo>;
public roamingMobDeck: DrawingBag<MobInfo>; public roamingMobDeck: DrawingBag<MobInfo>;
public treasureBag: DrawingBag<TreasureItem> = new DrawingBag<TreasureItem>(); public treasureBag: DrawingBag<TreasureItem> = new DrawingBag<TreasureItem>();

View File

@ -1,5 +1,5 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { AttackInfo, AttackTarget, CoreGameDarknessPhaseRule, DefenseInfo, DrawingBag, DrawingItem, HeroClass, IDarknessPhaseRule, MD2HeroInfo, MD2Icon, MD2Rules, MobInfo, MobType, RoundPhase, TreasureItem, TreasureType } from '../../games/massive-darkness2/massive-darkness2.model'; import { AttackInfo, AttackTarget, CoreGameDarknessPhaseRule, DrawingBag, DrawingItem, HeroClass, IDarknessPhaseRule, MD2HeroInfo, MD2Icon, MD2Rules, MobInfo, MobType, RoundPhase, TreasureItem, TreasureType } from '../../games/massive-darkness2/massive-darkness2.model';
import { first, map, reduce } from "rxjs/operators"; import { first, map, reduce } from "rxjs/operators";
import { NbDialogService } from '@nebular/theme'; import { NbDialogService } from '@nebular/theme';
import { Subject } from 'rxjs'; import { Subject } from 'rxjs';
@ -14,14 +14,16 @@ import { MsgBoxService } from '../msg-box.service';
import { SignalRService, SignalRSession, SignalRMessage } from '../signal-r.service'; import { SignalRService, SignalRSession, SignalRMessage } from '../signal-r.service';
import { MD2StateService } from './md2-state.service'; import { MD2StateService } from './md2-state.service';
import { MD2BroadcastService } from './md2-broadcast.service'; import { MD2BroadcastService } from './md2-broadcast.service';
import { CoreGameMobFactories } from '../../games/massive-darkness2/factorys/mobs/CoreGame';
import { MD2Logic } from '../../games/massive-darkness2/massive-darkness2.logic'; import { MD2Logic } from '../../games/massive-darkness2/massive-darkness2.logic';
import { CoreGameRMFactories } from '../../games/massive-darkness2/factorys/roamingMonsters/CoreGame'; import { CoreGameRMFactories } from '../../games/massive-darkness2/factorys/roamingMonsters/CoreGame';
import { MD2InitService } from './md2-init.service'; import { MD2InitService } from './md2-init.service';
import { ArrayUtils } from '../../utilities/array-utils'; import { ArrayUtils } from '../../utilities/array-utils';
import { DropDownOption } from '../../entity/dropDownOption'; import { DropDownOption } from '../../entity/dropDownOption';
import { GameBundle, MD2MobInfo } from '../../games/massive-darkness2/massive-darkness2.db.model';
import { environment } from '../../../environments/environment';
const MD2_IMG_URL = (id: string = null) => { return `${environment.apiUrl}/Files/Images/MD2/Mobs${(id ? `${encodeURI(id)}` : '')}` };
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
}) })
@ -49,6 +51,9 @@ export class MD2Service {
public get mobs() { public get mobs() {
return this.stateService.info.mobs; return this.stateService.info.mobs;
} }
public get allMobInfos() {
return this.stateService.mobInfos;
}
public get info(): MD2GameInfo { public get info(): MD2GameInfo {
@ -176,7 +181,7 @@ export class MD2Service {
exitingMob.imageUrl = newSpawnMob.imageUrl; exitingMob.imageUrl = newSpawnMob.imageUrl;
exitingMob.attackInfos = newSpawnMob.attackInfos; exitingMob.attackInfos = newSpawnMob.attackInfos;
exitingMob.defenseInfo = newSpawnMob.defenseInfo; exitingMob.defenseInfo = newSpawnMob.defenseInfo;
exitingMob.combatSkill = newSpawnMob.combatSkill; exitingMob.skills = newSpawnMob.skills;
} else { } else {
if (isRoamingMonster) { if (isRoamingMonster) {
newSpawnMob = CoreGameRMFactories.find(f => f.mobName == newSpawnMob.name).generate(level); newSpawnMob = CoreGameRMFactories.find(f => f.mobName == newSpawnMob.name).generate(level);
@ -185,19 +190,42 @@ export class MD2Service {
newSpawnMob.mobAmount = 0; newSpawnMob.mobAmount = 0;
this.roamingMonsters.push(newSpawnMob); this.roamingMonsters.push(newSpawnMob);
} else { } else {
newSpawnMob = CoreGameMobFactories.find(f => f.mobName == newSpawnMob.name).generate(level); newSpawnMob = this.generateMob(newSpawnMob.name, level);
newSpawnMob.mobAmount = this.playerAmount + 1;
this.mobs.push(newSpawnMob); this.mobs.push(newSpawnMob);
} }
newSpawnMob.carriedTreasure = this.treasureBag.DrawAndRemove(newSpawnMob.rewardTokens); newSpawnMob.carriedTreasure = this.treasureBag.DrawAndRemove(newSpawnMob.rewardTokens);
this.refreshTreasureBagSubject.next(this.treasureBag); this.refreshTreasureBagSubject.next(this.treasureBag);
} }
newSpawnMob.imageUrl = this.mobImage(newSpawnMob.name, newSpawnMob.level, isRoamingMonster); newSpawnMob.imageUrl = this.mobImage(newSpawnMob.name, newSpawnMob.level, isRoamingMonster);
return { exitingMob, mob: newSpawnMob }; return { exitingMob, mob: newSpawnMob };
} }
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 mobInfo = new MobInfo({
name: dbMobInfo.name,
hp: levelInfo.hpPerHero,
hpPerHero: levelInfo.hpPerHero,
level: level,
rewardTokens: levelInfo.rewardTokens,
defenseInfo: levelInfo.defenceInfo,
skills: levelInfo.skills
});
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`);
mobInfo.fixedCarriedTreasure = [];
levelInfo.fixedRareTreasure > 0 && mobInfo.fixedCarriedTreasure.push(new TreasureItem(TreasureType.Rare, levelInfo.fixedRareTreasure));
levelInfo.fixedEpicTreasure > 0 && mobInfo.fixedCarriedTreasure.push(new TreasureItem(TreasureType.Epic, levelInfo.fixedEpicTreasure));
levelInfo.fixedLegendTreasure > 0 && mobInfo.fixedCarriedTreasure.push(new TreasureItem(TreasureType.Legendary, levelInfo.fixedLegendTreasure));
//Maybe add more mobs later
mobInfo.mobAmount = this.playerAmount + 1;
return mobInfo;
}
public enemyPhase() { public enemyPhase() {
//this.msgBoxService //this.msgBoxService
this.enemyPhaseMobs = this.roamingMonsters.concat(this.mobs); this.enemyPhaseMobs = this.roamingMonsters.concat(this.mobs);

View File

@ -1,16 +1,16 @@
@use "../../../app/@theme/styles/themes"; @use "../../../app/@theme/styles/themes";
::-webkit-scrollbar { // ::-webkit-scrollbar {
width: 1rem !important; // width: 1rem !important;
} // }
::-webkit-scrollbar-thumb { // ::-webkit-scrollbar-thumb {
background-color: nb-theme(color-primary-300) !important; // background-color: nb-theme(color-primary-300) !important;
} // }
::-webkit-scrollbar-track { // ::-webkit-scrollbar-track {
background: nb-theme(color-primary-200) !important; // background: nb-theme(color-primary-200) !important;
} // }
.label { .label {
color: #736f6f; color: #736f6f;