diff --git a/App/game.html b/App/game.html
index 9bacac4..61f6412 100644
--- a/App/game.html
+++ b/App/game.html
@@ -56,7 +56,7 @@
/* === CENTER: Game Canvas + Controls === */
.center { display:flex; flex-direction:column; gap:.6rem; }
- .canvas-wrap { background:var(--white); border-radius:14px; border:1px solid rgba(0,0,0,.05); overflow:hidden; box-shadow:0 4px 16px rgba(0,0,0,.05); position:relative; }
+ .canvas-wrap { background:var(--white); border-radius:14px; border:1px solid rgba(0,0,0,.05); overflow:visible; box-shadow:0 4px 16px rgba(0,0,0,.05); position:relative; min-height:450px; }
/* Tutorial Overlay */
.tutorial-overlay { position:absolute; inset:0; background:rgba(15,30,40,.85); backdrop-filter:blur(8px); display:flex; align-items:center; justify-content:center; z-index:10; padding:1.5rem; }
diff --git a/App/src/sims/sim-05-treibhaus/game-renderer.ts b/App/src/sims/sim-05-treibhaus/game-renderer.ts
index 11c7f3a..5b40dbe 100644
--- a/App/src/sims/sim-05-treibhaus/game-renderer.ts
+++ b/App/src/sims/sim-05-treibhaus/game-renderer.ts
@@ -192,6 +192,26 @@ export class KlimawaechterRenderer {
const x = 0.95
return { type: 'sea-wall', x, scale: 1 + index * 0.08, ownerId: stableId, builtTick: tick }
}
+ if (id === 'bikes') {
+ return { type: 'bikes', x: 0.35 + index * 0.04, scale: 1, ownerId: stableId, builtTick: tick }
+ }
+ if (id === 'mangrove') {
+ const x = 0.75 + index * 0.03
+ return { type: 'mangrove', x, scale: baseScale, ownerId: stableId, builtTick: tick }
+ }
+ if (id === 'sand-fill') {
+ const x = 0.82 + index * 0.025
+ return { type: 'sand-fill', x, scale: 1, ownerId: stableId, builtTick: tick }
+ }
+ if (id === 'coal') {
+ return { type: 'coal', x: 0.12, scale: 1 + index * 0.05, ownerId: stableId, builtTick: tick }
+ }
+ if (id === 'airport') {
+ return { type: 'airport', x: 0.55, scale: 1, ownerId: stableId, builtTick: tick }
+ }
+ if (id === 'cloud-seed') {
+ return { type: 'cloud-seed', x: 0.5, scale: 1, ownerId: stableId, builtTick: tick }
+ }
return { type: 'tree', x: 0.5, scale: 1, ownerId: stableId, builtTick: tick }
}
@@ -312,9 +332,9 @@ export class KlimawaechterRenderer {
// === VULKAN mit Gletscher-Deckel (links, ragt aus der Landschaft) ===
const volcanoBaseX = W * 0.16
const volcanoBaseY = landSurface(volcanoBaseX) - 2
- const volcanoHeight = 120
- const volcanoHalfBase = 55
- const volcanoTopHalf = 14
+ const volcanoHeight = 95 // flacher
+ const volcanoHalfBase = 65 // breiter
+ const volcanoTopHalf = 16 // breitere Spitze
// Fels
ctx.fillStyle = `rgb(${106 + tempStress * 20},${90 + tempStress * 10},${74})`
ctx.beginPath()
@@ -337,8 +357,9 @@ export class KlimawaechterRenderer {
const glacierBaseY = volcanoBaseY - (volcanoHeight - glacierFullH + glacierFullH - glacierH)
const grime = (1 - glacierFraction) * 40
// Die Deckel-Form ist ein Trapez, breiter als der Vulkan-Top
- const capBottomHalf = (volcanoTopHalf + 6) * (0.5 + glacierFraction * 0.5)
- const capTopHalf = volcanoTopHalf * (0.6 + glacierFraction * 0.4)
+ // Breiter: Eis deckt die gesamte Spitze ab (keine braunen Raender)
+ const capBottomHalf = (volcanoTopHalf + 12) * (0.6 + glacierFraction * 0.4)
+ const capTopHalf = (volcanoTopHalf + 4) * (0.7 + glacierFraction * 0.3)
ctx.fillStyle = `rgb(${240 - grime},${246 - grime},${250 - grime})`
ctx.beginPath()
ctx.moveTo(volcanoBaseX - capBottomHalf, glacierBaseY)
@@ -445,13 +466,88 @@ export class KlimawaechterRenderer {
}
ctx.globalAlpha = 1
- // ===== DEICHE & MAUERN =====
+ // ===== KÜSTENBAUWERKE =====
+ for (const obj of this.placed.filter(p => p.type === 'sand-fill')) {
+ // Sand-Aufschüttung: kleine Hügel an der Wasserlinie
+ const sx = obj.x * W, sy = seaY
+ ctx.fillStyle = '#d4c090'
+ ctx.beginPath()
+ ctx.ellipse(sx, sy, 12, 5, 0, Math.PI, 0)
+ ctx.fill()
+ ctx.fillStyle = '#c8b480'
+ ctx.beginPath()
+ ctx.ellipse(sx + 8, sy, 8, 3, 0, Math.PI, 0)
+ ctx.fill()
+ }
+ for (const obj of this.placed.filter(p => p.type === 'mangrove')) {
+ // Mangroven: grüne Büsche an der Uferlinie
+ const mx = obj.x * W, my = seaY - 4
+ ctx.fillStyle = '#2a6a3a'
+ ctx.beginPath(); ctx.arc(mx, my, 6 * obj.scale, 0, Math.PI * 2); ctx.fill()
+ ctx.fillStyle = '#3a8a4a'
+ ctx.beginPath(); ctx.arc(mx + 4, my - 2, 4 * obj.scale, 0, Math.PI * 2); ctx.fill()
+ // Wurzeln im Wasser
+ ctx.strokeStyle = '#3a5a2a'; ctx.lineWidth = 1
+ ctx.beginPath(); ctx.moveTo(mx - 3, my + 3); ctx.lineTo(mx - 5, my + 10); ctx.stroke()
+ ctx.beginPath(); ctx.moveTo(mx + 2, my + 3); ctx.lineTo(mx + 4, my + 8); ctx.stroke()
+ }
for (const obj of this.placed.filter(p => p.type === 'dike')) {
this.drawDike(ctx, obj.x * W, groundY)
}
for (const obj of this.placed.filter(p => p.type === 'sea-wall')) {
this.drawSeaWall(ctx, obj.x * W, groundY - 18, baseSeaY)
}
+ // Kohlekraftwerk: vor dem Vulkan
+ for (const obj of this.placed.filter(p => p.type === 'coal')) {
+ const cx = obj.x * W, cy = this.landSurfaceFn(obj.x * W) - 5
+ ctx.fillStyle = '#5a5a5a'
+ ctx.fillRect(cx - 10, cy - 12, 20, 12)
+ // Schornstein
+ ctx.fillStyle = '#4a4a4a'
+ ctx.fillRect(cx + 4, cy - 22, 6, 12)
+ // Rauch
+ ctx.fillStyle = 'rgba(80,80,80,0.3)'
+ ctx.beginPath(); ctx.arc(cx + 7, cy - 26 - Math.sin(this.t) * 3, 4, 0, Math.PI * 2); ctx.fill()
+ ctx.beginPath(); ctx.arc(cx + 9, cy - 32 - Math.sin(this.t * 0.7) * 4, 3, 0, Math.PI * 2); ctx.fill()
+ }
+ // Radwege: Fahrräder auf der Strasse (vor den Häusern)
+ for (const obj of this.placed.filter(p => p.type === 'bikes')) {
+ const bx = obj.x * W, by = groundY - 2
+ // Kleines Fahrrad-Symbol
+ ctx.strokeStyle = '#4a8a4a'; ctx.lineWidth = 1.2
+ ctx.beginPath(); ctx.arc(bx - 3, by, 2.5, 0, Math.PI * 2); ctx.stroke()
+ ctx.beginPath(); ctx.arc(bx + 3, by, 2.5, 0, Math.PI * 2); ctx.stroke()
+ ctx.beginPath(); ctx.moveTo(bx - 3, by); ctx.lineTo(bx, by - 3); ctx.lineTo(bx + 3, by); ctx.stroke()
+ }
+ // Flughafen
+ for (const obj of this.placed.filter(p => p.type === 'airport')) {
+ const ax = obj.x * W, ay = groundY - 8
+ // Landebahn
+ ctx.fillStyle = '#5a5a5a'; ctx.fillRect(ax - 18, ay, 36, 4)
+ ctx.strokeStyle = '#fff'; ctx.lineWidth = 0.5; ctx.setLineDash([3, 2])
+ ctx.beginPath(); ctx.moveTo(ax - 16, ay + 2); ctx.lineTo(ax + 16, ay + 2); ctx.stroke()
+ ctx.setLineDash([])
+ // Flugzeug
+ const flyX = ax + Math.sin(this.t * 0.3) * 40
+ const flyY = ay - 15 - Math.abs(Math.sin(this.t * 0.3)) * 20
+ ctx.fillStyle = '#eee'; ctx.globalAlpha = 0.7
+ ctx.beginPath(); ctx.ellipse(flyX, flyY, 6, 1.5, Math.sin(this.t * 0.3) * 0.3, 0, Math.PI * 2); ctx.fill()
+ ctx.globalAlpha = 1
+ }
+ // Wolkenimpfung
+ for (const obj of this.placed.filter(p => p.type === 'cloud-seed')) {
+ // Spezialwolke mit Partikeln
+ const cx = W * 0.5 + Math.sin(this.t * 0.2) * 30, cy = H * 0.12
+ ctx.fillStyle = 'rgba(200,220,240,0.4)'
+ ctx.beginPath(); ctx.ellipse(cx, cy, 20, 8, 0, 0, Math.PI * 2); ctx.fill()
+ ctx.beginPath(); ctx.ellipse(cx - 10, cy + 2, 14, 6, 0, 0, Math.PI * 2); ctx.fill()
+ // Partikel
+ ctx.fillStyle = 'rgba(180,200,220,0.3)'
+ for (let i = 0; i < 4; i++) {
+ const px = cx - 8 + i * 5 + Math.sin(this.t + i) * 2
+ ctx.beginPath(); ctx.arc(px, cy + 10 + Math.sin(this.t * 2 + i) * 3, 1.5, 0, Math.PI * 2); ctx.fill()
+ }
+ }
// ===== BEWOHNER =====
const popLossPct = Math.max(0, 10000 - snap.resources.population) / 10000