2026-07-07 23:05:22 +02:00
|
|
|
// 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
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const LOCATIONS: Omit<MapMarker, 'dreadLevel'>[] = [
|
|
|
|
|
{ id: 'rosengard', lat: 55.5894, lng: 13.0414, label: 'Källaren i Rosengård' },
|
|
|
|
|
{ id: 'varnhem', lat: 55.5982, lng: 13.0058, label: 'Värnhemstorget' },
|
|
|
|
|
{ id: 'torso', lat: 55.6130, lng: 12.9758, label: 'Turning Torso' },
|
|
|
|
|
{ id: 'oresund', lat: 55.5789, lng: 12.9200, label: 'Øresundsbron' },
|
|
|
|
|
{ id: 'ribersborg',lat: 55.6063, lng: 12.9652, label: 'Ribersborgsstranden' },
|
|
|
|
|
{ id: 'davidshall',lat: 55.5963, lng: 13.0021, label: 'Davidshallsgatan' },
|
|
|
|
|
{ id: 'stortorget',lat: 55.6047, lng: 13.0038, label: 'Stortorget' },
|
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
|
|
|
{ id: 'mollan', lat: 55.5904, lng: 13.0203, label: 'Möllevångstorget' },
|
|
|
|
|
{ id: 'universitet', lat: 55.5721, lng: 12.9998, label: 'Malmö universitet' },
|
2026-07-07 23:05:22 +02:00
|
|
|
];
|
|
|
|
|
|
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`;
|
|
|
|
|
|
2026-07-07 23:05:22 +02:00
|
|
|
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)];
|
|
|
|
|
}
|
|
|
|
|
|
Add help modal, changelog, map visits, Dockerfile, CI
- Help modal (? button or keyboard shortcut): how-to-play in Swedish,
flavor text, full changelog sourced from src/data/version.ts
- src/data/version.ts: versioned changelog entries, in-universe Malmö voice
- Map zone clicks: each location on the Leaflet map is now clickable.
Unlocked cult areas give resources + log entries. Locked locations show
lore hints. 30s cooldown per location so it's a decision, not a spam button.
- Dockerfile + nginx.conf + docker-compose.yml (port 5684)
- Gitea CI workflow (identical to 2048 — derives image from repo path, needs
TKNTKN secret, pushes :latest and :sha tags)
- README.md with mechanics summary and docker instructions
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-07 23:31:37 +02:00
|
|
|
export function initMap(containerId: string, onClick: (id: string) => void): void {
|
2026-07-07 23:05:22 +02:00
|
|
|
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 loc of 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(loc.id)}" alt=""
|
|
|
|
|
onerror="this.remove()">
|
|
|
|
|
<span>${loc.label}</span>
|
|
|
|
|
</div>`,
|
|
|
|
|
{ className: 'map-tooltip', permanent: false },
|
|
|
|
|
);
|
Add help modal, changelog, map visits, Dockerfile, CI
- Help modal (? button or keyboard shortcut): how-to-play in Swedish,
flavor text, full changelog sourced from src/data/version.ts
- src/data/version.ts: versioned changelog entries, in-universe Malmö voice
- Map zone clicks: each location on the Leaflet map is now clickable.
Unlocked cult areas give resources + log entries. Locked locations show
lore hints. 30s cooldown per location so it's a decision, not a spam button.
- Dockerfile + nginx.conf + docker-compose.yml (port 5684)
- Gitea CI workflow (identical to 2048 — derives image from repo path, needs
TKNTKN secret, pushes :latest and :sha tags)
- README.md with mechanics summary and docker instructions
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-07 23:31:37 +02:00
|
|
|
m.on('click', () => onClick(loc.id));
|
2026-07-07 23:05:22 +02:00
|
|
|
markers.set(loc.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)),
|
2026-07-07 23:05:22 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
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,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|