From a2231808358ef6be3e130eac35e5453b88276167 Mon Sep 17 00:00:00 2001 From: Josh Wright Date: Wed, 7 Oct 2026 22:49:01 -0400 Subject: [PATCH] Remove T6 Grief and Turned map selections --- docs/guides/autoscaling.md | 2 +- .../player-achievements-and-visual-refresh-plan.md | 4 ++-- src/lib/map-aliases.ts | 9 +-------- src/lib/ui/components/ScriptUploadDrawer.svelte | 2 +- tests/unit/autoscaling-game.test.ts | 12 ++++++++++++ tests/unit/map-aliases.test.ts | 10 ++++++++++ tests/unit/ui-collection-summary.test.ts | 4 ++-- tests/unit/ui-identity-status.test.ts | 2 +- 8 files changed, 30 insertions(+), 15 deletions(-) diff --git a/docs/guides/autoscaling.md b/docs/guides/autoscaling.md index 68c3f35..1d7d6ff 100644 --- a/docs/guides/autoscaling.md +++ b/docs/guides/autoscaling.md @@ -4,7 +4,7 @@ Open **Fleet → Autoscaling** to keep empty lobbies available for new groups. P Autoscaling is opt-in. Installing the feature creates no policies and changes no lobby counts. Choose On and save a policy to enable autoscaling. -T5 game-wide policies cover the ten standard Zombies maps. Dead Ops Arcade is not supported. +T5 game-wide policies cover the ten standard Zombies maps; T6 policies cover nine co-op map selections. Dead Ops Arcade, Grief, and Turned are not supported. ## Configure a policy diff --git a/docs/plans/player-achievements-and-visual-refresh-plan.md b/docs/plans/player-achievements-and-visual-refresh-plan.md index 1fc4f7b..1704b5f 100644 --- a/docs/plans/player-achievements-and-visual-refresh-plan.md +++ b/docs/plans/player-achievements-and-visual-refresh-plan.md @@ -192,8 +192,8 @@ emblems: a theater marquee for Kino, a rocket for Ascension, a moon for Moon, prison bars for Mob, and excavation/gears for Origins. Complete the catalog with the same simple line or silhouette style and a neutral custom-map fallback. -Maps sharing an environment may share artwork, while Survival, Grief, Turned, -and other variants retain explicit names. Historical views resolve identity from +Maps sharing an environment may share artwork, while supported Survival +variants retain explicit names. Historical views resolve identity from their stored game/map key and variant, never from a replacement live server. An ambiguous engine map must use a fallback rather than inventing a variant. Extend `MatchDetail`, `PlayerMatch`, and their queries with the stored map key; diff --git a/src/lib/map-aliases.ts b/src/lib/map-aliases.ts index db5b86f..22fed8a 100644 --- a/src/lib/map-aliases.ts +++ b/src/lib/map-aliases.ts @@ -44,14 +44,7 @@ export const T6_ZOMBIE_MAPS: readonly ZombieMapEntry[] = Object.freeze([ { friendly: 'Die Rise', slug: 'highrise', canonical: 'zm_highrise', gameSettings: 'zm_classic_rooftop.cfg' }, { friendly: 'Mob of the Dead', slug: 'prison', canonical: 'zm_prison', gameSettings: 'zm_classic_prison.cfg' }, { friendly: 'Buried', slug: 'buried', canonical: 'zm_buried', gameSettings: 'zm_classic_processing.cfg' }, - { friendly: 'Origins', slug: 'tomb', canonical: 'zm_tomb', gameSettings: 'zm_classic_tomb.cfg' }, - { friendly: 'Town Grief', slug: 'towngrief', canonical: 'zm_transit', gameSettings: 'zm_grief_town.cfg' }, - { friendly: 'Farm Grief', slug: 'farmgrief', canonical: 'zm_transit', gameSettings: 'zm_grief_farm.cfg' }, - { friendly: 'Bus Depot Grief', slug: 'busdepotgrief', canonical: 'zm_transit', gameSettings: 'zm_grief_transit.cfg' }, - { friendly: 'Cell Block Grief', slug: 'cellblock', canonical: 'zm_prison', gameSettings: 'zm_grief_cellblock.cfg' }, - { friendly: 'Buried Grief', slug: 'buriedgrief', canonical: 'zm_buried', gameSettings: 'zm_grief_street.cfg' }, - { friendly: 'Diner Turned', slug: 'diner', canonical: 'zm_transit_dr', gameSettings: 'zm_cleansed_diner.cfg' }, - { friendly: 'Buried Turned', slug: 'buriedturned', canonical: 'zm_buried', gameSettings: 'zm_cleansed_street.cfg' } + { friendly: 'Origins', slug: 'tomb', canonical: 'zm_tomb', gameSettings: 'zm_classic_tomb.cfg' } ]); export function zombieMaps(game: string | null): readonly ZombieMapEntry[] { diff --git a/src/lib/ui/components/ScriptUploadDrawer.svelte b/src/lib/ui/components/ScriptUploadDrawer.svelte index f087321..372f594 100644 --- a/src/lib/ui/components/ScriptUploadDrawer.svelte +++ b/src/lib/ui/components/ScriptUploadDrawer.svelte @@ -181,7 +181,7 @@ {#if scopeType === 'map'}{/if} {#if scopeValue}

