Files
geograsim/App/sims/tourismusregion/js/maps.js
T
Adminator 8047778a5b Tourismusregion: Komplett-Integration (zweite neue Sim, beta)
Wellenbasierte Routen-Sim (DefensegeograSimMac) nach dem Tourismustal-
Playbook integriert: Sim nach App/sims/tourismusregion (game.html,
Sprites 47MB->9.5MB, ohne Eigen-Backend/Editor/Dashboard/Keys),
Plattform-Hooks (GGS_LIVE_STATE mit Welle/Budget/Umwelt/Sterne/Lenkung,
Submit bei Partie-Ende mit fertigem 0-100-Score, GGS_TUTORIAL, Home-
Button, Musik leise). Wrapper + Modul-Detailseite. SQL: module_info
(beta, Karte), Glossar-Kernbegriff Besucherlenkung (+Bild, Leichte
Sprache) + 12 Zuordnungen, Lehrplan-Mapping auf tourismus-
raumentwicklung (primaer) + verkehrserziehung/systemisches-denken.
LEHRPLAN.md mit Schwerpunkt Besucherlenkung & Mobilitaet. Lehrer-
Backend: Benchmark (Sim-Score direkt), Live-Cockpit-Spalten,
needsHelp, Highlights.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 01:14:12 +02:00

