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:
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user