{matches.length} matching servers: {matches.map(s => s.name).join(', ') || 'None'}

{/if} - {#if scopeType === 'map' && scopeGame === 't6'}

Map scope includes every server using this engine map, including its Survival, Grief, or other variants.

{/if} + {#if scopeType === 'map' && scopeGame === 't6'}

Map scope includes every server using this engine map, including its Survival variants.

{/if} {:else}

Unscoped scripts deploy only to explicitly selected beta targets.

{/if}

Existing scripts keep their current scope.

{/if} diff --git a/tests/unit/autoscaling-game.test.ts b/tests/unit/autoscaling-game.test.ts index 9609847..96ab15e 100644 --- a/tests/unit/autoscaling-game.test.ts +++ b/tests/unit/autoscaling-game.test.ts @@ -30,6 +30,18 @@ async function setup() { return { db, scaling }; } +it('satisfies a T6 game-wide policy with nine co-op maps and rejects Grief and Turned selections', () => { + const now = 2_000_000; + const policy: ScalingPolicy = { ...scalingSettings(settings), id: 'policy', revision: 1, pausedReason: null, updatedAt: '' }; + const members: ScalingMember[] = maps.map(map => ({ name: `t6_zombie_${map.slug}_1`, mapSlug: map.slug, + identity: map.slug, state: 'empty', players: 0, observedAt: now, source: 'rcon', emptySince: 1, blocker: null, operationId: null })); + const snapshot = { members, reservedNames: members.map(m => m.name), keyPool: { total: 20, available: 11 }, blockers: [] }; + expect(planScaling(policy, snapshot, now)).toMatchObject({ action: 'wait', server: null, desired: 9, deficit: 0, empty: 9 }); + for (const mapSlug of ['towngrief', 'farmgrief', 'busdepotgrief', 'cellblock', 'buriedgrief', 'diner', 'buriedturned']) { + expect(() => scalingSettings({ ...settings, mapSlug })).toThrow('supported game and map'); + } +}); + it('applies targets and spare deficits independently to every map', () => { const now = 2_000_000; const policy: ScalingPolicy = { ...scalingSettings(settings), id: 'policy', revision: 1, pausedReason: null, updatedAt: '' }; diff --git a/tests/unit/map-aliases.test.ts b/tests/unit/map-aliases.test.ts index 1e6ee01..6701169 100644 --- a/tests/unit/map-aliases.test.ts +++ b/tests/unit/map-aliases.test.ts @@ -3,12 +3,22 @@ import { parseServerName, selectedZombieMap, t5ZombieMapBySlug, + zombieMapBySlug, T5_ZOMBIE_MAPS, T6_ZOMBIE_MAPS } from '../../src/lib/server/fleet/map-aliases.js'; import { serverTitle } from '../../src/lib/ui/server-labels.js'; describe('T6 map identity', () => { + it.each([ + ['towngrief', 'zm_transit'], ['farmgrief', 'zm_transit'], ['busdepotgrief', 'zm_transit'], + ['cellblock', 'zm_prison'], ['buriedgrief', 'zm_buried'], ['diner', 'zm_transit_dr'], ['buriedturned', 'zm_buried'] + ])('excludes %s without falling back to a supported variant of the same engine map', (slug, canonical) => { + expect(zombieMapBySlug('t6', slug)).toBeUndefined(); + expect(selectedZombieMap('t6', canonical, slug)).toBeUndefined(); + expect(parseServerName(`t6_zombie_${slug}_1`)?.mapCanonical).toBeNull(); + }); + it.each(T6_ZOMBIE_MAPS)('parses and labels $friendly without losing its variant', (map) => { const name = `t6_zombie_${map.slug}_2`; expect(parseServerName(name)).toMatchObject({ game: 't6', gameMode: 'zombie', mapCanonical: map.canonical, mapSlug: map.slug, lobby: 2 }); diff --git a/tests/unit/ui-collection-summary.test.ts b/tests/unit/ui-collection-summary.test.ts index 66dd25b..0fe6839 100644 --- a/tests/unit/ui-collection-summary.test.ts +++ b/tests/unit/ui-collection-summary.test.ts @@ -79,14 +79,14 @@ describe('collection map summaries', () => { retainedServers: ['t6_zombie_town_1'], removals: [ { name: 't5_zombie_moon_1', reason: 'Outside collection' }, { name: 't6_zombie_farm_1', reason: 'Outside collection' }, - { name: 't6_zombie_town_grief_1', reason: 'Outside collection' }, + { name: 't6_zombie_bus_depot_survival_1', reason: 'Outside collection' }, ] }); expect(collectionMapGroups(plan)).toEqual([ { game: 't5', label: 'Black Ops I', rows: [{ key: 't5:moon', mapName: 'Moon', target: 0, existing: 1, create: 0, remove: 1 }] }, { game: 't6', label: 'Black Ops II', rows: [ { key: 't6:town', mapName: 'Town Survival', target: 1, existing: 1, create: 0, remove: 0 }, { key: 't6:farm', mapName: 'Farm Survival', target: 0, existing: 1, create: 0, remove: 1 }, - { key: 't6:towngrief', mapName: 'Town Grief', target: 0, existing: 1, create: 0, remove: 1 }, + { key: 't6:busdepot', mapName: 'Bus Depot Survival', target: 0, existing: 1, create: 0, remove: 1 }, ] }, ]); }); diff --git a/tests/unit/ui-identity-status.test.ts b/tests/unit/ui-identity-status.test.ts index 7805786..c4fa6b0 100644 --- a/tests/unit/ui-identity-status.test.ts +++ b/tests/unit/ui-identity-status.test.ts @@ -5,7 +5,7 @@ import { statusPresentation } from '../../src/lib/ui/status.js'; describe('operator-facing identities and states', () => { it('preserves lobby numbers and distinguishes T6 variants sharing an engine map', () => { expect(serverIdentity('t6_zombie_town_12')).toEqual({ map:'Town Survival', lobby:12, game:'Black Ops II' }); - expect(serverIdentity('t6_zombie_towngrief_2')).toEqual({ map:'Town Grief', lobby:2, game:'Black Ops II' }); + expect(serverIdentity('t6_zombie_farm_2')).toEqual({ map:'Farm Survival', lobby:2, game:'Black Ops II' }); expect(serverIdentity('custom-server')).toEqual({ map:'custom-server', lobby:null, game:'' }); }); it('keeps normal waiting neutral and distinguishes test success from promotion', () => {