326 lines
16 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Die 5 Wegkarten: je ein vorgerendertes 3D-Diorama (assets/maps/*.png,
// 1536×1024) mit handvermessenen Routen-Polylinien (Bild-Pixel), festen
// Bauplatz-Slots und optionalem Lift (Seilbahn zum Berg mit Rundweg oben).
// Zonen: standard · road (Parkplatz/Bus) · lake (Badesteg) · hang (Skilift)
// · berg (Almhütte/Aussicht, erst mit Lift erreichbar).
export const TILE2PX = 36; // 1 „Feld" Reichweite = 36 Bild-Pixel
export const MAPS = {
talschleife: {
id: 'talschleife', name: 'Talschleife', icon: '🏞️',
desc: 'Der Klassiker: ein Weg vom Westrand durchs Dorf zum Talausgang See und Berg locken abseits.',
image: 'assets/maps/talschleife.png', w: 1536, h: 1024,
routes: {
westost: {
entry: 'W', exit: 'SE',
points: [[304, 340], [301, 354], [302, 370], [312, 379], [330, 382],
[346, 390], [359, 398], [347, 383], [344, 364], [353, 350],
[368, 338], [384, 333], [400, 335], [419, 347], [430, 357],
[440, 367], [447, 376], [455, 396], [461, 414], [471, 435],
[477, 455], [477, 473], [485, 488], [502, 502], [515, 516],
[532, 532], [549, 541], [564, 544], [572, 531], [579, 544],
[594, 551], [611, 555], [624, 567], [626, 581], [624, 565],
[610, 554], [595, 550], [577, 554], [563, 564], [557, 576],
[549, 591], [552, 611], [562, 627], [568, 640], [576, 658],
[578, 677], [578, 695], [588, 711], [600, 726], [606, 742],
[616, 754], [626, 766], [640, 773], [652, 784], [666, 786],
[686, 784], [705, 788], [716, 800], [715, 816], [728, 816],
[741, 826], [754, 836], [768, 840], [779, 851], [795, 860],
[814, 865], [829, 874], [836, 886], [838, 889]],
},
gegenzug: {
entry: 'S', exit: 'E', reverseOf: 'westost',
},
},
entryRoutes: { W: ['westost'], N: ['westost'], S: ['gegenzug'] },
slots: [
{ x: 300, y: 292, zone: 'road' },
{ x: 245, y: 425, zone: 'road' },
{ x: 430, y: 378, zone: 'standard' },
{ x: 588, y: 298, zone: 'standard' },
{ x: 634, y: 372, zone: 'standard' },
{ x: 697, y: 397, zone: 'standard' },
{ x: 485, y: 595, zone: 'standard' },
{ x: 700, y: 713, zone: 'standard' },
{ x: 776, y: 742, zone: 'standard' },
{ x: 357, y: 619, zone: 'standard' },
{ x: 1235, y: 546, zone: 'standard' },
{ x: 545, y: 655, zone: 'standard' },
{ x: 900, y: 788, zone: 'standard' },
{ x: 261, y: 520, zone: 'standard' },
{ x: 885, y: 615, zone: 'lake' },
{ x: 1005, y: 782, zone: 'lake' },
{ x: 987, y: 381, zone: 'hang' },
{ x: 888, y: 218, zone: 'berg' },
{ x: 1049, y: 296, zone: 'berg' },
],
lift: { topX: 952, topY: 168, loop: [[1000, 212], [935, 242]] },
},
seerunde: {
id: 'seerunde', name: 'Seerunde', icon: '🏖️',
desc: 'Ein Rundweg um den großen Bergsee Nord- oder Südufer? Beide Ströme wollen versorgt sein.',
image: 'assets/maps/seerunde.png', w: 1536, h: 1024,
routes: {
nordufer: {
entry: 'W', exit: 'E',
points: [[274, 784], [290, 768], [300, 756], [311, 746], [323, 733],
[336, 718], [348, 706], [359, 695], [368, 686], [378, 672],
[371, 658], [358, 646], [348, 636], [336, 629], [325, 622],
[308, 608], [302, 590], [310, 570], [322, 555], [336, 542],
[350, 532], [368, 523], [384, 519], [396, 509], [407, 499],
[420, 493], [436, 480], [445, 467], [451, 452], [454, 433],
[456, 411], [459, 389], [466, 370], [477, 353], [490, 338],
[510, 326], [522, 322], [535, 318], [550, 315], [566, 313],
[584, 312], [603, 311], [620, 311], [636, 311], [648, 311],
[668, 312], [683, 315], [698, 318], [714, 315], [734, 322],
[748, 328], [760, 332], [780, 338], [792, 340], [804, 343],
[818, 346], [830, 348], [850, 353], [866, 358], [882, 366],
[902, 372], [921, 374], [942, 377], [960, 380], [976, 384],
[991, 391], [1010, 406], [1020, 414], [1028, 424], [1035, 435],
[1040, 446], [1044, 459], [1045, 471], [1046, 484], [1050, 502],
[1063, 514], [1082, 522], [1100, 531], [1118, 543], [1130, 554],
[1144, 555], [1158, 562], [1167, 574], [1170, 588], [1170, 604],
[1163, 618], [1151, 633], [1137, 642], [1116, 652], [1100, 662],
[1086, 670], [1068, 676], [1052, 678], [1032, 684], [1014, 691],
[1000, 697], [977, 700], [965, 701], [942, 702], [930, 705],
[914, 712], [897, 720], [880, 723], [866, 728], [852, 738],
[837, 746], [822, 751], [814, 762], [808, 780], [796, 798],
[780, 813], [763, 821], [744, 824], [728, 831], [702, 837],
[689, 838], [664, 837], [649, 836], [636, 834], [624, 834],
[605, 831], [588, 826], [576, 816], [588, 812], [606, 814],
[588, 812], [572, 802], [563, 793], [563, 808], [550, 807],
[536, 799], [522, 785], [506, 770], [488, 756], [474, 746],
[457, 736], [449, 728], [440, 715], [429, 701], [415, 686],
[401, 678], [384, 679], [369, 690], [360, 699], [348, 710],
[336, 722], [323, 735], [311, 747], [300, 758], [292, 766],
[279, 779], [274, 784]],
},
suedufer: {
entry: 'S', exit: 'SE', lake: true,
points: [[274, 784], [290, 768], [300, 756], [311, 746], [323, 733],
[336, 718], [349, 706], [360, 696], [370, 688], [387, 680],
[403, 686], [416, 696], [427, 702], [443, 715], [462, 732],
[473, 743], [486, 756], [497, 766], [506, 776], [521, 789],
[534, 796], [552, 805], [568, 808], [588, 812], [604, 815],
[589, 809], [579, 817], [596, 828], [614, 832], [636, 834],
[649, 836], [664, 837], [677, 838], [700, 838], [718, 834],
[735, 826], [750, 822], [770, 818], [788, 807], [797, 798],
[808, 780], [812, 763], [830, 753], [845, 745], [860, 735],
[874, 725], [892, 717], [910, 713], [927, 706], [947, 700],
[959, 699], [973, 699], [991, 698], [1014, 693], [1026, 688],
[1038, 684], [1055, 678], [1070, 676], [1086, 664], [1105, 654],
[1120, 650], [1140, 641], [1157, 626], [1167, 610], [1170, 593],
[1169, 576], [1158, 565], [1144, 561], [1131, 550], [1114, 538],
[1104, 532], [1090, 528], [1079, 522], [1060, 513], [1050, 502],
[1044, 481], [1042, 467], [1039, 450], [1031, 430], [1018, 412],
[1000, 398], [990, 391], [978, 386], [960, 380], [942, 377],
[921, 374], [902, 372], [882, 366], [866, 359], [840, 351],
[827, 348], [806, 345], [785, 340], [766, 334], [748, 327],
[732, 320], [716, 316], [698, 315], [681, 316], [664, 312],
[647, 311], [626, 310], [612, 310], [600, 310], [580, 311],
[562, 312], [545, 315], [534, 318], [518, 325], [503, 334],
[488, 344], [474, 355], [464, 366], [456, 385], [452, 408],
[452, 421], [453, 435], [452, 448], [448, 460], [443, 471],
[436, 481], [420, 494], [402, 502], [388, 512], [372, 522],
[356, 527], [337, 538], [324, 548], [310, 566], [303, 588],
[308, 607], [326, 622], [336, 629], [348, 636], [358, 645],
[368, 655], [381, 669], [368, 687], [357, 697], [347, 708],
[335, 720], [321, 734], [309, 746], [299, 758], [291, 766],
[279, 779], [274, 784]],
},
},
entryRoutes: { W: ['nordufer'], N: ['nordufer'], S: ['suedufer'] },
slots: [
{ x: 255, y: 641, zone: 'road' },
{ x: 330, y: 800, zone: 'road' },
{ x: 395, y: 330, zone: 'standard' },
{ x: 520, y: 285, zone: 'standard' },
{ x: 700, y: 245, zone: 'standard' },
{ x: 966, y: 300, zone: 'standard' },
{ x: 1075, y: 385, zone: 'standard' },
{ x: 1230, y: 651, zone: 'standard' },
{ x: 620, y: 772, zone: 'standard' },
{ x: 900, y: 792, zone: 'standard' },
{ x: 1080, y: 720, zone: 'standard' },
{ x: 598, y: 346, zone: 'lake' },
{ x: 700, y: 655, zone: 'lake' },
{ x: 880, y: 635, zone: 'lake' },
],
},
serpentinen: {
id: 'serpentinen', name: 'Serpentinen', icon: '⛰️',
desc: 'Über den Berg ins Tal: langer Abstieg in Kehren die Seilbahn verbindet Dorf und Gipfelterrasse.',
image: 'assets/maps/serpentinen.png', w: 1536, h: 1024,
routes: {
kehren: {
entry: 'W', exit: 'SE',
points: [[355, 229], [357, 244], [362, 268], [367, 280], [379, 299],
[388, 308], [396, 318], [403, 329], [411, 340], [419, 351],
[432, 364], [446, 372], [463, 379], [480, 385], [498, 389],
[515, 392], [532, 394], [546, 396], [564, 401], [584, 406],
[601, 408], [619, 407], [640, 404], [664, 398], [677, 394],
[690, 390], [704, 384], [720, 377], [734, 372], [748, 367],
[761, 364], [774, 361], [786, 360], [798, 358], [819, 360],
[838, 362], [858, 362], [879, 363], [900, 370], [918, 378],
[936, 380], [945, 370], [952, 356], [950, 373], [939, 383],
[923, 385], [904, 375], [920, 378], [936, 378], [926, 393],
[916, 408], [895, 416], [881, 423], [869, 430], [858, 436],
[840, 446], [822, 455], [806, 462], [791, 467], [777, 472],
[757, 484], [747, 491], [732, 506], [724, 520], [716, 532],
[704, 542], [691, 557], [678, 569], [664, 583], [650, 593],
[635, 601], [614, 607], [602, 608], [584, 607], [566, 605],
[550, 604], [536, 604], [515, 608], [499, 617], [494, 630],
[503, 643], [513, 656], [526, 669], [542, 676], [557, 688],
[572, 704], [586, 712], [580, 731], [570, 740], [560, 752],
[549, 770], [544, 787], [548, 802], [561, 819], [558, 833],
[544, 848], [542, 868], [551, 884], [568, 898], [584, 911],
[598, 922], [601, 925]],
},
talwaerts: { entry: 'S', exit: 'E', reverseOf: 'kehren' },
},
entryRoutes: { W: ['kehren'], N: ['kehren'], S: ['talwaerts'] },
slots: [
{ x: 548, y: 901, zone: 'road' },
{ x: 725, y: 890, zone: 'road' },
{ x: 538, y: 325, zone: 'standard' },
{ x: 665, y: 436, zone: 'standard' },
{ x: 835, y: 428, zone: 'standard' },
{ x: 1006, y: 480, zone: 'standard' },
{ x: 415, y: 646, zone: 'standard' },
{ x: 303, y: 578, zone: 'standard' },
{ x: 695, y: 616, zone: 'standard' },
{ x: 855, y: 636, zone: 'standard' },
{ x: 1090, y: 780, zone: 'standard' },
{ x: 1087, y: 627, zone: 'hang' },
{ x: 845, y: 292, zone: 'berg' },
{ x: 951, y: 312, zone: 'berg' },
],
lift: { topX: 898, topY: 292, loop: [[858, 300], [938, 315]] },
},
kreuzung: {
id: 'kreuzung', name: 'Kreuzung', icon: '🛣️',
desc: 'Zwei Täler kreuzen sich am Dorfplatz: vier Ströme, ein Zentrum wer deckt alle Richtungen ab?',
image: 'assets/maps/kreuzung.png', w: 1536, h: 1024,
routes: {
nordsued: {
entry: 'N', exit: 'SE',
points: [[487, 255], [498, 264], [511, 276], [528, 292], [538, 300],
[546, 308], [556, 316], [565, 325], [575, 333], [585, 342],
[595, 350], [605, 360], [615, 368], [624, 376], [642, 391],
[658, 406], [674, 418], [687, 430], [698, 440], [712, 456],
[716, 477], [712, 494], [705, 510], [695, 528], [682, 546],
[668, 565], [660, 575], [650, 585], [642, 595], [633, 604],
[624, 614], [616, 623], [607, 632], [598, 642], [590, 650],
[580, 660], [572, 668], [563, 677], [547, 694], [532, 710],
[516, 727], [504, 740], [493, 752], [490, 755]],
},
westost: {
entry: 'W', exit: 'E',
points: [[135, 472], [158, 472], [174, 472], [189, 472], [207, 472],
[228, 472], [248, 472], [270, 472], [290, 472], [312, 472],
[332, 472], [354, 472], [374, 472], [396, 472], [416, 472],
[436, 472], [456, 472], [474, 472], [493, 472], [510, 471],
[527, 471], [543, 471], [559, 471], [575, 470], [591, 470],
[607, 470], [623, 470], [638, 471], [654, 471], [670, 471],
[686, 472], [701, 472], [717, 474], [732, 476], [748, 478],
[763, 481], [779, 484], [795, 488], [811, 492], [828, 495],
[844, 499], [862, 502], [879, 506], [897, 509], [916, 513],
[934, 517], [953, 521], [972, 524], [990, 528], [1010, 532],
[1028, 536], [1047, 539], [1066, 543], [1084, 547], [1103, 551],
[1122, 554], [1140, 558], [1160, 561], [1178, 564], [1197, 568],
[1216, 571], [1234, 574], [1253, 577], [1271, 580], [1289, 582],
[1306, 585], [1324, 587], [1340, 590], [1357, 592], [1373, 593],
[1387, 595], [1400, 596], [1418, 598], [1430, 600]],
},
},
entryRoutes: { W: ['westost'], N: ['nordsued'], S: ['nordsued'] },
slots: [
{ x: 425, y: 285, zone: 'road' },
{ x: 300, y: 694, zone: 'road' },
{ x: 645, y: 218, zone: 'standard' },
{ x: 330, y: 380, zone: 'standard' },
{ x: 545, y: 435, zone: 'standard' },
{ x: 933, y: 546, zone: 'standard' },
{ x: 760, y: 665, zone: 'standard' },
{ x: 610, y: 782, zone: 'standard' },
{ x: 890, y: 795, zone: 'standard' },
{ x: 1140, y: 640, zone: 'standard' },
{ x: 1180, y: 478, zone: 'standard' },
{ x: 1405, y: 465, zone: 'standard' },
{ x: 391, y: 512, zone: 'lake' },
{ x: 310, y: 611, zone: 'lake' },
],
},
passstrasse: {
id: 'passstrasse', name: 'Passstraße', icon: '🛤️',
desc: 'Ein langer Anstieg zum Pass, kaum Bauplätze: Hier zählt jede Standortentscheidung doppelt.',
image: 'assets/maps/passstrasse.png', w: 1536, h: 1024,
routes: {
bergauf: {
entry: 'W', exit: 'E',
points: [[700, 859], [687, 855], [684, 840], [692, 824], [705, 814],
[707, 798], [697, 789], [686, 774], [670, 758], [656, 748],
[643, 740], [629, 733], [614, 725], [600, 718], [582, 705],
[570, 690], [564, 675], [564, 660], [572, 643], [592, 626],
[603, 619], [624, 606], [638, 599], [649, 592], [669, 582],
[686, 574], [702, 569], [710, 584], [695, 593], [672, 603],
[656, 611], [642, 620], [658, 612], [669, 606], [688, 598],
[710, 590], [723, 585], [743, 578], [757, 571], [766, 559],
[779, 548], [794, 541], [811, 537], [828, 532], [843, 527],
[863, 517], [880, 510], [897, 514], [913, 511], [925, 498],
[928, 479], [927, 460], [922, 444], [910, 432], [888, 418],
[870, 408], [856, 400], [842, 388], [837, 374], [847, 356],
[859, 345], [870, 336], [890, 324], [909, 315], [926, 311],
[937, 304]],
},
bergab: { entry: 'S', exit: 'SE', reverseOf: 'bergauf' },
},
entryRoutes: { W: ['bergauf'], N: ['bergauf'], S: ['bergab'] },
slots: [
{ x: 562, y: 815, zone: 'road' },
{ x: 760, y: 875, zone: 'road' },
{ x: 300, y: 565, zone: 'standard' },
{ x: 415, y: 660, zone: 'standard' },
{ x: 560, y: 600, zone: 'standard' },
{ x: 850, y: 548, zone: 'standard' },
{ x: 905, y: 400, zone: 'standard' },
{ x: 1016, y: 330, zone: 'standard' },
],
},
};
// Editor-Overrides (js/maps-custom.json) über die eingebauten Daten legen:
// routes ersetzt die Punktlisten (entry/exit/lake-Flags bleiben erhalten,
// unbekannte Routen-IDs werden neu angelegt), slots ersetzt die Slot-Liste.
export function applyMapOverrides(overrides) {
if (!overrides) return;
for (const [mid, o] of Object.entries(overrides)) {
const def = MAPS[mid];
if (!def) continue;
if (o.routes) {
for (const [rk, pts] of Object.entries(o.routes)) {
if (!Array.isArray(pts) || pts.length < 2) continue;
if (def.routes[rk]) {
def.routes[rk] = { ...def.routes[rk], points: pts, reverseOf: undefined };
} else {
def.routes[rk] = { entry: 'W', exit: 'E', points: pts };
}
}
// reverseOf-Varianten zeigen ggf. auf ersetzte Routen bleibt gültig,
// solange die Basisroute existiert (prepMap löst sie auf)
}
if (Array.isArray(o.slots) && o.slots.length) {
def.slots = o.slots.map(s => ({ x: s.x, y: s.y, zone: s.zone || 'standard' }));
}
if (o.lift) def.lift = o.lift;
}
}
// Zubringer-Reihenfolge im Startbildschirm
export const MAP_ORDER = ['talschleife', 'seerunde', 'serpentinen', 'kreuzung', 'passstrasse'];