Remove T6 Grief and Turned map selections

This commit is contained in:
2026-10-07 22:49:01 -04:00
parent 6146bef51d
commit a223180835
8 changed files with 30 additions and 15 deletions
+1 -1
View File
@@ -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
@@ -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;
+1 -8
View File
@@ -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[] {
@@ -181,7 +181,7 @@
<label>Game<select bind:value={scopeGame} disabled={busy || !scopeLoaded} onchange={() => scopeMap = ''}><option value="">Choose a game…</option>{#each scopeOptions.games as g}<option value={g}>{gameTitle(g)}</option>{/each}</select></label>
{#if scopeType === 'map'}<label>Map<select bind:value={scopeMap} disabled={busy || !scopeGame}><option value="">Choose a map…</option>{#each scopeOptions.mapsByGame[scopeGame] ?? [] as m}<option value={m}>{mapLabel(m)}</option>{/each}</select></label>{/if}
{#if scopeValue}<p class="note">{matches.length} matching servers: {matches.map(s => s.name).join(', ') || 'None'}</p>{/if}
{#if scopeType === 'map' && scopeGame === 't6'}<p class="note">Map scope includes every server using this engine map, including its Survival, Grief, or other variants.</p>{/if}
{#if scopeType === 'map' && scopeGame === 't6'}<p class="note">Map scope includes every server using this engine map, including its Survival variants.</p>{/if}
{:else}<p class="note">Unscoped scripts deploy only to explicitly selected beta targets.</p>{/if}
<p class="note">Existing scripts keep their current scope.</p>
{/if}
+12
View File
@@ -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: '' };
+10
View File
@@ -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 });
+2 -2
View File
@@ -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 },
] },
]);
});
+1 -1
View File
@@ -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', () => {