From 525d8fe21e44433ce8aacf82292253e915a03fcc Mon Sep 17 00:00:00 2001 From: Jelle Meeus Date: Sun, 14 Dec 2025 11:45:25 +0100 Subject: [PATCH 01/14] feat(trainer): add trainer support --- apps/keira/src/app/routes.ts | 27 +- apps/keira/src/assets/i18n/en.json | 40 ++- .../creature-default-trainer.component.html | 40 +++ .../creature-default-trainer.component.ts | 20 ++ .../creature-default-trainer.service.ts | 19 ++ .../creature/src/creature-handler.service.ts | 8 +- .../creature-template.component.html | 40 --- .../creature-template.component.ts | 3 - libs/features/creature/src/index.ts | 2 +- .../npc-trainer/npc-trainer.component.html | 111 ------- .../npc-trainer.integration.spec.ts | 313 ------------------ .../npc-trainer/npc-trainer.service.spec.ts | 34 -- .../src/npc-trainer/npc-trainer.service.ts | 20 -- libs/features/trainer/karma.conf.js | 44 +++ libs/features/trainer/project.json | 24 ++ .../src/edit-trainer/trainer.component.html | 51 +++ .../src/edit-trainer/trainer.component.ts | 30 ++ .../src/edit-trainer/trainer.service.ts | 19 ++ libs/features/trainer/src/index.ts | 7 + .../select-trainer.component.html | 59 ++++ .../select-trainer.component.ts | 32 ++ .../select-trainer/select-trainer.service.ts | 20 ++ .../src/trainer-handler.service.spec.ts | 15 + .../trainer/src/trainer-handler.service.ts | 23 ++ .../trainer-spell.component.html | 158 +++++++++ .../trainer-spell.component.scss} | 0 .../trainer-spell/trainer-spell.component.ts} | 19 +- .../trainer-spell/trainer-spell.service.ts | 20 ++ libs/features/trainer/tsconfig.json | 29 ++ libs/features/trainer/tsconfig.lib.json | 12 + libs/features/trainer/tsconfig.spec.json | 10 + .../src/sidebar/sidebar.component.html | 42 ++- .../src/sidebar/sidebar.component.ts | 7 +- .../entities/creature-default-trainer.type.ts | 9 + .../src/entities/creature-template.type.ts | 4 - .../src/entities/npc-trainer.type.ts | 14 - .../src/entities/trainer-locale.type.ts | 12 + .../src/entities/trainer-spell.type.ts | 18 + .../src/entities/trainer.type.ts | 12 + libs/shared/acore-world-model/src/index.ts | 5 +- package-lock.json | 79 ----- package.json | 3 + tsconfig.base.json | 1 + 43 files changed, 806 insertions(+), 649 deletions(-) create mode 100644 libs/features/creature/src/creature-default-trainer/creature-default-trainer.component.html create mode 100644 libs/features/creature/src/creature-default-trainer/creature-default-trainer.component.ts create mode 100644 libs/features/creature/src/creature-default-trainer/creature-default-trainer.service.ts delete mode 100644 libs/features/creature/src/npc-trainer/npc-trainer.component.html delete mode 100644 libs/features/creature/src/npc-trainer/npc-trainer.integration.spec.ts delete mode 100644 libs/features/creature/src/npc-trainer/npc-trainer.service.spec.ts delete mode 100644 libs/features/creature/src/npc-trainer/npc-trainer.service.ts create mode 100644 libs/features/trainer/karma.conf.js create mode 100644 libs/features/trainer/project.json create mode 100644 libs/features/trainer/src/edit-trainer/trainer.component.html create mode 100644 libs/features/trainer/src/edit-trainer/trainer.component.ts create mode 100644 libs/features/trainer/src/edit-trainer/trainer.service.ts create mode 100644 libs/features/trainer/src/index.ts create mode 100644 libs/features/trainer/src/select-trainer/select-trainer.component.html create mode 100644 libs/features/trainer/src/select-trainer/select-trainer.component.ts create mode 100644 libs/features/trainer/src/select-trainer/select-trainer.service.ts create mode 100644 libs/features/trainer/src/trainer-handler.service.spec.ts create mode 100644 libs/features/trainer/src/trainer-handler.service.ts create mode 100644 libs/features/trainer/src/trainer-spell/trainer-spell.component.html rename libs/features/{creature/src/npc-trainer/npc-trainer.component.scss => trainer/src/trainer-spell/trainer-spell.component.scss} (100%) rename libs/features/{creature/src/npc-trainer/npc-trainer.component.ts => trainer/src/trainer-spell/trainer-spell.component.ts} (67%) create mode 100644 libs/features/trainer/src/trainer-spell/trainer-spell.service.ts create mode 100644 libs/features/trainer/tsconfig.json create mode 100644 libs/features/trainer/tsconfig.lib.json create mode 100644 libs/features/trainer/tsconfig.spec.json create mode 100644 libs/shared/acore-world-model/src/entities/creature-default-trainer.type.ts delete mode 100644 libs/shared/acore-world-model/src/entities/npc-trainer.type.ts create mode 100644 libs/shared/acore-world-model/src/entities/trainer-locale.type.ts create mode 100644 libs/shared/acore-world-model/src/entities/trainer-spell.type.ts create mode 100644 libs/shared/acore-world-model/src/entities/trainer.type.ts diff --git a/apps/keira/src/app/routes.ts b/apps/keira/src/app/routes.ts index af72c06ab12..001fa54f7cd 100644 --- a/apps/keira/src/app/routes.ts +++ b/apps/keira/src/app/routes.ts @@ -19,7 +19,7 @@ import { CreatureTemplateResistanceComponent, CreatureTemplateSpellComponent, CreatureTextComponent, - NpcTrainerComponent, + CreatureDefaultTrainerComponent, NpcVendorComponent, PickpocketingLootTemplateComponent, SaiCreatureComponent, @@ -94,6 +94,7 @@ import { SelectAcoreStringComponent, } from 'texts'; import { GameTeleComponent, GameTeleHandlerService, SelectGameTeleComponent } from '@keira/features/game-tele'; +import { SelectTrainerComponent, TrainerComponent, TrainerHandlerService, TrainerSpellComponent } from '@keira/features/trainer'; import { UnusedGuidSearchComponent } from '@keira/features/unused-guid-search'; export const KEIRA_ROUTES: Routes = [ @@ -178,10 +179,11 @@ export const KEIRA_ROUTES: Routes = [ canActivate: [CreatureHandlerService], }, { - path: 'npc-trainer', - component: NpcTrainerComponent, + path: 'creature-default-trainer', + component: CreatureDefaultTrainerComponent, canActivate: [CreatureHandlerService], }, + { path: 'creature-spawn', component: CreatureSpawnComponent, @@ -506,6 +508,25 @@ export const KEIRA_ROUTES: Routes = [ }, ], }, + { + path: 'trainer', + children: [ + { + path: 'select', + component: SelectTrainerComponent, + }, + { + path: 'trainer', + component: TrainerComponent, + canActivate: [TrainerHandlerService], + }, + { + path: 'trainer-spell', + component: TrainerSpellComponent, + canActivate: [TrainerHandlerService], + }, + ], + }, { path: 'unused-guid-search', component: UnusedGuidSearchComponent, diff --git a/apps/keira/src/assets/i18n/en.json b/apps/keira/src/assets/i18n/en.json index a2ad6a758dc..e87f2fabc23 100644 --- a/apps/keira/src/assets/i18n/en.json +++ b/apps/keira/src/assets/i18n/en.json @@ -86,7 +86,7 @@ "ONKILL_REPUTATION": "Onkill Reputation", "EQUIP_TEMPLATE": "Equip Template", "VENDOR": "Vendor", - "TRAINER": "Trainer", + "DEFAULT_TRAINER": "Default Trainer", "QUEST_ITEM": "Quest Item", "CREATURE_LOOT": "Creature Loot", "PICKPOCKETING_LOOT": "Pickpocketing Loot", @@ -182,6 +182,12 @@ "SEARCH_GAME_TELE": "Search Teleport", "SELECT_GAME_TELE": "Game Tele Editor" }, + "TRAINER": { + "TITLE": "Trainer", + "SEARCH_TRAINER": "Search Trainer", + "SELECT_TRAINER": "Trainer", + "TRAINER_SPELL": "Trainer Spell" + }, "UNUSED_GUID_SEARCH": "Unused GUIDs" }, "DASHBOARD": { @@ -216,7 +222,6 @@ "KILL_CREDITS": "KillCredits", "MODELS": "Models", "MONEY_LOOT": "Money Loot", - "TRAINER": "Trainer", "LOOTS": "Loots", "DIFFICULTY_ENTRIES": "Difficulty Entries", "DAMAGE": "Damage", @@ -299,18 +304,16 @@ "TEMPLATE_SPELL": { "INDEX": "Allowed values: 0-7" }, - "NPC_TRAINER": { - "MONEY_COST": "The cost to pay to learn the spell represented in copper (1 gold = 100 silver = 10000 cooper)", - "REQ_SKILL_LINE": "The required skill the player needs to have in order to be able to learn the spell", - "REQ_SKILL_RANK": "The proficiency in the skill from reqskill that the player needs to meet to learn the spell", - "REQ_LEVEL": "The minimum level the player needs to be in order to learn the spell." - }, "NPC_VENDOR": { "SLOT": "Position of the item in the vendor window", "MAXCOUNT": "The maximum number of items carried by the vendor at any time. 0 for infinite (if choosing a value of 1 or higher also requires incrtime value to work)", "INCRTIME": "Combined with maxcount, how often (in seconds) the vendor list is refreshed", "EXTENDED_COST": "Value comes from DBC and a selector for this will be implemented later in Keira3" }, + "DEFAULT_TRAINER": { + "TITLE": "Default Trainer", + "TRAINER_ID_TOOLTIP": "ID of the trainer template (trainer.Id) assigned to this creature. Use 0 for no default trainer. Examples: 1=Trainer Warrior, 3=Trainer Paladin, 7=Trainer Hunter, 9=Trainer Rogue, 11=Trainer Priest, 13=Trainer Death Knight, 14=Trainer Shaman, 16=Trainer Mage, 31=Trainer Warlock, 33=Trainer Druid, 36=Trainer Mount & Fly. See the trainer wiki for the full list." + }, "TEXT": { "GROUP_ID": "If there is more than one of the same entry (more than one text the creature says), this column is used to choose if it is a random say or an ordered list. If a creature has got more than one say text to be shown in a given order, it must be incremented for each new matching entry (ex. 0, 1, 2, 3...). If there is only one entry or only one group, this value should be 0. If there are multiple groups of texts, this value stays the same within the group while the id increments within the same group.", "ID": "Entry for each group of texts. This is the unique identifier when entry (creature) is the same and groupid is unchanged, it must be incremented (ex. 0, 1, 2, 3...). A creature say will be randomly selected from this list based on the groupid it belongs to.", @@ -902,6 +905,27 @@ "GAME_TELE": { "EDITOR": "Teleport Editor" }, + "TRAINER": { + "EDITOR": "Trainer Editor", + "TRAINER_ID_TOOLTIP": "References trainer.id (trainer template). Examples: 1=Trainer Warrior, 3=Trainer Paladin, 7=Trainer Hunter, 9=Trainer Rogue, 11=Trainer Priest, 13=Trainer Death Knight, 14=Trainer Shaman, 16=Trainer Mage, 31=Trainer Warlock, 33=Trainer Druid, 36=Trainer Mount & Fly. See the trainer wiki for the full list.", + "REQUIREMENT_TOOLTIP": "Meaning depends on Type - use 0 for none. Types: 0-Class (ChrClass ID e.g. 1=Warrior, 2=Paladin, 3=Hunter, 4=Rogue, 5=Priest, 6=Death Knight, 7=Shaman, 8=Mage, 9=Warlock, 11=Druid), 1-Mount (ChrRace ID (e.g. 1=Human, 2=Orc, 3=Dwarf, 4=Night Elf, 5=Undead, 6=Tauren, 7=Gnome, 8=Troll, 10=Blood Elf, 11=Draenei), 2-Tradeskill Spell ID (player must know this spell to learn from this trainer), 3-Pet ChrClass ID (see above). ", + "GREETING_TOOLTIP": "Text shown at the top of the trainer window when opened (this is not gossip). For localized greetings add entries in the \"trainer_locale\" table (Greeting_lang).", + "SPELL": { + "TRAINER_ID": "References trainer.id (trainer template linked to this entry).", + "SPELL_ID": "Spell ID being taught.", + "MONEY_COST": "Cost in copper to learn this spell from the trainer (1 gold = 100 silver = 10000 copper).", + "REQ_SKILL_LINE": "SkillLine ID required to learn this spell (e.g., profession ID). Use 0 if none.", + "REQ_SKILL_RANK": "Minimum skill rank in ReqSkillLine required to learn the spell.", + "REQ_ABILITY_1": "Spell ID the player is required to already know (first required ability).", + "REQ_ABILITY_1_TOOLTIP": "Spell ID the player must already know to be taught this spell (first prerequisite). Use 0 if none.", + "REQ_ABILITY_2": "Spell ID the player is required to already know (second required ability).", + "REQ_ABILITY_2_TOOLTIP": "Spell ID the player must already know to be taught this spell (second prerequisite). Use 0 if none.", + "REQ_ABILITY_3": "Spell ID the player is required to already know (third required ability).", + "REQ_ABILITY_3_TOOLTIP": "Spell ID the player must already know to be taught this spell (third prerequisite). Use 0 if none.", + "REQ_LEVEL": "Minimum player level required to learn this spell.", + "VERIFIED_BUILD": "Used by AzerothCore to indicate whether this entry was verified against WDB files (0 = not parsed; >0 = parsed; -1 = placeholder; - = parsed with specific client build and manually edited)." + } + }, "UNUSED_GUID_SEARCH": { "TABLE": "Table", "START_INDEX": "Start Index", diff --git a/libs/features/creature/src/creature-default-trainer/creature-default-trainer.component.html b/libs/features/creature/src/creature-default-trainer/creature-default-trainer.component.html new file mode 100644 index 00000000000..52e271ff1c0 --- /dev/null +++ b/libs/features/creature/src/creature-default-trainer/creature-default-trainer.component.html @@ -0,0 +1,40 @@ + + +
+ @if (editorService.loading) { + + } + + @if (editorService.form && !!editorService.loadedEntityId && !editorService.loading) { +
+
+ +
+
+
+ +
+
+ + +
+
+ + + +
+
+
+
+
+ } +
diff --git a/libs/features/creature/src/creature-default-trainer/creature-default-trainer.component.ts b/libs/features/creature/src/creature-default-trainer/creature-default-trainer.component.ts new file mode 100644 index 00000000000..c0df37741c2 --- /dev/null +++ b/libs/features/creature/src/creature-default-trainer/creature-default-trainer.component.ts @@ -0,0 +1,20 @@ +import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { CreatureDefaultTrainer } from '@keira/shared/acore-world-model'; +import { SingleRowEditorComponent } from '@keira/shared/base-abstract-classes'; +import { QueryOutputComponent, TopBarComponent } from '@keira/shared/base-editor-components'; +import { TranslateModule } from '@ngx-translate/core'; +import { TooltipModule } from 'ngx-bootstrap/tooltip'; +import { CreatureHandlerService } from '../creature-handler.service'; +import { CreatureDefaultTrainerService } from './creature-default-trainer.service'; + +@Component({ + changeDetection: ChangeDetectionStrategy.OnPush, + selector: 'keira-creature-default-trainer', + templateUrl: './creature-default-trainer.component.html', + imports: [TopBarComponent, TranslateModule, QueryOutputComponent, FormsModule, ReactiveFormsModule, TooltipModule], +}) +export class CreatureDefaultTrainerComponent extends SingleRowEditorComponent { + protected override readonly editorService = inject(CreatureDefaultTrainerService); + readonly handlerService = inject(CreatureHandlerService); +} diff --git a/libs/features/creature/src/creature-default-trainer/creature-default-trainer.service.ts b/libs/features/creature/src/creature-default-trainer/creature-default-trainer.service.ts new file mode 100644 index 00000000000..170914319a5 --- /dev/null +++ b/libs/features/creature/src/creature-default-trainer/creature-default-trainer.service.ts @@ -0,0 +1,19 @@ +import { Injectable, inject } from '@angular/core'; +import { SingleRowEditorService } from '@keira/shared/base-abstract-classes'; +import { CREATURE_DEFAULT_TRAINER_ID, CREATURE_DEFAULT_TRAINER_TABLE, CreatureDefaultTrainer } from '@keira/shared/acore-world-model'; +import { CreatureHandlerService } from '../creature-handler.service'; + +@Injectable({ + providedIn: 'root', +}) +export class CreatureDefaultTrainerService extends SingleRowEditorService { + protected override readonly handlerService = inject(CreatureHandlerService); + protected override readonly _entityClass = CreatureDefaultTrainer; + protected override readonly _entityTable = CREATURE_DEFAULT_TRAINER_TABLE; + protected override readonly _entityIdField = CREATURE_DEFAULT_TRAINER_ID; + + constructor() { + super(); + this.init(); + } +} diff --git a/libs/features/creature/src/creature-handler.service.ts b/libs/features/creature/src/creature-handler.service.ts index 8d47d9be8c2..69bb0332cfc 100644 --- a/libs/features/creature/src/creature-handler.service.ts +++ b/libs/features/creature/src/creature-handler.service.ts @@ -15,7 +15,7 @@ import { CREATURE_TEMPLATE_TABLE, CREATURE_TEXT_TABLE, CreatureTemplate, - NPC_TRAINER_TABLE, + CREATURE_DEFAULT_TRAINER_TABLE, NPC_VENDOR_TABLE, PICKPOCKETING_LOOT_TEMPLATE_TABLE, SAI_TABLE, @@ -58,8 +58,8 @@ export class CreatureHandlerService extends HandlerService { get isNpcVendorUnsaved(): Signal { return this.statusMap[NPC_VENDOR_TABLE].asReadonly(); } - get isNpcTrainerUnsaved(): Signal { - return this.statusMap[NPC_TRAINER_TABLE].asReadonly(); + get isCreatureDefaultTrainerUnsaved(): Signal { + return this.statusMap[CREATURE_DEFAULT_TRAINER_TABLE].asReadonly(); } get isCreatureQuestitemUnsaved(): Signal { return this.statusMap[CREATURE_QUESTITEM_TABLE].asReadonly(); @@ -99,7 +99,7 @@ export class CreatureHandlerService extends HandlerService { [CREATURE_ONKLL_REPUTATION_TABLE]: signal(false), [CREATURE_EQUIP_TEMPLATE_TABLE]: signal(false), [NPC_VENDOR_TABLE]: signal(false), - [NPC_TRAINER_TABLE]: signal(false), + [CREATURE_DEFAULT_TRAINER_TABLE]: signal(false), [CREATURE_QUESTITEM_TABLE]: signal(false), [CREATURE_LOOT_TEMPLATE_TABLE]: signal(false), [PICKPOCKETING_LOOT_TEMPLATE_TABLE]: signal(false), diff --git a/libs/features/creature/src/creature-template/creature-template.component.html b/libs/features/creature/src/creature-template/creature-template.component.html index 6197883ac72..1b3f53aefd3 100644 --- a/libs/features/creature/src/creature-template/creature-template.component.html +++ b/libs/features/creature/src/creature-template/creature-template.component.html @@ -219,46 +219,6 @@ -
- -
-
- - -
-
- - - - -
-
- - -
-
- - -
-
-
diff --git a/libs/features/creature/src/creature-template/creature-template.component.ts b/libs/features/creature/src/creature-template/creature-template.component.ts index 5b5035ffa20..e985b47e840 100644 --- a/libs/features/creature/src/creature-template/creature-template.component.ts +++ b/libs/features/creature/src/creature-template/creature-template.component.ts @@ -18,7 +18,6 @@ import { NPC_FLAGS, RANK, SPELL_SCHOOL_MASK, - TRAINER_TYPE, UNIT_CLASS, UNIT_FLAGS, UNIT_FLAGS_2, @@ -53,7 +52,6 @@ import { CreatureTemplateService } from './creature-template.service'; SingleValueSelectorBtnComponent, FactionSelectorBtnComponent, FlagsSelectorBtnComponent, - SpellSelectorBtnComponent, CreatureSelectorBtnComponent, GenericOptionSelectorComponent, BooleanOptionSelectorComponent, @@ -62,7 +60,6 @@ import { CreatureTemplateService } from './creature-template.service'; export class CreatureTemplateComponent extends SingleRowEditorComponent { protected readonly UNIT_FLAGS = UNIT_FLAGS; protected readonly UNIT_FLAGS_2 = UNIT_FLAGS_2; - protected readonly TRAINER_TYPE = TRAINER_TYPE; protected readonly NPC_FLAGS = NPC_FLAGS; protected readonly CREATURE_FAMILY = CREATURE_FAMILY; protected readonly CREATURE_TYPE = CREATURE_TYPE; diff --git a/libs/features/creature/src/index.ts b/libs/features/creature/src/index.ts index c18763f387c..3a80fe56ee4 100644 --- a/libs/features/creature/src/index.ts +++ b/libs/features/creature/src/index.ts @@ -12,7 +12,7 @@ export * from './creature-template-resistance/creature-template-resistance.compo export * from './creature-template-spell/creature-template-spell.component'; export * from './creature-template/creature-template.component'; export * from './creature-text/creature-text.component'; -export * from './npc-trainer/npc-trainer.component'; +export * from './creature-default-trainer/creature-default-trainer.component'; export * from './npc-vendor/npc-vendor.component'; export * from './pickpocketing-loot-template/pickpocketing-loot-template.component'; export * from './sai-creature-handler.service'; diff --git a/libs/features/creature/src/npc-trainer/npc-trainer.component.html b/libs/features/creature/src/npc-trainer/npc-trainer.component.html deleted file mode 100644 index c9a9eec044f..00000000000 --- a/libs/features/creature/src/npc-trainer/npc-trainer.component.html +++ /dev/null @@ -1,111 +0,0 @@ - - -
- @if (editorService.loading) { - - } - - @if (editorService.form && !!editorService.loadedEntityId && !editorService.loading) { -
-
- -
-
-
-
-
- - - -
-
- - - -
-
- - - - -
-
- - - -
-
- - - -
-
- - -
-
-
-
-
- - - - - - - - - - - - - - - {{ sqliteQueryService.getSpellNameById(row.SpellID) | async }} - - - - - - - -
-
-
-
- } -
diff --git a/libs/features/creature/src/npc-trainer/npc-trainer.integration.spec.ts b/libs/features/creature/src/npc-trainer/npc-trainer.integration.spec.ts deleted file mode 100644 index e92acb75312..00000000000 --- a/libs/features/creature/src/npc-trainer/npc-trainer.integration.spec.ts +++ /dev/null @@ -1,313 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { provideZonelessChangeDetection } from '@angular/core'; -import { provideNoopAnimations } from '@angular/platform-browser/animations'; -import { RouterTestingModule } from '@angular/router/testing'; -import { MysqlQueryService, SqliteQueryService } from '@keira/shared/db-layer'; -import { MultiRowEditorPageObject, TranslateTestingModule } from '@keira/shared/test-utils'; -import { NpcTrainer } from '@keira/shared/acore-world-model'; -import { ModalModule } from 'ngx-bootstrap/modal'; -import { ToastrModule } from 'ngx-toastr'; -import { of } from 'rxjs'; -import { CreatureHandlerService } from '../creature-handler.service'; -import { SaiCreatureHandlerService } from '../sai-creature-handler.service'; -import { NpcTrainerComponent } from './npc-trainer.component'; -import Spy = jasmine.Spy; -import { KEIRA_APP_CONFIG_TOKEN, KEIRA_MOCK_CONFIG } from '@keira/shared/config'; - -class NpcTrainerPage extends MultiRowEditorPageObject {} - -describe('NpcTrainer integration tests', () => { - let fixture: ComponentFixture; - let queryService: MysqlQueryService; - let querySpy: Spy; - let handlerService: CreatureHandlerService; - let page: NpcTrainerPage; - - const id = 1234; - - const originalRow0 = new NpcTrainer(); - const originalRow1 = new NpcTrainer(); - const originalRow2 = new NpcTrainer(); - originalRow0.ID = originalRow1.ID = originalRow2.ID = id; - originalRow0.SpellID = 0; - originalRow1.SpellID = 1; - originalRow2.SpellID = 2; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [ToastrModule.forRoot(), ModalModule.forRoot(), NpcTrainerComponent, RouterTestingModule, TranslateTestingModule], - providers: [ - provideZonelessChangeDetection(), - provideNoopAnimations(), - CreatureHandlerService, - SaiCreatureHandlerService, - { provide: KEIRA_APP_CONFIG_TOKEN, useValue: KEIRA_MOCK_CONFIG }, - ], - }).compileComponents(); - }); - - function setup(creatingNew: boolean) { - handlerService = TestBed.inject(CreatureHandlerService); - handlerService['_selected'] = `${id}`; - handlerService.isNew = creatingNew; - - queryService = TestBed.inject(MysqlQueryService); - querySpy = spyOn(queryService, 'query').and.returnValue(of([])); - spyOn(queryService, 'queryValue').and.returnValue(of()); - - spyOn(queryService, 'selectAll').and.returnValue(of(creatingNew ? [] : [originalRow0, originalRow1, originalRow2])); - - fixture = TestBed.createComponent(NpcTrainerComponent); - page = new NpcTrainerPage(fixture); - fixture.autoDetectChanges(true); - fixture.detectChanges(); - } - - describe('Creating new', () => { - beforeEach(() => setup(true)); - - it('should correctly initialise', () => { - page.expectDiffQueryToBeEmpty(); - page.expectFullQueryToBeEmpty(); - expect(page.formError.hidden).toBe(true); - expect(page.addNewRowBtn.disabled).toBe(false); - expect(page.deleteSelectedRowBtn.disabled).toBe(true); - expect(page.getInputById('SpellID').disabled).toBe(true); - expect(page.getInputById('MoneyCost').disabled).toBe(true); - expect(page.getInputById('ReqSkillLine').disabled).toBe(true); - expect(page.getInputById('ReqSkillRank').disabled).toBe(true); - expect(page.getInputById('ReqLevel').disabled).toBe(true); - expect(page.getEditorTableRowsCount()).toBe(0); - }); - - it('should correctly update the unsaved status', () => { - expect(handlerService.isNpcTrainerUnsaved()).toBe(false); - page.addNewRow(); - expect(handlerService.isNpcTrainerUnsaved()).toBe(true); - page.deleteRow(); - expect(handlerService.isNpcTrainerUnsaved()).toBe(false); - }); - - it('adding new rows and executing the query should correctly work', () => { - const expectedQuery = - 'DELETE FROM `npc_trainer` WHERE (`ID` = 1234) AND (`SpellID` IN (0, 1, 2));\n' + - 'INSERT INTO `npc_trainer` (`ID`, `SpellID`, `MoneyCost`, `ReqSkillLine`, `ReqSkillRank`, `ReqLevel`) VALUES\n' + - '(1234, 0, 0, 0, 0, 0),\n' + - '(1234, 1, 0, 0, 0, 0),\n' + - '(1234, 2, 0, 0, 0, 0);'; - querySpy.calls.reset(); - - page.addNewRow(); - expect(page.getEditorTableRowsCount()).toBe(1); - page.addNewRow(); - expect(page.getEditorTableRowsCount()).toBe(2); - page.addNewRow(); - expect(page.getEditorTableRowsCount()).toBe(3); - page.expectDiffQueryToContain(expectedQuery); - - page.clickExecuteQuery(); - expect(querySpy).toHaveBeenCalledTimes(1); - expect(querySpy.calls.mostRecent().args[0]).toContain(expectedQuery); - }); - - it('adding a row and changing its values should correctly update the queries', () => { - page.addNewRow(); - page.expectDiffQueryToContain( - 'DELETE FROM `npc_trainer` WHERE (`ID` = 1234) AND (`SpellID` IN (0));\n' + - 'INSERT INTO `npc_trainer` (`ID`, `SpellID`, `MoneyCost`, `ReqSkillLine`, `ReqSkillRank`, `ReqLevel`) VALUES\n' + - '(1234, 0, 0, 0, 0, 0);', - ); - page.expectFullQueryToContain( - 'DELETE FROM `npc_trainer` WHERE (`ID` = 1234);\n' + - 'INSERT INTO `npc_trainer` (`ID`, `SpellID`, `MoneyCost`, `ReqSkillLine`, `ReqSkillRank`, `ReqLevel`) VALUES\n' + - '(1234, 0, 0, 0, 0, 0);', - ); - - page.setInputValueById('MoneyCost', '1'); - page.expectDiffQueryToContain( - 'DELETE FROM `npc_trainer` WHERE (`ID` = 1234) AND (`SpellID` IN (0));\n' + - 'INSERT INTO `npc_trainer` (`ID`, `SpellID`, `MoneyCost`, `ReqSkillLine`, `ReqSkillRank`, `ReqLevel`) VALUES\n' + - '(1234, 0, 1, 0, 0, 0);', - ); - page.expectFullQueryToContain( - 'DELETE FROM `npc_trainer` WHERE (`ID` = 1234);\n' + - 'INSERT INTO `npc_trainer` (`ID`, `SpellID`, `MoneyCost`, `ReqSkillLine`, `ReqSkillRank`, `ReqLevel`) VALUES\n' + - '(1234, 0, 1, 0, 0, 0);', - ); - - page.setInputValueById('ReqSkillLine', '2'); - page.expectDiffQueryToContain( - 'DELETE FROM `npc_trainer` WHERE (`ID` = 1234) AND (`SpellID` IN (0));\n' + - 'INSERT INTO `npc_trainer` (`ID`, `SpellID`, `MoneyCost`, `ReqSkillLine`, `ReqSkillRank`, `ReqLevel`) VALUES\n' + - '(1234, 0, 1, 2, 0, 0);', - ); - page.expectFullQueryToContain( - 'DELETE FROM `npc_trainer` WHERE (`ID` = 1234);\n' + - 'INSERT INTO `npc_trainer` (`ID`, `SpellID`, `MoneyCost`, `ReqSkillLine`, `ReqSkillRank`, `ReqLevel`) VALUES\n' + - '(1234, 0, 1, 2, 0, 0);', - ); - - page.setInputValueById('SpellID', '123'); - page.expectDiffQueryToContain( - 'DELETE FROM `npc_trainer` WHERE (`ID` = 1234) AND (`SpellID` IN (123));\n' + - 'INSERT INTO `npc_trainer` (`ID`, `SpellID`, `MoneyCost`, `ReqSkillLine`, `ReqSkillRank`, `ReqLevel`) VALUES\n' + - '(1234, 123, 1, 2, 0, 0);', - ); - page.expectFullQueryToContain( - 'DELETE FROM `npc_trainer` WHERE (`ID` = 1234);\n' + - 'INSERT INTO `npc_trainer` (`ID`, `SpellID`, `MoneyCost`, `ReqSkillLine`, `ReqSkillRank`, `ReqLevel`) VALUES\n' + - '(1234, 123, 1, 2, 0, 0);', - ); - }); - - it('adding a row changing its values and duplicate it should correctly update the queries', () => { - page.addNewRow(); - page.setInputValueById('MoneyCost', '1'); - page.setInputValueById('ReqSkillLine', '2'); - page.setInputValueById('SpellID', '123'); - page.expectDiffQueryToContain( - 'DELETE FROM `npc_trainer` WHERE (`ID` = 1234) AND (`SpellID` IN (123));\n' + - 'INSERT INTO `npc_trainer` (`ID`, `SpellID`, `MoneyCost`, `ReqSkillLine`, `ReqSkillRank`, `ReqLevel`) VALUES\n' + - '(1234, 123, 1, 2, 0, 0);', - ); - page.expectFullQueryToContain( - 'DELETE FROM `npc_trainer` WHERE (`ID` = 1234);\n' + - 'INSERT INTO `npc_trainer` (`ID`, `SpellID`, `MoneyCost`, `ReqSkillLine`, `ReqSkillRank`, `ReqLevel`) VALUES\n' + - '(1234, 123, 1, 2, 0, 0);', - ); - }); - }); - - describe('Editing existing', () => { - beforeEach(() => setup(false)); - - it('should correctly initialise', () => { - expect(page.formError.hidden).toBe(true); - page.expectDiffQueryToBeShown(); - page.expectDiffQueryToBeEmpty(); - page.expectFullQueryToContain( - 'DELETE FROM `npc_trainer` WHERE (`ID` = 1234);\n' + - 'INSERT INTO `npc_trainer` (`ID`, `SpellID`, `MoneyCost`, `ReqSkillLine`, `ReqSkillRank`, `ReqLevel`) VALUES\n' + - '(1234, 0, 0, 0, 0, 0),\n' + - '(1234, 1, 0, 0, 0, 0),\n' + - '(1234, 2, 0, 0, 0, 0);', - ); - expect(page.getEditorTableRowsCount()).toBe(3); - }); - - it('deleting rows should correctly work', () => { - page.deleteRow(1); - expect(page.getEditorTableRowsCount()).toBe(2); - page.expectDiffQueryToContain('DELETE FROM `npc_trainer` WHERE (`ID` = 1234) AND (`SpellID` IN (1));'); - page.expectFullQueryToContain( - 'DELETE FROM `npc_trainer` WHERE (`ID` = 1234);\n' + - 'INSERT INTO `npc_trainer` (`ID`, `SpellID`, `MoneyCost`, `ReqSkillLine`, `ReqSkillRank`, `ReqLevel`) VALUES\n' + - '(1234, 0, 0, 0, 0, 0),\n' + - '(1234, 2, 0, 0, 0, 0);', - ); - - page.deleteRow(1); - expect(page.getEditorTableRowsCount()).toBe(1); - page.expectDiffQueryToContain('DELETE FROM `npc_trainer` WHERE (`ID` = 1234) AND (`SpellID` IN (1, 2));'); - page.expectFullQueryToContain( - 'DELETE FROM `npc_trainer` WHERE (`ID` = 1234);\n' + - 'INSERT INTO `npc_trainer` (`ID`, `SpellID`, `MoneyCost`, `ReqSkillLine`, `ReqSkillRank`, `ReqLevel`) VALUES\n' + - '(1234, 0, 0, 0, 0, 0);', - ); - - page.deleteRow(0); - expect(page.getEditorTableRowsCount()).toBe(0); - page.expectDiffQueryToContain('DELETE FROM `npc_trainer` WHERE `ID` = 1234;'); - page.expectFullQueryToBeEmpty(); - }); - - it('editing existing rows should correctly work', () => { - page.clickRowOfDatatable(1); - page.setInputValueById('ReqSkillRank', 1); - - page.clickRowOfDatatable(2); - page.setInputValueById('ReqLevel', 2); - - page.expectDiffQueryToContain( - 'DELETE FROM `npc_trainer` WHERE (`ID` = 1234) AND (`SpellID` IN (1, 2));\n' + - 'INSERT INTO `npc_trainer` (`ID`, `SpellID`, `MoneyCost`, `ReqSkillLine`, `ReqSkillRank`, `ReqLevel`) VALUES\n' + - '(1234, 1, 0, 0, 1, 0),\n' + - '(1234, 2, 0, 0, 0, 2);', - ); - page.expectFullQueryToContain( - 'DELETE FROM `npc_trainer` WHERE (`ID` = 1234);\n' + - 'INSERT INTO `npc_trainer` (`ID`, `SpellID`, `MoneyCost`, `ReqSkillLine`, `ReqSkillRank`, `ReqLevel`) VALUES\n' + - '(1234, 0, 0, 0, 0, 0),\n' + - '(1234, 1, 0, 0, 1, 0),\n' + - '(1234, 2, 0, 0, 0, 2);', - ); - }); - - it('combining add, edit and delete should correctly work', () => { - page.addNewRow(); - expect(page.getEditorTableRowsCount()).toBe(4); - - page.clickRowOfDatatable(1); - page.setInputValueById('MoneyCost', 10); - expect(page.getEditorTableRowsCount()).toBe(4); - - page.deleteRow(2); - expect(page.getEditorTableRowsCount()).toBe(3); - - page.expectDiffQueryToContain( - 'DELETE FROM `npc_trainer` WHERE (`ID` = 1234) AND (`SpellID` IN (1, 2, 3));\n' + - 'INSERT INTO `npc_trainer` (`ID`, `SpellID`, `MoneyCost`, `ReqSkillLine`, `ReqSkillRank`, `ReqLevel`) VALUES\n' + - '(1234, 1, 10, 0, 0, 0),\n' + - '(1234, 3, 0, 0, 0, 0);', - ); - page.expectFullQueryToContain( - 'DELETE FROM `npc_trainer` WHERE (`ID` = 1234);\n' + - 'INSERT INTO `npc_trainer` (`ID`, `SpellID`, `MoneyCost`, `ReqSkillLine`, `ReqSkillRank`, `ReqLevel`) VALUES\n' + - '(1234, 0, 0, 0, 0, 0),\n' + - '(1234, 1, 10, 0, 0, 0),\n' + - '(1234, 3, 0, 0, 0, 0);', - ); - }); - - it('using the same row id for multiple rows should correctly show an error', () => { - page.clickRowOfDatatable(2); - page.setInputValueById('SpellID', 0); - - page.expectUniqueError(); - }); - - xit('changing a value via SkillSelector should correctly work', async () => { - const field = 'ReqSkillLine'; - const sqliteQueryService = TestBed.inject(SqliteQueryService); - spyOn(sqliteQueryService, 'query').and.returnValue(of([{ id: 123, name: 'Mock Skill' }])); - - // because this is a multi-row editor - page.clickRowOfDatatable(0); - await page.whenReady(); - - page.clickElement(page.getSelectorBtn(field)); - await page.whenReady(); - page.expectModalDisplayed(); - - page.clickSearchBtn(); - await fixture.whenStable(); - page.clickRowOfDatatableInModal(0); - await page.whenReady(); - page.clickModalSelect(); - await page.whenReady(); - - page.expectDiffQueryToContain( - 'DELETE FROM `npc_trainer` WHERE (`ID` = 1234) AND (`SpellID` IN (0));\n' + - 'INSERT INTO `npc_trainer` (`ID`, `SpellID`, `MoneyCost`, `ReqSkillLine`, `ReqSkillRank`, `ReqLevel`) VALUES\n' + - '(1234, 0, 0, 123, 0, 0);', - ); - page.expectFullQueryToContain( - 'DELETE FROM `npc_trainer` WHERE (`ID` = 1234);\n' + - 'INSERT INTO `npc_trainer` (`ID`, `SpellID`, `MoneyCost`, `ReqSkillLine`, `ReqSkillRank`, `ReqLevel`) VALUES\n' + - '(1234, 0, 0, 123, 0, 0),\n' + - '(1234, 1, 0, 0, 0, 0),\n' + - '(1234, 2, 0, 0, 0, 0);', - ); - }); - }); -}); diff --git a/libs/features/creature/src/npc-trainer/npc-trainer.service.spec.ts b/libs/features/creature/src/npc-trainer/npc-trainer.service.spec.ts deleted file mode 100644 index 8ea7fcdbe7b..00000000000 --- a/libs/features/creature/src/npc-trainer/npc-trainer.service.spec.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { TestBed } from '@angular/core/testing'; -import { provideZonelessChangeDetection } from '@angular/core'; -import { provideNoopAnimations } from '@angular/platform-browser/animations'; -import { RouterTestingModule } from '@angular/router/testing'; -import { MysqlQueryService, SqliteService } from '@keira/shared/db-layer'; - -import { ToastrService } from 'ngx-toastr'; -import { instance, mock } from 'ts-mockito'; -import { CreatureHandlerService } from '../creature-handler.service'; -import { SaiCreatureHandlerService } from '../sai-creature-handler.service'; -import { NpcTrainerService } from './npc-trainer.service'; - -describe('NpcTrainerService', () => { - beforeEach(() => - TestBed.configureTestingModule({ - imports: [RouterTestingModule], - providers: [ - provideZonelessChangeDetection(), - provideNoopAnimations(), - { provide: MysqlQueryService, useValue: instance(mock(MysqlQueryService)) }, - { provide: ToastrService, useValue: instance(mock(ToastrService)) }, - { provide: SqliteService, useValue: instance(mock(SqliteService)) }, - CreatureHandlerService, - SaiCreatureHandlerService, - NpcTrainerService, - ], - }), - ); - - it('should be created', () => { - const service: NpcTrainerService = TestBed.inject(NpcTrainerService); - expect(service).toBeTruthy(); - }); -}); diff --git a/libs/features/creature/src/npc-trainer/npc-trainer.service.ts b/libs/features/creature/src/npc-trainer/npc-trainer.service.ts deleted file mode 100644 index 498cff55d09..00000000000 --- a/libs/features/creature/src/npc-trainer/npc-trainer.service.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Injectable, inject } from '@angular/core'; -import { MultiRowEditorService } from '@keira/shared/base-abstract-classes'; -import { NPC_TRAINER_ID, NPC_TRAINER_ID_2, NPC_TRAINER_TABLE, NpcTrainer } from '@keira/shared/acore-world-model'; -import { CreatureHandlerService } from '../creature-handler.service'; - -@Injectable({ - providedIn: 'root', -}) -export class NpcTrainerService extends MultiRowEditorService { - protected override readonly handlerService = inject(CreatureHandlerService); - protected override readonly _entityClass = NpcTrainer; - protected override readonly _entityTable = NPC_TRAINER_TABLE; - protected override readonly _entityIdField = NPC_TRAINER_ID; - protected override readonly _entitySecondIdField = NPC_TRAINER_ID_2; - - constructor() { - super(); - this.init(); - } -} diff --git a/libs/features/trainer/karma.conf.js b/libs/features/trainer/karma.conf.js new file mode 100644 index 00000000000..63aac3d3708 --- /dev/null +++ b/libs/features/trainer/karma.conf.js @@ -0,0 +1,44 @@ +// Karma configuration file, see link for more information +// https://karma-runner.github.io/1.0/config/configuration-file.html + +const { join } = require('path'); +const { constants } = require('karma'); + +module.exports = () => { + return { + basePath: '', + frameworks: ['jasmine', '@angular-devkit/build-angular'], + plugins: [ + require('karma-jasmine'), + require('karma-chrome-launcher'), + require('karma-jasmine-html-reporter'), + require('karma-coverage'), + require('@angular-devkit/build-angular/plugins/karma'), + ], + client: { + jasmine: { + // you can add configuration options for Jasmine here + // the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html + // for example, you can disable the random execution with `random: false` + // or set a specific seed with `seed: 4321` + }, + clearContext: false, // leave Jasmine Spec Runner output visible in browser + }, + jasmineHtmlReporter: { + suppressAll: true, // removes the duplicated traces + }, + coverageReporter: { + dir: join(__dirname, '../../../coverage/libs/features/trainer'), + subdir: '.', + reporters: [{ type: 'html' }, { type: 'text-summary' }, { type: 'lcovonly' }], + }, + reporters: ['progress', 'kjhtml'], + port: 9876, + colors: true, + logLevel: constants.LOG_INFO, + autoWatch: true, + browsers: ['ChromeHeadless'], + singleRun: true, + restartOnFileChange: true, + }; +}; diff --git a/libs/features/trainer/project.json b/libs/features/trainer/project.json new file mode 100644 index 00000000000..32081f6982c --- /dev/null +++ b/libs/features/trainer/project.json @@ -0,0 +1,24 @@ +{ + "name": "keira-features-trainer", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "libs/features/trainer/src", + "prefix": "keira", + "tags": ["scope:features"], + "projectType": "library", + "targets": { + "test": { + "executor": "@angular-devkit/build-angular:karma", + "options": { + "tsConfig": "libs/features/trainer/tsconfig.spec.json", + "karmaConfig": "libs/features/trainer/karma.conf.js", + "sourceMap": true, + "codeCoverage": true, + "styles": ["apps/keira/src/app/scss/main-test.scss"], + "scripts": ["node_modules/squel/dist/squel.min.js"] + } + }, + "lint": { + "executor": "@nx/eslint:lint" + } + } +} diff --git a/libs/features/trainer/src/edit-trainer/trainer.component.html b/libs/features/trainer/src/edit-trainer/trainer.component.html new file mode 100644 index 00000000000..5cd16d5c15a --- /dev/null +++ b/libs/features/trainer/src/edit-trainer/trainer.component.html @@ -0,0 +1,51 @@ + + +
+ @if (editorService.loading) { + + } + + @if (editorService.form && !!editorService.loadedEntityId && !editorService.loading) { +
+
+ +
+
+
+ +
+
+ + +
+
+ + +
+
+ + + +
+
+
+
+ + + +
+
+
+
+
+ } +
diff --git a/libs/features/trainer/src/edit-trainer/trainer.component.ts b/libs/features/trainer/src/edit-trainer/trainer.component.ts new file mode 100644 index 00000000000..7c3844d7bf7 --- /dev/null +++ b/libs/features/trainer/src/edit-trainer/trainer.component.ts @@ -0,0 +1,30 @@ +import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { TRAINER_TYPE, Trainer } from '@keira/shared/acore-world-model'; +import { SingleRowEditorComponent } from '@keira/shared/base-abstract-classes'; +import { TranslateModule } from '@ngx-translate/core'; +import { TooltipModule } from 'ngx-bootstrap/tooltip'; +import { TrainerService } from './trainer.service'; +import { TrainerHandlerService } from '../trainer-handler.service'; +import { QueryOutputComponent, TopBarComponent } from '@keira/shared/base-editor-components'; +import { GenericOptionSelectorComponent } from '@keira/shared/selectors'; + +@Component({ + changeDetection: ChangeDetectionStrategy.OnPush, + selector: 'keira-trainer', + templateUrl: './trainer.component.html', + imports: [ + TopBarComponent, + TranslateModule, + FormsModule, + ReactiveFormsModule, + TooltipModule, + QueryOutputComponent, + GenericOptionSelectorComponent, + ], +}) +export class TrainerComponent extends SingleRowEditorComponent { + protected override readonly editorService = inject(TrainerService); + protected readonly handlerService = inject(TrainerHandlerService); + protected readonly TRAINER_TYPE = TRAINER_TYPE; +} diff --git a/libs/features/trainer/src/edit-trainer/trainer.service.ts b/libs/features/trainer/src/edit-trainer/trainer.service.ts new file mode 100644 index 00000000000..aed43c705ea --- /dev/null +++ b/libs/features/trainer/src/edit-trainer/trainer.service.ts @@ -0,0 +1,19 @@ +import { Injectable, inject } from '@angular/core'; +import { SingleRowEditorService } from '@keira/shared/base-abstract-classes'; +import { TRAINER_ID, TRAINER_TABLE, Trainer } from '@keira/shared/acore-world-model'; +import { TrainerHandlerService } from '../trainer-handler.service'; + +@Injectable({ + providedIn: 'root', +}) +export class TrainerService extends SingleRowEditorService { + protected override readonly handlerService = inject(TrainerHandlerService); + protected override readonly _entityClass = Trainer; + protected override readonly _entityTable = TRAINER_TABLE; + protected override readonly _entityIdField = TRAINER_ID; + + constructor() { + super(); + this.init(); + } +} diff --git a/libs/features/trainer/src/index.ts b/libs/features/trainer/src/index.ts new file mode 100644 index 00000000000..557168e9b8f --- /dev/null +++ b/libs/features/trainer/src/index.ts @@ -0,0 +1,7 @@ +export * from './trainer-handler.service'; +export * from './select-trainer/select-trainer.component'; +export * from './select-trainer/select-trainer.service'; +export * from './edit-trainer/trainer.component'; +export * from './edit-trainer/trainer.service'; +export * from './trainer-spell/trainer-spell.component'; +export * from './trainer-spell/trainer-spell.service'; diff --git a/libs/features/trainer/src/select-trainer/select-trainer.component.html b/libs/features/trainer/src/select-trainer/select-trainer.component.html new file mode 100644 index 00000000000..71bef3c2538 --- /dev/null +++ b/libs/features/trainer/src/select-trainer/select-trainer.component.html @@ -0,0 +1,59 @@ + + +
+
+ +
+ +
+

+
+
+ +
+ +
+
+ +
+
+
+ +
+
+ +
+
+ + + + @if (selectService.rows) { +
+ + + + + + +
+ } +
+
diff --git a/libs/features/trainer/src/select-trainer/select-trainer.component.ts b/libs/features/trainer/src/select-trainer/select-trainer.component.ts new file mode 100644 index 00000000000..c855439d81f --- /dev/null +++ b/libs/features/trainer/src/select-trainer/select-trainer.component.ts @@ -0,0 +1,32 @@ +import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; +import { SelectComponent } from '@keira/shared/base-abstract-classes'; +import { TRAINER_ID, TRAINER_TABLE, Trainer } from '@keira/shared/acore-world-model'; +import { NgxDatatableModule } from '@siemens/ngx-datatable'; +import { TranslateModule } from '@ngx-translate/core'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { TrainerHandlerService } from '../trainer-handler.service'; +import { SelectTrainerService } from './select-trainer.service'; +import { WIKI_BASE_URL } from '@keira/shared/constants'; +import { CreateComponent, HighlightjsWrapperComponent, TopBarComponent } from '@keira/shared/base-editor-components'; + +@Component({ + changeDetection: ChangeDetectionStrategy.OnPush, + templateUrl: './select-trainer.component.html', + imports: [ + FormsModule, + ReactiveFormsModule, + TranslateModule, + NgxDatatableModule, + CreateComponent, + HighlightjsWrapperComponent, + TopBarComponent, + ], +}) +export class SelectTrainerComponent extends SelectComponent { + protected override readonly entityTable = TRAINER_TABLE; + protected override readonly entityIdField = TRAINER_ID; + readonly customStartingId = 1000000; + protected readonly selectService = inject(SelectTrainerService); + readonly handlerService = inject(TrainerHandlerService); + protected readonly WIKI_BASE_URL = WIKI_BASE_URL; +} diff --git a/libs/features/trainer/src/select-trainer/select-trainer.service.ts b/libs/features/trainer/src/select-trainer/select-trainer.service.ts new file mode 100644 index 00000000000..44e83a48d1f --- /dev/null +++ b/libs/features/trainer/src/select-trainer/select-trainer.service.ts @@ -0,0 +1,20 @@ +import { Injectable, inject } from '@angular/core'; +import { SelectService } from '@keira/shared/base-abstract-classes'; +import { MysqlQueryService } from '@keira/shared/db-layer'; +import { TrainerHandlerService } from '../trainer-handler.service'; +import { TRAINER_ID, TRAINER_TABLE, Trainer } from '@keira/shared/acore-world-model'; + +@Injectable({ + providedIn: 'root', +}) +export class SelectTrainerService extends SelectService { + override readonly queryService = inject(MysqlQueryService); + override readonly handlerService = inject(TrainerHandlerService); + protected override readonly entityTable = TRAINER_TABLE; + protected override readonly entityIdField = TRAINER_ID; + protected override readonly fieldList = [TRAINER_ID, 'Type', 'Requirement']; + constructor() { + super(); + this.init(); + } +} diff --git a/libs/features/trainer/src/trainer-handler.service.spec.ts b/libs/features/trainer/src/trainer-handler.service.spec.ts new file mode 100644 index 00000000000..2f24ddd719c --- /dev/null +++ b/libs/features/trainer/src/trainer-handler.service.spec.ts @@ -0,0 +1,15 @@ +import { TestBed } from '@angular/core/testing'; +import { TrainerHandlerService } from './trainer-handler.service'; + +describe('TrainerHandlerService', () => { + let service: TrainerHandlerService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(TrainerHandlerService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/libs/features/trainer/src/trainer-handler.service.ts b/libs/features/trainer/src/trainer-handler.service.ts new file mode 100644 index 00000000000..39e0f897c25 --- /dev/null +++ b/libs/features/trainer/src/trainer-handler.service.ts @@ -0,0 +1,23 @@ +import { Injectable, signal, Signal } from '@angular/core'; +import { HandlerService } from '@keira/shared/base-abstract-classes'; +import { TRAINER_TABLE, TRAINER_SPELL_TABLE, Trainer } from '@keira/shared/acore-world-model'; + +@Injectable({ + providedIn: 'root', +}) +export class TrainerHandlerService extends HandlerService { + protected readonly mainEditorRoutePath = 'trainer/trainer'; + + get isTrainerUnsaved(): Signal { + return this.statusMap[TRAINER_TABLE].asReadonly(); + } + + get isTrainerSpellUnsaved(): Signal { + return this.statusMap[TRAINER_SPELL_TABLE].asReadonly(); + } + + protected _statusMap = { + [TRAINER_TABLE]: signal(false), + [TRAINER_SPELL_TABLE]: signal(false), + }; +} diff --git a/libs/features/trainer/src/trainer-spell/trainer-spell.component.html b/libs/features/trainer/src/trainer-spell/trainer-spell.component.html new file mode 100644 index 00000000000..8352f4534ed --- /dev/null +++ b/libs/features/trainer/src/trainer-spell/trainer-spell.component.html @@ -0,0 +1,158 @@ + + +
+ @if (editorService.loading) { + + } + + @if (editorService.form && !!editorService.loadedEntityId && !editorService.loading) { +
+
+ +
+
+
+
+
+ + + +
+
+ + + +
+
+ + + + +
+
+ + + +
+
+ + + + +
+
+ + + + +
+
+
+
+ + + + +
+
+ + + +
+
+
+ + + + + + + @if (sqliteQueryService.getSpellNameById(value) | async; as spellName) { + {{ value }}: {{ spellName }} + } + + + + + + + + @if (value !== 0) { + @if (sqliteQueryService.getSpellNameById(value) | async; as spellName) { + {{ value }}: {{ spellName }} + } + } + + + + + @if (value !== 0) { + @if (sqliteQueryService.getSpellNameById(value) | async; as spellName) { + {{ value }}: {{ spellName }} + } + } + + + + + @if (value !== 0) { + @if (sqliteQueryService.getSpellNameById(value) | async; as spellName) { + {{ value }}: {{ spellName }} + } + } + + + + +
+
+ } +
diff --git a/libs/features/creature/src/npc-trainer/npc-trainer.component.scss b/libs/features/trainer/src/trainer-spell/trainer-spell.component.scss similarity index 100% rename from libs/features/creature/src/npc-trainer/npc-trainer.component.scss rename to libs/features/trainer/src/trainer-spell/trainer-spell.component.scss diff --git a/libs/features/creature/src/npc-trainer/npc-trainer.component.ts b/libs/features/trainer/src/trainer-spell/trainer-spell.component.ts similarity index 67% rename from libs/features/creature/src/npc-trainer/npc-trainer.component.ts rename to libs/features/trainer/src/trainer-spell/trainer-spell.component.ts index 806e0c74feb..a95a7c5dd50 100644 --- a/libs/features/creature/src/npc-trainer/npc-trainer.component.ts +++ b/libs/features/trainer/src/trainer-spell/trainer-spell.component.ts @@ -1,7 +1,7 @@ import { AsyncPipe } from '@angular/common'; import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { NpcTrainer } from '@keira/shared/acore-world-model'; +import { TrainerSpell } from '@keira/shared/acore-world-model'; import { MultiRowEditorComponent } from '@keira/shared/base-abstract-classes'; import { EditorButtonsComponent, IconComponent, QueryOutputComponent, TopBarComponent } from '@keira/shared/base-editor-components'; import { SqliteQueryService } from '@keira/shared/db-layer'; @@ -9,14 +9,14 @@ import { SkillSelectorBtnComponent, SpellSelectorBtnComponent } from '@keira/sha import { TranslateModule } from '@ngx-translate/core'; import { NgxDatatableModule } from '@siemens/ngx-datatable'; import { TooltipModule } from 'ngx-bootstrap/tooltip'; -import { CreatureHandlerService } from '../creature-handler.service'; -import { NpcTrainerService } from './npc-trainer.service'; +import { TrainerHandlerService } from '../trainer-handler.service'; +import { TrainerSpellService } from './trainer-spell.service'; @Component({ changeDetection: ChangeDetectionStrategy.OnPush, - selector: 'keira-npc-trainer', - templateUrl: './npc-trainer.component.html', - styleUrls: ['./npc-trainer.component.scss'], + selector: 'keira-trainer-spell', + templateUrl: './trainer-spell.component.html', + styleUrls: ['./trainer-spell.component.scss'], imports: [ TopBarComponent, TranslateModule, @@ -29,11 +29,10 @@ import { NpcTrainerService } from './npc-trainer.service'; EditorButtonsComponent, NgxDatatableModule, AsyncPipe, - IconComponent, ], }) -export class NpcTrainerComponent extends MultiRowEditorComponent { - protected override readonly editorService = inject(NpcTrainerService); - readonly handlerService = inject(CreatureHandlerService); +export class TrainerSpellComponent extends MultiRowEditorComponent { + protected override readonly editorService = inject(TrainerSpellService); + readonly handlerService = inject(TrainerHandlerService); readonly sqliteQueryService = inject(SqliteQueryService); } diff --git a/libs/features/trainer/src/trainer-spell/trainer-spell.service.ts b/libs/features/trainer/src/trainer-spell/trainer-spell.service.ts new file mode 100644 index 00000000000..8d0f65887c4 --- /dev/null +++ b/libs/features/trainer/src/trainer-spell/trainer-spell.service.ts @@ -0,0 +1,20 @@ +import { Injectable, inject } from '@angular/core'; +import { MultiRowEditorService } from '@keira/shared/base-abstract-classes'; +import { TRAINER_SPELL_ID, TRAINER_SPELL_ID_2, TRAINER_SPELL_TABLE, TrainerSpell } from '@keira/shared/acore-world-model'; +import { TrainerHandlerService } from '../trainer-handler.service'; + +@Injectable({ + providedIn: 'root', +}) +export class TrainerSpellService extends MultiRowEditorService { + protected override readonly handlerService = inject(TrainerHandlerService); + protected override readonly _entityClass = TrainerSpell; + protected override readonly _entityTable = TRAINER_SPELL_TABLE; + protected override readonly _entityIdField = TRAINER_SPELL_ID; + protected override readonly _entitySecondIdField = TRAINER_SPELL_ID_2; + + constructor() { + super(); + this.init(); + } +} diff --git a/libs/features/trainer/tsconfig.json b/libs/features/trainer/tsconfig.json new file mode 100644 index 00000000000..dc5452d1bc5 --- /dev/null +++ b/libs/features/trainer/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "target": "ES2022", + "useDefineForClassFields": false, + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ], + "extends": "../../../tsconfig.base.json", + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + } +} diff --git a/libs/features/trainer/tsconfig.lib.json b/libs/features/trainer/tsconfig.lib.json new file mode 100644 index 00000000000..b70a86075b3 --- /dev/null +++ b/libs/features/trainer/tsconfig.lib.json @@ -0,0 +1,12 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../dist/out-tsc", + "declaration": true, + "declarationMap": true, + "inlineSources": true, + "types": [] + }, + "exclude": ["src/**/*.spec.ts", "src/test-setup.ts", "**/*.test.ts"], + "include": ["src/**/*.ts"] +} diff --git a/libs/features/trainer/tsconfig.spec.json b/libs/features/trainer/tsconfig.spec.json new file mode 100644 index 00000000000..9a55f0ed5ac --- /dev/null +++ b/libs/features/trainer/tsconfig.spec.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../dist/out-tsc", + "module": "commonjs", + "types": ["jasmine", "node"] + }, + "files": ["src/test-setup.ts"], + "include": ["**/*.spec.ts", "**/*.test.ts", "**/*.d.ts"] +} diff --git a/libs/main/main-window/src/sidebar/sidebar.component.html b/libs/main/main-window/src/sidebar/sidebar.component.html index e5ca20b3826..aebc10deb60 100644 --- a/libs/main/main-window/src/sidebar/sidebar.component.html +++ b/libs/main/main-window/src/sidebar/sidebar.component.html @@ -146,13 +146,14 @@
  • - - {{ 'SIDEBAR.CREATURE.TRAINER' | translate }} - @if (creatureHandlerService.isNpcTrainerUnsaved()) { + + {{ 'SIDEBAR.CREATURE.DEFAULT_TRAINER' | translate }} + @if (creatureHandlerService.isCreatureDefaultTrainerUnsaved()) { }
  • +
  • {{ 'SIDEBAR.CREATURE.QUEST_ITEM' | translate }} @@ -763,6 +764,41 @@
  • + +
  • {{ 'SIDEBAR.UNUSED_GUID_SEARCH' | translate }} diff --git a/libs/main/main-window/src/sidebar/sidebar.component.ts b/libs/main/main-window/src/sidebar/sidebar.component.ts index 2034cb2ab25..9487b767fc7 100644 --- a/libs/main/main-window/src/sidebar/sidebar.component.ts +++ b/libs/main/main-window/src/sidebar/sidebar.component.ts @@ -23,6 +23,7 @@ import { AcoreStringHandlerService, } from '@keira/features/texts'; import { GameTeleHandlerService } from '@keira/features/game-tele'; +import { TrainerHandlerService } from '@keira/features/trainer'; import { LocationService } from '@keira/shared/common-services'; import { MysqlService } from '@keira/shared/db-layer'; import { SaiHandlerService } from '@keira/shared/sai-editor'; @@ -47,6 +48,7 @@ interface MenuStats { gossip: ToggleType; spell: ToggleType; gameTele: ToggleType; + trainer: ToggleType; } @Component({ @@ -84,6 +86,7 @@ export class SidebarComponent { gossip: 'up', spell: 'up', gameTele: 'up', + trainer: 'up', }; private readonly IMAGES_COUNT = 7; private readonly RANDOM_IMAGE = Math.floor(Math.random() * this.IMAGES_COUNT) + 1; @@ -108,6 +111,7 @@ export class SidebarComponent { protected readonly npcTextHandlerService = inject(NpcTextHandlerService); protected readonly acoreStringHandlerService = inject(AcoreStringHandlerService); protected readonly gameTeleHandlerService = inject(GameTeleHandlerService); + protected readonly trainerHandlerService = inject(TrainerHandlerService); private readonly locationService = inject(LocationService); getSideBarState(): boolean { @@ -140,10 +144,11 @@ export class SidebarComponent { this.menuStates.otherLoot = 'up'; this.menuStates.smartAi = 'up'; this.menuStates.conditions = 'up'; - this.menuStates.texts = 'up'; this.menuStates.gossip = 'up'; this.menuStates.spell = 'up'; this.menuStates.gameTele = 'up'; + this.menuStates.trainer = 'up'; + this.menuStates.gameTele = 'up'; } logout(): void { diff --git a/libs/shared/acore-world-model/src/entities/creature-default-trainer.type.ts b/libs/shared/acore-world-model/src/entities/creature-default-trainer.type.ts new file mode 100644 index 00000000000..4a0f508ac8e --- /dev/null +++ b/libs/shared/acore-world-model/src/entities/creature-default-trainer.type.ts @@ -0,0 +1,9 @@ +import { TableRow } from '@keira/shared/constants'; + +export const CREATURE_DEFAULT_TRAINER_TABLE = 'creature_default_trainer'; +export const CREATURE_DEFAULT_TRAINER_ID = 'CreatureId'; + +export class CreatureDefaultTrainer extends TableRow { + CreatureId: number = 0; + TrainerId: number = 0; +} diff --git a/libs/shared/acore-world-model/src/entities/creature-template.type.ts b/libs/shared/acore-world-model/src/entities/creature-template.type.ts index c3160fb842c..56da7b8cc32 100644 --- a/libs/shared/acore-world-model/src/entities/creature-template.type.ts +++ b/libs/shared/acore-world-model/src/entities/creature-template.type.ts @@ -44,10 +44,6 @@ export class CreatureTemplate extends TableRow { unit_flags2: number = 0; dynamicflags: number = 0; family: number = 0; - trainer_type: number = 0; - trainer_spell: number = 0; - trainer_class: number = 0; - trainer_race: number = 0; type: number = 0; type_flags: number = 0; lootid: number = 0; diff --git a/libs/shared/acore-world-model/src/entities/npc-trainer.type.ts b/libs/shared/acore-world-model/src/entities/npc-trainer.type.ts deleted file mode 100644 index 55b123c9452..00000000000 --- a/libs/shared/acore-world-model/src/entities/npc-trainer.type.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { TableRow } from '@keira/shared/constants'; - -export const NPC_TRAINER_TABLE = 'npc_trainer'; -export const NPC_TRAINER_ID = 'ID'; -export const NPC_TRAINER_ID_2 = 'SpellID'; - -export class NpcTrainer extends TableRow { - ID: number = 0; - SpellID: number = 0; - MoneyCost: number = 0; - ReqSkillLine: number = 0; - ReqSkillRank: number = 0; - ReqLevel: number = 0; -} diff --git a/libs/shared/acore-world-model/src/entities/trainer-locale.type.ts b/libs/shared/acore-world-model/src/entities/trainer-locale.type.ts new file mode 100644 index 00000000000..b7281429bf0 --- /dev/null +++ b/libs/shared/acore-world-model/src/entities/trainer-locale.type.ts @@ -0,0 +1,12 @@ +import { TableRow } from '@keira/shared/constants'; + +export const TRAINER_LOCALE_TABLE = 'trainer_locale'; +export const TRAINER_LOCALE_ID = 'Id'; +export const TRAINER_LOCALE_ID_2 = 'locale'; + +export class TrainerLocale extends TableRow { + Id: number = 0; + locale: string = ''; + Greeting_lang: string = ''; + VerifiedBuild: number = 0; +} diff --git a/libs/shared/acore-world-model/src/entities/trainer-spell.type.ts b/libs/shared/acore-world-model/src/entities/trainer-spell.type.ts new file mode 100644 index 00000000000..67680df2fa1 --- /dev/null +++ b/libs/shared/acore-world-model/src/entities/trainer-spell.type.ts @@ -0,0 +1,18 @@ +import { TableRow } from '@keira/shared/constants'; + +export const TRAINER_SPELL_TABLE = 'trainer_spell'; +export const TRAINER_SPELL_ID = 'TrainerId'; +export const TRAINER_SPELL_ID_2 = 'SpellId'; + +export class TrainerSpell extends TableRow { + TrainerId: number = 0; + SpellId: number = 0; + MoneyCost: number = 0; + ReqSkillLine: number = 0; + ReqSkillRank: number = 0; + ReqAbility1: number = 0; + ReqAbility2: number = 0; + ReqAbility3: number = 0; + ReqLevel: number = 0; + VerifiedBuild: number = 0; +} diff --git a/libs/shared/acore-world-model/src/entities/trainer.type.ts b/libs/shared/acore-world-model/src/entities/trainer.type.ts new file mode 100644 index 00000000000..3d86de6a0a5 --- /dev/null +++ b/libs/shared/acore-world-model/src/entities/trainer.type.ts @@ -0,0 +1,12 @@ +import { TableRow } from '@keira/shared/constants'; + +export const TRAINER_TABLE = 'trainer'; +export const TRAINER_ID = 'Id'; + +export class Trainer extends TableRow { + Id: number = 0; + Type: number = 2; + Requirement: number = 0; + Greeting: string = ''; + VerifiedBuild: number = 0; +} diff --git a/libs/shared/acore-world-model/src/index.ts b/libs/shared/acore-world-model/src/index.ts index 3e2c651d64b..fcb618fbdf1 100644 --- a/libs/shared/acore-world-model/src/index.ts +++ b/libs/shared/acore-world-model/src/index.ts @@ -46,9 +46,12 @@ export * from './entities/mail-loot-template.type'; export * from './entities/map.type'; export * from './entities/milling-loot-template.type'; export * from './entities/npc-text.type'; -export * from './entities/npc-trainer.type'; export * from './entities/npc-vendor.type'; export * from './entities/page-text.type'; +export * from './entities/trainer.type'; +export * from './entities/trainer-locale.type'; +export * from './entities/trainer-spell.type'; +export * from './entities/creature-default-trainer.type'; export * from './entities/pickpocketing-loot-template.type'; export * from './entities/prospecting-loot-template.type'; export * from './entities/quest-offer-reward.type'; diff --git a/package-lock.json b/package-lock.json index b4cd6321c97..a4c3f7b1e6b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4204,45 +4204,6 @@ "node": ">=14.14" } }, - "node_modules/@electron/windows-sign": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@electron/windows-sign/-/windows-sign-1.2.2.tgz", - "integrity": "sha512-dfZeox66AvdPtb2lD8OsIIQh12Tp0GNCRUDfBHIKGpbmopZto2/A8nSpYYLoedPIHpqkeblZ/k8OV0Gy7PYuyQ==", - "dev": true, - "license": "BSD-2-Clause", - "optional": true, - "peer": true, - "dependencies": { - "cross-dirname": "^0.1.0", - "debug": "^4.3.4", - "fs-extra": "^11.1.1", - "minimist": "^1.2.8", - "postject": "^1.0.0-alpha.6" - }, - "bin": { - "electron-windows-sign": "bin/electron-windows-sign.js" - }, - "engines": { - "node": ">=14.14" - } - }, - "node_modules/@electron/windows-sign/node_modules/fs-extra": { - "version": "11.3.2", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.2.tgz", - "integrity": "sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=14.14" - } - }, "node_modules/@emnapi/core": { "version": "1.4.5", "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.4.5.tgz", @@ -13633,15 +13594,6 @@ "node": ">=12.0.0" } }, - "node_modules/cross-dirname": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/cross-dirname/-/cross-dirname-0.1.0.tgz", - "integrity": "sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true - }, "node_modules/cross-env": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-10.1.0.tgz", @@ -24059,36 +24011,6 @@ "dev": true, "license": "MIT" }, - "node_modules/postject": { - "version": "1.0.0-alpha.6", - "resolved": "https://registry.npmjs.org/postject/-/postject-1.0.0-alpha.6.tgz", - "integrity": "sha512-b9Eb8h2eVqNE8edvKdwqkrY6O7kAwmI8kcnBv1NScolYJbo59XUF0noFq+lxbC1yN20bmC0WBEbDC5H/7ASb0A==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "commander": "^9.4.0" - }, - "bin": { - "postject": "dist/cli.js" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/postject/node_modules/commander": { - "version": "9.5.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", - "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": "^12.20.0 || >=14" - } - }, "node_modules/prebuild-install": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", @@ -28273,7 +28195,6 @@ "integrity": "sha512-uzcxnSDVjAopEUjljkWh8EIrg6tlzrjFUfMcR1EVsRDGwf/ccef0qQPRyOrROwhrTDaApueq+ja+KLPlzR/zdg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", diff --git a/package.json b/package.json index 434b5274765..8c6b221dd1c 100644 --- a/package.json +++ b/package.json @@ -149,6 +149,9 @@ "@angular/core": "$@angular/core" } }, + "resolutions": { + "ora": "5.4.1" + }, "husky": { "hooks": { "pre-commit": "lint-staged", diff --git a/tsconfig.base.json b/tsconfig.base.json index acf13cc8779..b7c58cd715e 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -37,6 +37,7 @@ "@keira/features/spell": ["libs/features/spell/src/index.ts"], "@keira/features/sql-editor": ["libs/features/sql-editor/src/index.ts"], "@keira/features/texts": ["libs/features/texts/src/index.ts"], + "@keira/features/trainer": ["libs/features/trainer/src/index.ts"], "@keira/features/unused-guid-search": ["libs/features/unused-guid-search/src/index.ts"], "@keira/main/connection-window": ["libs/main/connection-window/src/index.ts"], "@keira/main/main-window": ["libs/main/main-window/src/index.ts"], From e3fbe041f58543e26873a9f977cfbfcd95058b11 Mon Sep 17 00:00:00 2001 From: i18n Sync Bot Date: Sun, 14 Dec 2025 11:38:42 +0000 Subject: [PATCH 02/14] fix: missing translation keys --- apps/keira/src/assets/i18n/de.json | 40 ++++++++++++++++++++++++------ apps/keira/src/assets/i18n/el.json | 40 ++++++++++++++++++++++++------ apps/keira/src/assets/i18n/es.json | 40 ++++++++++++++++++++++++------ apps/keira/src/assets/i18n/fr.json | 40 ++++++++++++++++++++++++------ apps/keira/src/assets/i18n/it.json | 40 ++++++++++++++++++++++++------ apps/keira/src/assets/i18n/ko.json | 40 ++++++++++++++++++++++++------ apps/keira/src/assets/i18n/nl.json | 40 ++++++++++++++++++++++++------ apps/keira/src/assets/i18n/pl.json | 40 ++++++++++++++++++++++++------ apps/keira/src/assets/i18n/pt.json | 40 ++++++++++++++++++++++++------ apps/keira/src/assets/i18n/ro.json | 40 ++++++++++++++++++++++++------ apps/keira/src/assets/i18n/ru.json | 40 ++++++++++++++++++++++++------ apps/keira/src/assets/i18n/sk.json | 40 ++++++++++++++++++++++++------ apps/keira/src/assets/i18n/sv.json | 40 ++++++++++++++++++++++++------ apps/keira/src/assets/i18n/zh.json | 40 ++++++++++++++++++++++++------ 14 files changed, 448 insertions(+), 112 deletions(-) diff --git a/apps/keira/src/assets/i18n/de.json b/apps/keira/src/assets/i18n/de.json index ad6a80bacbc..24e6986e858 100644 --- a/apps/keira/src/assets/i18n/de.json +++ b/apps/keira/src/assets/i18n/de.json @@ -86,7 +86,7 @@ "ONKILL_REPUTATION": "Ruf bei Tötung", "EQUIP_TEMPLATE": "Ausrüstungsvorlage", "VENDOR": "Händler", - "TRAINER": "Trainer", + "DEFAULT_TRAINER": "Default Trainer", "QUEST_ITEM": "Quest-Gegenstand", "CREATURE_LOOT": "Kreaturenbeute", "PICKPOCKETING_LOOT": "Taschendiebstahl-Beute", @@ -182,6 +182,12 @@ "SEARCH_GAME_TELE": "Search Teleport", "SELECT_GAME_TELE": "Game Tele Editor" }, + "TRAINER": { + "TITLE": "Trainer", + "SEARCH_TRAINER": "Search Trainer", + "SELECT_TRAINER": "Trainer", + "TRAINER_SPELL": "Trainer Spell" + }, "UNUSED_GUID_SEARCH": "Unused GUIDs" }, "DASHBOARD": { @@ -216,7 +222,6 @@ "KILL_CREDITS": "Tötungsgutschriften", "MODELS": "Modelle", "MONEY_LOOT": "Geldbeute", - "TRAINER": "Trainer", "LOOTS": "Beute", "DIFFICULTY_ENTRIES": "Schwierigkeitsstufen", "DAMAGE": "Schaden", @@ -299,18 +304,16 @@ "TEMPLATE_SPELL": { "INDEX": "Allowed values: 0-7" }, - "NPC_TRAINER": { - "MONEY_COST": "The cost to pay to learn the spell represented in copper (1 gold = 100 silver = 10000 cooper)", - "REQ_SKILL_LINE": "The required skill the player needs to have in order to be able to learn the spell", - "REQ_SKILL_RANK": "The proficiency in the skill from reqskill that the player needs to meet to learn the spell", - "REQ_LEVEL": "The minimum level the player needs to be in order to learn the spell." - }, "NPC_VENDOR": { "SLOT": "Position of the item in the vendor window", "MAXCOUNT": "The maximum number of items carried by the vendor at any time. 0 for infinite (if choosing a value of 1 or higher also requires incrtime value to work)", "INCRTIME": "Combined with maxcount, how often (in seconds) the vendor list is refreshed", "EXTENDED_COST": "Value comes from DBC and a selector for this will be implemented later in Keira3" }, + "DEFAULT_TRAINER": { + "TITLE": "Default Trainer", + "TRAINER_ID_TOOLTIP": "ID of the trainer template (trainer.Id) assigned to this creature. Use 0 for no default trainer. Examples: 1=Trainer Warrior, 3=Trainer Paladin, 7=Trainer Hunter, 9=Trainer Rogue, 11=Trainer Priest, 13=Trainer Death Knight, 14=Trainer Shaman, 16=Trainer Mage, 31=Trainer Warlock, 33=Trainer Druid, 36=Trainer Mount & Fly. See the trainer wiki for the full list." + }, "TEXT": { "GROUP_ID": "If there is more than one of the same entry (more than one text the creature says), this column is used to choose if it is a random say or an ordered list. If a creature has got more than one say text to be shown in a given order, it must be incremented for each new matching entry (ex. 0, 1, 2, 3...). If there is only one entry or only one group, this value should be 0. If there are multiple groups of texts, this value stays the same within the group while the id increments within the same group.", "ID": "Entry for each group of texts. This is the unique identifier when entry (creature) is the same and groupid is unchanged, it must be incremented (ex. 0, 1, 2, 3...). A creature say will be randomly selected from this list based on the groupid it belongs to.", @@ -900,6 +903,27 @@ "GAME_TELE": { "EDITOR": "Teleport Editor" }, + "TRAINER": { + "EDITOR": "Trainer Editor", + "TRAINER_ID_TOOLTIP": "References trainer.id (trainer template). Examples: 1=Trainer Warrior, 3=Trainer Paladin, 7=Trainer Hunter, 9=Trainer Rogue, 11=Trainer Priest, 13=Trainer Death Knight, 14=Trainer Shaman, 16=Trainer Mage, 31=Trainer Warlock, 33=Trainer Druid, 36=Trainer Mount & Fly. See the trainer wiki for the full list.", + "REQUIREMENT_TOOLTIP": "Meaning depends on Type - use 0 for none. Types: 0-Class (ChrClass ID e.g. 1=Warrior, 2=Paladin, 3=Hunter, 4=Rogue, 5=Priest, 6=Death Knight, 7=Shaman, 8=Mage, 9=Warlock, 11=Druid), 1-Mount (ChrRace ID (e.g. 1=Human, 2=Orc, 3=Dwarf, 4=Night Elf, 5=Undead, 6=Tauren, 7=Gnome, 8=Troll, 10=Blood Elf, 11=Draenei), 2-Tradeskill Spell ID (player must know this spell to learn from this trainer), 3-Pet ChrClass ID (see above). ", + "GREETING_TOOLTIP": "Text shown at the top of the trainer window when opened (this is not gossip). For localized greetings add entries in the \"trainer_locale\" table (Greeting_lang).", + "SPELL": { + "TRAINER_ID": "References trainer.id (trainer template linked to this entry).", + "SPELL_ID": "Spell ID being taught.", + "MONEY_COST": "Cost in copper to learn this spell from the trainer (1 gold = 100 silver = 10000 copper).", + "REQ_SKILL_LINE": "SkillLine ID required to learn this spell (e.g., profession ID). Use 0 if none.", + "REQ_SKILL_RANK": "Minimum skill rank in ReqSkillLine required to learn the spell.", + "REQ_ABILITY_1": "Spell ID the player is required to already know (first required ability).", + "REQ_ABILITY_1_TOOLTIP": "Spell ID the player must already know to be taught this spell (first prerequisite). Use 0 if none.", + "REQ_ABILITY_2": "Spell ID the player is required to already know (second required ability).", + "REQ_ABILITY_2_TOOLTIP": "Spell ID the player must already know to be taught this spell (second prerequisite). Use 0 if none.", + "REQ_ABILITY_3": "Spell ID the player is required to already know (third required ability).", + "REQ_ABILITY_3_TOOLTIP": "Spell ID the player must already know to be taught this spell (third prerequisite). Use 0 if none.", + "REQ_LEVEL": "Minimum player level required to learn this spell.", + "VERIFIED_BUILD": "Used by AzerothCore to indicate whether this entry was verified against WDB files (0 = not parsed; >0 = parsed; -1 = placeholder; - = parsed with specific client build and manually edited)." + } + }, "UNUSED_GUID_SEARCH": { "TABLE": "Table", "START_INDEX": "Start Index", diff --git a/apps/keira/src/assets/i18n/el.json b/apps/keira/src/assets/i18n/el.json index 280e1d84b38..0c3248df955 100644 --- a/apps/keira/src/assets/i18n/el.json +++ b/apps/keira/src/assets/i18n/el.json @@ -86,7 +86,7 @@ "ONKILL_REPUTATION": "Onkill Reputation", "EQUIP_TEMPLATE": "Equip Template", "VENDOR": "Vendor", - "TRAINER": "Trainer", + "DEFAULT_TRAINER": "Default Trainer", "QUEST_ITEM": "Quest Item", "CREATURE_LOOT": "Creature Loot", "PICKPOCKETING_LOOT": "Pickpocketing Loot", @@ -182,6 +182,12 @@ "SEARCH_GAME_TELE": "Search Teleport", "SELECT_GAME_TELE": "Game Tele Editor" }, + "TRAINER": { + "TITLE": "Trainer", + "SEARCH_TRAINER": "Search Trainer", + "SELECT_TRAINER": "Trainer", + "TRAINER_SPELL": "Trainer Spell" + }, "UNUSED_GUID_SEARCH": "Unused GUIDs" }, "DASHBOARD": { @@ -216,7 +222,6 @@ "KILL_CREDITS": "KillCredits", "MODELS": "Models", "MONEY_LOOT": "Money Loot", - "TRAINER": "Trainer", "LOOTS": "Loots", "DIFFICULTY_ENTRIES": "Difficulty Entries", "DAMAGE": "Damage", @@ -299,18 +304,16 @@ "TEMPLATE_SPELL": { "INDEX": "Allowed values: 0-7" }, - "NPC_TRAINER": { - "MONEY_COST": "The cost to pay to learn the spell represented in copper (1 gold = 100 silver = 10000 cooper)", - "REQ_SKILL_LINE": "The required skill the player needs to have in order to be able to learn the spell", - "REQ_SKILL_RANK": "The proficiency in the skill from reqskill that the player needs to meet to learn the spell", - "REQ_LEVEL": "The minimum level the player needs to be in order to learn the spell." - }, "NPC_VENDOR": { "SLOT": "Position of the item in the vendor window", "MAXCOUNT": "The maximum number of items carried by the vendor at any time. 0 for infinite (if choosing a value of 1 or higher also requires incrtime value to work)", "INCRTIME": "Combined with maxcount, how often (in seconds) the vendor list is refreshed", "EXTENDED_COST": "Value comes from DBC and a selector for this will be implemented later in Keira3" }, + "DEFAULT_TRAINER": { + "TITLE": "Default Trainer", + "TRAINER_ID_TOOLTIP": "ID of the trainer template (trainer.Id) assigned to this creature. Use 0 for no default trainer. Examples: 1=Trainer Warrior, 3=Trainer Paladin, 7=Trainer Hunter, 9=Trainer Rogue, 11=Trainer Priest, 13=Trainer Death Knight, 14=Trainer Shaman, 16=Trainer Mage, 31=Trainer Warlock, 33=Trainer Druid, 36=Trainer Mount & Fly. See the trainer wiki for the full list." + }, "TEXT": { "GROUP_ID": "If there is more than one of the same entry (more than one text the creature says), this column is used to choose if it is a random say or an ordered list. If a creature has got more than one say text to be shown in a given order, it must be incremented for each new matching entry (ex. 0, 1, 2, 3...). If there is only one entry or only one group, this value should be 0. If there are multiple groups of texts, this value stays the same within the group while the id increments within the same group.", "ID": "Entry for each group of texts. This is the unique identifier when entry (creature) is the same and groupid is unchanged, it must be incremented (ex. 0, 1, 2, 3...). A creature say will be randomly selected from this list based on the groupid it belongs to.", @@ -900,6 +903,27 @@ "GAME_TELE": { "EDITOR": "Teleport Editor" }, + "TRAINER": { + "EDITOR": "Trainer Editor", + "TRAINER_ID_TOOLTIP": "References trainer.id (trainer template). Examples: 1=Trainer Warrior, 3=Trainer Paladin, 7=Trainer Hunter, 9=Trainer Rogue, 11=Trainer Priest, 13=Trainer Death Knight, 14=Trainer Shaman, 16=Trainer Mage, 31=Trainer Warlock, 33=Trainer Druid, 36=Trainer Mount & Fly. See the trainer wiki for the full list.", + "REQUIREMENT_TOOLTIP": "Meaning depends on Type - use 0 for none. Types: 0-Class (ChrClass ID e.g. 1=Warrior, 2=Paladin, 3=Hunter, 4=Rogue, 5=Priest, 6=Death Knight, 7=Shaman, 8=Mage, 9=Warlock, 11=Druid), 1-Mount (ChrRace ID (e.g. 1=Human, 2=Orc, 3=Dwarf, 4=Night Elf, 5=Undead, 6=Tauren, 7=Gnome, 8=Troll, 10=Blood Elf, 11=Draenei), 2-Tradeskill Spell ID (player must know this spell to learn from this trainer), 3-Pet ChrClass ID (see above). ", + "GREETING_TOOLTIP": "Text shown at the top of the trainer window when opened (this is not gossip). For localized greetings add entries in the \"trainer_locale\" table (Greeting_lang).", + "SPELL": { + "TRAINER_ID": "References trainer.id (trainer template linked to this entry).", + "SPELL_ID": "Spell ID being taught.", + "MONEY_COST": "Cost in copper to learn this spell from the trainer (1 gold = 100 silver = 10000 copper).", + "REQ_SKILL_LINE": "SkillLine ID required to learn this spell (e.g., profession ID). Use 0 if none.", + "REQ_SKILL_RANK": "Minimum skill rank in ReqSkillLine required to learn the spell.", + "REQ_ABILITY_1": "Spell ID the player is required to already know (first required ability).", + "REQ_ABILITY_1_TOOLTIP": "Spell ID the player must already know to be taught this spell (first prerequisite). Use 0 if none.", + "REQ_ABILITY_2": "Spell ID the player is required to already know (second required ability).", + "REQ_ABILITY_2_TOOLTIP": "Spell ID the player must already know to be taught this spell (second prerequisite). Use 0 if none.", + "REQ_ABILITY_3": "Spell ID the player is required to already know (third required ability).", + "REQ_ABILITY_3_TOOLTIP": "Spell ID the player must already know to be taught this spell (third prerequisite). Use 0 if none.", + "REQ_LEVEL": "Minimum player level required to learn this spell.", + "VERIFIED_BUILD": "Used by AzerothCore to indicate whether this entry was verified against WDB files (0 = not parsed; >0 = parsed; -1 = placeholder; - = parsed with specific client build and manually edited)." + } + }, "UNUSED_GUID_SEARCH": { "TABLE": "Table", "START_INDEX": "Start Index", diff --git a/apps/keira/src/assets/i18n/es.json b/apps/keira/src/assets/i18n/es.json index 2575cd8d04f..0fb4e5d92b2 100644 --- a/apps/keira/src/assets/i18n/es.json +++ b/apps/keira/src/assets/i18n/es.json @@ -86,7 +86,7 @@ "ONKILL_REPUTATION": "Reputación Al Matar", "EQUIP_TEMPLATE": "Plantilla de Equipamiento", "VENDOR": "Vendedor", - "TRAINER": "Entrenador", + "DEFAULT_TRAINER": "Default Trainer", "QUEST_ITEM": "Item de Misión", "CREATURE_LOOT": "Botín de Criatura", "PICKPOCKETING_LOOT": "Botín de Robo con ganzúa", @@ -182,6 +182,12 @@ "SEARCH_GAME_TELE": "Search Teleport", "SELECT_GAME_TELE": "Game Tele Editor" }, + "TRAINER": { + "TITLE": "Trainer", + "SEARCH_TRAINER": "Search Trainer", + "SELECT_TRAINER": "Trainer", + "TRAINER_SPELL": "Trainer Spell" + }, "UNUSED_GUID_SEARCH": "Unused GUIDs" }, "DASHBOARD": { @@ -216,7 +222,6 @@ "KILL_CREDITS": "Créditos de Muerte", "MODELS": "Modelos", "MONEY_LOOT": "Botín de Dinero", - "TRAINER": "Entrenador", "LOOTS": "Botines", "DIFFICULTY_ENTRIES": "Entradas de Dificultad", "DAMAGE": "Daño", @@ -299,18 +304,16 @@ "TEMPLATE_SPELL": { "INDEX": "Valores permitidos: 0-7" }, - "NPC_TRAINER": { - "MONEY_COST": "El coste a pagar para poder aprender el Hechizo, representado en monedas de cobre (1 de oro = 100 de plata = 10000 de cobre)", - "REQ_SKILL_LINE": "La Habilidad requerida que debe tener previamente el jugador para poder aprender el Hechizo.", - "REQ_SKILL_RANK": "La Aptitud en la Habilidad (La cantidad de Puntos de Habilidad) dentro de 'reqskill' que el jugador necesita tener previamente para poder aprender el Hechizo.", - "REQ_LEVEL": "El nivel mínimo que debe tener el jugador para poder aprender el Hechizo." - }, "NPC_VENDOR": { "SLOT": "Posición del Item dentro de la Ventana del Vendedor", "MAXCOUNT": "El número máximo de aquellos mismos Items cargados por el vendedor en cualquier momento. 0 para que el Item sea infinito.", "INCRTIME": "En combinación con 'maxcount', la frecuencia (en segundos) con la que se actualiza la lista de proveedores.", "EXTENDED_COST": "El valor que aquí se encuentre almacenado proviene del mismo archivo 'DBC' del cual se presta justamente el nombre de la casilla; un selector para esto se implementará en un futuro dentro de Keira3" }, + "DEFAULT_TRAINER": { + "TITLE": "Default Trainer", + "TRAINER_ID_TOOLTIP": "ID of the trainer template (trainer.Id) assigned to this creature. Use 0 for no default trainer. Examples: 1=Trainer Warrior, 3=Trainer Paladin, 7=Trainer Hunter, 9=Trainer Rogue, 11=Trainer Priest, 13=Trainer Death Knight, 14=Trainer Shaman, 16=Trainer Mage, 31=Trainer Warlock, 33=Trainer Druid, 36=Trainer Mount & Fly. See the trainer wiki for the full list." + }, "TEXT": { "GROUP_ID": "If there is more than one of the same entry (more than one text the creature says), this column is used to choose if it is a random say or an ordered list. If a creature has got more than one say text to be shown in a given order, it must be incremented for each new matching entry (ex. 0, 1, 2, 3...). If there is only one entry or only one group, this value should be 0. If there are multiple groups of texts, this value stays the same within the group while the id increments within the same group.", "ID": "Entry for each group of texts. This is the unique identifier when entry (creature) is the same and groupid is unchanged, it must be incremented (ex. 0, 1, 2, 3...). A creature say will be randomly selected from this list based on the groupid it belongs to.", @@ -900,6 +903,27 @@ "GAME_TELE": { "EDITOR": "Teleport Editor" }, + "TRAINER": { + "EDITOR": "Trainer Editor", + "TRAINER_ID_TOOLTIP": "References trainer.id (trainer template). Examples: 1=Trainer Warrior, 3=Trainer Paladin, 7=Trainer Hunter, 9=Trainer Rogue, 11=Trainer Priest, 13=Trainer Death Knight, 14=Trainer Shaman, 16=Trainer Mage, 31=Trainer Warlock, 33=Trainer Druid, 36=Trainer Mount & Fly. See the trainer wiki for the full list.", + "REQUIREMENT_TOOLTIP": "Meaning depends on Type - use 0 for none. Types: 0-Class (ChrClass ID e.g. 1=Warrior, 2=Paladin, 3=Hunter, 4=Rogue, 5=Priest, 6=Death Knight, 7=Shaman, 8=Mage, 9=Warlock, 11=Druid), 1-Mount (ChrRace ID (e.g. 1=Human, 2=Orc, 3=Dwarf, 4=Night Elf, 5=Undead, 6=Tauren, 7=Gnome, 8=Troll, 10=Blood Elf, 11=Draenei), 2-Tradeskill Spell ID (player must know this spell to learn from this trainer), 3-Pet ChrClass ID (see above). ", + "GREETING_TOOLTIP": "Text shown at the top of the trainer window when opened (this is not gossip). For localized greetings add entries in the \"trainer_locale\" table (Greeting_lang).", + "SPELL": { + "TRAINER_ID": "References trainer.id (trainer template linked to this entry).", + "SPELL_ID": "Spell ID being taught.", + "MONEY_COST": "Cost in copper to learn this spell from the trainer (1 gold = 100 silver = 10000 copper).", + "REQ_SKILL_LINE": "SkillLine ID required to learn this spell (e.g., profession ID). Use 0 if none.", + "REQ_SKILL_RANK": "Minimum skill rank in ReqSkillLine required to learn the spell.", + "REQ_ABILITY_1": "Spell ID the player is required to already know (first required ability).", + "REQ_ABILITY_1_TOOLTIP": "Spell ID the player must already know to be taught this spell (first prerequisite). Use 0 if none.", + "REQ_ABILITY_2": "Spell ID the player is required to already know (second required ability).", + "REQ_ABILITY_2_TOOLTIP": "Spell ID the player must already know to be taught this spell (second prerequisite). Use 0 if none.", + "REQ_ABILITY_3": "Spell ID the player is required to already know (third required ability).", + "REQ_ABILITY_3_TOOLTIP": "Spell ID the player must already know to be taught this spell (third prerequisite). Use 0 if none.", + "REQ_LEVEL": "Minimum player level required to learn this spell.", + "VERIFIED_BUILD": "Used by AzerothCore to indicate whether this entry was verified against WDB files (0 = not parsed; >0 = parsed; -1 = placeholder; - = parsed with specific client build and manually edited)." + } + }, "UNUSED_GUID_SEARCH": { "TABLE": "Table", "START_INDEX": "Start Index", diff --git a/apps/keira/src/assets/i18n/fr.json b/apps/keira/src/assets/i18n/fr.json index 1c0c017206f..809f79fec55 100644 --- a/apps/keira/src/assets/i18n/fr.json +++ b/apps/keira/src/assets/i18n/fr.json @@ -86,7 +86,7 @@ "ONKILL_REPUTATION": "Réputation OnKill", "EQUIP_TEMPLATE": "Modèle d'équipement", "VENDOR": "Vendeur", - "TRAINER": "Entraineur", + "DEFAULT_TRAINER": "Default Trainer", "QUEST_ITEM": "Objet de quête", "CREATURE_LOOT": "Loot de créature", "PICKPOCKETING_LOOT": "Loot de pickpocketing", @@ -182,6 +182,12 @@ "SEARCH_GAME_TELE": "Search Teleport", "SELECT_GAME_TELE": "Game Tele Editor" }, + "TRAINER": { + "TITLE": "Trainer", + "SEARCH_TRAINER": "Search Trainer", + "SELECT_TRAINER": "Trainer", + "TRAINER_SPELL": "Trainer Spell" + }, "UNUSED_GUID_SEARCH": "Unused GUIDs" }, "DASHBOARD": { @@ -216,7 +222,6 @@ "KILL_CREDITS": "KillCredits", "MODELS": "Models", "MONEY_LOOT": "Money Loot", - "TRAINER": "Trainer", "LOOTS": "Loots", "DIFFICULTY_ENTRIES": "Difficulty Entries", "DAMAGE": "Damage", @@ -299,18 +304,16 @@ "TEMPLATE_SPELL": { "INDEX": "Allowed values: 0-7" }, - "NPC_TRAINER": { - "MONEY_COST": "The cost to pay to learn the spell represented in copper (1 gold = 100 silver = 10000 cooper)", - "REQ_SKILL_LINE": "The required skill the player needs to have in order to be able to learn the spell", - "REQ_SKILL_RANK": "The proficiency in the skill from reqskill that the player needs to meet to learn the spell", - "REQ_LEVEL": "The minimum level the player needs to be in order to learn the spell." - }, "NPC_VENDOR": { "SLOT": "Position of the item in the vendor window", "MAXCOUNT": "The maximum number of items carried by the vendor at any time. 0 for infinite (if choosing a value of 1 or higher also requires incrtime value to work)", "INCRTIME": "Combined with maxcount, how often (in seconds) the vendor list is refreshed", "EXTENDED_COST": "Value comes from DBC and a selector for this will be implemented later in Keira3" }, + "DEFAULT_TRAINER": { + "TITLE": "Default Trainer", + "TRAINER_ID_TOOLTIP": "ID of the trainer template (trainer.Id) assigned to this creature. Use 0 for no default trainer. Examples: 1=Trainer Warrior, 3=Trainer Paladin, 7=Trainer Hunter, 9=Trainer Rogue, 11=Trainer Priest, 13=Trainer Death Knight, 14=Trainer Shaman, 16=Trainer Mage, 31=Trainer Warlock, 33=Trainer Druid, 36=Trainer Mount & Fly. See the trainer wiki for the full list." + }, "TEXT": { "GROUP_ID": "If there is more than one of the same entry (more than one text the creature says), this column is used to choose if it is a random say or an ordered list. If a creature has got more than one say text to be shown in a given order, it must be incremented for each new matching entry (ex. 0, 1, 2, 3...). If there is only one entry or only one group, this value should be 0. If there are multiple groups of texts, this value stays the same within the group while the id increments within the same group.", "ID": "Entry for each group of texts. This is the unique identifier when entry (creature) is the same and groupid is unchanged, it must be incremented (ex. 0, 1, 2, 3...). A creature say will be randomly selected from this list based on the groupid it belongs to.", @@ -900,6 +903,27 @@ "GAME_TELE": { "EDITOR": "Teleport Editor" }, + "TRAINER": { + "EDITOR": "Trainer Editor", + "TRAINER_ID_TOOLTIP": "References trainer.id (trainer template). Examples: 1=Trainer Warrior, 3=Trainer Paladin, 7=Trainer Hunter, 9=Trainer Rogue, 11=Trainer Priest, 13=Trainer Death Knight, 14=Trainer Shaman, 16=Trainer Mage, 31=Trainer Warlock, 33=Trainer Druid, 36=Trainer Mount & Fly. See the trainer wiki for the full list.", + "REQUIREMENT_TOOLTIP": "Meaning depends on Type - use 0 for none. Types: 0-Class (ChrClass ID e.g. 1=Warrior, 2=Paladin, 3=Hunter, 4=Rogue, 5=Priest, 6=Death Knight, 7=Shaman, 8=Mage, 9=Warlock, 11=Druid), 1-Mount (ChrRace ID (e.g. 1=Human, 2=Orc, 3=Dwarf, 4=Night Elf, 5=Undead, 6=Tauren, 7=Gnome, 8=Troll, 10=Blood Elf, 11=Draenei), 2-Tradeskill Spell ID (player must know this spell to learn from this trainer), 3-Pet ChrClass ID (see above). ", + "GREETING_TOOLTIP": "Text shown at the top of the trainer window when opened (this is not gossip). For localized greetings add entries in the \"trainer_locale\" table (Greeting_lang).", + "SPELL": { + "TRAINER_ID": "References trainer.id (trainer template linked to this entry).", + "SPELL_ID": "Spell ID being taught.", + "MONEY_COST": "Cost in copper to learn this spell from the trainer (1 gold = 100 silver = 10000 copper).", + "REQ_SKILL_LINE": "SkillLine ID required to learn this spell (e.g., profession ID). Use 0 if none.", + "REQ_SKILL_RANK": "Minimum skill rank in ReqSkillLine required to learn the spell.", + "REQ_ABILITY_1": "Spell ID the player is required to already know (first required ability).", + "REQ_ABILITY_1_TOOLTIP": "Spell ID the player must already know to be taught this spell (first prerequisite). Use 0 if none.", + "REQ_ABILITY_2": "Spell ID the player is required to already know (second required ability).", + "REQ_ABILITY_2_TOOLTIP": "Spell ID the player must already know to be taught this spell (second prerequisite). Use 0 if none.", + "REQ_ABILITY_3": "Spell ID the player is required to already know (third required ability).", + "REQ_ABILITY_3_TOOLTIP": "Spell ID the player must already know to be taught this spell (third prerequisite). Use 0 if none.", + "REQ_LEVEL": "Minimum player level required to learn this spell.", + "VERIFIED_BUILD": "Used by AzerothCore to indicate whether this entry was verified against WDB files (0 = not parsed; >0 = parsed; -1 = placeholder; - = parsed with specific client build and manually edited)." + } + }, "UNUSED_GUID_SEARCH": { "TABLE": "Table", "START_INDEX": "Start Index", diff --git a/apps/keira/src/assets/i18n/it.json b/apps/keira/src/assets/i18n/it.json index b0af53d990b..bc8ed2badd2 100644 --- a/apps/keira/src/assets/i18n/it.json +++ b/apps/keira/src/assets/i18n/it.json @@ -86,7 +86,7 @@ "ONKILL_REPUTATION": "Reputazione alla morte", "EQUIP_TEMPLATE": "Equipaggia Template", "VENDOR": "Venditore", - "TRAINER": "Istruttore", + "DEFAULT_TRAINER": "Default Trainer", "QUEST_ITEM": "Oggetto Missione", "CREATURE_LOOT": "Loot Creatura", "PICKPOCKETING_LOOT": "Loot Scippo", @@ -182,6 +182,12 @@ "SEARCH_GAME_TELE": "Cerca Teletrasporto", "SELECT_GAME_TELE": "Editor Tele Gioco" }, + "TRAINER": { + "TITLE": "Trainer", + "SEARCH_TRAINER": "Search Trainer", + "SELECT_TRAINER": "Trainer", + "TRAINER_SPELL": "Trainer Spell" + }, "UNUSED_GUID_SEARCH": "GUID non utilizzati" }, "DASHBOARD": { @@ -216,7 +222,6 @@ "KILL_CREDITS": "Crediti Uccisione", "MODELS": "Modelli", "MONEY_LOOT": "Loot Oro", - "TRAINER": "Istruttore", "LOOTS": "Loots", "DIFFICULTY_ENTRIES": "Voci di Difficoltà", "DAMAGE": "Danno", @@ -299,18 +304,16 @@ "TEMPLATE_SPELL": { "INDEX": "Valori consentiti: 0-7" }, - "NPC_TRAINER": { - "MONEY_COST": "Il costo da pagare per apprendere l'incantesimo rappresentato in rame (1 oro = 100 argento = 10000 rame)", - "REQ_SKILL_LINE": "L'abilità richiesta che il giocatore deve avere per poter apprendere l'incantesimo", - "REQ_SKILL_RANK": "La competenza nell'abilità da reqskill che il giocatore deve raggiungere per apprendere l'incantesimo", - "REQ_LEVEL": "Il livello minimo che il giocatore deve avere per poter apprendere l'incantesimo." - }, "NPC_VENDOR": { "SLOT": "Posizione dell'oggetto nella finestra del venditore", "MAXCOUNT": "Il numero massimo di oggetti trasportati dal venditore in qualsiasi momento. 0 per infinito (se si sceglie un valore di 1 o superiore, è necessario anche il valore incrtime per funzionare)", "INCRTIME": "Combinato con maxcount, quanto spesso (in secondi) viene aggiornato l'elenco dei venditori", "EXTENDED_COST": "Il valore proviene da DBC e un selettore per questo sarà implementato in seguito in Keira3" }, + "DEFAULT_TRAINER": { + "TITLE": "Default Trainer", + "TRAINER_ID_TOOLTIP": "ID of the trainer template (trainer.Id) assigned to this creature. Use 0 for no default trainer. Examples: 1=Trainer Warrior, 3=Trainer Paladin, 7=Trainer Hunter, 9=Trainer Rogue, 11=Trainer Priest, 13=Trainer Death Knight, 14=Trainer Shaman, 16=Trainer Mage, 31=Trainer Warlock, 33=Trainer Druid, 36=Trainer Mount & Fly. See the trainer wiki for the full list." + }, "TEXT": { "GROUP_ID": "Se ci sono più di un'entrata (più di un testo che la creatura dice), questa colonna viene utilizzata per scegliere se si tratta di un dillo casuale o di un elenco ordinato. Se una creatura ha più di un testo da dire in un dato ordine, deve essere incrementato per ogni nuova entrata corrispondente (es. 0, 1, 2, 3...). Se c'è solo un'entrata o solo un gruppo, questo valore dovrebbe essere 0. Se ci sono più gruppi di testi, questo valore rimane lo stesso all'interno del gruppo mentre l'id viene incrementato all'interno dello stesso gruppo.", "ID": "Entry for each group of texts. This is the unique identifier when entry (creature) is the same and groupid is unchanged, it must be incremented (ex. 0, 1, 2, 3...). A creature say will be randomly selected from this list based on the groupid it belongs to.", @@ -900,6 +903,27 @@ "GAME_TELE": { "EDITOR": "Editor Teletrasporto" }, + "TRAINER": { + "EDITOR": "Trainer Editor", + "TRAINER_ID_TOOLTIP": "References trainer.id (trainer template). Examples: 1=Trainer Warrior, 3=Trainer Paladin, 7=Trainer Hunter, 9=Trainer Rogue, 11=Trainer Priest, 13=Trainer Death Knight, 14=Trainer Shaman, 16=Trainer Mage, 31=Trainer Warlock, 33=Trainer Druid, 36=Trainer Mount & Fly. See the trainer wiki for the full list.", + "REQUIREMENT_TOOLTIP": "Meaning depends on Type - use 0 for none. Types: 0-Class (ChrClass ID e.g. 1=Warrior, 2=Paladin, 3=Hunter, 4=Rogue, 5=Priest, 6=Death Knight, 7=Shaman, 8=Mage, 9=Warlock, 11=Druid), 1-Mount (ChrRace ID (e.g. 1=Human, 2=Orc, 3=Dwarf, 4=Night Elf, 5=Undead, 6=Tauren, 7=Gnome, 8=Troll, 10=Blood Elf, 11=Draenei), 2-Tradeskill Spell ID (player must know this spell to learn from this trainer), 3-Pet ChrClass ID (see above). ", + "GREETING_TOOLTIP": "Text shown at the top of the trainer window when opened (this is not gossip). For localized greetings add entries in the \"trainer_locale\" table (Greeting_lang).", + "SPELL": { + "TRAINER_ID": "References trainer.id (trainer template linked to this entry).", + "SPELL_ID": "Spell ID being taught.", + "MONEY_COST": "Cost in copper to learn this spell from the trainer (1 gold = 100 silver = 10000 copper).", + "REQ_SKILL_LINE": "SkillLine ID required to learn this spell (e.g., profession ID). Use 0 if none.", + "REQ_SKILL_RANK": "Minimum skill rank in ReqSkillLine required to learn the spell.", + "REQ_ABILITY_1": "Spell ID the player is required to already know (first required ability).", + "REQ_ABILITY_1_TOOLTIP": "Spell ID the player must already know to be taught this spell (first prerequisite). Use 0 if none.", + "REQ_ABILITY_2": "Spell ID the player is required to already know (second required ability).", + "REQ_ABILITY_2_TOOLTIP": "Spell ID the player must already know to be taught this spell (second prerequisite). Use 0 if none.", + "REQ_ABILITY_3": "Spell ID the player is required to already know (third required ability).", + "REQ_ABILITY_3_TOOLTIP": "Spell ID the player must already know to be taught this spell (third prerequisite). Use 0 if none.", + "REQ_LEVEL": "Minimum player level required to learn this spell.", + "VERIFIED_BUILD": "Used by AzerothCore to indicate whether this entry was verified against WDB files (0 = not parsed; >0 = parsed; -1 = placeholder; - = parsed with specific client build and manually edited)." + } + }, "UNUSED_GUID_SEARCH": { "TABLE": "Tabella", "START_INDEX": "Indice Inizio", diff --git a/apps/keira/src/assets/i18n/ko.json b/apps/keira/src/assets/i18n/ko.json index 280e1d84b38..0c3248df955 100644 --- a/apps/keira/src/assets/i18n/ko.json +++ b/apps/keira/src/assets/i18n/ko.json @@ -86,7 +86,7 @@ "ONKILL_REPUTATION": "Onkill Reputation", "EQUIP_TEMPLATE": "Equip Template", "VENDOR": "Vendor", - "TRAINER": "Trainer", + "DEFAULT_TRAINER": "Default Trainer", "QUEST_ITEM": "Quest Item", "CREATURE_LOOT": "Creature Loot", "PICKPOCKETING_LOOT": "Pickpocketing Loot", @@ -182,6 +182,12 @@ "SEARCH_GAME_TELE": "Search Teleport", "SELECT_GAME_TELE": "Game Tele Editor" }, + "TRAINER": { + "TITLE": "Trainer", + "SEARCH_TRAINER": "Search Trainer", + "SELECT_TRAINER": "Trainer", + "TRAINER_SPELL": "Trainer Spell" + }, "UNUSED_GUID_SEARCH": "Unused GUIDs" }, "DASHBOARD": { @@ -216,7 +222,6 @@ "KILL_CREDITS": "KillCredits", "MODELS": "Models", "MONEY_LOOT": "Money Loot", - "TRAINER": "Trainer", "LOOTS": "Loots", "DIFFICULTY_ENTRIES": "Difficulty Entries", "DAMAGE": "Damage", @@ -299,18 +304,16 @@ "TEMPLATE_SPELL": { "INDEX": "Allowed values: 0-7" }, - "NPC_TRAINER": { - "MONEY_COST": "The cost to pay to learn the spell represented in copper (1 gold = 100 silver = 10000 cooper)", - "REQ_SKILL_LINE": "The required skill the player needs to have in order to be able to learn the spell", - "REQ_SKILL_RANK": "The proficiency in the skill from reqskill that the player needs to meet to learn the spell", - "REQ_LEVEL": "The minimum level the player needs to be in order to learn the spell." - }, "NPC_VENDOR": { "SLOT": "Position of the item in the vendor window", "MAXCOUNT": "The maximum number of items carried by the vendor at any time. 0 for infinite (if choosing a value of 1 or higher also requires incrtime value to work)", "INCRTIME": "Combined with maxcount, how often (in seconds) the vendor list is refreshed", "EXTENDED_COST": "Value comes from DBC and a selector for this will be implemented later in Keira3" }, + "DEFAULT_TRAINER": { + "TITLE": "Default Trainer", + "TRAINER_ID_TOOLTIP": "ID of the trainer template (trainer.Id) assigned to this creature. Use 0 for no default trainer. Examples: 1=Trainer Warrior, 3=Trainer Paladin, 7=Trainer Hunter, 9=Trainer Rogue, 11=Trainer Priest, 13=Trainer Death Knight, 14=Trainer Shaman, 16=Trainer Mage, 31=Trainer Warlock, 33=Trainer Druid, 36=Trainer Mount & Fly. See the trainer wiki for the full list." + }, "TEXT": { "GROUP_ID": "If there is more than one of the same entry (more than one text the creature says), this column is used to choose if it is a random say or an ordered list. If a creature has got more than one say text to be shown in a given order, it must be incremented for each new matching entry (ex. 0, 1, 2, 3...). If there is only one entry or only one group, this value should be 0. If there are multiple groups of texts, this value stays the same within the group while the id increments within the same group.", "ID": "Entry for each group of texts. This is the unique identifier when entry (creature) is the same and groupid is unchanged, it must be incremented (ex. 0, 1, 2, 3...). A creature say will be randomly selected from this list based on the groupid it belongs to.", @@ -900,6 +903,27 @@ "GAME_TELE": { "EDITOR": "Teleport Editor" }, + "TRAINER": { + "EDITOR": "Trainer Editor", + "TRAINER_ID_TOOLTIP": "References trainer.id (trainer template). Examples: 1=Trainer Warrior, 3=Trainer Paladin, 7=Trainer Hunter, 9=Trainer Rogue, 11=Trainer Priest, 13=Trainer Death Knight, 14=Trainer Shaman, 16=Trainer Mage, 31=Trainer Warlock, 33=Trainer Druid, 36=Trainer Mount & Fly. See the trainer wiki for the full list.", + "REQUIREMENT_TOOLTIP": "Meaning depends on Type - use 0 for none. Types: 0-Class (ChrClass ID e.g. 1=Warrior, 2=Paladin, 3=Hunter, 4=Rogue, 5=Priest, 6=Death Knight, 7=Shaman, 8=Mage, 9=Warlock, 11=Druid), 1-Mount (ChrRace ID (e.g. 1=Human, 2=Orc, 3=Dwarf, 4=Night Elf, 5=Undead, 6=Tauren, 7=Gnome, 8=Troll, 10=Blood Elf, 11=Draenei), 2-Tradeskill Spell ID (player must know this spell to learn from this trainer), 3-Pet ChrClass ID (see above). ", + "GREETING_TOOLTIP": "Text shown at the top of the trainer window when opened (this is not gossip). For localized greetings add entries in the \"trainer_locale\" table (Greeting_lang).", + "SPELL": { + "TRAINER_ID": "References trainer.id (trainer template linked to this entry).", + "SPELL_ID": "Spell ID being taught.", + "MONEY_COST": "Cost in copper to learn this spell from the trainer (1 gold = 100 silver = 10000 copper).", + "REQ_SKILL_LINE": "SkillLine ID required to learn this spell (e.g., profession ID). Use 0 if none.", + "REQ_SKILL_RANK": "Minimum skill rank in ReqSkillLine required to learn the spell.", + "REQ_ABILITY_1": "Spell ID the player is required to already know (first required ability).", + "REQ_ABILITY_1_TOOLTIP": "Spell ID the player must already know to be taught this spell (first prerequisite). Use 0 if none.", + "REQ_ABILITY_2": "Spell ID the player is required to already know (second required ability).", + "REQ_ABILITY_2_TOOLTIP": "Spell ID the player must already know to be taught this spell (second prerequisite). Use 0 if none.", + "REQ_ABILITY_3": "Spell ID the player is required to already know (third required ability).", + "REQ_ABILITY_3_TOOLTIP": "Spell ID the player must already know to be taught this spell (third prerequisite). Use 0 if none.", + "REQ_LEVEL": "Minimum player level required to learn this spell.", + "VERIFIED_BUILD": "Used by AzerothCore to indicate whether this entry was verified against WDB files (0 = not parsed; >0 = parsed; -1 = placeholder; - = parsed with specific client build and manually edited)." + } + }, "UNUSED_GUID_SEARCH": { "TABLE": "Table", "START_INDEX": "Start Index", diff --git a/apps/keira/src/assets/i18n/nl.json b/apps/keira/src/assets/i18n/nl.json index 280e1d84b38..0c3248df955 100644 --- a/apps/keira/src/assets/i18n/nl.json +++ b/apps/keira/src/assets/i18n/nl.json @@ -86,7 +86,7 @@ "ONKILL_REPUTATION": "Onkill Reputation", "EQUIP_TEMPLATE": "Equip Template", "VENDOR": "Vendor", - "TRAINER": "Trainer", + "DEFAULT_TRAINER": "Default Trainer", "QUEST_ITEM": "Quest Item", "CREATURE_LOOT": "Creature Loot", "PICKPOCKETING_LOOT": "Pickpocketing Loot", @@ -182,6 +182,12 @@ "SEARCH_GAME_TELE": "Search Teleport", "SELECT_GAME_TELE": "Game Tele Editor" }, + "TRAINER": { + "TITLE": "Trainer", + "SEARCH_TRAINER": "Search Trainer", + "SELECT_TRAINER": "Trainer", + "TRAINER_SPELL": "Trainer Spell" + }, "UNUSED_GUID_SEARCH": "Unused GUIDs" }, "DASHBOARD": { @@ -216,7 +222,6 @@ "KILL_CREDITS": "KillCredits", "MODELS": "Models", "MONEY_LOOT": "Money Loot", - "TRAINER": "Trainer", "LOOTS": "Loots", "DIFFICULTY_ENTRIES": "Difficulty Entries", "DAMAGE": "Damage", @@ -299,18 +304,16 @@ "TEMPLATE_SPELL": { "INDEX": "Allowed values: 0-7" }, - "NPC_TRAINER": { - "MONEY_COST": "The cost to pay to learn the spell represented in copper (1 gold = 100 silver = 10000 cooper)", - "REQ_SKILL_LINE": "The required skill the player needs to have in order to be able to learn the spell", - "REQ_SKILL_RANK": "The proficiency in the skill from reqskill that the player needs to meet to learn the spell", - "REQ_LEVEL": "The minimum level the player needs to be in order to learn the spell." - }, "NPC_VENDOR": { "SLOT": "Position of the item in the vendor window", "MAXCOUNT": "The maximum number of items carried by the vendor at any time. 0 for infinite (if choosing a value of 1 or higher also requires incrtime value to work)", "INCRTIME": "Combined with maxcount, how often (in seconds) the vendor list is refreshed", "EXTENDED_COST": "Value comes from DBC and a selector for this will be implemented later in Keira3" }, + "DEFAULT_TRAINER": { + "TITLE": "Default Trainer", + "TRAINER_ID_TOOLTIP": "ID of the trainer template (trainer.Id) assigned to this creature. Use 0 for no default trainer. Examples: 1=Trainer Warrior, 3=Trainer Paladin, 7=Trainer Hunter, 9=Trainer Rogue, 11=Trainer Priest, 13=Trainer Death Knight, 14=Trainer Shaman, 16=Trainer Mage, 31=Trainer Warlock, 33=Trainer Druid, 36=Trainer Mount & Fly. See the trainer wiki for the full list." + }, "TEXT": { "GROUP_ID": "If there is more than one of the same entry (more than one text the creature says), this column is used to choose if it is a random say or an ordered list. If a creature has got more than one say text to be shown in a given order, it must be incremented for each new matching entry (ex. 0, 1, 2, 3...). If there is only one entry or only one group, this value should be 0. If there are multiple groups of texts, this value stays the same within the group while the id increments within the same group.", "ID": "Entry for each group of texts. This is the unique identifier when entry (creature) is the same and groupid is unchanged, it must be incremented (ex. 0, 1, 2, 3...). A creature say will be randomly selected from this list based on the groupid it belongs to.", @@ -900,6 +903,27 @@ "GAME_TELE": { "EDITOR": "Teleport Editor" }, + "TRAINER": { + "EDITOR": "Trainer Editor", + "TRAINER_ID_TOOLTIP": "References trainer.id (trainer template). Examples: 1=Trainer Warrior, 3=Trainer Paladin, 7=Trainer Hunter, 9=Trainer Rogue, 11=Trainer Priest, 13=Trainer Death Knight, 14=Trainer Shaman, 16=Trainer Mage, 31=Trainer Warlock, 33=Trainer Druid, 36=Trainer Mount & Fly. See the trainer wiki for the full list.", + "REQUIREMENT_TOOLTIP": "Meaning depends on Type - use 0 for none. Types: 0-Class (ChrClass ID e.g. 1=Warrior, 2=Paladin, 3=Hunter, 4=Rogue, 5=Priest, 6=Death Knight, 7=Shaman, 8=Mage, 9=Warlock, 11=Druid), 1-Mount (ChrRace ID (e.g. 1=Human, 2=Orc, 3=Dwarf, 4=Night Elf, 5=Undead, 6=Tauren, 7=Gnome, 8=Troll, 10=Blood Elf, 11=Draenei), 2-Tradeskill Spell ID (player must know this spell to learn from this trainer), 3-Pet ChrClass ID (see above). ", + "GREETING_TOOLTIP": "Text shown at the top of the trainer window when opened (this is not gossip). For localized greetings add entries in the \"trainer_locale\" table (Greeting_lang).", + "SPELL": { + "TRAINER_ID": "References trainer.id (trainer template linked to this entry).", + "SPELL_ID": "Spell ID being taught.", + "MONEY_COST": "Cost in copper to learn this spell from the trainer (1 gold = 100 silver = 10000 copper).", + "REQ_SKILL_LINE": "SkillLine ID required to learn this spell (e.g., profession ID). Use 0 if none.", + "REQ_SKILL_RANK": "Minimum skill rank in ReqSkillLine required to learn the spell.", + "REQ_ABILITY_1": "Spell ID the player is required to already know (first required ability).", + "REQ_ABILITY_1_TOOLTIP": "Spell ID the player must already know to be taught this spell (first prerequisite). Use 0 if none.", + "REQ_ABILITY_2": "Spell ID the player is required to already know (second required ability).", + "REQ_ABILITY_2_TOOLTIP": "Spell ID the player must already know to be taught this spell (second prerequisite). Use 0 if none.", + "REQ_ABILITY_3": "Spell ID the player is required to already know (third required ability).", + "REQ_ABILITY_3_TOOLTIP": "Spell ID the player must already know to be taught this spell (third prerequisite). Use 0 if none.", + "REQ_LEVEL": "Minimum player level required to learn this spell.", + "VERIFIED_BUILD": "Used by AzerothCore to indicate whether this entry was verified against WDB files (0 = not parsed; >0 = parsed; -1 = placeholder; - = parsed with specific client build and manually edited)." + } + }, "UNUSED_GUID_SEARCH": { "TABLE": "Table", "START_INDEX": "Start Index", diff --git a/apps/keira/src/assets/i18n/pl.json b/apps/keira/src/assets/i18n/pl.json index 280e1d84b38..0c3248df955 100644 --- a/apps/keira/src/assets/i18n/pl.json +++ b/apps/keira/src/assets/i18n/pl.json @@ -86,7 +86,7 @@ "ONKILL_REPUTATION": "Onkill Reputation", "EQUIP_TEMPLATE": "Equip Template", "VENDOR": "Vendor", - "TRAINER": "Trainer", + "DEFAULT_TRAINER": "Default Trainer", "QUEST_ITEM": "Quest Item", "CREATURE_LOOT": "Creature Loot", "PICKPOCKETING_LOOT": "Pickpocketing Loot", @@ -182,6 +182,12 @@ "SEARCH_GAME_TELE": "Search Teleport", "SELECT_GAME_TELE": "Game Tele Editor" }, + "TRAINER": { + "TITLE": "Trainer", + "SEARCH_TRAINER": "Search Trainer", + "SELECT_TRAINER": "Trainer", + "TRAINER_SPELL": "Trainer Spell" + }, "UNUSED_GUID_SEARCH": "Unused GUIDs" }, "DASHBOARD": { @@ -216,7 +222,6 @@ "KILL_CREDITS": "KillCredits", "MODELS": "Models", "MONEY_LOOT": "Money Loot", - "TRAINER": "Trainer", "LOOTS": "Loots", "DIFFICULTY_ENTRIES": "Difficulty Entries", "DAMAGE": "Damage", @@ -299,18 +304,16 @@ "TEMPLATE_SPELL": { "INDEX": "Allowed values: 0-7" }, - "NPC_TRAINER": { - "MONEY_COST": "The cost to pay to learn the spell represented in copper (1 gold = 100 silver = 10000 cooper)", - "REQ_SKILL_LINE": "The required skill the player needs to have in order to be able to learn the spell", - "REQ_SKILL_RANK": "The proficiency in the skill from reqskill that the player needs to meet to learn the spell", - "REQ_LEVEL": "The minimum level the player needs to be in order to learn the spell." - }, "NPC_VENDOR": { "SLOT": "Position of the item in the vendor window", "MAXCOUNT": "The maximum number of items carried by the vendor at any time. 0 for infinite (if choosing a value of 1 or higher also requires incrtime value to work)", "INCRTIME": "Combined with maxcount, how often (in seconds) the vendor list is refreshed", "EXTENDED_COST": "Value comes from DBC and a selector for this will be implemented later in Keira3" }, + "DEFAULT_TRAINER": { + "TITLE": "Default Trainer", + "TRAINER_ID_TOOLTIP": "ID of the trainer template (trainer.Id) assigned to this creature. Use 0 for no default trainer. Examples: 1=Trainer Warrior, 3=Trainer Paladin, 7=Trainer Hunter, 9=Trainer Rogue, 11=Trainer Priest, 13=Trainer Death Knight, 14=Trainer Shaman, 16=Trainer Mage, 31=Trainer Warlock, 33=Trainer Druid, 36=Trainer Mount & Fly. See the trainer wiki for the full list." + }, "TEXT": { "GROUP_ID": "If there is more than one of the same entry (more than one text the creature says), this column is used to choose if it is a random say or an ordered list. If a creature has got more than one say text to be shown in a given order, it must be incremented for each new matching entry (ex. 0, 1, 2, 3...). If there is only one entry or only one group, this value should be 0. If there are multiple groups of texts, this value stays the same within the group while the id increments within the same group.", "ID": "Entry for each group of texts. This is the unique identifier when entry (creature) is the same and groupid is unchanged, it must be incremented (ex. 0, 1, 2, 3...). A creature say will be randomly selected from this list based on the groupid it belongs to.", @@ -900,6 +903,27 @@ "GAME_TELE": { "EDITOR": "Teleport Editor" }, + "TRAINER": { + "EDITOR": "Trainer Editor", + "TRAINER_ID_TOOLTIP": "References trainer.id (trainer template). Examples: 1=Trainer Warrior, 3=Trainer Paladin, 7=Trainer Hunter, 9=Trainer Rogue, 11=Trainer Priest, 13=Trainer Death Knight, 14=Trainer Shaman, 16=Trainer Mage, 31=Trainer Warlock, 33=Trainer Druid, 36=Trainer Mount & Fly. See the trainer wiki for the full list.", + "REQUIREMENT_TOOLTIP": "Meaning depends on Type - use 0 for none. Types: 0-Class (ChrClass ID e.g. 1=Warrior, 2=Paladin, 3=Hunter, 4=Rogue, 5=Priest, 6=Death Knight, 7=Shaman, 8=Mage, 9=Warlock, 11=Druid), 1-Mount (ChrRace ID (e.g. 1=Human, 2=Orc, 3=Dwarf, 4=Night Elf, 5=Undead, 6=Tauren, 7=Gnome, 8=Troll, 10=Blood Elf, 11=Draenei), 2-Tradeskill Spell ID (player must know this spell to learn from this trainer), 3-Pet ChrClass ID (see above). ", + "GREETING_TOOLTIP": "Text shown at the top of the trainer window when opened (this is not gossip). For localized greetings add entries in the \"trainer_locale\" table (Greeting_lang).", + "SPELL": { + "TRAINER_ID": "References trainer.id (trainer template linked to this entry).", + "SPELL_ID": "Spell ID being taught.", + "MONEY_COST": "Cost in copper to learn this spell from the trainer (1 gold = 100 silver = 10000 copper).", + "REQ_SKILL_LINE": "SkillLine ID required to learn this spell (e.g., profession ID). Use 0 if none.", + "REQ_SKILL_RANK": "Minimum skill rank in ReqSkillLine required to learn the spell.", + "REQ_ABILITY_1": "Spell ID the player is required to already know (first required ability).", + "REQ_ABILITY_1_TOOLTIP": "Spell ID the player must already know to be taught this spell (first prerequisite). Use 0 if none.", + "REQ_ABILITY_2": "Spell ID the player is required to already know (second required ability).", + "REQ_ABILITY_2_TOOLTIP": "Spell ID the player must already know to be taught this spell (second prerequisite). Use 0 if none.", + "REQ_ABILITY_3": "Spell ID the player is required to already know (third required ability).", + "REQ_ABILITY_3_TOOLTIP": "Spell ID the player must already know to be taught this spell (third prerequisite). Use 0 if none.", + "REQ_LEVEL": "Minimum player level required to learn this spell.", + "VERIFIED_BUILD": "Used by AzerothCore to indicate whether this entry was verified against WDB files (0 = not parsed; >0 = parsed; -1 = placeholder; - = parsed with specific client build and manually edited)." + } + }, "UNUSED_GUID_SEARCH": { "TABLE": "Table", "START_INDEX": "Start Index", diff --git a/apps/keira/src/assets/i18n/pt.json b/apps/keira/src/assets/i18n/pt.json index 5a5fa930646..436d802ccbd 100644 --- a/apps/keira/src/assets/i18n/pt.json +++ b/apps/keira/src/assets/i18n/pt.json @@ -86,7 +86,7 @@ "ONKILL_REPUTATION": "Onkill Reputation", "EQUIP_TEMPLATE": "Equip Template", "VENDOR": "Vendor", - "TRAINER": "Trainer", + "DEFAULT_TRAINER": "Default Trainer", "QUEST_ITEM": "Quest Item", "CREATURE_LOOT": "Creature Loot", "PICKPOCKETING_LOOT": "Pickpocketing Loot", @@ -182,6 +182,12 @@ "SEARCH_GAME_TELE": "Search Teleport", "SELECT_GAME_TELE": "Game Tele Editor" }, + "TRAINER": { + "TITLE": "Trainer", + "SEARCH_TRAINER": "Search Trainer", + "SELECT_TRAINER": "Trainer", + "TRAINER_SPELL": "Trainer Spell" + }, "UNUSED_GUID_SEARCH": "Unused GUIDs" }, "DASHBOARD": { @@ -216,7 +222,6 @@ "KILL_CREDITS": "KillCredits", "MODELS": "Models", "MONEY_LOOT": "Money Loot", - "TRAINER": "Trainer", "LOOTS": "Loots", "DIFFICULTY_ENTRIES": "Difficulty Entries", "DAMAGE": "Damage", @@ -299,18 +304,16 @@ "TEMPLATE_SPELL": { "INDEX": "Valores permitidos: 0-7" }, - "NPC_TRAINER": { - "MONEY_COST": "O preço para aprender o spell, representado em copper (1 gold = 100 silver = 10000 copper)", - "REQ_SKILL_LINE": "O skill necessário para o jogador aprender o spell", - "REQ_SKILL_RANK": "A proficiência na skill de reqskill necessária para o jogador aprender o spell", - "REQ_LEVEL": "O level mínimo necessário para o jogador aprender o spell." - }, "NPC_VENDOR": { "SLOT": "Posição do item na janela do vendedor", "MAXCOUNT": "O número máximo de items carregados pelo vendedor em qualquer momento. 0 para infinito.", "INCRTIME": "Combinado com maxcount, qual a frequência (em segundos) que a lista do vendedor é atualizada", "EXTENDED_COST": "Valor vem do DBC e um selecionador para isso será implementado futuramente no Keira3" }, + "DEFAULT_TRAINER": { + "TITLE": "Default Trainer", + "TRAINER_ID_TOOLTIP": "ID of the trainer template (trainer.Id) assigned to this creature. Use 0 for no default trainer. Examples: 1=Trainer Warrior, 3=Trainer Paladin, 7=Trainer Hunter, 9=Trainer Rogue, 11=Trainer Priest, 13=Trainer Death Knight, 14=Trainer Shaman, 16=Trainer Mage, 31=Trainer Warlock, 33=Trainer Druid, 36=Trainer Mount & Fly. See the trainer wiki for the full list." + }, "TEXT": { "GROUP_ID": "If there is more than one of the same entry (more than one text the creature says), this column is used to choose if it is a random say or an ordered list. If a creature has got more than one say text to be shown in a given order, it must be incremented for each new matching entry (ex. 0, 1, 2, 3...). If there is only one entry or only one group, this value should be 0. If there are multiple groups of texts, this value stays the same within the group while the id increments within the same group.", "ID": "Entry for each group of texts. This is the unique identifier when entry (creature) is the same and groupid is unchanged, it must be incremented (ex. 0, 1, 2, 3...). A creature say will be randomly selected from this list based on the groupid it belongs to.", @@ -900,6 +903,27 @@ "GAME_TELE": { "EDITOR": "Teleport Editor" }, + "TRAINER": { + "EDITOR": "Trainer Editor", + "TRAINER_ID_TOOLTIP": "References trainer.id (trainer template). Examples: 1=Trainer Warrior, 3=Trainer Paladin, 7=Trainer Hunter, 9=Trainer Rogue, 11=Trainer Priest, 13=Trainer Death Knight, 14=Trainer Shaman, 16=Trainer Mage, 31=Trainer Warlock, 33=Trainer Druid, 36=Trainer Mount & Fly. See the trainer wiki for the full list.", + "REQUIREMENT_TOOLTIP": "Meaning depends on Type - use 0 for none. Types: 0-Class (ChrClass ID e.g. 1=Warrior, 2=Paladin, 3=Hunter, 4=Rogue, 5=Priest, 6=Death Knight, 7=Shaman, 8=Mage, 9=Warlock, 11=Druid), 1-Mount (ChrRace ID (e.g. 1=Human, 2=Orc, 3=Dwarf, 4=Night Elf, 5=Undead, 6=Tauren, 7=Gnome, 8=Troll, 10=Blood Elf, 11=Draenei), 2-Tradeskill Spell ID (player must know this spell to learn from this trainer), 3-Pet ChrClass ID (see above). ", + "GREETING_TOOLTIP": "Text shown at the top of the trainer window when opened (this is not gossip). For localized greetings add entries in the \"trainer_locale\" table (Greeting_lang).", + "SPELL": { + "TRAINER_ID": "References trainer.id (trainer template linked to this entry).", + "SPELL_ID": "Spell ID being taught.", + "MONEY_COST": "Cost in copper to learn this spell from the trainer (1 gold = 100 silver = 10000 copper).", + "REQ_SKILL_LINE": "SkillLine ID required to learn this spell (e.g., profession ID). Use 0 if none.", + "REQ_SKILL_RANK": "Minimum skill rank in ReqSkillLine required to learn the spell.", + "REQ_ABILITY_1": "Spell ID the player is required to already know (first required ability).", + "REQ_ABILITY_1_TOOLTIP": "Spell ID the player must already know to be taught this spell (first prerequisite). Use 0 if none.", + "REQ_ABILITY_2": "Spell ID the player is required to already know (second required ability).", + "REQ_ABILITY_2_TOOLTIP": "Spell ID the player must already know to be taught this spell (second prerequisite). Use 0 if none.", + "REQ_ABILITY_3": "Spell ID the player is required to already know (third required ability).", + "REQ_ABILITY_3_TOOLTIP": "Spell ID the player must already know to be taught this spell (third prerequisite). Use 0 if none.", + "REQ_LEVEL": "Minimum player level required to learn this spell.", + "VERIFIED_BUILD": "Used by AzerothCore to indicate whether this entry was verified against WDB files (0 = not parsed; >0 = parsed; -1 = placeholder; - = parsed with specific client build and manually edited)." + } + }, "UNUSED_GUID_SEARCH": { "TABLE": "Table", "START_INDEX": "Start Index", diff --git a/apps/keira/src/assets/i18n/ro.json b/apps/keira/src/assets/i18n/ro.json index 280e1d84b38..0c3248df955 100644 --- a/apps/keira/src/assets/i18n/ro.json +++ b/apps/keira/src/assets/i18n/ro.json @@ -86,7 +86,7 @@ "ONKILL_REPUTATION": "Onkill Reputation", "EQUIP_TEMPLATE": "Equip Template", "VENDOR": "Vendor", - "TRAINER": "Trainer", + "DEFAULT_TRAINER": "Default Trainer", "QUEST_ITEM": "Quest Item", "CREATURE_LOOT": "Creature Loot", "PICKPOCKETING_LOOT": "Pickpocketing Loot", @@ -182,6 +182,12 @@ "SEARCH_GAME_TELE": "Search Teleport", "SELECT_GAME_TELE": "Game Tele Editor" }, + "TRAINER": { + "TITLE": "Trainer", + "SEARCH_TRAINER": "Search Trainer", + "SELECT_TRAINER": "Trainer", + "TRAINER_SPELL": "Trainer Spell" + }, "UNUSED_GUID_SEARCH": "Unused GUIDs" }, "DASHBOARD": { @@ -216,7 +222,6 @@ "KILL_CREDITS": "KillCredits", "MODELS": "Models", "MONEY_LOOT": "Money Loot", - "TRAINER": "Trainer", "LOOTS": "Loots", "DIFFICULTY_ENTRIES": "Difficulty Entries", "DAMAGE": "Damage", @@ -299,18 +304,16 @@ "TEMPLATE_SPELL": { "INDEX": "Allowed values: 0-7" }, - "NPC_TRAINER": { - "MONEY_COST": "The cost to pay to learn the spell represented in copper (1 gold = 100 silver = 10000 cooper)", - "REQ_SKILL_LINE": "The required skill the player needs to have in order to be able to learn the spell", - "REQ_SKILL_RANK": "The proficiency in the skill from reqskill that the player needs to meet to learn the spell", - "REQ_LEVEL": "The minimum level the player needs to be in order to learn the spell." - }, "NPC_VENDOR": { "SLOT": "Position of the item in the vendor window", "MAXCOUNT": "The maximum number of items carried by the vendor at any time. 0 for infinite (if choosing a value of 1 or higher also requires incrtime value to work)", "INCRTIME": "Combined with maxcount, how often (in seconds) the vendor list is refreshed", "EXTENDED_COST": "Value comes from DBC and a selector for this will be implemented later in Keira3" }, + "DEFAULT_TRAINER": { + "TITLE": "Default Trainer", + "TRAINER_ID_TOOLTIP": "ID of the trainer template (trainer.Id) assigned to this creature. Use 0 for no default trainer. Examples: 1=Trainer Warrior, 3=Trainer Paladin, 7=Trainer Hunter, 9=Trainer Rogue, 11=Trainer Priest, 13=Trainer Death Knight, 14=Trainer Shaman, 16=Trainer Mage, 31=Trainer Warlock, 33=Trainer Druid, 36=Trainer Mount & Fly. See the trainer wiki for the full list." + }, "TEXT": { "GROUP_ID": "If there is more than one of the same entry (more than one text the creature says), this column is used to choose if it is a random say or an ordered list. If a creature has got more than one say text to be shown in a given order, it must be incremented for each new matching entry (ex. 0, 1, 2, 3...). If there is only one entry or only one group, this value should be 0. If there are multiple groups of texts, this value stays the same within the group while the id increments within the same group.", "ID": "Entry for each group of texts. This is the unique identifier when entry (creature) is the same and groupid is unchanged, it must be incremented (ex. 0, 1, 2, 3...). A creature say will be randomly selected from this list based on the groupid it belongs to.", @@ -900,6 +903,27 @@ "GAME_TELE": { "EDITOR": "Teleport Editor" }, + "TRAINER": { + "EDITOR": "Trainer Editor", + "TRAINER_ID_TOOLTIP": "References trainer.id (trainer template). Examples: 1=Trainer Warrior, 3=Trainer Paladin, 7=Trainer Hunter, 9=Trainer Rogue, 11=Trainer Priest, 13=Trainer Death Knight, 14=Trainer Shaman, 16=Trainer Mage, 31=Trainer Warlock, 33=Trainer Druid, 36=Trainer Mount & Fly. See the trainer wiki for the full list.", + "REQUIREMENT_TOOLTIP": "Meaning depends on Type - use 0 for none. Types: 0-Class (ChrClass ID e.g. 1=Warrior, 2=Paladin, 3=Hunter, 4=Rogue, 5=Priest, 6=Death Knight, 7=Shaman, 8=Mage, 9=Warlock, 11=Druid), 1-Mount (ChrRace ID (e.g. 1=Human, 2=Orc, 3=Dwarf, 4=Night Elf, 5=Undead, 6=Tauren, 7=Gnome, 8=Troll, 10=Blood Elf, 11=Draenei), 2-Tradeskill Spell ID (player must know this spell to learn from this trainer), 3-Pet ChrClass ID (see above). ", + "GREETING_TOOLTIP": "Text shown at the top of the trainer window when opened (this is not gossip). For localized greetings add entries in the \"trainer_locale\" table (Greeting_lang).", + "SPELL": { + "TRAINER_ID": "References trainer.id (trainer template linked to this entry).", + "SPELL_ID": "Spell ID being taught.", + "MONEY_COST": "Cost in copper to learn this spell from the trainer (1 gold = 100 silver = 10000 copper).", + "REQ_SKILL_LINE": "SkillLine ID required to learn this spell (e.g., profession ID). Use 0 if none.", + "REQ_SKILL_RANK": "Minimum skill rank in ReqSkillLine required to learn the spell.", + "REQ_ABILITY_1": "Spell ID the player is required to already know (first required ability).", + "REQ_ABILITY_1_TOOLTIP": "Spell ID the player must already know to be taught this spell (first prerequisite). Use 0 if none.", + "REQ_ABILITY_2": "Spell ID the player is required to already know (second required ability).", + "REQ_ABILITY_2_TOOLTIP": "Spell ID the player must already know to be taught this spell (second prerequisite). Use 0 if none.", + "REQ_ABILITY_3": "Spell ID the player is required to already know (third required ability).", + "REQ_ABILITY_3_TOOLTIP": "Spell ID the player must already know to be taught this spell (third prerequisite). Use 0 if none.", + "REQ_LEVEL": "Minimum player level required to learn this spell.", + "VERIFIED_BUILD": "Used by AzerothCore to indicate whether this entry was verified against WDB files (0 = not parsed; >0 = parsed; -1 = placeholder; - = parsed with specific client build and manually edited)." + } + }, "UNUSED_GUID_SEARCH": { "TABLE": "Table", "START_INDEX": "Start Index", diff --git a/apps/keira/src/assets/i18n/ru.json b/apps/keira/src/assets/i18n/ru.json index 88486b03bf5..6454adb5639 100644 --- a/apps/keira/src/assets/i18n/ru.json +++ b/apps/keira/src/assets/i18n/ru.json @@ -86,7 +86,7 @@ "ONKILL_REPUTATION": "Onkill Reputation", "EQUIP_TEMPLATE": "Equip Template", "VENDOR": "Vendor", - "TRAINER": "Trainer", + "DEFAULT_TRAINER": "Default Trainer", "QUEST_ITEM": "Quest Item", "CREATURE_LOOT": "Creature Loot", "PICKPOCKETING_LOOT": "Pickpocketing Loot", @@ -182,6 +182,12 @@ "SEARCH_GAME_TELE": "Search Teleport", "SELECT_GAME_TELE": "Game Tele Editor" }, + "TRAINER": { + "TITLE": "Trainer", + "SEARCH_TRAINER": "Search Trainer", + "SELECT_TRAINER": "Trainer", + "TRAINER_SPELL": "Trainer Spell" + }, "UNUSED_GUID_SEARCH": "Unused GUIDs" }, "DASHBOARD": { @@ -216,7 +222,6 @@ "KILL_CREDITS": "KillCredits", "MODELS": "Models", "MONEY_LOOT": "Money Loot", - "TRAINER": "Trainer", "LOOTS": "Loots", "DIFFICULTY_ENTRIES": "Difficulty Entries", "DAMAGE": "Damage", @@ -299,18 +304,16 @@ "TEMPLATE_SPELL": { "INDEX": "Allowed values: 0-7" }, - "NPC_TRAINER": { - "MONEY_COST": "The cost to pay to learn the spell represented in copper (1 gold = 100 silver = 10000 cooper)", - "REQ_SKILL_LINE": "The required skill the player needs to have in order to be able to learn the spell", - "REQ_SKILL_RANK": "The proficiency in the skill from reqskill that the player needs to meet to learn the spell", - "REQ_LEVEL": "The minimum level the player needs to be in order to learn the spell." - }, "NPC_VENDOR": { "SLOT": "Position of the item in the vendor window", "MAXCOUNT": "The maximum number of items carried by the vendor at any time. 0 for infinite (if choosing a value of 1 or higher also requires incrtime value to work)", "INCRTIME": "Combined with maxcount, how often (in seconds) the vendor list is refreshed", "EXTENDED_COST": "Value comes from DBC and a selector for this will be implemented later in Keira3" }, + "DEFAULT_TRAINER": { + "TITLE": "Default Trainer", + "TRAINER_ID_TOOLTIP": "ID of the trainer template (trainer.Id) assigned to this creature. Use 0 for no default trainer. Examples: 1=Trainer Warrior, 3=Trainer Paladin, 7=Trainer Hunter, 9=Trainer Rogue, 11=Trainer Priest, 13=Trainer Death Knight, 14=Trainer Shaman, 16=Trainer Mage, 31=Trainer Warlock, 33=Trainer Druid, 36=Trainer Mount & Fly. See the trainer wiki for the full list." + }, "TEXT": { "GROUP_ID": "If there is more than one of the same entry (more than one text the creature says), this column is used to choose if it is a random say or an ordered list. If a creature has got more than one say text to be shown in a given order, it must be incremented for each new matching entry (ex. 0, 1, 2, 3...). If there is only one entry or only one group, this value should be 0. If there are multiple groups of texts, this value stays the same within the group while the id increments within the same group.", "ID": "Entry for each group of texts. This is the unique identifier when entry (creature) is the same and groupid is unchanged, it must be incremented (ex. 0, 1, 2, 3...). A creature say will be randomly selected from this list based on the groupid it belongs to.", @@ -900,6 +903,27 @@ "GAME_TELE": { "EDITOR": "Teleport Editor" }, + "TRAINER": { + "EDITOR": "Trainer Editor", + "TRAINER_ID_TOOLTIP": "References trainer.id (trainer template). Examples: 1=Trainer Warrior, 3=Trainer Paladin, 7=Trainer Hunter, 9=Trainer Rogue, 11=Trainer Priest, 13=Trainer Death Knight, 14=Trainer Shaman, 16=Trainer Mage, 31=Trainer Warlock, 33=Trainer Druid, 36=Trainer Mount & Fly. See the trainer wiki for the full list.", + "REQUIREMENT_TOOLTIP": "Meaning depends on Type - use 0 for none. Types: 0-Class (ChrClass ID e.g. 1=Warrior, 2=Paladin, 3=Hunter, 4=Rogue, 5=Priest, 6=Death Knight, 7=Shaman, 8=Mage, 9=Warlock, 11=Druid), 1-Mount (ChrRace ID (e.g. 1=Human, 2=Orc, 3=Dwarf, 4=Night Elf, 5=Undead, 6=Tauren, 7=Gnome, 8=Troll, 10=Blood Elf, 11=Draenei), 2-Tradeskill Spell ID (player must know this spell to learn from this trainer), 3-Pet ChrClass ID (see above). ", + "GREETING_TOOLTIP": "Text shown at the top of the trainer window when opened (this is not gossip). For localized greetings add entries in the \"trainer_locale\" table (Greeting_lang).", + "SPELL": { + "TRAINER_ID": "References trainer.id (trainer template linked to this entry).", + "SPELL_ID": "Spell ID being taught.", + "MONEY_COST": "Cost in copper to learn this spell from the trainer (1 gold = 100 silver = 10000 copper).", + "REQ_SKILL_LINE": "SkillLine ID required to learn this spell (e.g., profession ID). Use 0 if none.", + "REQ_SKILL_RANK": "Minimum skill rank in ReqSkillLine required to learn the spell.", + "REQ_ABILITY_1": "Spell ID the player is required to already know (first required ability).", + "REQ_ABILITY_1_TOOLTIP": "Spell ID the player must already know to be taught this spell (first prerequisite). Use 0 if none.", + "REQ_ABILITY_2": "Spell ID the player is required to already know (second required ability).", + "REQ_ABILITY_2_TOOLTIP": "Spell ID the player must already know to be taught this spell (second prerequisite). Use 0 if none.", + "REQ_ABILITY_3": "Spell ID the player is required to already know (third required ability).", + "REQ_ABILITY_3_TOOLTIP": "Spell ID the player must already know to be taught this spell (third prerequisite). Use 0 if none.", + "REQ_LEVEL": "Minimum player level required to learn this spell.", + "VERIFIED_BUILD": "Used by AzerothCore to indicate whether this entry was verified against WDB files (0 = not parsed; >0 = parsed; -1 = placeholder; - = parsed with specific client build and manually edited)." + } + }, "UNUSED_GUID_SEARCH": { "TABLE": "Table", "START_INDEX": "Start Index", diff --git a/apps/keira/src/assets/i18n/sk.json b/apps/keira/src/assets/i18n/sk.json index 280e1d84b38..0c3248df955 100644 --- a/apps/keira/src/assets/i18n/sk.json +++ b/apps/keira/src/assets/i18n/sk.json @@ -86,7 +86,7 @@ "ONKILL_REPUTATION": "Onkill Reputation", "EQUIP_TEMPLATE": "Equip Template", "VENDOR": "Vendor", - "TRAINER": "Trainer", + "DEFAULT_TRAINER": "Default Trainer", "QUEST_ITEM": "Quest Item", "CREATURE_LOOT": "Creature Loot", "PICKPOCKETING_LOOT": "Pickpocketing Loot", @@ -182,6 +182,12 @@ "SEARCH_GAME_TELE": "Search Teleport", "SELECT_GAME_TELE": "Game Tele Editor" }, + "TRAINER": { + "TITLE": "Trainer", + "SEARCH_TRAINER": "Search Trainer", + "SELECT_TRAINER": "Trainer", + "TRAINER_SPELL": "Trainer Spell" + }, "UNUSED_GUID_SEARCH": "Unused GUIDs" }, "DASHBOARD": { @@ -216,7 +222,6 @@ "KILL_CREDITS": "KillCredits", "MODELS": "Models", "MONEY_LOOT": "Money Loot", - "TRAINER": "Trainer", "LOOTS": "Loots", "DIFFICULTY_ENTRIES": "Difficulty Entries", "DAMAGE": "Damage", @@ -299,18 +304,16 @@ "TEMPLATE_SPELL": { "INDEX": "Allowed values: 0-7" }, - "NPC_TRAINER": { - "MONEY_COST": "The cost to pay to learn the spell represented in copper (1 gold = 100 silver = 10000 cooper)", - "REQ_SKILL_LINE": "The required skill the player needs to have in order to be able to learn the spell", - "REQ_SKILL_RANK": "The proficiency in the skill from reqskill that the player needs to meet to learn the spell", - "REQ_LEVEL": "The minimum level the player needs to be in order to learn the spell." - }, "NPC_VENDOR": { "SLOT": "Position of the item in the vendor window", "MAXCOUNT": "The maximum number of items carried by the vendor at any time. 0 for infinite (if choosing a value of 1 or higher also requires incrtime value to work)", "INCRTIME": "Combined with maxcount, how often (in seconds) the vendor list is refreshed", "EXTENDED_COST": "Value comes from DBC and a selector for this will be implemented later in Keira3" }, + "DEFAULT_TRAINER": { + "TITLE": "Default Trainer", + "TRAINER_ID_TOOLTIP": "ID of the trainer template (trainer.Id) assigned to this creature. Use 0 for no default trainer. Examples: 1=Trainer Warrior, 3=Trainer Paladin, 7=Trainer Hunter, 9=Trainer Rogue, 11=Trainer Priest, 13=Trainer Death Knight, 14=Trainer Shaman, 16=Trainer Mage, 31=Trainer Warlock, 33=Trainer Druid, 36=Trainer Mount & Fly. See the trainer wiki for the full list." + }, "TEXT": { "GROUP_ID": "If there is more than one of the same entry (more than one text the creature says), this column is used to choose if it is a random say or an ordered list. If a creature has got more than one say text to be shown in a given order, it must be incremented for each new matching entry (ex. 0, 1, 2, 3...). If there is only one entry or only one group, this value should be 0. If there are multiple groups of texts, this value stays the same within the group while the id increments within the same group.", "ID": "Entry for each group of texts. This is the unique identifier when entry (creature) is the same and groupid is unchanged, it must be incremented (ex. 0, 1, 2, 3...). A creature say will be randomly selected from this list based on the groupid it belongs to.", @@ -900,6 +903,27 @@ "GAME_TELE": { "EDITOR": "Teleport Editor" }, + "TRAINER": { + "EDITOR": "Trainer Editor", + "TRAINER_ID_TOOLTIP": "References trainer.id (trainer template). Examples: 1=Trainer Warrior, 3=Trainer Paladin, 7=Trainer Hunter, 9=Trainer Rogue, 11=Trainer Priest, 13=Trainer Death Knight, 14=Trainer Shaman, 16=Trainer Mage, 31=Trainer Warlock, 33=Trainer Druid, 36=Trainer Mount & Fly. See the trainer wiki for the full list.", + "REQUIREMENT_TOOLTIP": "Meaning depends on Type - use 0 for none. Types: 0-Class (ChrClass ID e.g. 1=Warrior, 2=Paladin, 3=Hunter, 4=Rogue, 5=Priest, 6=Death Knight, 7=Shaman, 8=Mage, 9=Warlock, 11=Druid), 1-Mount (ChrRace ID (e.g. 1=Human, 2=Orc, 3=Dwarf, 4=Night Elf, 5=Undead, 6=Tauren, 7=Gnome, 8=Troll, 10=Blood Elf, 11=Draenei), 2-Tradeskill Spell ID (player must know this spell to learn from this trainer), 3-Pet ChrClass ID (see above). ", + "GREETING_TOOLTIP": "Text shown at the top of the trainer window when opened (this is not gossip). For localized greetings add entries in the \"trainer_locale\" table (Greeting_lang).", + "SPELL": { + "TRAINER_ID": "References trainer.id (trainer template linked to this entry).", + "SPELL_ID": "Spell ID being taught.", + "MONEY_COST": "Cost in copper to learn this spell from the trainer (1 gold = 100 silver = 10000 copper).", + "REQ_SKILL_LINE": "SkillLine ID required to learn this spell (e.g., profession ID). Use 0 if none.", + "REQ_SKILL_RANK": "Minimum skill rank in ReqSkillLine required to learn the spell.", + "REQ_ABILITY_1": "Spell ID the player is required to already know (first required ability).", + "REQ_ABILITY_1_TOOLTIP": "Spell ID the player must already know to be taught this spell (first prerequisite). Use 0 if none.", + "REQ_ABILITY_2": "Spell ID the player is required to already know (second required ability).", + "REQ_ABILITY_2_TOOLTIP": "Spell ID the player must already know to be taught this spell (second prerequisite). Use 0 if none.", + "REQ_ABILITY_3": "Spell ID the player is required to already know (third required ability).", + "REQ_ABILITY_3_TOOLTIP": "Spell ID the player must already know to be taught this spell (third prerequisite). Use 0 if none.", + "REQ_LEVEL": "Minimum player level required to learn this spell.", + "VERIFIED_BUILD": "Used by AzerothCore to indicate whether this entry was verified against WDB files (0 = not parsed; >0 = parsed; -1 = placeholder; - = parsed with specific client build and manually edited)." + } + }, "UNUSED_GUID_SEARCH": { "TABLE": "Table", "START_INDEX": "Start Index", diff --git a/apps/keira/src/assets/i18n/sv.json b/apps/keira/src/assets/i18n/sv.json index 8012c8b856c..4f49011f5f1 100644 --- a/apps/keira/src/assets/i18n/sv.json +++ b/apps/keira/src/assets/i18n/sv.json @@ -86,7 +86,7 @@ "ONKILL_REPUTATION": "Onkill Reputation", "EQUIP_TEMPLATE": "Equip Template", "VENDOR": "Vendor", - "TRAINER": "Trainer", + "DEFAULT_TRAINER": "Default Trainer", "QUEST_ITEM": "Quest Item", "CREATURE_LOOT": "Creature Loot", "PICKPOCKETING_LOOT": "Pickpocketing Loot", @@ -182,6 +182,12 @@ "SEARCH_GAME_TELE": "Search Teleport", "SELECT_GAME_TELE": "Game Tele Editor" }, + "TRAINER": { + "TITLE": "Trainer", + "SEARCH_TRAINER": "Search Trainer", + "SELECT_TRAINER": "Trainer", + "TRAINER_SPELL": "Trainer Spell" + }, "UNUSED_GUID_SEARCH": "Unused GUIDs" }, "DASHBOARD": { @@ -216,7 +222,6 @@ "KILL_CREDITS": "KillCredits", "MODELS": "Models", "MONEY_LOOT": "Money Loot", - "TRAINER": "Trainer", "LOOTS": "Loots", "DIFFICULTY_ENTRIES": "Difficulty Entries", "DAMAGE": "Damage", @@ -299,18 +304,16 @@ "TEMPLATE_SPELL": { "INDEX": "Allowed values: 0-7" }, - "NPC_TRAINER": { - "MONEY_COST": "Vad det kommer att kosta att lära sig en Spell i coppar (1 gold = 100 silver = 10000 copper)", - "REQ_SKILL_LINE": "Vilken Spell som behövs för att spelaren ska kunna lära sig denna Spell", - "REQ_SKILL_RANK": "Den rank som behövs från ReqSkill som spelaren behöver ha för att kunna lära sig denna Spell", - "REQ_LEVEL": "Den minimala leveln som spelaren måste vara för att kunna lära sig denna Spell." - }, "NPC_VENDOR": { "SLOT": "Positionen för Item i Vendor Window", "MAXCOUNT": "Det maximala antalet denna Vendor kan ha utav ett Item. 0 för oändligt.", "INCRTIME": "Kombinerat med MaxCount, hur ofta (i sekunder) Vendor listan Refreshas", "EXTENDED_COST": "ID kommer från DBC och kommer att implementeras senare i Keira3" }, + "DEFAULT_TRAINER": { + "TITLE": "Default Trainer", + "TRAINER_ID_TOOLTIP": "ID of the trainer template (trainer.Id) assigned to this creature. Use 0 for no default trainer. Examples: 1=Trainer Warrior, 3=Trainer Paladin, 7=Trainer Hunter, 9=Trainer Rogue, 11=Trainer Priest, 13=Trainer Death Knight, 14=Trainer Shaman, 16=Trainer Mage, 31=Trainer Warlock, 33=Trainer Druid, 36=Trainer Mount & Fly. See the trainer wiki for the full list." + }, "TEXT": { "GROUP_ID": "If there is more than one of the same entry (more than one text the creature says), this column is used to choose if it is a random say or an ordered list. If a creature has got more than one say text to be shown in a given order, it must be incremented for each new matching entry (ex. 0, 1, 2, 3...). If there is only one entry or only one group, this value should be 0. If there are multiple groups of texts, this value stays the same within the group while the id increments within the same group.", "ID": "Entry for each group of texts. This is the unique identifier when entry (creature) is the same and groupid is unchanged, it must be incremented (ex. 0, 1, 2, 3...). A creature say will be randomly selected from this list based on the groupid it belongs to.", @@ -900,6 +903,27 @@ "GAME_TELE": { "EDITOR": "Teleport Editor" }, + "TRAINER": { + "EDITOR": "Trainer Editor", + "TRAINER_ID_TOOLTIP": "References trainer.id (trainer template). Examples: 1=Trainer Warrior, 3=Trainer Paladin, 7=Trainer Hunter, 9=Trainer Rogue, 11=Trainer Priest, 13=Trainer Death Knight, 14=Trainer Shaman, 16=Trainer Mage, 31=Trainer Warlock, 33=Trainer Druid, 36=Trainer Mount & Fly. See the trainer wiki for the full list.", + "REQUIREMENT_TOOLTIP": "Meaning depends on Type - use 0 for none. Types: 0-Class (ChrClass ID e.g. 1=Warrior, 2=Paladin, 3=Hunter, 4=Rogue, 5=Priest, 6=Death Knight, 7=Shaman, 8=Mage, 9=Warlock, 11=Druid), 1-Mount (ChrRace ID (e.g. 1=Human, 2=Orc, 3=Dwarf, 4=Night Elf, 5=Undead, 6=Tauren, 7=Gnome, 8=Troll, 10=Blood Elf, 11=Draenei), 2-Tradeskill Spell ID (player must know this spell to learn from this trainer), 3-Pet ChrClass ID (see above). ", + "GREETING_TOOLTIP": "Text shown at the top of the trainer window when opened (this is not gossip). For localized greetings add entries in the \"trainer_locale\" table (Greeting_lang).", + "SPELL": { + "TRAINER_ID": "References trainer.id (trainer template linked to this entry).", + "SPELL_ID": "Spell ID being taught.", + "MONEY_COST": "Cost in copper to learn this spell from the trainer (1 gold = 100 silver = 10000 copper).", + "REQ_SKILL_LINE": "SkillLine ID required to learn this spell (e.g., profession ID). Use 0 if none.", + "REQ_SKILL_RANK": "Minimum skill rank in ReqSkillLine required to learn the spell.", + "REQ_ABILITY_1": "Spell ID the player is required to already know (first required ability).", + "REQ_ABILITY_1_TOOLTIP": "Spell ID the player must already know to be taught this spell (first prerequisite). Use 0 if none.", + "REQ_ABILITY_2": "Spell ID the player is required to already know (second required ability).", + "REQ_ABILITY_2_TOOLTIP": "Spell ID the player must already know to be taught this spell (second prerequisite). Use 0 if none.", + "REQ_ABILITY_3": "Spell ID the player is required to already know (third required ability).", + "REQ_ABILITY_3_TOOLTIP": "Spell ID the player must already know to be taught this spell (third prerequisite). Use 0 if none.", + "REQ_LEVEL": "Minimum player level required to learn this spell.", + "VERIFIED_BUILD": "Used by AzerothCore to indicate whether this entry was verified against WDB files (0 = not parsed; >0 = parsed; -1 = placeholder; - = parsed with specific client build and manually edited)." + } + }, "UNUSED_GUID_SEARCH": { "TABLE": "Table", "START_INDEX": "Start Index", diff --git a/apps/keira/src/assets/i18n/zh.json b/apps/keira/src/assets/i18n/zh.json index 98386d4df10..4d06dbf9f76 100644 --- a/apps/keira/src/assets/i18n/zh.json +++ b/apps/keira/src/assets/i18n/zh.json @@ -86,7 +86,7 @@ "ONKILL_REPUTATION": "声望配置", "EQUIP_TEMPLATE": "装备模板", "VENDOR": "商贩", - "TRAINER": "训练师", + "DEFAULT_TRAINER": "Default Trainer", "QUEST_ITEM": "任务物品", "CREATURE_LOOT": "生物掉落", "PICKPOCKETING_LOOT": "扒窃掉落", @@ -182,6 +182,12 @@ "SEARCH_GAME_TELE": "Search Teleport", "SELECT_GAME_TELE": "Game Tele Editor" }, + "TRAINER": { + "TITLE": "Trainer", + "SEARCH_TRAINER": "Search Trainer", + "SELECT_TRAINER": "Trainer", + "TRAINER_SPELL": "Trainer Spell" + }, "UNUSED_GUID_SEARCH": "Unused GUIDs" }, "DASHBOARD": { @@ -216,7 +222,6 @@ "KILL_CREDITS": "荣誉击杀", "MODELS": "模组", "MONEY_LOOT": "金钱掉落", - "TRAINER": "训练师", "LOOTS": "掉落", "DIFFICULTY_ENTRIES": "副本难度", "DAMAGE": "伤害", @@ -299,18 +304,16 @@ "TEMPLATE_SPELL": { "INDEX": "范围值:0-7" }, - "NPC_TRAINER": { - "MONEY_COST": "学习该法术的金钱,用铜币表示(1金=100银=10000铜)", - "REQ_SKILL_LINE": "玩家学习技能所需的前置技能", - "REQ_SKILL_RANK": "玩家学习技能所需要的技能熟练度要求", - "REQ_LEVEL": "玩家学习技能锁需要的最低角色等级要求" - }, "NPC_VENDOR": { "SLOT": "物品在商贩售卖窗口中的显示位置", "MAXCOUNT": "供应商在销售物品的最大数量。0表示无限制。", "INCRTIME": "结合供应商销售物品的最大数量,如果设置了最大数量限制,则在此处设置物品在售卖窗口的刷新时间(单位:秒)", "EXTENDED_COST": "值来自DBC,稍后将在Keira3中实现该值的选择器" }, + "DEFAULT_TRAINER": { + "TITLE": "Default Trainer", + "TRAINER_ID_TOOLTIP": "ID of the trainer template (trainer.Id) assigned to this creature. Use 0 for no default trainer. Examples: 1=Trainer Warrior, 3=Trainer Paladin, 7=Trainer Hunter, 9=Trainer Rogue, 11=Trainer Priest, 13=Trainer Death Knight, 14=Trainer Shaman, 16=Trainer Mage, 31=Trainer Warlock, 33=Trainer Druid, 36=Trainer Mount & Fly. See the trainer wiki for the full list." + }, "TEXT": { "GROUP_ID": "If there is more than one of the same entry (more than one text the creature says), this column is used to choose if it is a random say or an ordered list. If a creature has got more than one say text to be shown in a given order, it must be incremented for each new matching entry (ex. 0, 1, 2, 3...). If there is only one entry or only one group, this value should be 0. If there are multiple groups of texts, this value stays the same within the group while the id increments within the same group.", "ID": "Entry for each group of texts. This is the unique identifier when entry (creature) is the same and groupid is unchanged, it must be incremented (ex. 0, 1, 2, 3...). A creature say will be randomly selected from this list based on the groupid it belongs to.", @@ -900,6 +903,27 @@ "GAME_TELE": { "EDITOR": "Teleport Editor" }, + "TRAINER": { + "EDITOR": "Trainer Editor", + "TRAINER_ID_TOOLTIP": "References trainer.id (trainer template). Examples: 1=Trainer Warrior, 3=Trainer Paladin, 7=Trainer Hunter, 9=Trainer Rogue, 11=Trainer Priest, 13=Trainer Death Knight, 14=Trainer Shaman, 16=Trainer Mage, 31=Trainer Warlock, 33=Trainer Druid, 36=Trainer Mount & Fly. See the trainer wiki for the full list.", + "REQUIREMENT_TOOLTIP": "Meaning depends on Type - use 0 for none. Types: 0-Class (ChrClass ID e.g. 1=Warrior, 2=Paladin, 3=Hunter, 4=Rogue, 5=Priest, 6=Death Knight, 7=Shaman, 8=Mage, 9=Warlock, 11=Druid), 1-Mount (ChrRace ID (e.g. 1=Human, 2=Orc, 3=Dwarf, 4=Night Elf, 5=Undead, 6=Tauren, 7=Gnome, 8=Troll, 10=Blood Elf, 11=Draenei), 2-Tradeskill Spell ID (player must know this spell to learn from this trainer), 3-Pet ChrClass ID (see above). ", + "GREETING_TOOLTIP": "Text shown at the top of the trainer window when opened (this is not gossip). For localized greetings add entries in the \"trainer_locale\" table (Greeting_lang).", + "SPELL": { + "TRAINER_ID": "References trainer.id (trainer template linked to this entry).", + "SPELL_ID": "Spell ID being taught.", + "MONEY_COST": "Cost in copper to learn this spell from the trainer (1 gold = 100 silver = 10000 copper).", + "REQ_SKILL_LINE": "SkillLine ID required to learn this spell (e.g., profession ID). Use 0 if none.", + "REQ_SKILL_RANK": "Minimum skill rank in ReqSkillLine required to learn the spell.", + "REQ_ABILITY_1": "Spell ID the player is required to already know (first required ability).", + "REQ_ABILITY_1_TOOLTIP": "Spell ID the player must already know to be taught this spell (first prerequisite). Use 0 if none.", + "REQ_ABILITY_2": "Spell ID the player is required to already know (second required ability).", + "REQ_ABILITY_2_TOOLTIP": "Spell ID the player must already know to be taught this spell (second prerequisite). Use 0 if none.", + "REQ_ABILITY_3": "Spell ID the player is required to already know (third required ability).", + "REQ_ABILITY_3_TOOLTIP": "Spell ID the player must already know to be taught this spell (third prerequisite). Use 0 if none.", + "REQ_LEVEL": "Minimum player level required to learn this spell.", + "VERIFIED_BUILD": "Used by AzerothCore to indicate whether this entry was verified against WDB files (0 = not parsed; >0 = parsed; -1 = placeholder; - = parsed with specific client build and manually edited)." + } + }, "UNUSED_GUID_SEARCH": { "TABLE": "Table", "START_INDEX": "Start Index", From 49e26db994cb0bbd23ddb4c4a8da9454863c288c Mon Sep 17 00:00:00 2001 From: sogla Date: Wed, 7 Jan 2026 22:38:53 +0100 Subject: [PATCH 03/14] chore: remove unused var --- .eslintrc.json | 2 +- .../src/creature-template/creature-template.component.ts | 1 - .../trainer/src/trainer-spell/trainer-spell.component.ts | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 344216df08b..11d84f35b4c 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,6 +1,6 @@ { "root": true, - "ignorePatterns": ["**/*"], + "ignorePatterns": [], "overrides": [ { "files": ["*.ts"], diff --git a/libs/features/creature/src/creature-template/creature-template.component.ts b/libs/features/creature/src/creature-template/creature-template.component.ts index e985b47e840..9b61b4cc08e 100644 --- a/libs/features/creature/src/creature-template/creature-template.component.ts +++ b/libs/features/creature/src/creature-template/creature-template.component.ts @@ -31,7 +31,6 @@ import { FlagsSelectorBtnComponent, GenericOptionSelectorComponent, SingleValueSelectorBtnComponent, - SpellSelectorBtnComponent, } from '@keira/shared/selectors'; import { TranslateModule } from '@ngx-translate/core'; import { TooltipModule } from 'ngx-bootstrap/tooltip'; diff --git a/libs/features/trainer/src/trainer-spell/trainer-spell.component.ts b/libs/features/trainer/src/trainer-spell/trainer-spell.component.ts index a95a7c5dd50..4606bc0a931 100644 --- a/libs/features/trainer/src/trainer-spell/trainer-spell.component.ts +++ b/libs/features/trainer/src/trainer-spell/trainer-spell.component.ts @@ -3,7 +3,7 @@ import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { TrainerSpell } from '@keira/shared/acore-world-model'; import { MultiRowEditorComponent } from '@keira/shared/base-abstract-classes'; -import { EditorButtonsComponent, IconComponent, QueryOutputComponent, TopBarComponent } from '@keira/shared/base-editor-components'; +import { EditorButtonsComponent, QueryOutputComponent, TopBarComponent } from '@keira/shared/base-editor-components'; import { SqliteQueryService } from '@keira/shared/db-layer'; import { SkillSelectorBtnComponent, SpellSelectorBtnComponent } from '@keira/shared/selectors'; import { TranslateModule } from '@ngx-translate/core'; From 219d0f1de64c1da713d3e01e7e8d4786da210fc9 Mon Sep 17 00:00:00 2001 From: sogla Date: Wed, 7 Jan 2026 22:50:56 +0100 Subject: [PATCH 04/14] fix: set width to spellId column previously, this column only showed a few characters and was not readable --- .../trainer/src/trainer-spell/trainer-spell.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/features/trainer/src/trainer-spell/trainer-spell.component.html b/libs/features/trainer/src/trainer-spell/trainer-spell.component.html index 8352f4534ed..09f77f91f74 100644 --- a/libs/features/trainer/src/trainer-spell/trainer-spell.component.html +++ b/libs/features/trainer/src/trainer-spell/trainer-spell.component.html @@ -113,7 +113,7 @@ [selectionType]="DTCFG.selectionType" (select)="editorService.onRowSelection($event)" > - + @if (sqliteQueryService.getSpellNameById(value) | async; as spellName) { {{ value }}: {{ spellName }} From c213bf473a000f33f3afcffa0b4144aebcfcd074 Mon Sep 17 00:00:00 2001 From: sogla Date: Wed, 7 Jan 2026 22:54:20 +0100 Subject: [PATCH 05/14] fix: reverse touching project-wide eslint --- .eslintrc.json | 2 +- libs/features/trainer/.eslintrc.json | 33 ++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 libs/features/trainer/.eslintrc.json diff --git a/.eslintrc.json b/.eslintrc.json index 11d84f35b4c..344216df08b 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,6 +1,6 @@ { "root": true, - "ignorePatterns": [], + "ignorePatterns": ["**/*"], "overrides": [ { "files": ["*.ts"], diff --git a/libs/features/trainer/.eslintrc.json b/libs/features/trainer/.eslintrc.json new file mode 100644 index 00000000000..a20cf65c221 --- /dev/null +++ b/libs/features/trainer/.eslintrc.json @@ -0,0 +1,33 @@ +{ + "extends": ["../../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts"], + "extends": ["plugin:@nx/angular", "plugin:@angular-eslint/template/process-inline-templates"], + "rules": { + "@angular-eslint/directive-selector": [ + "error", + { + "type": "attribute", + "prefix": "keira", + "style": "camelCase" + } + ], + "@angular-eslint/component-selector": [ + "error", + { + "type": "element", + "prefix": "keira", + "style": "kebab-case" + } + ] + } + }, + { + "files": ["*.html"], + "extends": ["plugin:@nx/angular-template"], + "rules": {} + } + ] +} From c9e5c3dce585202b33a656b27679f9d8942a119a Mon Sep 17 00:00:00 2001 From: sogla Date: Fri, 9 Jan 2026 00:07:05 +0100 Subject: [PATCH 06/14] add protected --- .../trainer/src/select-trainer/select-trainer.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/features/trainer/src/select-trainer/select-trainer.component.ts b/libs/features/trainer/src/select-trainer/select-trainer.component.ts index c855439d81f..a76902a6cc5 100644 --- a/libs/features/trainer/src/select-trainer/select-trainer.component.ts +++ b/libs/features/trainer/src/select-trainer/select-trainer.component.ts @@ -25,7 +25,7 @@ import { CreateComponent, HighlightjsWrapperComponent, TopBarComponent } from '@ export class SelectTrainerComponent extends SelectComponent { protected override readonly entityTable = TRAINER_TABLE; protected override readonly entityIdField = TRAINER_ID; - readonly customStartingId = 1000000; + protected readonly customStartingId = 1000000; protected readonly selectService = inject(SelectTrainerService); readonly handlerService = inject(TrainerHandlerService); protected readonly WIKI_BASE_URL = WIKI_BASE_URL; From 2e07297d4bdbacfabf55cd8a0c04a4617c25691d Mon Sep 17 00:00:00 2001 From: sogla Date: Fri, 9 Jan 2026 00:07:15 +0100 Subject: [PATCH 07/14] set to default number --- libs/shared/acore-world-model/src/entities/trainer.type.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/shared/acore-world-model/src/entities/trainer.type.ts b/libs/shared/acore-world-model/src/entities/trainer.type.ts index 3d86de6a0a5..70753b0ce7e 100644 --- a/libs/shared/acore-world-model/src/entities/trainer.type.ts +++ b/libs/shared/acore-world-model/src/entities/trainer.type.ts @@ -5,7 +5,7 @@ export const TRAINER_ID = 'Id'; export class Trainer extends TableRow { Id: number = 0; - Type: number = 2; + Type: number = 0; Requirement: number = 0; Greeting: string = ''; VerifiedBuild: number = 0; From 717f14169cb9567007c9c4861478900e014f90df Mon Sep 17 00:00:00 2001 From: sogla Date: Fri, 9 Jan 2026 00:12:55 +0100 Subject: [PATCH 08/14] remove: "ora" --- package.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/package.json b/package.json index 7552507f978..8099b321138 100644 --- a/package.json +++ b/package.json @@ -149,9 +149,6 @@ "@angular/core": "$@angular/core" } }, - "resolutions": { - "ora": "5.4.1" - }, "husky": { "hooks": { "pre-commit": "lint-staged", From 2eda14c84b06ee7e5a60a541cce7c683088806cf Mon Sep 17 00:00:00 2001 From: sogla Date: Fri, 9 Jan 2026 00:14:44 +0100 Subject: [PATCH 09/14] remove trainer fields from test --- .../creature-template/creature-template.integration.spec.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/features/creature/src/creature-template/creature-template.integration.spec.ts b/libs/features/creature/src/creature-template/creature-template.integration.spec.ts index e80a01a6d35..d98a8593e20 100644 --- a/libs/features/creature/src/creature-template/creature-template.integration.spec.ts +++ b/libs/features/creature/src/creature-template/creature-template.integration.spec.ts @@ -33,8 +33,8 @@ describe('CreatureTemplate integration tests', () => { '`KillCredit1`, `KillCredit2`, `name`, `subname`, ' + '`IconName`, `gossip_menu_id`, `minlevel`, `maxlevel`, `exp`, `faction`, `npcflag`, `speed_walk`, `speed_run`, `speed_swim`, `speed_flight`, `detection_range`, ' + '`scale`, `rank`, `dmgschool`, `DamageModifier`, `BaseAttackTime`, `RangeAttackTime`, `BaseVariance`, `RangeVariance`, ' + - '`unit_class`, `unit_flags`, `unit_flags2`, `dynamicflags`, `family`, `trainer_type`, `trainer_spell`, `trainer_class`, ' + - '`trainer_race`, `type`, `type_flags`, `lootid`, `pickpocketloot`, `skinloot`, `PetSpellDataId`, `VehicleId`, `mingold`, ' + + '`unit_class`, `unit_flags`, `unit_flags2`, `dynamicflags`, `family`, ' + + '`type`, `type_flags`, `lootid`, `pickpocketloot`, `skinloot`, `PetSpellDataId`, `VehicleId`, `mingold`, ' + '`maxgold`, `AIName`, `MovementType`, `HoverHeight`, `HealthModifier`, `ManaModifier`, `ArmorModifier`, `ExperienceModifier`, ' + '`RacialLeader`, `movementId`, `RegenHealth`, `mechanic_immune_mask`, `spell_school_immune_mask`, ' + '`flags_extra`, `ScriptName`, `VerifiedBuild`) VALUES\n' + @@ -93,7 +93,7 @@ describe('CreatureTemplate integration tests', () => { '`gossip_menu_id`, `minlevel`, `maxlevel`, `exp`, `faction`, `npcflag`, `speed_walk`, `speed_run`, `speed_swim`, `speed_flight`, `detection_range`, ' + '`scale`, `rank`, `dmgschool`, `DamageModifier`, `BaseAttackTime`, `RangeAttackTime`, `BaseVariance`, ' + '`RangeVariance`, `unit_class`, `unit_flags`, `unit_flags2`, `dynamicflags`, `family`, ' + - '`trainer_type`, `trainer_spell`, `trainer_class`, `trainer_race`, `type`, `type_flags`, ' + + '`type`, `type_flags`, ' + '`lootid`, `pickpocketloot`, `skinloot`, `PetSpellDataId`, `VehicleId`, `mingold`, `maxgold`, ' + '`AIName`, `MovementType`, `HoverHeight`, `HealthModifier`, `ManaModifier`, `ArmorModifier`, `ExperienceModifier`, `RacialLeader`, ' + '`movementId`, `RegenHealth`, `mechanic_immune_mask`, `spell_school_immune_mask`, `flags_extra`, `ScriptName`, `VerifiedBuild`) VALUES\n' + From 784352846794bcd042e254e7ecd095928353aa0c Mon Sep 17 00:00:00 2001 From: sogla Date: Sat, 10 Jan 2026 16:46:38 +0100 Subject: [PATCH 10/14] fixup! remove trainer fields from test --- .../creature-template.integration.spec.ts | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/libs/features/creature/src/creature-template/creature-template.integration.spec.ts b/libs/features/creature/src/creature-template/creature-template.integration.spec.ts index d98a8593e20..d7e0dcf9fa1 100644 --- a/libs/features/creature/src/creature-template/creature-template.integration.spec.ts +++ b/libs/features/creature/src/creature-template/creature-template.integration.spec.ts @@ -39,7 +39,7 @@ describe('CreatureTemplate integration tests', () => { '`RacialLeader`, `movementId`, `RegenHealth`, `mechanic_immune_mask`, `spell_school_immune_mask`, ' + '`flags_extra`, `ScriptName`, `VerifiedBuild`) VALUES\n' + "(1234, 0, 0, 0, 0, 0, '', '', '', 0, 1, 1, 0, 0, 0, 1, 1.14286, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, " + - "0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, '', 0);\n"; + "0, 0, 0, 0, 0, 0, 0, 0, '', 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, '', 0);\n"; const originalEntity = new CreatureTemplate(); originalEntity.entry = id; @@ -98,7 +98,7 @@ describe('CreatureTemplate integration tests', () => { '`AIName`, `MovementType`, `HoverHeight`, `HealthModifier`, `ManaModifier`, `ArmorModifier`, `ExperienceModifier`, `RacialLeader`, ' + '`movementId`, `RegenHealth`, `mechanic_immune_mask`, `spell_school_immune_mask`, `flags_extra`, `ScriptName`, `VerifiedBuild`) VALUES\n' + "(1234, 0, 0, 0, 0, 0, 'Shin', '', '', 0, 1, 1, 0, 0, 0, 1, 1.14286, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0," + - " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, '', 0);"; + " 0, 0, 0, 0, 0, 0, 0, 0, '', 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, '', 0);"; querySpy.calls.reset(); @@ -143,13 +143,10 @@ describe('CreatureTemplate integration tests', () => { values[25] = 1; // dmgschool await page.setNgxSelectValueByIndex('unit_class', 1); values[35] = 1; // family - values[36] = 1; // trainer_type - values[38] = 1; // trainer_class - await page.setNgxSelectValueByIndex('trainer_race', 1); - values[40] = 1; // type - values[50] = 2; // MovementType - values[56] = 1; // RacialLeader - values[58] = 0; // RegenHealth + values[36] = 1; // type + values[46] = 2; // MovementType + values[52] = 1; // RacialLeader + values[54] = 0; // RegenHealth const expectedQuery = 'UPDATE `creature_template` ' + @@ -158,8 +155,8 @@ describe('CreatureTemplate integration tests', () => { '`faction` = 12, `npcflag` = 13, `speed_walk` = 14, `speed_run` = 15, `speed_swim` = 16, ' + '`speed_flight` = 17, `detection_range` = 18, `scale` = 19, `DamageModifier` = 22, ' + '`BaseAttackTime` = 23, `RangeAttackTime` = 24, `BaseVariance` = 25, `RangeVariance` = 26, `unit_class` = 2, ' + - '`unit_flags` = 28, `unit_flags2` = 29, `dynamicflags` = 30, `trainer_spell` = 33, ' + - '`trainer_race` = 1, `type_flags` = 37, `lootid` = 38, `pickpocketloot` = 39, `skinloot` = 40,' + + '`unit_flags` = 28, `unit_flags2` = 29, `dynamicflags` = 30, ' + + '`type_flags` = 37, `lootid` = 38, `pickpocketloot` = 39, `skinloot` = 40,' + " `PetSpellDataId` = 41, `VehicleId` = 42, `mingold` = 43, `maxgold` = 44, `AIName` = '45', " + '`HoverHeight` = 47, `HealthModifier` = 48, `ManaModifier` = 49, `ArmorModifier` = 50, ' + '`ExperienceModifier` = 51, `movementId` = 53, `mechanic_immune_mask` = 55, ' + From e7596409ea102f4356f5e315de8a9be053625be6 Mon Sep 17 00:00:00 2001 From: sogla Date: Sat, 10 Jan 2026 19:45:27 +0100 Subject: [PATCH 11/14] fixup! fixup! remove trainer fields from test --- .../creature-template.integration.spec.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libs/features/creature/src/creature-template/creature-template.integration.spec.ts b/libs/features/creature/src/creature-template/creature-template.integration.spec.ts index d7e0dcf9fa1..8496fddee98 100644 --- a/libs/features/creature/src/creature-template/creature-template.integration.spec.ts +++ b/libs/features/creature/src/creature-template/creature-template.integration.spec.ts @@ -156,11 +156,11 @@ describe('CreatureTemplate integration tests', () => { '`speed_flight` = 17, `detection_range` = 18, `scale` = 19, `DamageModifier` = 22, ' + '`BaseAttackTime` = 23, `RangeAttackTime` = 24, `BaseVariance` = 25, `RangeVariance` = 26, `unit_class` = 2, ' + '`unit_flags` = 28, `unit_flags2` = 29, `dynamicflags` = 30, ' + - '`type_flags` = 37, `lootid` = 38, `pickpocketloot` = 39, `skinloot` = 40,' + - " `PetSpellDataId` = 41, `VehicleId` = 42, `mingold` = 43, `maxgold` = 44, `AIName` = '45', " + - '`HoverHeight` = 47, `HealthModifier` = 48, `ManaModifier` = 49, `ArmorModifier` = 50, ' + - '`ExperienceModifier` = 51, `movementId` = 53, `mechanic_immune_mask` = 55, ' + - "`spell_school_immune_mask` = 56, `flags_extra` = 57, `ScriptName` = '58' WHERE (`entry` = 1234);"; + '`type_flags` = 33, `lootid` = 34, `pickpocketloot` = 35, `skinloot` = 36,' + + " `PetSpellDataId` = 37, `VehicleId` = 38, `mingold` = 39, `maxgold` = 40, `AIName` = '41', " + + '`HoverHeight` = 43, `HealthModifier` = 44, `ManaModifier` = 45, `ArmorModifier` = 46, ' + + '`ExperienceModifier` = 47, `movementId` = 49, `mechanic_immune_mask` = 51, ' + + "`spell_school_immune_mask` = 52, `flags_extra` = 53, `ScriptName` = '54' WHERE (`entry` = 1234);"; querySpy.calls.reset(); From 9725f5fbcf3223bc471a609925aecd496c283105 Mon Sep 17 00:00:00 2001 From: Helias Date: Sun, 11 Jan 2026 11:33:04 +0100 Subject: [PATCH 12/14] feat(trainer-spell): add spells icons --- .../src/trainer-spell/trainer-spell.component.html | 11 ++++++----- .../src/trainer-spell/trainer-spell.component.ts | 3 ++- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/libs/features/trainer/src/trainer-spell/trainer-spell.component.html b/libs/features/trainer/src/trainer-spell/trainer-spell.component.html index 09f77f91f74..1659759acbf 100644 --- a/libs/features/trainer/src/trainer-spell/trainer-spell.component.html +++ b/libs/features/trainer/src/trainer-spell/trainer-spell.component.html @@ -113,10 +113,11 @@ [selectionType]="DTCFG.selectionType" (select)="editorService.onRowSelection($event)" > - + + @if (sqliteQueryService.getSpellNameById(value) | async; as spellName) { - {{ value }}: {{ spellName }} +
    {{ spellName }}
    }
    @@ -127,7 +128,7 @@ @if (value !== 0) { @if (sqliteQueryService.getSpellNameById(value) | async; as spellName) { - {{ value }}: {{ spellName }} +
    {{ value }}: {{ spellName }}
    } }
    @@ -136,7 +137,7 @@ @if (value !== 0) { @if (sqliteQueryService.getSpellNameById(value) | async; as spellName) { - {{ value }}: {{ spellName }} +
    {{ value }}: {{ spellName }}
    } }
    @@ -145,7 +146,7 @@ @if (value !== 0) { @if (sqliteQueryService.getSpellNameById(value) | async; as spellName) { - {{ value }}: {{ spellName }} +
    {{ value }}: {{ spellName }}
    } }
    diff --git a/libs/features/trainer/src/trainer-spell/trainer-spell.component.ts b/libs/features/trainer/src/trainer-spell/trainer-spell.component.ts index 4606bc0a931..a0fc3247560 100644 --- a/libs/features/trainer/src/trainer-spell/trainer-spell.component.ts +++ b/libs/features/trainer/src/trainer-spell/trainer-spell.component.ts @@ -3,7 +3,7 @@ import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { TrainerSpell } from '@keira/shared/acore-world-model'; import { MultiRowEditorComponent } from '@keira/shared/base-abstract-classes'; -import { EditorButtonsComponent, QueryOutputComponent, TopBarComponent } from '@keira/shared/base-editor-components'; +import { EditorButtonsComponent, IconComponent, QueryOutputComponent, TopBarComponent } from '@keira/shared/base-editor-components'; import { SqliteQueryService } from '@keira/shared/db-layer'; import { SkillSelectorBtnComponent, SpellSelectorBtnComponent } from '@keira/shared/selectors'; import { TranslateModule } from '@ngx-translate/core'; @@ -29,6 +29,7 @@ import { TrainerSpellService } from './trainer-spell.service'; EditorButtonsComponent, NgxDatatableModule, AsyncPipe, + IconComponent, ], }) export class TrainerSpellComponent extends MultiRowEditorComponent { From 2d66fa47aad325e5924f8d3d95afca638a06e19d Mon Sep 17 00:00:00 2001 From: Helias Date: Sun, 11 Jan 2026 11:37:47 +0100 Subject: [PATCH 13/14] chore(spell-selector-modal): minor style improvement --- .../spell-selector/spell-selector-modal.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/shared/selectors/src/selectors/spell-selector/spell-selector-modal.component.html b/libs/shared/selectors/src/selectors/spell-selector/spell-selector-modal.component.html index 23deebe4ed4..329388bb9a2 100644 --- a/libs/shared/selectors/src/selectors/spell-selector/spell-selector-modal.component.html +++ b/libs/shared/selectors/src/selectors/spell-selector/spell-selector-modal.component.html @@ -43,7 +43,7 @@
    - {{ row.spellName }} +
    {{ row.spellName }}
    From d28640438ddf4706945f3d8ea0c30f21f8aec822 Mon Sep 17 00:00:00 2001 From: Helias Date: Sun, 11 Jan 2026 13:46:51 +0100 Subject: [PATCH 14/14] test(creature-default-trainer): add and improve creature-default trainer tests --- ...eature-default-trainer.integration.spec.ts | 147 ++++++++++++++++++ .../creature-default-trainer.service.spec.ts | 33 ++++ libs/features/trainer/karma.conf.js | 47 ++---- .../edit-trainer/trainer.component.spec.ts | 65 ++++++++ .../select-trainer.component.spec.ts | 56 +++++++ .../src/trainer-handler.service.spec.ts | 34 +++- .../trainer-spell.service.spec.ts | 48 ++++++ libs/features/trainer/tsconfig.spec.json | 7 +- 8 files changed, 389 insertions(+), 48 deletions(-) create mode 100644 libs/features/creature/src/creature-default-trainer/creature-default-trainer.integration.spec.ts create mode 100644 libs/features/creature/src/creature-default-trainer/creature-default-trainer.service.spec.ts create mode 100644 libs/features/trainer/src/edit-trainer/trainer.component.spec.ts create mode 100644 libs/features/trainer/src/select-trainer/select-trainer.component.spec.ts create mode 100644 libs/features/trainer/src/trainer-spell/trainer-spell.service.spec.ts diff --git a/libs/features/creature/src/creature-default-trainer/creature-default-trainer.integration.spec.ts b/libs/features/creature/src/creature-default-trainer/creature-default-trainer.integration.spec.ts new file mode 100644 index 00000000000..48ad6ea46b5 --- /dev/null +++ b/libs/features/creature/src/creature-default-trainer/creature-default-trainer.integration.spec.ts @@ -0,0 +1,147 @@ +import { provideZonelessChangeDetection } from '@angular/core'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { provideNoopAnimations } from '@angular/platform-browser/animations'; +import { RouterTestingModule } from '@angular/router/testing'; +import { CreatureDefaultTrainer } from '@keira/shared/acore-world-model'; +import { MysqlQueryService, SqliteService } from '@keira/shared/db-layer'; +import { EditorPageObject, TranslateTestingModule } from '@keira/shared/test-utils'; +import { ModalModule } from 'ngx-bootstrap/modal'; +import { ToastrModule } from 'ngx-toastr'; +import { of } from 'rxjs'; +import { instance, mock } from 'ts-mockito'; +import { CreatureHandlerService } from '../creature-handler.service'; +import { SaiCreatureHandlerService } from '../sai-creature-handler.service'; +import { CreatureDefaultTrainerComponent } from './creature-default-trainer.component'; +import Spy = jasmine.Spy; + +class CreatureDefaultTrainerPage extends EditorPageObject {} + +describe('CreatureDefaultTrainer integration tests', () => { + let fixture: ComponentFixture; + let queryService: MysqlQueryService; + let querySpy: Spy; + let handlerService: CreatureHandlerService; + let page: CreatureDefaultTrainerPage; + + const id = 1234; + const expectedFullCreateQuery = + 'DELETE FROM `creature_default_trainer` WHERE (`CreatureId` = 1234);\n' + + 'INSERT INTO `creature_default_trainer` (`CreatureId`, `TrainerId`) VALUES\n' + + '(1234, 0);'; + + const originalEntity = new CreatureDefaultTrainer(); + originalEntity.CreatureId = id; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ + ToastrModule.forRoot(), + ModalModule.forRoot(), + CreatureDefaultTrainerComponent, + RouterTestingModule, + TranslateTestingModule, + ], + providers: [ + provideZonelessChangeDetection(), + provideNoopAnimations(), + CreatureHandlerService, + SaiCreatureHandlerService, + { provide: SqliteService, useValue: instance(mock(SqliteService)) }, + ], + }).compileComponents(); + }); + + function setup(creatingNew: boolean) { + handlerService = TestBed.inject(CreatureHandlerService); + handlerService['_selected'] = `${id}`; + handlerService.isNew = creatingNew; + + queryService = TestBed.inject(MysqlQueryService); + querySpy = spyOn(queryService, 'query').and.returnValue(of([])); + spyOn(queryService, 'queryValue').and.returnValue(of()); + + spyOn(queryService, 'selectAll').and.returnValue(of(creatingNew ? [] : [originalEntity])); + + fixture = TestBed.createComponent(CreatureDefaultTrainerComponent); + page = new CreatureDefaultTrainerPage(fixture); + fixture.autoDetectChanges(true); + fixture.detectChanges(); + } + + describe('Creating new', () => { + beforeEach(() => setup(true)); + + it('should correctly initialise', () => { + page.expectQuerySwitchToBeHidden(); + page.expectFullQueryToBeShown(); + page.expectFullQueryToContain(expectedFullCreateQuery); + }); + + it('should correctly update the unsaved status', () => { + const field = 'TrainerId'; + expect(handlerService.isCreatureDefaultTrainerUnsaved()).toBe(false); + page.setInputValueById(field, 3); + expect(handlerService.isCreatureDefaultTrainerUnsaved()).toBe(true); + page.setInputValueById(field, 0); + expect(handlerService.isCreatureDefaultTrainerUnsaved()).toBe(false); + }); + + it('changing a property and executing the query should correctly work', () => { + const expectedQuery = + 'DELETE FROM `creature_default_trainer` WHERE (`CreatureId` = 1234);\n' + + 'INSERT INTO `creature_default_trainer` (`CreatureId`, `TrainerId`) VALUES\n' + + '(1234, 100);'; + querySpy.calls.reset(); + + page.setInputValueById('TrainerId', '100'); + page.expectFullQueryToContain(expectedQuery); + + page.clickExecuteQuery(); + + expect(querySpy).toHaveBeenCalledTimes(1); + expect(querySpy.calls.mostRecent().args[0]).toContain(expectedQuery); + }); + }); + + describe('Editing existing', () => { + beforeEach(() => setup(false)); + + it('should correctly initialise', () => { + page.expectDiffQueryToBeShown(); + page.expectDiffQueryToBeEmpty(); + page.expectFullQueryToContain(expectedFullCreateQuery); + }); + + it('changing all properties and executing the query should correctly work', () => { + const expectedQuery = 'UPDATE `creature_default_trainer` SET `TrainerId` = 1 WHERE (`CreatureId` = 1234);'; + querySpy.calls.reset(); + + page.setInputValueById('TrainerId', '1'); + + page.expectDiffQueryToContain(expectedQuery); + + page.clickExecuteQuery(); + + expect(querySpy).toHaveBeenCalledTimes(1); + expect(querySpy.calls.mostRecent().args[0]).toContain(expectedQuery); + }); + + it('changing values should correctly update the queries', () => { + page.setInputValueById('TrainerId', '50'); + page.expectDiffQueryToContain('UPDATE `creature_default_trainer` SET `TrainerId` = 50 WHERE (`CreatureId` = 1234);'); + page.expectFullQueryToContain( + 'DELETE FROM `creature_default_trainer` WHERE (`CreatureId` = 1234);\n' + + 'INSERT INTO `creature_default_trainer` (`CreatureId`, `TrainerId`) VALUES\n' + + '(1234, 50);', + ); + + page.setInputValueById('TrainerId', '75'); + page.expectDiffQueryToContain('UPDATE `creature_default_trainer` SET `TrainerId` = 75 WHERE (`CreatureId` = 1234);'); + page.expectFullQueryToContain( + 'DELETE FROM `creature_default_trainer` WHERE (`CreatureId` = 1234);\n' + + 'INSERT INTO `creature_default_trainer` (`CreatureId`, `TrainerId`) VALUES\n' + + '(1234, 75);', + ); + }); + }); +}); diff --git a/libs/features/creature/src/creature-default-trainer/creature-default-trainer.service.spec.ts b/libs/features/creature/src/creature-default-trainer/creature-default-trainer.service.spec.ts new file mode 100644 index 00000000000..47bce2de5bb --- /dev/null +++ b/libs/features/creature/src/creature-default-trainer/creature-default-trainer.service.spec.ts @@ -0,0 +1,33 @@ +import { provideZonelessChangeDetection } from '@angular/core'; +import { TestBed } from '@angular/core/testing'; +import { provideNoopAnimations } from '@angular/platform-browser/animations'; +import { RouterTestingModule } from '@angular/router/testing'; +import { MysqlQueryService, SqliteService } from '@keira/shared/db-layer'; +import { ToastrService } from 'ngx-toastr'; +import { instance, mock } from 'ts-mockito'; +import { CreatureHandlerService } from '../creature-handler.service'; +import { SaiCreatureHandlerService } from '../sai-creature-handler.service'; +import { CreatureDefaultTrainerService } from './creature-default-trainer.service'; + +describe('CreatureDefaultTrainerService', () => { + beforeEach(() => + TestBed.configureTestingModule({ + imports: [RouterTestingModule], + providers: [ + provideZonelessChangeDetection(), + provideNoopAnimations(), + { provide: MysqlQueryService, useValue: instance(mock(MysqlQueryService)) }, + { provide: ToastrService, useValue: instance(mock(ToastrService)) }, + { provide: SqliteService, useValue: instance(mock(SqliteService)) }, + CreatureHandlerService, + SaiCreatureHandlerService, + CreatureDefaultTrainerService, + ], + }), + ); + + it('should be created', () => { + const service: CreatureDefaultTrainerService = TestBed.inject(CreatureDefaultTrainerService); + expect(service).toBeTruthy(); + }); +}); diff --git a/libs/features/trainer/karma.conf.js b/libs/features/trainer/karma.conf.js index 63aac3d3708..eb946d5780f 100644 --- a/libs/features/trainer/karma.conf.js +++ b/libs/features/trainer/karma.conf.js @@ -1,44 +1,15 @@ -// Karma configuration file, see link for more information -// https://karma-runner.github.io/1.0/config/configuration-file.html - const { join } = require('path'); -const { constants } = require('karma'); +const getBaseKarmaConfig = require('../../../karma.conf'); -module.exports = () => { - return { - basePath: '', - frameworks: ['jasmine', '@angular-devkit/build-angular'], - plugins: [ - require('karma-jasmine'), - require('karma-chrome-launcher'), - require('karma-jasmine-html-reporter'), - require('karma-coverage'), - require('@angular-devkit/build-angular/plugins/karma'), - ], - client: { - jasmine: { - // you can add configuration options for Jasmine here - // the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html - // for example, you can disable the random execution with `random: false` - // or set a specific seed with `seed: 4321` - }, - clearContext: false, // leave Jasmine Spec Runner output visible in browser - }, - jasmineHtmlReporter: { - suppressAll: true, // removes the duplicated traces - }, +module.exports = function (config) { + const baseConfig = getBaseKarmaConfig(config); + config.set({ + ...baseConfig, + frameworks: [...baseConfig.frameworks], + plugins: [...baseConfig.plugins], coverageReporter: { + ...baseConfig.coverageReporter, dir: join(__dirname, '../../../coverage/libs/features/trainer'), - subdir: '.', - reporters: [{ type: 'html' }, { type: 'text-summary' }, { type: 'lcovonly' }], }, - reporters: ['progress', 'kjhtml'], - port: 9876, - colors: true, - logLevel: constants.LOG_INFO, - autoWatch: true, - browsers: ['ChromeHeadless'], - singleRun: true, - restartOnFileChange: true, - }; + }); }; diff --git a/libs/features/trainer/src/edit-trainer/trainer.component.spec.ts b/libs/features/trainer/src/edit-trainer/trainer.component.spec.ts new file mode 100644 index 00000000000..f2258483ddd --- /dev/null +++ b/libs/features/trainer/src/edit-trainer/trainer.component.spec.ts @@ -0,0 +1,65 @@ +import { Component, provideZonelessChangeDetection, viewChild } from '@angular/core'; +import { TestBed } from '@angular/core/testing'; +import { provideNoopAnimations } from '@angular/platform-browser/animations'; +import { RouterTestingModule } from '@angular/router/testing'; +import { MysqlQueryService } from '@keira/shared/db-layer'; +import { TranslateTestingModule } from '@keira/shared/test-utils'; +import { ModalModule } from 'ngx-bootstrap/modal'; +import { ToastrModule } from 'ngx-toastr'; +import { of } from 'rxjs'; +import { TrainerHandlerService } from '../trainer-handler.service'; +import { TrainerComponent } from './trainer.component'; +import { TrainerService } from './trainer.service'; + +describe('TrainerComponent', () => { + @Component({ + template: '', + imports: [TrainerComponent], + }) + class TestHostComponent { + readonly child = viewChild.required(TrainerComponent); + } + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ + ModalModule.forRoot(), + ToastrModule.forRoot(), + TestHostComponent, + TrainerComponent, + RouterTestingModule, + TranslateTestingModule, + ], + providers: [provideZonelessChangeDetection(), provideNoopAnimations(), TrainerHandlerService], + }).compileComponents(); + }); + + const setup = () => { + const queryService = TestBed.inject(MysqlQueryService); + spyOn(queryService, 'query').and.returnValue(of()); + + const fixture = TestBed.createComponent(TestHostComponent); + const host = fixture.componentInstance; + const component = host.child(); + const trainerService = TestBed.inject(TrainerService); + fixture.detectChanges(); + + return { fixture, host, component, queryService, trainerService }; + }; + + it('should create', () => { + const { component } = setup(); + expect(component).toBeTruthy(); + }); + + it('should have editorService injected', () => { + const { component, trainerService } = setup(); + expect(component['editorService']).toBeTruthy(); + expect(component['editorService']).toEqual(trainerService); + }); + + it('should have TRAINER_TYPE constant available', () => { + const { component } = setup(); + expect(component['TRAINER_TYPE']).toBeDefined(); + }); +}); diff --git a/libs/features/trainer/src/select-trainer/select-trainer.component.spec.ts b/libs/features/trainer/src/select-trainer/select-trainer.component.spec.ts new file mode 100644 index 00000000000..0921608fb87 --- /dev/null +++ b/libs/features/trainer/src/select-trainer/select-trainer.component.spec.ts @@ -0,0 +1,56 @@ +import { provideZonelessChangeDetection } from '@angular/core'; +import { TestBed } from '@angular/core/testing'; +import { provideNoopAnimations } from '@angular/platform-browser/animations'; +import { Router } from '@angular/router'; +import { RouterTestingModule } from '@angular/router/testing'; +import { MysqlQueryService } from '@keira/shared/db-layer'; +import { TranslateTestingModule } from '@keira/shared/test-utils'; +import { ModalModule } from 'ngx-bootstrap/modal'; +import { ToastrModule } from 'ngx-toastr'; +import { of } from 'rxjs'; +import { TrainerHandlerService } from '../trainer-handler.service'; +import { SelectTrainerComponent } from './select-trainer.component'; +import { SelectTrainerService } from './select-trainer.service'; + +describe('SelectTrainerComponent', () => { + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ModalModule.forRoot(), ToastrModule.forRoot(), SelectTrainerComponent, RouterTestingModule, TranslateTestingModule], + providers: [provideZonelessChangeDetection(), provideNoopAnimations(), TrainerHandlerService], + }).compileComponents(); + }); + + const setup = () => { + const queryService = TestBed.inject(MysqlQueryService); + spyOn(queryService, 'query').and.returnValue(of()); + + const fixture = TestBed.createComponent(SelectTrainerComponent); + const component = fixture.componentInstance; + const selectService = TestBed.inject(SelectTrainerService); + const handlerService = TestBed.inject(TrainerHandlerService); + const router = TestBed.inject(Router); + fixture.detectChanges(); + + return { fixture, component, queryService, selectService, handlerService, router }; + }; + + it('should create', () => { + const { component } = setup(); + expect(component).toBeTruthy(); + }); + + it('should have correct entity table', () => { + const { component } = setup(); + expect(component['entityTable']).toBe('trainer'); + }); + + it('should have correct entity id field', () => { + const { component } = setup(); + expect(component['entityIdField']).toBe('Id'); + }); + + it('should have customStartingId set to 1000000', () => { + const { component } = setup(); + expect(component['customStartingId']).toBe(1000000); + }); +}); diff --git a/libs/features/trainer/src/trainer-handler.service.spec.ts b/libs/features/trainer/src/trainer-handler.service.spec.ts index 2f24ddd719c..62e0813494a 100644 --- a/libs/features/trainer/src/trainer-handler.service.spec.ts +++ b/libs/features/trainer/src/trainer-handler.service.spec.ts @@ -1,15 +1,37 @@ +import { provideZonelessChangeDetection } from '@angular/core'; import { TestBed } from '@angular/core/testing'; +import { provideNoopAnimations } from '@angular/platform-browser/animations'; +import { RouterTestingModule } from '@angular/router/testing'; import { TrainerHandlerService } from './trainer-handler.service'; describe('TrainerHandlerService', () => { - let service: TrainerHandlerService; - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(TrainerHandlerService); + TestBed.configureTestingModule({ + imports: [RouterTestingModule], + providers: [provideZonelessChangeDetection(), provideNoopAnimations(), TrainerHandlerService], + }); + }); + + const setup = () => { + const service = TestBed.inject(TrainerHandlerService); + return { service }; + }; + + it('should update isTrainerUnsaved status', () => { + const { service } = setup(); + expect(service.isTrainerUnsaved()).toBe(false); + + service['_statusMap']['trainer'].set(true); + + expect(service.isTrainerUnsaved()).toBe(true); }); - it('should be created', () => { - expect(service).toBeTruthy(); + it('should update isTrainerSpellUnsaved status', () => { + const { service } = setup(); + expect(service.isTrainerSpellUnsaved()).toBe(false); + + service['_statusMap']['trainer_spell'].set(true); + + expect(service.isTrainerSpellUnsaved()).toBe(true); }); }); diff --git a/libs/features/trainer/src/trainer-spell/trainer-spell.service.spec.ts b/libs/features/trainer/src/trainer-spell/trainer-spell.service.spec.ts new file mode 100644 index 00000000000..e24c685394c --- /dev/null +++ b/libs/features/trainer/src/trainer-spell/trainer-spell.service.spec.ts @@ -0,0 +1,48 @@ +import { provideZonelessChangeDetection } from '@angular/core'; +import { TestBed } from '@angular/core/testing'; +import { provideNoopAnimations } from '@angular/platform-browser/animations'; +import { RouterTestingModule } from '@angular/router/testing'; +import { MysqlQueryService } from '@keira/shared/db-layer'; +import { ToastrModule } from 'ngx-toastr'; +import { instance, mock } from 'ts-mockito'; +import { TrainerHandlerService } from '../trainer-handler.service'; +import { TrainerSpellService } from './trainer-spell.service'; + +describe('TrainerSpellService', () => { + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ToastrModule.forRoot(), RouterTestingModule], + providers: [ + provideZonelessChangeDetection(), + provideNoopAnimations(), + { provide: MysqlQueryService, useValue: instance(mock(MysqlQueryService)) }, + TrainerHandlerService, + ], + }); + }); + + const setup = () => { + const service = TestBed.inject(TrainerSpellService); + return { service }; + }; + + it('should be created', () => { + const { service } = setup(); + expect(service).toBeTruthy(); + }); + + it('should have correct entity table', () => { + const { service } = setup(); + expect(service['_entityTable']).toBe('trainer_spell'); + }); + + it('should have correct entity id field', () => { + const { service } = setup(); + expect(service['_entityIdField']).toBe('TrainerId'); + }); + + it('should have correct entity second id field', () => { + const { service } = setup(); + expect(service['_entitySecondIdField']).toBe('SpellId'); + }); +}); diff --git a/libs/features/trainer/tsconfig.spec.json b/libs/features/trainer/tsconfig.spec.json index 9a55f0ed5ac..b864ec66ae9 100644 --- a/libs/features/trainer/tsconfig.spec.json +++ b/libs/features/trainer/tsconfig.spec.json @@ -1,10 +1,9 @@ { "extends": "./tsconfig.json", "compilerOptions": { - "outDir": "../../../dist/out-tsc", - "module": "commonjs", + "outDir": "../out-tsc/spec", "types": ["jasmine", "node"] }, - "files": ["src/test-setup.ts"], - "include": ["**/*.spec.ts", "**/*.test.ts", "**/*.d.ts"] + "include": ["**/*.spec.ts", "**/*.d.ts"], + "exclude": ["dist", "release", "node_modules"] }