diff --git a/src/scripts/main.js b/src/scripts/main.js index 9f3f1385..e80359e7 100644 --- a/src/scripts/main.js +++ b/src/scripts/main.js @@ -1180,7 +1180,6 @@ import * as detailingFuncs from './modules/details/legacy'; "Foreword Farm": stagingFuncs.addForewordFarmStage, "Furoma Rift": stagingFuncs.addFuromaRiftStage, "Gnawnian Express Station": stagingFuncs.addTrainStage, - "Iceberg": stagingFuncs.addIcebergStage, "Seasonal Garden": stagingFuncs.addSeasonalGardenStage, "Sunken City": stagingFuncs.addSunkenCityStage, "Toxic Spill": stagingFuncs.addToxicSpillStage, diff --git a/src/scripts/modules/stages/environments/iceberg.ts b/src/scripts/modules/stages/environments/iceberg.ts new file mode 100644 index 00000000..6511c8fb --- /dev/null +++ b/src/scripts/modules/stages/environments/iceberg.ts @@ -0,0 +1,41 @@ +import {type User} from '@scripts/types/hg'; +import {type IntakeMessage} from '@scripts/types/mhct'; +import {IcebergPhases, type IcebergPhase} from '@scripts/types/quests'; +import {type IStager} from '../stages.types'; + +export class IcebergStager implements IStager { + readonly environment: string = 'Iceberg'; + + readonly phaseToStage: Record = { + 'Treacherous Tunnels': '0-300ft', + 'Brutal Bulwark': '301-600ft', + 'Bombing Run': '601-1600ft', + 'The Mad Depths': '1601-1800ft', + 'Icewing\'s Lair': '1800ft', + 'Hidden Depths': '1801-2000ft', + 'The Deep Lair': '2000ft', + 'General': 'Generals', + }; + + /** + * Report the current distance / obstacle. + * TODO: Stage / hunt details for first & second icewing hunting? + */ + addStage(message: IntakeMessage, userPre: User, userPost: User, journal: unknown): void { + const quest = userPre.quests.QuestIceberg; + + if (!quest) { + throw new Error('QuestIceberg is undefined'); + } + + if (!this.isIcebergPhase(quest.current_phase)) { + throw new Error('Skipping unknown Iceberg stage'); + } + + message.stage = this.phaseToStage[quest.current_phase]; + } + + private isIcebergPhase(value: string): value is IcebergPhase { + return IcebergPhases.includes(value as IcebergPhase); + } +} diff --git a/src/scripts/modules/stages/index.ts b/src/scripts/modules/stages/index.ts index dbe38a83..feedef72 100644 --- a/src/scripts/modules/stages/index.ts +++ b/src/scripts/modules/stages/index.ts @@ -10,6 +10,7 @@ import {ForbiddenGroveStager} from './environments/forbiddenGrove'; import {FortRoxStager} from './environments/fortRox'; import {FungalCavernStager} from './environments/fungalCavern'; import {HarbourStager} from './environments/harbour'; +import {IcebergStager} from './environments/iceberg'; import {IceFortressStager} from './environments/iceFortress'; import {LabyrinthStager} from './environments/labyrinth'; import {LivingGardenStager} from './environments/livingGarden'; @@ -37,6 +38,7 @@ const stageModules: IStager[] = [ new FortRoxStager(), new FungalCavernStager(), new HarbourStager(), + new IcebergStager(), new IceFortressStager(), new LabyrinthStager(), new LivingGardenStager(), diff --git a/src/scripts/modules/stages/legacy.js b/src/scripts/modules/stages/legacy.js index d3cd4e2c..0980ea98 100644 --- a/src/scripts/modules/stages/legacy.js +++ b/src/scripts/modules/stages/legacy.js @@ -105,32 +105,6 @@ export function addSeasonalGardenStage(message, user, user_post, hunt) { } } -/** - * Report the current distance / obstacle. - * TODO: Stage / hunt details for first & second icewing hunting? - * @param {import("@scripts/types/mhct").IntakeMessage} message The message to be sent. - * @param {import("@scripts/types/hg").User} user The user state object, when the hunt was invoked (pre-hunt). - * @param {import("@scripts/types/hg").User} user_post The user state object, after the hunt. - * @param {unknown} hunt The journal entry corresponding to the active hunt. - */ -export function addIcebergStage(message, user, user_post, hunt) { - const quest = user.quests.QuestIceberg; - message.stage = (({ - "Treacherous Tunnels": "0-300ft", - "Brutal Bulwark": "301-600ft", - "Bombing Run": "601-1600ft", - "The Mad Depths": "1601-1800ft", - "Icewing's Lair": "1800ft", - "Hidden Depths": "1801-2000ft", - "The Deep Lair": "2000ft", - "General": "Generals", - })[quest.current_phase]); - - if (!message.stage) { - message.location = null; - } -} - /** * Report the zone and depth, if any. * @param {Object } message The message to be sent. diff --git a/tests/scripts/hunt-filter/exemptions/environments/iceberg.spec.ts b/tests/scripts/hunt-filter/exemptions/environments/iceberg.spec.ts index dbb3532e..636cb25f 100644 --- a/tests/scripts/hunt-filter/exemptions/environments/iceberg.spec.ts +++ b/tests/scripts/hunt-filter/exemptions/environments/iceberg.spec.ts @@ -1,5 +1,6 @@ import {IntakeRejectionEngine} from '@scripts/hunt-filter/engine'; -import {addIcebergStage} from '@scripts/modules/stages/legacy'; +import {IcebergStager} from '@scripts/modules/stages/environments/iceberg'; +import {IStager} from '@scripts/modules/stages/stages.types'; import {User} from '@scripts/types/hg'; import {IntakeMessage} from '@scripts/types/mhct'; import {LoggerService} from '@scripts/util/logger'; @@ -7,12 +8,12 @@ import {getDefaultIntakeMessage, getDefaultUser} from '@tests/scripts/hunt-filte describe('Iceberg exemptions', () => { let logger: LoggerService; - let stager: (message: IntakeMessage, pre: User, post: User, journal: unknown) => void; + let stager: IStager; let target: IntakeRejectionEngine; beforeEach(() => { logger = {} as LoggerService; - stager = addIcebergStage; + stager = new IcebergStager(); target = new IntakeRejectionEngine(logger); logger.debug = jest.fn(); @@ -93,8 +94,8 @@ describe('Iceberg exemptions', () => { /** Sets the pre and post message stage based on current pre and post user */ function calculateStage() { - stager(preMessage, preUser, {} as User, {}); - stager(postMessage, postUser, {} as User, {}); + stager.addStage(preMessage, preUser, {} as User, {}); + stager.addStage(postMessage, postUser, {} as User, {}); } }); diff --git a/tests/scripts/modules/stages/environments/iceberg.spec.ts b/tests/scripts/modules/stages/environments/iceberg.spec.ts new file mode 100644 index 00000000..25e63184 --- /dev/null +++ b/tests/scripts/modules/stages/environments/iceberg.spec.ts @@ -0,0 +1,58 @@ +import {IcebergStager} from "@scripts/modules/stages/environments/iceberg"; +import {User} from "@scripts/types/hg"; +import {IntakeMessage} from "@scripts/types/mhct"; + +describe('Iceberg Stages', () => { + it('should be for the "Iceberg" environment', () => { + const stager = new IcebergStager(); + expect(stager.environment).toBe('Iceberg'); + }); + + it.each` + phase | expected + ${'Treacherous Tunnels'} | ${'0-300ft'} + ${'Brutal Bulwark'} | ${'301-600ft'} + ${'Bombing Run'} | ${'601-1600ft'} + ${'The Mad Depths'} | ${'1601-1800ft'} + ${'Icewing\'s Lair'} | ${'1800ft'} + ${'Hidden Depths'} | ${'1801-2000ft'} + ${'The Deep Lair'} | ${'2000ft'} + ${'General'} | ${'Generals'} + `('should set stage to $expected when in the $phase phase', ({expected, phase}) => { + const stager = new IcebergStager(); + const message = {} as IntakeMessage; + const preUser = {quests: {QuestIceberg: { + current_phase: phase, + }}} as User; + const postUser = {} as User; + const journal = {}; + + stager.addStage(message, preUser, postUser, journal); + + expect(message.stage).toBe(expected); + }); + + it('should should throw on unknown phase', () => { + const stager = new IcebergStager(); + const message = {location: {}} as IntakeMessage; + const preUser = {quests: {QuestIceberg: { + current_phase: 'Aard\'s Lair', + }}} as unknown as User; + const postUser = {} as User; + const journal = {}; + + expect(() => stager.addStage(message, preUser, postUser, journal)) + .toThrow('Skipping unknown Iceberg stage'); + }); + + it.each([undefined, null])('should throw when QuestIceberg is %p', (state) => { + const stager = new IcebergStager(); + const message = {location: {}} as IntakeMessage; + const preUser = {quests: {QuestIceberg: state}} as User; + const postUser = {} as User; + const journal = {}; + + expect(() => stager.addStage(message, preUser, postUser, journal)) + .toThrow('QuestIceberg is undefined'); + }); +});