Atlas: Deploy-Buendel vor Staustufen-Sprint
- Logistik: Musik-Player Playlist-Modus (5 Gruppen, 20 Tracks) - Heli: End-Screen auf .ggs-endscreen, Mission-Bilder, Voice-Lines, Briefing-Audio - Logistik: Layout-Tausch Auftraege+Fahrzeuge links, Karte rechts - Logistik: Tier-1-Staedte ausgebaut, Auto-Timescale-Badge - Logistik: Roadnet/Railnet Dijkstra-Routing, Balance-Updates - Atlas: 5 Atlas-Inbox-Nachrichten (Cards-Pattern, DALL-E-Key, Musik-Playlists) - Status-Updates Heli + Logistik Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -16,7 +16,7 @@
|
||||
import { KlimawaechterGame } from './game'
|
||||
|
||||
interface PlacedObject {
|
||||
type: 'tree' | 'solar' | 'wind' | 'green-roof' | 'dike' | 'sea-wall'
|
||||
type: 'tree' | 'solar' | 'wind' | 'green-roof' | 'dike' | 'sea-wall' | 'bikes' | 'mangrove' | 'sand-fill' | 'coal' | 'airport' | 'cloud-seed'
|
||||
x: number // 0..1
|
||||
scale: number
|
||||
ownerId: string
|
||||
@@ -184,13 +184,14 @@ export class KlimawaechterRenderer {
|
||||
return { type: 'green-roof', x: 0, scale: 1, ownerId: stableId, builtTick: tick }
|
||||
}
|
||||
if (id === 'dike') {
|
||||
const slot = index % 4
|
||||
const x = 0.83 + slot * 0.035
|
||||
// Deiche breiter entlang der Kueste verteilen
|
||||
const x = 0.55 + index * 0.06 + this.seededRand(index * 41 + 9) * 0.02
|
||||
return { type: 'dike', x, scale: 1, ownerId: stableId, builtTick: tick }
|
||||
}
|
||||
if (id === 'sea-wall') {
|
||||
const x = 0.95
|
||||
return { type: 'sea-wall', x, scale: 1 + index * 0.08, ownerId: stableId, builtTick: tick }
|
||||
// Mehrere Mauern entlang der Kueste verteilen
|
||||
const x = 0.6 + index * 0.07 + this.seededRand(index * 29 + 3) * 0.03
|
||||
return { type: 'sea-wall', x, scale: 1, ownerId: stableId, builtTick: tick }
|
||||
}
|
||||
if (id === 'bikes') {
|
||||
return { type: 'bikes', x: 0.35 + index * 0.04, scale: 1, ownerId: stableId, builtTick: tick }
|
||||
@@ -200,8 +201,9 @@ export class KlimawaechterRenderer {
|
||||
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 }
|
||||
// Entlang der ganzen Kuestenlinie verteilen
|
||||
const x = 0.55 + index * 0.06 + this.seededRand(index * 37 + 5) * 0.03
|
||||
return { type: 'sand-fill', x, scale: 1 + this.seededRand(index * 19) * 0.3, ownerId: stableId, builtTick: tick }
|
||||
}
|
||||
if (id === 'coal') {
|
||||
return { type: 'coal', x: 0.12, scale: 1 + index * 0.05, ownerId: stableId, builtTick: tick }
|
||||
@@ -468,16 +470,22 @@ export class KlimawaechterRenderer {
|
||||
|
||||
// ===== KÜSTENBAUWERKE =====
|
||||
for (const obj of this.placed.filter(p => p.type === 'sand-fill')) {
|
||||
// Sand-Aufschüttung: kleine Hügel an der Wasserlinie
|
||||
// Sand-Aufschüttung: sichtbare Hügel an der Wasserlinie
|
||||
const sx = obj.x * W, sy = seaY
|
||||
const sc = obj.scale
|
||||
ctx.fillStyle = '#d4c090'
|
||||
ctx.beginPath()
|
||||
ctx.ellipse(sx, sy, 12, 5, 0, Math.PI, 0)
|
||||
ctx.ellipse(sx, sy, 16 * sc, 7 * sc, 0, Math.PI, 0)
|
||||
ctx.fill()
|
||||
ctx.fillStyle = '#c8b480'
|
||||
ctx.beginPath()
|
||||
ctx.ellipse(sx + 8, sy, 8, 3, 0, Math.PI, 0)
|
||||
ctx.ellipse(sx + 10 * sc, sy, 10 * sc, 4 * sc, 0, Math.PI, 0)
|
||||
ctx.fill()
|
||||
// Rand
|
||||
ctx.strokeStyle = '#b8a470'; ctx.lineWidth = 0.5
|
||||
ctx.beginPath()
|
||||
ctx.ellipse(sx, sy, 16 * sc, 7 * sc, 0, Math.PI, 0)
|
||||
ctx.stroke()
|
||||
}
|
||||
for (const obj of this.placed.filter(p => p.type === 'mangrove')) {
|
||||
// Mangroven: grüne Büsche an der Uferlinie
|
||||
@@ -521,18 +529,20 @@ export class KlimawaechterRenderer {
|
||||
}
|
||||
// Flughafen
|
||||
for (const obj of this.placed.filter(p => p.type === 'airport')) {
|
||||
const ax = obj.x * W, ay = groundY - 8
|
||||
const ax = obj.x * W, ay = groundY + 4 // weiter unten, nicht auf der Strasse
|
||||
// Landebahn
|
||||
ctx.fillStyle = '#5a5a5a'; ctx.fillRect(ax - 18, ay, 36, 4)
|
||||
ctx.fillStyle = '#5a5a5a'; ctx.fillRect(ax - 20, ay, 40, 5)
|
||||
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.beginPath(); ctx.moveTo(ax - 18, ay + 2.5); ctx.lineTo(ax + 18, ay + 2.5); 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
|
||||
// Helikopter auf der Landebahn (klein)
|
||||
ctx.font = '8px serif'; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'
|
||||
ctx.fillText('🚁', ax, ay + 2.5)
|
||||
// Fliegender Helikopter oben
|
||||
const flyX = ax + Math.sin(this.t * 0.3) * 50
|
||||
const flyY = ay - 25 - Math.abs(Math.sin(this.t * 0.3)) * 25
|
||||
ctx.font = '6px serif'
|
||||
ctx.fillText('🚁', flyX, flyY)
|
||||
}
|
||||
// Wolkenimpfung
|
||||
for (const obj of this.placed.filter(p => p.type === 'cloud-seed')) {
|
||||
|
||||
Reference in New Issue
Block a user