Tourismustal: Naturwert aktiv zurueckgewinnen (Oeko-Umbau + Aufforsten)

Antwort auf die Design-Frage 'Naturwert zurueck ausser weniger bauen':
- Oeko-Umbau pro Gebaeude (Button im Gebaeude-Dialog): einmalig, 40 % des
  Bauwerts, dafuer -20 % Betriebskosten, +2 Naturwert, Gebaeude belastet
  die taegliche Natur-Regeneration nicht mehr. Sichtbar: Solardach-Overlay
  (auch auf Megabauwerken, 1,6x). Didaktik: Investition vs. laufende
  Kosten, nachhaltiges Wirtschaften (GW 4.10).
- Aufforsten als wiederholbare Aktion im Baumenue (1.500 Euro): pflanzt
  Wald auf freie Wiese/Alm/Feld, +3 Naturwert, Werkzeug bleibt aktiv fuer
  Serien-Pflanzung. Wissen: Renaturierung + Schutzwald (1/3 des
  oesterreichischen Walds).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-11 18:16:40 +02:00
parent 328d542fdc
commit d195b085d9
6 changed files with 105 additions and 5 deletions
+38 -3
View File
@@ -305,6 +305,9 @@ export function canPlace(state, type, c, r) {
if (type === 'platform' && tile.elev < 5) {
return { ok: false, reason: 'Die Aussichtsplattform braucht Aussicht hoch am Berg bauen (weiter oben)!' };
}
if (type === 'forest' && !['meadow', 'alm', 'field'].includes(tile.terrain)) {
return { ok: false, reason: 'Aufforsten geht nur auf freien Wiesen, Almen oder Feldern.' };
}
if (type === 'access') {
let nearRoad = false;
for (let rr = r - 1; rr <= r + 1 && !nearRoad; rr++) {
@@ -320,6 +323,14 @@ export function canPlace(state, type, c, r) {
export function place(state, type, c, r) {
const def = BUILDINGS[type];
const tile = state.map[r][c];
// Aktion statt Gebäude: Aufforsten pflanzt Wald auf die Kachel
if (def.action === 'plant') {
state.money -= def.cost;
tile.terrain = 'forest';
tile.deco = null;
state.nature = Math.min(100, state.nature + 3);
return { planted: true };
}
const wasForest = tile.terrain === 'forest';
const size = def.size || 1;
state.buildings.push({ type, c, r, alt: tile.elev, size });
@@ -476,7 +487,7 @@ export function buildingReport(state, c, r) {
const def = BUILDINGS[b.type];
const level = b.level || 1;
const sf = seasonFactor(b.type, state.season);
const dailyUpkeep = Math.round(effVal(b, 'upkeep') * sf);
const dailyUpkeep = Math.round(effVal(b, 'upkeep') * sf * (b.eco ? 0.8 : 1));
const dailyWage = Math.round(effVal(b, 'staff') * sf) * state.scenario.wage;
const lines = [];
if (def.cap) lines.push(`Förderleistung: ${effVal(b, 'cap')} Gäste/Tag`);
@@ -489,6 +500,7 @@ export function buildingReport(state, c, r) {
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');
if (b.eco) lines.push('🌱 Öko-Betrieb: 20 % Betriebskosten, schont die Natur (Solardach)');
// Aktuelle Probleme dieses Gebäudes (erscheinen im Klick-Dialog)
const problems = [];
@@ -513,6 +525,8 @@ export function buildingReport(state, c, r) {
knowledge: KNOWLEDGE[b.type] || [],
canUpgrade: level < MAX_LEVEL && !b.underConstruction,
nextCost: level < MAX_LEVEL ? upgradeCost(b.type, level) : null,
eco: !!b.eco,
ecoCost: b.eco ? null : Math.round(def.cost * 0.4 * (b.mega ? 4 : 1)),
};
}
@@ -521,6 +535,27 @@ export function upgradeCost(type, level) {
return Math.round(BUILDINGS[type].cost * (0.25 + 0.25 * level));
}
// Öko-Umbau: einmalig pro Gebäude. Teuer (40 % des Bauwerts), dafür 20 %
// Betriebskosten (Solar/Wärmepumpe), +2 Naturwert sofort, und das Gebäude
// belastet die tägliche Natur-Regeneration nicht mehr. Sichtbar: Solardach.
export function ecoUpgrade(state, c, r) {
const ref = state.map[r]?.[c]?.buildingRef;
if (ref) ({ c, r } = ref);
const tile = state.map[r]?.[c];
const b = state.buildings.find(x => x.c === c && x.r === r);
if (!tile?.building || !b) return { ok: false, reason: 'Hier steht kein Gebäude.' };
if (b.eco) return { ok: false, reason: 'Läuft schon als Öko-Betrieb.' };
if (b.underConstruction) return { ok: false, reason: 'Wird gerade umgebaut bitte warten.' };
const def = BUILDINGS[b.type];
const cost = Math.round(def.cost * 0.4 * (b.mega ? 4 : 1));
if (state.money < cost) return { ok: false, reason: `Öko-Umbau kostet ${cost.toLocaleString('de-AT')} nicht genug Geld.` };
state.money -= cost;
b.eco = true;
tile.eco = true;
state.nature = Math.min(100, state.nature + 2);
return { ok: true, cost, name: def.name };
}
export function upgrade(state, c, r) {
const ref = state.map[r]?.[c]?.buildingRef;
if (ref) ({ c, r } = ref);
@@ -767,7 +802,7 @@ export function simulateDay(state) {
// Betriebskosten je Gast (Liftstrom, Reinigung, Wäsche …): 55 % vom Umsatz
const opsCost = Math.round(income * 0.58);
const upkeep = Math.round(state.buildings.reduce((a, b) =>
a + effVal(b, 'upkeep') * seasonFactor(b.type, state.season), 0));
a + effVal(b, 'upkeep') * seasonFactor(b.type, state.season) * (b.eco ? 0.8 : 1), 0));
const wages = staffWorking * S.wage;
state.money = Math.round(state.money + income - opsCost - upkeep - wages - cannonCost);
state.lastNet = Math.round(income - opsCost - upkeep - wages - cannonCost);
@@ -791,7 +826,7 @@ export function simulateDay(state) {
// --- Natur erholt sich langsam ---
state.nature = Math.min(100,
state.nature + 0.04 - state.buildings.length * 0.004);
state.nature + 0.04 - state.buildings.filter(b => !b.eco).length * 0.004);
// --- Umbau-Fertigstellung (Fallback) ---
// Primär animiert der Renderer den Umbau (10 s Spielzeit = 5 Tage bei 1×)