Tourismustal: 2x2-Gebaeude korrekt im Painter (vorderste Kachel zeichnet)

Grosse Gebaeude wurden von davorliegenden Kacheln uebermalt (Grasbueschel
ueber dem Hotelfuss). Jetzt zeichnet die VORDERSTE Footprint-Kachel das
Sprite, Terrain-Details entfallen auf bebauten Kacheln, Sprite-Mitte =
Mitte der 4 Kacheln, w/bottom so dass der Fuss die vordere Spitze deckt.
SQL-Migration audio_info MySQL-kompatibel (information_schema-Guard statt
MariaDB IF NOT EXISTS - Prod ist echtes MySQL).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-11 18:10:46 +02:00
parent 55a83d5daf
commit 328d542fdc
2 changed files with 41 additions and 17 deletions
@@ -1,7 +1,16 @@
-- ============================================================
-- class_modules.audio_info: Lehrer-Schalter für den Vorlese-Modus
-- (Audio-Info-Modus in Sims, derzeit Tourismustal). Default AN.
-- Stand: 2026-07-11 · Atlas · idempotent (MariaDB IF NOT EXISTS)
-- Stand: 2026-07-11 · Atlas
-- ACHTUNG: Prod ist echtes MySQL (kein MariaDB) → kein "IF NOT EXISTS"
-- bei ADD COLUMN. Guard über information_schema, damit idempotent.
-- ============================================================
ALTER TABLE class_modules
ADD COLUMN IF NOT EXISTS audio_info TINYINT(1) NOT NULL DEFAULT 1;
SET @exists := (SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'class_modules'
AND COLUMN_NAME = 'audio_info');
SET @ddl := IF(@exists = 0,
'ALTER TABLE class_modules ADD COLUMN audio_info TINYINT(1) NOT NULL DEFAULT 1',
'SELECT 1');
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
+29 -14
View File
@@ -35,17 +35,20 @@ const SPRITE_DEFS = {
access: { w: 52, bottom: 8 },
rescue: { w: 60, bottom: 9 },
snow: { w: 44, bottom: 7 },
bikepark: { w: 108, bottom: 14 }, // 2×2-Areal, zentriert gezeichnet
// 2×2-Areale: Mitte des Sprites = Mitte der 4 Kacheln; w/bottom so
// gewählt, dass der Fuß bis zur vorderen Kachel-Spitze reicht (~40 px
// unter dem Zentrum: bottom + 0.12·w ≈ 38).
bikepark: { w: 116, bottom: 24 },
// Megabauwerke: eigene Motive (mehr Elemente statt vergrößerter Fenster)
mega_restaurant: { w: 104, bottom: 12 },
mega_hotel: { w: 106, bottom: 12 },
mega_staffhouse: { w: 102, bottom: 12 },
mega_snow: { w: 96, bottom: 11 },
mega_badesee: { w: 110, bottom: 14 },
mega_ropes: { w: 106, bottom: 11 },
mega_playground: { w: 104, bottom: 12 },
mega_bikerental: { w: 98, bottom: 12 },
mega_trail: { w: 100, bottom: 11 },
mega_restaurant: { w: 116, bottom: 24 },
mega_hotel: { w: 118, bottom: 24 },
mega_staffhouse: { w: 114, bottom: 24 },
mega_snow: { w: 108, bottom: 24 },
mega_badesee: { w: 122, bottom: 26 },
mega_ropes: { w: 116, bottom: 22 },
mega_playground: { w: 116, bottom: 24 },
mega_bikerental: { w: 110, bottom: 24 },
mega_trail: { w: 112, bottom: 22 },
ropes: { w: 58, bottom: 8 },
bikerental: { w: 50, bottom: 8 },
platform: { w: 62, bottom: 9 },
@@ -1088,8 +1091,9 @@ export class IsoRenderer {
ctx.strokeStyle = 'rgba(47,62,70,0.06)';
ctx.stroke();
// kleine Details je Untergrund
if (!snowy && !tile.road) this._tileDetail(tile, x, y);
// kleine Details je Untergrund (nicht auf bebauten Kacheln sonst
// liegen Grasbüschel ÜBER dem Fuß großer 2×2-Gebäude)
if (!snowy && !tile.road && !tile.building) this._tileDetail(tile, x, y);
if (tile.terrain === 'water' && !tile.bridge) this._waterStreak(tile, x, y);
// Talstraße (bzw. Brücke über den Fluss)
@@ -1130,8 +1134,19 @@ export class IsoRenderer {
this._drawTree(x, y, snowy, tile.tint);
}
if (tile.deco) this._drawDeco(tile.deco, x, y);
// Große Gebäude (2×2) zeichnet nur die Anker-Kachel zentriert übers Areal
if (tile.building && !tile.buildingRef) this._drawBuilding(tile.building, x, y, tile);
// Gebäude: 1×1 zeichnet seine Kachel. Große (2×2) zeichnet die VORDERSTE
// Teil-Kachel (Painter-Reihenfolge!) sonst übermalen die davorliegenden
// Kacheln den Gebäudefuß. Gezeichnet wird zentriert über dem Areal.
if (tile.building) {
const a = tile.buildingRef || { c: tile.c, r: tile.r };
const at = this.state.map[a.r]?.[a.c];
const big = at && ((BUILDINGS[at.building]?.size || 1) > 1 || at.mega);
if (!big) {
if (!tile.buildingRef) this._drawBuilding(tile.building, x, y, tile);
} else if (tile.c === a.c + 1 && tile.r === a.r + 1) {
this._drawBuilding(at.building, x, y, at);
}
}
// Noch nicht erschlossene Hochlagen liegen unter Nebel
if (tile.r < this.state.stageRow) {