Files
djupet/src/map.ts

143 lines
5.1 KiB
TypeScript
Raw Normal View History

// Leaflet is loaded via CDN in index.html
// @ts-expect-error - Leaflet global
const L = window.L;
export interface MapMarker {
id: string;
lat: number;
lng: number;
label: string;
dreadLevel: number; // 0-3
}
interface LocationInfo {
lat: number;
lng: number;
label: string;
// A standing description of the place itself, shown in the art modal —
// distinct from LOCATION_VISITS' randomized per-visit outcome text in
// engine.ts, which changes every time. This doesn't.
blurb: string;
}
const LOCATIONS: Record<string, LocationInfo> = {
rosengard: {
lat: 55.5894, lng: 13.0414, label: 'Källaren i Rosengård',
blurb: 'Ett källarförråd som blev något annat. Ingen av er minns exakt när. Hyresvärden vet fortfarande inte om det.',
},
varnhem: {
lat: 55.5982, lng: 13.0058, label: 'Värnhemstorget',
blurb: 'Ett vanligt torg med spårvagnshållplats och krita på asfalten som inte suddas, hur mycket det än regnar.',
},
torso: {
lat: 55.6130, lng: 12.9758, label: 'Turning Torso',
blurb: 'Calatrava-Santiago ritade byggnaden som en vridande ryggrad. Det visade sig inte vara en metafor.',
},
oresund: {
lat: 55.5789, lng: 12.9200, label: 'Øresundsbron',
blurb: 'Bron till Danmark. Vattnet under den är stillare än det borde vara, oftare än det borde vara.',
},
ribersborg: {
lat: 55.6063, lng: 12.9652, label: 'Ribersborgsstranden',
blurb: 'En strand med kallbadhus och änder som står stilla i vattenbrynet, vända mot samma håll, oavsett väder.',
},
davidshall: {
lat: 55.5963, lng: 13.0021, label: 'Davidshallsgatan',
blurb: 'Ett bostadshus med kakel från 1923 i trapphuset. Kallt att röra vid, oavsett årstid.',
},
stortorget: {
lat: 55.6047, lng: 13.0038, label: 'Stortorget',
blurb: 'Stadens gamla torg, statyn i mitten, klockor på fasaderna runtom som sällan visar exakt samma tid.',
},
mollan: {
lat: 55.5904, lng: 13.0203, label: 'Möllevångstorget',
blurb: 'Marknad, dofter från femtio kök samtidigt, musik från tre högtalare som aldrig riktigt spelar samma låt.',
},
universitet: {
lat: 55.5721, lng: 12.9998, label: 'Malmö universitet',
blurb: 'Bibliotek och föreläsningssalar. Ett rum för sällan efterfrågade samlingar som er kod alltid fungerar till.',
},
};
export const LOCATION_INFO: Record<string, { label: string; blurb: string }> =
Object.fromEntries(Object.entries(LOCATIONS).map(([id, l]) => [id, { label: l.label, blurb: l.blurb }]));
Location thumbnails on the map, full-art archive mode, more content - Map markers now show a tiny thumbnail preview in their tooltip when art exists for that location (same missing-asset-is-fine fallback as character portraits — onerror just removes the broken img). - Two new locations, both free-roam from the start: Möllevångstorget and Malmö universitet (the latter ties into the researcher character's arc). VISITABLE_LOCATION_IDS picks them up automatically since it's derived from the data, not a separate list. - Sällskapet gets a second mode: "Fullständigt arkiv" shows every character's real portrait and bio regardless of story progress (bypassing the usedEventIds lock), and clicking any known portrait opens a lightbox at full size instead of the cropped card thumbnail. - All 9 character portraits are now in and wired (fixed two more filename mismatches along the way: anneli-karin and the rest use hyphens, not underscores, matching what was actually generated). - More content: 2 new location-visit variants each for the two new areas, 6 new Standard events (including a found 1930s photograph that seems to show Lindqvist in a room nobody recognizes), 4 new Kaos events tied to the new locations and existing ones. - Caught and fixed a bug in my own new content before commit: an event's requires.completedEventId pointed at an upgrade id, which can never appear in usedEventIds — switched to a minRitual check that actually gates on the right precondition. Verified: 15/15 tests, clean typecheck and build, and a real headless-browser pass — all 9 map markers present, full-archive mode correctly bypassing locks, and the lightbox opening at full size with a caption. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-01 21:09:43 +02:00
// Optional tiny preview shown in each location's tooltip — same
// missing-asset-is-fine convention as the character portraits. Path is
// tried once per marker; a 404 just means the tooltip falls back to text.
const THUMB = (id: string): string => `/img/locations/${id}.png`;
type LeafletMap = ReturnType<typeof L.map>;
type LeafletMarker = ReturnType<typeof L.circleMarker>;
let map: LeafletMap | null = null;
const markers = new Map<string, LeafletMarker>();
function dreadColor(level: number): string {
return ['#1a1a2e', '#4a1a4a', '#8b0a8b', '#cc00cc'][Math.min(level, 3)];
}
function dreadRadius(level: number): number {
return [6, 10, 16, 24][Math.min(level, 3)];
}
export function initMap(containerId: string, onClick: (id: string) => void): void {
if (!L) return;
map = L.map(containerId, {
center: [55.597, 13.002],
zoom: 12,
zoomControl: false,
attributionControl: false,
});
L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png', {
maxZoom: 18,
}).addTo(map);
for (const [id, loc] of Object.entries(LOCATIONS)) {
const m = L.circleMarker([loc.lat, loc.lng], {
radius: 6,
color: '#1a1a2e',
fillColor: '#1a1a2e',
fillOpacity: 0.3,
weight: 1,
Location thumbnails on the map, full-art archive mode, more content - Map markers now show a tiny thumbnail preview in their tooltip when art exists for that location (same missing-asset-is-fine fallback as character portraits — onerror just removes the broken img). - Two new locations, both free-roam from the start: Möllevångstorget and Malmö universitet (the latter ties into the researcher character's arc). VISITABLE_LOCATION_IDS picks them up automatically since it's derived from the data, not a separate list. - Sällskapet gets a second mode: "Fullständigt arkiv" shows every character's real portrait and bio regardless of story progress (bypassing the usedEventIds lock), and clicking any known portrait opens a lightbox at full size instead of the cropped card thumbnail. - All 9 character portraits are now in and wired (fixed two more filename mismatches along the way: anneli-karin and the rest use hyphens, not underscores, matching what was actually generated). - More content: 2 new location-visit variants each for the two new areas, 6 new Standard events (including a found 1930s photograph that seems to show Lindqvist in a room nobody recognizes), 4 new Kaos events tied to the new locations and existing ones. - Caught and fixed a bug in my own new content before commit: an event's requires.completedEventId pointed at an upgrade id, which can never appear in usedEventIds — switched to a minRitual check that actually gates on the right precondition. Verified: 15/15 tests, clean typecheck and build, and a real headless-browser pass — all 9 map markers present, full-archive mode correctly bypassing locks, and the lightbox opening at full size with a caption. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-01 21:09:43 +02:00
}).addTo(map).bindTooltip(
`<div class="map-tooltip-inner">
<img class="map-tooltip-thumb" src="${THUMB(id)}" alt=""
Location thumbnails on the map, full-art archive mode, more content - Map markers now show a tiny thumbnail preview in their tooltip when art exists for that location (same missing-asset-is-fine fallback as character portraits — onerror just removes the broken img). - Two new locations, both free-roam from the start: Möllevångstorget and Malmö universitet (the latter ties into the researcher character's arc). VISITABLE_LOCATION_IDS picks them up automatically since it's derived from the data, not a separate list. - Sällskapet gets a second mode: "Fullständigt arkiv" shows every character's real portrait and bio regardless of story progress (bypassing the usedEventIds lock), and clicking any known portrait opens a lightbox at full size instead of the cropped card thumbnail. - All 9 character portraits are now in and wired (fixed two more filename mismatches along the way: anneli-karin and the rest use hyphens, not underscores, matching what was actually generated). - More content: 2 new location-visit variants each for the two new areas, 6 new Standard events (including a found 1930s photograph that seems to show Lindqvist in a room nobody recognizes), 4 new Kaos events tied to the new locations and existing ones. - Caught and fixed a bug in my own new content before commit: an event's requires.completedEventId pointed at an upgrade id, which can never appear in usedEventIds — switched to a minRitual check that actually gates on the right precondition. Verified: 15/15 tests, clean typecheck and build, and a real headless-browser pass — all 9 map markers present, full-archive mode correctly bypassing locks, and the lightbox opening at full size with a caption. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-01 21:09:43 +02:00
onerror="this.remove()">
<span>${loc.label}</span>
</div>`,
{ className: 'map-tooltip', permanent: false },
);
m.on('click', () => onClick(id));
markers.set(id, m);
}
}
export function updateMap(dread: number, areas: { rosengard: boolean; varnhem: boolean; torso: boolean }): void {
if (!map) return;
const levels: Record<string, number> = {
rosengard: areas.rosengard ? Math.min(3, Math.floor(dread / 40) + 1) : Math.min(1, Math.floor(dread / 60)),
varnhem: areas.varnhem ? Math.min(3, Math.floor(dread / 35) + 1) : 0,
torso: areas.torso ? 3 : Math.min(1, Math.floor(dread / 80)),
oresund: Math.min(2, Math.floor(dread / 50)),
ribersborg: Math.min(2, Math.floor(dread / 45)),
davidshall: Math.min(1, Math.floor(dread / 70)),
stortorget: Math.min(2, Math.floor(dread / 55)),
Location thumbnails on the map, full-art archive mode, more content - Map markers now show a tiny thumbnail preview in their tooltip when art exists for that location (same missing-asset-is-fine fallback as character portraits — onerror just removes the broken img). - Two new locations, both free-roam from the start: Möllevångstorget and Malmö universitet (the latter ties into the researcher character's arc). VISITABLE_LOCATION_IDS picks them up automatically since it's derived from the data, not a separate list. - Sällskapet gets a second mode: "Fullständigt arkiv" shows every character's real portrait and bio regardless of story progress (bypassing the usedEventIds lock), and clicking any known portrait opens a lightbox at full size instead of the cropped card thumbnail. - All 9 character portraits are now in and wired (fixed two more filename mismatches along the way: anneli-karin and the rest use hyphens, not underscores, matching what was actually generated). - More content: 2 new location-visit variants each for the two new areas, 6 new Standard events (including a found 1930s photograph that seems to show Lindqvist in a room nobody recognizes), 4 new Kaos events tied to the new locations and existing ones. - Caught and fixed a bug in my own new content before commit: an event's requires.completedEventId pointed at an upgrade id, which can never appear in usedEventIds — switched to a minRitual check that actually gates on the right precondition. Verified: 15/15 tests, clean typecheck and build, and a real headless-browser pass — all 9 map markers present, full-archive mode correctly bypassing locks, and the lightbox opening at full size with a caption. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-01 21:09:43 +02:00
mollan: Math.min(2, Math.floor(dread / 48)),
universitet: Math.min(2, Math.floor(dread / 65)),
};
for (const [id, marker] of markers) {
const level = levels[id] ?? 0;
marker.setStyle({
radius: dreadRadius(level),
color: dreadColor(level),
fillColor: dreadColor(level),
fillOpacity: 0.15 + level * 0.2,
weight: level > 0 ? 2 : 1,
});
}
}