Tourismustal: Megabauwerke + Figuren-Feinschliff

- Merge-Mechanik: 4 gleiche 1x1-Gebaeude im Quadrat verschmelzen zum
  2x2-Megabauwerk. Skaleneffekt als Lernmoment: 4-fache Leistung, nur
  3-fache Betriebskosten (Erklaerkarte beim ersten Mal). Level = Maximum
  der Teile, Abriss-Erloes auf 4-fachem Bauwert, Bahnen/Bus/Bikepark
  ausgenommen. Rendering zentriert und 1.75x skaliert.
- Gaeste stehen nicht mehr im Wasser (dwell auf Wasser -> sofort ans Ufer).
- Skifahrer schimpft "#*!", wenn ihm der Schnee unterm Ski ausgeht.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-11 10:43:06 +02:00
parent 727e82c8fe
commit 2591f37191
3 changed files with 84 additions and 15 deletions
+48 -5
View File
@@ -345,7 +345,9 @@ export function place(state, type, c, r) {
}
state.nature = Math.max(15, state.nature - 2);
}
return { wasForest };
// 4 gleiche im Quadrat? → Megabauwerk (Skaleneffekt)
const merged = tryMerge(state, c, r);
return { wasForest, merged };
}
export function demolish(state, c, r) {
@@ -354,8 +356,10 @@ export function demolish(state, c, r) {
// Klick auf eine Teilfläche eines großen Gebäudes → auf den Anker umlenken
if (tile.buildingRef) { ({ c, r } = tile.buildingRef); tile = state.map[r][c]; }
const def = BUILDINGS[tile.building];
const size = def.size || 1;
const refund = Math.round(def.cost * 0.3);
const entry = state.buildings.find(b => b.c === c && b.r === r);
const size = entry?.size || def.size || 1;
// Mega = 4 verschmolzene Gebäude → 4-facher Bauwert als Abriss-Basis
const refund = Math.round(def.cost * (entry?.mega ? 4 : 1) * 0.3);
state.money += refund;
state.nature = Math.min(100, state.nature + 1);
state.buildings = state.buildings.filter(b => !(b.c === c && b.r === r));
@@ -369,6 +373,7 @@ export function demolish(state, c, r) {
t.building = null;
t.level = null;
delete t.buildingRef;
delete t.mega;
}
}
return { ok: true, refund, name };
@@ -380,7 +385,44 @@ export const UPGRADABLE = Object.keys(BUILDINGS);
function effVal(b, key) {
const v = BUILDINGS[b.type][key] || 0;
return Math.round(v * (1 + 0.5 * ((b.level || 1) - 1)));
let val = v * (1 + 0.5 * ((b.level || 1) - 1));
// Megabauwerk (4 verschmolzene Gebäude): 4-fache Leistung, aber nur
// 3-fache Betriebskosten Skaleneffekt („economies of scale").
if (b.mega) val *= (key === 'upkeep' || key === 'staff') ? 3 : 4;
return Math.round(val);
}
// Verschmelzen: liegen 4 gleiche 1×1-Gebäude im 2×2-Quadrat, werden sie zu
// EINEM Megabauwerk (size 2, mega). Bahnen, Bus & Bikepark ausgenommen.
const MERGEABLE = ['restaurant', 'hotel', 'staffhouse', 'snow',
'badesee', 'sled', 'ropes', 'playground', 'bikerental', 'trail'];
function tryMerge(state, c, r) {
const type = state.map[r]?.[c]?.building;
if (!type || !MERGEABLE.includes(type)) return null;
const at = (cc, rr) => state.buildings.find(b =>
b.c === cc && b.r === rr && b.type === type
&& (b.size || 1) === 1 && !b.mega && !b.underConstruction);
// alle 4 möglichen Quadrate, die (c,r) enthalten
for (const [ac, ar] of [[c, r], [c - 1, r], [c, r - 1], [c - 1, r - 1]]) {
const parts = [at(ac, ar), at(ac + 1, ar), at(ac, ar + 1), at(ac + 1, ar + 1)];
if (parts.some(p => !p)) continue;
const level = Math.max(...parts.map(p => p.level || 1));
// drei Teile entfernen, Anker wird Mega
const anchor = parts[0];
state.buildings = state.buildings.filter(b => b === anchor || !parts.includes(b));
anchor.size = 2; anchor.mega = true; anchor.level = level;
for (let dr = 0; dr < 2; dr++) {
for (let dc = 0; dc < 2; dc++) {
const t = state.map[ar + dr][ac + dc];
t.building = type;
t.level = level;
if (dr || dc) t.buildingRef = { c: ac, r: ar };
else { delete t.buildingRef; t.mega = true; }
}
}
return { type, name: BUILDINGS[type].name, c: ac, r: ar, level };
}
return null;
}
function dist(a, b) {
@@ -431,6 +473,7 @@ export function buildingReport(state, c, r) {
if (def.snowPower) lines.push(`Beschneiung: +${effVal(b, 'snowPower').toFixed(1)} cm/Tag`);
if (def.boost) lines.push(`Verstärker: Bikepark & Panoramaweg im Umkreis +${Math.round(def.boost * 100)} % Gäste`);
if (def.trailLen) lines.push(`Flowtrails: ${def.trailLen} Abschnitte talwärts`);
if (b.mega) lines.push('🏛️ Skaleneffekt: 4-fache Leistung, aber nur 3-fache Betriebskosten');
// Aktuelle Probleme dieses Gebäudes (erscheinen im Klick-Dialog)
const problems = [];
@@ -445,7 +488,7 @@ export function buildingReport(state, c, r) {
problems.push('💤 Nebensaison: ruht gerade die laufenden Kosten laufen (reduziert) weiter.');
return {
type: b.type, name: def.name, emoji: def.emoji, level,
type: b.type, name: b.mega ? `Mega-${def.name}` : def.name, emoji: def.emoji, level,
alt: b.alt ?? 3,
dailyUpkeep, dailyWage,
dailyCost: dailyUpkeep + dailyWage,