Files
bordervillegame/map_editor.html
T
2026-08-22 08:40:29 +02:00

318 lines
18 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<title>Map Editor</title>
<style>
* { box-sizing: border-box; }
html, body { margin: 0; height: 100%; background: #0a0a0a; color: #eee; font-family: Arial, sans-serif; overflow: hidden; }
#appLayout { display: flex; height: 100vh; width: 100vw; }
/* ---------- Linke Seite: Kopfzeile + Karte ---------- */
#mainArea { flex: 1; display: flex; flex-direction: column; min-width: 0; }
#topBar {
display: flex;
flex-wrap: wrap;
gap: 8px;
align-items: center;
padding: 8px 12px;
background: #1a1a1a;
border-bottom: 1px solid #333;
}
a.back { color: #6fbf73; text-decoration: none; font-size: 14px; margin-right: 6px; }
a.back:hover { text-decoration: underline; }
#topBar input, #topBar select, #topBar button {
background: #222; border: 1px solid #444; color: #eee;
padding: 6px 8px; border-radius: 4px; font-size: 13px;
}
#topBar button { background: #2c7a3d; cursor: pointer; border-color: #2c7a3d; }
#topBar button:hover { opacity: 0.85; }
#camLabel { color: #888; font-size: 12px; margin-left: auto; white-space: nowrap; }
#canvasWrap { flex: 1; position: relative; background: #000; min-height: 0; }
#canvas { display: block; position: absolute; top: 0; left: 0; }
#hintBar {
padding: 4px 12px;
background: #161616;
color: #777;
font-size: 11px;
border-top: 1px solid #2a2a2a;
}
/* ---------- Rechte Seite: Sidebar mit Tabs ---------- */
#sidebar {
width: 360px;
flex-shrink: 0;
background: #161616;
border-left: 1px solid #333;
display: flex;
flex-direction: column;
}
#sidebarTabs {
display: flex;
border-bottom: 1px solid #333;
}
.sidebar-tab-btn {
flex: 1;
background: #1a1a1a;
border: none;
border-right: 1px solid #333;
color: #999;
padding: 10px 4px;
font-size: 12px;
cursor: pointer;
}
.sidebar-tab-btn:last-child { border-right: none; }
.sidebar-tab-btn:hover { background: #222; }
.sidebar-tab-btn.active { background: #222; color: #f5d90a; border-bottom: 2px solid #f5d90a; }
#sidebarBody { flex: 1; overflow-y: auto; padding: 12px; }
.sidebar-panel { display: none; }
.sidebar-panel.active { display: block; }
.toolbar-group { margin-bottom: 14px; }
.toolbar-group-label {
font-size: 10px; color: #777; text-transform: uppercase;
letter-spacing: 0.5px; display: block; margin-bottom: 6px;
}
.toolbar-group-buttons { display: flex; flex-wrap: wrap; gap: 6px; }
.mode-btn {
width: 42px; height: 42px; font-size: 19px;
background: #2a2a2a; border: 2px solid #444; border-radius: 6px;
cursor: pointer; display: flex; align-items: center; justify-content: center;
}
.mode-btn:hover { border-color: #666; }
.mode-btn.active { border-color: #f5d90a; background: #3a3520; box-shadow: 0 0 6px rgba(245,217,10,0.5); }
#layerToggles { display: flex; flex-direction: column; gap: 8px; font-size: 13px; color: #ccc; }
#layerToggles label { display: flex; align-items: center; gap: 8px; cursor: pointer; }
#tilePalette, #objectPalette { display: flex; flex-wrap: wrap; gap: 6px; }
.tile-swatch {
width: 56px; border: 2px solid #000; border-radius: 4px; cursor: pointer;
display: flex; flex-direction: column; align-items: center; overflow: hidden;
background: #1a1a1a; font-family: Arial, sans-serif;
}
.tile-swatch .color-box { width: 100%; height: 32px; position: relative; }
.tile-swatch .collision-icon { position: absolute; top: 1px; right: 1px; font-size: 9px; text-shadow: 0 0 2px black; }
.tile-swatch .tile-label {
font-size: 9px; color: #ccc; padding: 2px; text-align: center;
white-space: nowrap; overflow: hidden; text-overflow: ellipsis; width: 100%;
}
.tile-swatch.selected { border-color: #f5d90a; box-shadow: 0 0 6px #f5d90a; }
.sidebar-section-title { color: #f5d90a; font-size: 13px; margin: 0 0 8px 0; }
.sidebar-hint { color: #777; font-size: 11px; margin-bottom: 10px; }
#shopEditor {
position: absolute; right: 10px; top: 60px; width: 200px;
background: rgba(20,20,20,0.9); color: white; padding: 10px;
border: 2px solid #444; border-radius: 6px;
}
</style>
</head>
<body>
<div id="appLayout">
<div id="mainArea">
<div id="topBar">
<a class="back" href="/index.html">&larr; Startseite</a>
<input type="text" id="mapName" placeholder="Map-Name (z.B. stadt)">
<select id="mapSelect"><option value="">Map laden...</option></select>
<button id="newMapBtn">Neue Map</button>
<button id="saveMapBtn">Speichern</button>
<input type="text" id="doorTargetMap" placeholder="Ziel-Map" style="width:110px;">
<input type="number" id="doorTargetX" placeholder="Ziel X" style="width:70px;">
<input type="number" id="doorTargetY" placeholder="Ziel Y" style="width:70px;">
<input type="number" id="mapWidth" placeholder="Breite" style="width:70px;">
<input type="number" id="mapHeight" placeholder="Höhe" style="width:70px;">
<button id="resizeMapBtn">Größe ändern</button>
<span id="camLabel"></span>
</div>
<div id="canvasWrap">
<canvas id="canvas" width="1500" height="800"></canvas>
</div>
<div id="hintBar">
Pfeiltasten oder mittlere Maustaste (gedrückt halten + ziehen) zum Scrollen. Linksklick = setzen, Rechtsklick = löschen (außer Tile-Modus: da malt Rechtsklick "leer"). Werkzeuge und Paletten jetzt rechts →
</div>
</div>
<div id="sidebar">
<div id="sidebarTabs">
<button class="sidebar-tab-btn active" data-sidebar-tab="modes">🛠️ Werkzeuge</button>
<button class="sidebar-tab-btn" data-sidebar-tab="layers">👁️ Ebenen</button>
<button class="sidebar-tab-btn" data-sidebar-tab="palette">🧱📦 Tiles &amp; Objekte</button>
</div>
<div id="sidebarBody">
<!-- WERKZEUGE -->
<div class="sidebar-panel active" id="panel-modes">
<select id="modeSelect" style="display:none;">
<option value="tile">Tiles setzen</option>
<option value="rotate">Tile drehen</option>
<option value="spawn">Spawn-Punkt setzen</option>
<option value="door">Tür/Portal setzen</option>
<option value="object">Objekte setzen</option>
<option value="shop">Shop setzen</option>
<option value="atm">ATM setzen</option>
<option value="garage">Garage setzen</option>
<option value="jobcenter">Jobcenter setzen</option>
<option value="clothingshop">Kleidungsladen setzen</option>
<option value="insuranceoffice">Versicherungsbüro setzen</option>
<option value="plateoffice">Kfz-Zulassungsstelle setzen</option>
<option value="trailershop">Anhänger-Shop setzen</option>
<option value="gasstation">Tankstelle setzen</option>
<option value="repairshop">Werkstatt setzen</option>
<option value="house">Haus setzen</option>
<option value="jobpoint">Job-Punkt setzen</option>
<option value="taxistand">Taxi-Stand setzen</option>
<option value="hospital">Krankenhaus setzen</option>
<option value="prison">Gefängnis setzen</option>
<option value="zone">Territoriums-Zone setzen</option>
<option value="impound">Abschlepphof setzen</option>
<option value="firestation">Feuerwache setzen</option>
<option value="drug_harvest">Anbaustelle setzen</option>
<option value="drug_process">Labor setzen</option>
<option value="drug_dealer">Verkaufsort (Pool) setzen</option>
</select>
<div class="toolbar-group">
<span class="toolbar-group-label">Terrain</span>
<div class="toolbar-group-buttons">
<button class="mode-btn" data-mode="tile" title="Tiles setzen">🧱</button>
<button class="mode-btn" data-mode="rotate" title="Tile drehen (Linksklick=+90°, Rechtsklick=-90°)">🔄</button>
<button class="mode-btn" data-mode="object" title="Objekte setzen">📦</button>
<button class="mode-btn" data-mode="spawn" title="Spawn-Punkt setzen">🚩</button>
<button class="mode-btn" data-mode="door" title="Tür/Portal setzen">🚪</button>
</div>
</div>
<div class="toolbar-group">
<span class="toolbar-group-label">Shops &amp; Gebäude</span>
<div class="toolbar-group-buttons">
<button class="mode-btn" data-mode="shop" title="Shop setzen">🛒</button>
<button class="mode-btn" data-mode="atm" title="ATM setzen">🏧</button>
<button class="mode-btn" data-mode="garage" title="Garage setzen">🚗</button>
<button class="mode-btn" data-mode="gasstation" title="Tankstelle setzen"></button>
<button class="mode-btn" data-mode="repairshop" title="Werkstatt setzen">🔧</button>
<button class="mode-btn" data-mode="house" title="Haus setzen">🏠</button>
<button class="mode-btn" data-mode="jobcenter" title="Jobcenter setzen">💼</button>
<button class="mode-btn" data-mode="clothingshop" title="Kleidungsladen setzen">👕</button>
<button class="mode-btn" data-mode="insuranceoffice" title="Versicherungsbüro setzen">🛡️</button>
<button class="mode-btn" data-mode="plateoffice" title="Kfz-Zulassungsstelle setzen">🔖</button>
<button class="mode-btn" data-mode="trailershop" title="Anhänger-Shop setzen">🚛</button>
</div>
</div>
<div class="toolbar-group">
<span class="toolbar-group-label">Verkehr</span>
<div class="toolbar-group-buttons">
<button class="mode-btn" data-mode="taxistand" title="Taxi-Stand setzen">🚕</button>
<button class="mode-btn" data-mode="jobpoint" title="Job-Punkt setzen">📍</button>
<button class="mode-btn" data-mode="impound" title="Abschlepphof setzen">🚛</button>
<button class="mode-btn" data-mode="firestation" title="Feuerwache setzen">🚒</button>
</div>
</div>
<div class="toolbar-group">
<span class="toolbar-group-label">Sicherheit</span>
<div class="toolbar-group-buttons">
<button class="mode-btn" data-mode="hospital" title="Krankenhaus setzen">🏥</button>
<button class="mode-btn" data-mode="prison" title="Gefängnis setzen">🔒</button>
<button class="mode-btn" data-mode="zone" title="Territoriums-Zone setzen">🚩</button>
</div>
</div>
<div class="toolbar-group">
<span class="toolbar-group-label">Drogen</span>
<div class="toolbar-group-buttons">
<button class="mode-btn" data-mode="drug_harvest" title="Anbaustelle setzen">🌿</button>
<button class="mode-btn" data-mode="drug_process" title="Labor setzen">⚗️</button>
<button class="mode-btn" data-mode="drug_dealer" title="Verkaufsort (Pool) setzen">💰</button>
</div>
</div>
</div>
<!-- EBENEN -->
<div class="sidebar-panel" id="panel-layers">
<h3 class="sidebar-section-title">Sichtbarkeit</h3>
<div id="layerToggles">
<label><input type="checkbox" class="layer-toggle" data-layer="object" checked> 📦 Objekte</label>
<label><input type="checkbox" class="layer-toggle" data-layer="shop" checked> 🛒 Shops</label>
<label><input type="checkbox" class="layer-toggle" data-layer="atm" checked> 🏧 ATMs</label>
<label><input type="checkbox" class="layer-toggle" data-layer="garage" checked> 🚗 Garagen</label>
<label><input type="checkbox" class="layer-toggle" data-layer="jobcenter" checked> 💼 Jobcenter</label>
<label><input type="checkbox" class="layer-toggle" data-layer="clothingshop" checked> 👕 Kleidungsläden</label>
<label><input type="checkbox" class="layer-toggle" data-layer="insuranceoffice" checked> 🛡️ Versicherungsbüros</label>
<label><input type="checkbox" class="layer-toggle" data-layer="plateoffice" checked> 🔖 Zulassungsstellen</label>
<label><input type="checkbox" class="layer-toggle" data-layer="trailershop" checked> 🚛 Anhänger-Shops</label>
<label><input type="checkbox" class="layer-toggle" data-layer="gasstation" checked> ⛽ Tankstellen</label>
<label><input type="checkbox" class="layer-toggle" data-layer="repairshop" checked> 🔧 Werkstätten</label>
<label><input type="checkbox" class="layer-toggle" data-layer="house" checked> 🏠 Häuser</label>
<label><input type="checkbox" class="layer-toggle" data-layer="jobpoint" checked> 📍 Job-Punkte</label>
<label><input type="checkbox" class="layer-toggle" data-layer="taxistand" checked> 🚕 Taxi-Stände</label>
<label><input type="checkbox" class="layer-toggle" data-layer="hospital" checked> 🏥 Krankenhäuser</label>
<label><input type="checkbox" class="layer-toggle" data-layer="prison" checked> 🔒 Gefängnisse</label>
<label><input type="checkbox" class="layer-toggle" data-layer="zone" checked> 🚩 Zonen</label>
<label><input type="checkbox" class="layer-toggle" data-layer="impound" checked> 🚛 Abschlepphöfe</label>
<label><input type="checkbox" class="layer-toggle" data-layer="firestation" checked> 🚒 Feuerwachen</label>
<label><input type="checkbox" class="layer-toggle" data-layer="drug_harvest" checked> 🌿 Anbaustellen</label>
<label><input type="checkbox" class="layer-toggle" data-layer="drug_process" checked> ⚗️ Labore</label>
<label><input type="checkbox" class="layer-toggle" data-layer="drug_dealer" checked> 💰 Verkaufsorte</label>
</div>
</div>
<!-- TILES & OBJEKTE -->
<div class="sidebar-panel" id="panel-palette">
<h3 class="sidebar-section-title">🧱 Tile-Palette</h3>
<div style="margin-bottom:12px;">
<label for="brushSize" style="color:#ccc; font-size:13px; display:block; margin-bottom:4px;">Pinselgröße:</label>
<select id="brushSize">
<option value="1">1×1</option>
<option value="2">2×2</option>
<option value="4">4×4</option>
<option value="6">6×6</option>
<option value="8">8×8</option>
</select>
<div class="sidebar-hint">Klicken und ziehen malt durchgehend. Drehen-Werkzeug (🔄) dreht Tile ODER Objekt an der angeklickten Stelle.</div>
</div>
<div id="tilePalette"></div>
<h3 class="sidebar-section-title" style="margin-top:20px;">📦 Objekt-Palette</h3>
<div id="objectPalette"></div>
</div>
</div>
</div>
</div>
<script src="map_editor.js?v=26"></script>
<script>
// Sidebar-Tabs umschalten
document.querySelectorAll(".sidebar-tab-btn").forEach(btn => {
btn.addEventListener("click", () => {
document.querySelectorAll(".sidebar-tab-btn").forEach(b => b.classList.remove("active"));
document.querySelectorAll(".sidebar-panel").forEach(p => p.classList.remove("active"));
btn.classList.add("active");
document.getElementById("panel-" + btn.dataset.sidebarTab).classList.add("active");
});
});
// Canvas füllt den verfügbaren Platz aus, statt fest 1500x800 zu sein
function resizeEditorCanvas() {
const wrap = document.getElementById("canvasWrap");
const canvas = document.getElementById("canvas");
canvas.width = wrap.clientWidth;
canvas.height = wrap.clientHeight;
if (typeof render === "function") render();
}
window.addEventListener("resize", resizeEditorCanvas);
window.addEventListener("load", resizeEditorCanvas);
// Direkt beim Einbinden schon einmal versuchen (falls load-Event schon vorbei ist)
setTimeout(resizeEditorCanvas, 50);
</script>
</body>
</html>