From d0f33a5b4b7298938064d8e3724c9950bc044501 Mon Sep 17 00:00:00 2001 From: Mario Date: Sat, 22 Aug 2026 21:18:53 +0200 Subject: [PATCH] Anzeige von Area und Location Namen korrigiert --- .../de/blight/editor/ui/AreaEditorView.java | 40 ++--- .../de/blight/editor/ui/EditorNaming.java | 29 ++++ .../blight/editor/ui/LocationEditorView.java | 53 +++++++ .../java/de/blight/game/scene/WorldScene.java | 1 + .../de/blight/game/state/LocationState.java | 95 ++++++++---- .../de/blight/game/state/MusicSystem.java | 94 +----------- .../de/blight/game/state/NameBannerState.java | 140 ++++++++++++++++++ .../resources/lang/messages_de.properties | 5 + .../resources/lang/messages_en.properties | 5 + .../src/main/resources/lang/text_keys.txt | 5 + .../src/main/map/blight_location_zones.blz | 1 + blight-map/src/main/map/blight_locations.blo | 2 + 12 files changed, 337 insertions(+), 133 deletions(-) create mode 100644 blight-editor/src/main/java/de/blight/editor/ui/EditorNaming.java create mode 100644 blight-game/src/main/java/de/blight/game/state/NameBannerState.java create mode 100644 blight-map/src/main/map/blight_locations.blo diff --git a/blight-editor/src/main/java/de/blight/editor/ui/AreaEditorView.java b/blight-editor/src/main/java/de/blight/editor/ui/AreaEditorView.java index aadf79b..b518d34 100644 --- a/blight-editor/src/main/java/de/blight/editor/ui/AreaEditorView.java +++ b/blight-editor/src/main/java/de/blight/editor/ui/AreaEditorView.java @@ -58,7 +58,7 @@ public class AreaEditorView extends BorderPane { current = saved; reloading = false; persist(); - writeDefaultLocalisationIfAbsent(saved.id()); + writeDefaultLocalisation(saved.id()); } // ── Form panel ──────────────────────────────────────────────────────────── @@ -187,6 +187,7 @@ public class AreaEditorView extends BorderPane { private void createArea() { AreaDefinition d = new AreaDefinition(PREFIX + "neu_" + System.currentTimeMillis(), "", "", ""); areas.add(d); + writeDefaultLocalisation(d.id()); onSelected(current, d); } @@ -233,12 +234,12 @@ public class AreaEditorView extends BorderPane { // ── Localisation defaults ────────────────────────────────────────────────── - private void writeDefaultLocalisationIfAbsent(String fullId) { + private void writeDefaultLocalisation(String fullId) { if (fullId == null || fullId.isBlank()) return; String shortId = fullId.startsWith(PREFIX) ? fullId.substring(PREFIX.length()) : fullId; if (shortId.isBlank()) return; String key = fullId + ".name"; - String defaultName = Character.toUpperCase(shortId.charAt(0)) + shortId.substring(1); + String defaultName = EditorNaming.toDisplayName(shortId); Path langSrc = ProjectRoot.resolve("blight-lang", "src", "main", "resources", "lang"); Path[] langMirrors = { @@ -248,12 +249,11 @@ public class AreaEditorView extends BorderPane { for (String locale : new String[]{"de", "en"}) { Path src = langSrc.resolve("messages_" + locale + ".properties"); try { - if (appendKeyIfAbsent(src, key, defaultName)) { - for (Path mirrorDir : langMirrors) { - Path mirror = mirrorDir.resolve("messages_" + locale + ".properties"); - if (Files.exists(mirror)) { - Files.copy(src, mirror, StandardCopyOption.REPLACE_EXISTING); - } + writeOrUpdateKey(src, key, defaultName); + for (Path mirrorDir : langMirrors) { + Path mirror = mirrorDir.resolve("messages_" + locale + ".properties"); + if (Files.exists(mirror)) { + Files.copy(src, mirror, StandardCopyOption.REPLACE_EXISTING); } } } catch (IOException e) { @@ -262,20 +262,22 @@ public class AreaEditorView extends BorderPane { } } - /** Returns true if the key was absent and has been appended. */ - private static boolean appendKeyIfAbsent(Path file, String key, String value) throws IOException { - if (!Files.exists(file)) return false; + private static void writeOrUpdateKey(Path file, String key, String value) throws IOException { + if (!Files.exists(file)) return; String needle = key + "="; String needleSpace = key + " ="; - for (String line : Files.readAllLines(file, StandardCharsets.UTF_8)) { - String s = line.stripLeading(); - if (s.startsWith(needle) || s.startsWith(needleSpace)) return false; + java.util.List lines = new java.util.ArrayList<>(Files.readAllLines(file, StandardCharsets.UTF_8)); + boolean found = false; + for (int i = 0; i < lines.size(); i++) { + if (lines.get(i).stripLeading().startsWith(needle) || lines.get(i).stripLeading().startsWith(needleSpace)) { + lines.set(i, key + "=" + value); + found = true; + break; + } } - String existing = Files.readString(file, StandardCharsets.UTF_8); - String sep = existing.endsWith("\n") ? "" : "\n"; - Files.writeString(file, existing + sep + key + "=" + value + "\n", + if (!found) lines.add(key + "=" + value); + Files.writeString(file, String.join("\n", lines) + "\n", StandardCharsets.UTF_8, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING); - return true; } // ── Helpers ─────────────────────────────────────────────────────────────── diff --git a/blight-editor/src/main/java/de/blight/editor/ui/EditorNaming.java b/blight-editor/src/main/java/de/blight/editor/ui/EditorNaming.java new file mode 100644 index 0000000..446de91 --- /dev/null +++ b/blight-editor/src/main/java/de/blight/editor/ui/EditorNaming.java @@ -0,0 +1,29 @@ +package de.blight.editor.ui; + +public final class EditorNaming { + + private EditorNaming() {} + + /** + * Wandelt einen underscore_id-Bezeichner in einen lesbaren Anzeigenamen um: + * Unterstriche werden durch Leerzeichen ersetzt, jedes Wort beginnt mit Großbuchstaben. + * + * Beispiele: + * "wald" → "Wald" + * "dark_forest" → "Dark Forest" + * "neu_1234567890" → "Neu 1234567890" + */ + public static String toDisplayName(String id) { + if (id == null || id.isBlank()) return id; + String[] parts = id.split("_", -1); + StringBuilder sb = new StringBuilder(); + for (String part : parts) { + if (sb.length() > 0) sb.append(' '); + if (!part.isEmpty()) { + sb.append(Character.toUpperCase(part.charAt(0))); + sb.append(part.substring(1)); + } + } + return sb.toString(); + } +} diff --git a/blight-editor/src/main/java/de/blight/editor/ui/LocationEditorView.java b/blight-editor/src/main/java/de/blight/editor/ui/LocationEditorView.java index 896dc06..d101102 100644 --- a/blight-editor/src/main/java/de/blight/editor/ui/LocationEditorView.java +++ b/blight-editor/src/main/java/de/blight/editor/ui/LocationEditorView.java @@ -3,6 +3,7 @@ package de.blight.editor.ui; import de.blight.common.LocationIO; import de.blight.common.model.Location; import de.blight.common.model.TextReference; +import de.blight.editor.ProjectRoot; import javafx.animation.PauseTransition; import javafx.collections.FXCollections; import javafx.collections.ObservableList; @@ -14,6 +15,8 @@ import javafx.scene.layout.*; import javafx.util.Duration; import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.*; import java.util.List; public class LocationEditorView extends BorderPane { @@ -49,6 +52,7 @@ public class LocationEditorView extends BorderPane { saveFormToLocation(current); if (current.getId() == null || current.getId().isBlank()) return; persist(); + writeDefaultLocalisation(current.getId()); } // ── Form panel ──────────────────────────────────────────────────────────── @@ -133,6 +137,7 @@ public class LocationEditorView extends BorderPane { Location loc = new Location(); loc.setName(new TextReference(PREFIX + "neu_" + System.currentTimeMillis())); locations.add(loc); + writeDefaultLocalisation(loc.getId()); onSelected(current, loc); } @@ -177,6 +182,54 @@ public class LocationEditorView extends BorderPane { catch (IOException e) { locations.clear(); } } + // ── Localisation defaults ────────────────────────────────────────────────── + + private void writeDefaultLocalisation(String fullId) { + if (fullId == null || fullId.isBlank()) return; + String shortId = fullId.startsWith(PREFIX) ? fullId.substring(PREFIX.length()) : fullId; + if (shortId.isBlank()) return; + String key = fullId + ".name"; + String defaultName = EditorNaming.toDisplayName(shortId); + + Path langSrc = ProjectRoot.resolve("blight-lang", "src", "main", "resources", "lang"); + Path[] langMirrors = { + ProjectRoot.resolve("blight-lang", "bin", "main", "lang"), + ProjectRoot.resolve("blight-lang", "build", "resources", "main", "lang"), + }; + for (String locale : new String[]{"de", "en"}) { + Path src = langSrc.resolve("messages_" + locale + ".properties"); + try { + writeOrUpdateKey(src, key, defaultName); + for (Path mirrorDir : langMirrors) { + Path mirror = mirrorDir.resolve("messages_" + locale + ".properties"); + if (Files.exists(mirror)) { + Files.copy(src, mirror, StandardCopyOption.REPLACE_EXISTING); + } + } + } catch (IOException e) { + // non-critical + } + } + } + + private static void writeOrUpdateKey(Path file, String key, String value) throws IOException { + if (!Files.exists(file)) return; + String needle = key + "="; + String needleSpace = key + " ="; + java.util.List lines = new java.util.ArrayList<>(Files.readAllLines(file, StandardCharsets.UTF_8)); + boolean found = false; + for (int i = 0; i < lines.size(); i++) { + if (lines.get(i).stripLeading().startsWith(needle) || lines.get(i).stripLeading().startsWith(needleSpace)) { + lines.set(i, key + "=" + value); + found = true; + break; + } + } + if (!found) lines.add(key + "=" + value); + Files.writeString(file, String.join("\n", lines) + "\n", + StandardCharsets.UTF_8, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING); + } + // ── Helpers ─────────────────────────────────────────────────────────────── private static Label sectionTitle(String text) { diff --git a/blight-game/src/main/java/de/blight/game/scene/WorldScene.java b/blight-game/src/main/java/de/blight/game/scene/WorldScene.java index e6f7569..e824074 100644 --- a/blight-game/src/main/java/de/blight/game/scene/WorldScene.java +++ b/blight-game/src/main/java/de/blight/game/scene/WorldScene.java @@ -986,6 +986,7 @@ public class WorldScene extends BaseAppState { ambientSounds = new de.blight.game.state.AmbientSoundSystem(); app.getStateManager().attach(ambientSounds); + app.getStateManager().attach(new de.blight.game.state.NameBannerState()); musicSystem = new de.blight.game.state.MusicSystem(); app.getStateManager().attach(musicSystem); } diff --git a/blight-game/src/main/java/de/blight/game/state/LocationState.java b/blight-game/src/main/java/de/blight/game/state/LocationState.java index 44cf19e..6de6559 100644 --- a/blight-game/src/main/java/de/blight/game/state/LocationState.java +++ b/blight-game/src/main/java/de/blight/game/state/LocationState.java @@ -3,9 +3,10 @@ package de.blight.game.state; import com.jme3.app.Application; import com.jme3.app.state.BaseAppState; import com.jme3.math.Vector3f; -import de.blight.common.LocationIO; -import de.blight.common.model.Location; +import de.blight.common.LocationZoneIO; +import de.blight.common.PlacedLocationZone; import de.blight.common.model.MainCharacter; +import de.blight.lang.TextResolver; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -15,55 +16,95 @@ import java.util.Set; /** * Verfolgt die Spieler-Position und feuert Location-Trigger wenn der Charakter - * eine Location betritt (Übergang outside→inside). + * eine Location-Zone betritt (Übergang outside→inside). Zeigt den Location-Namen via NameBannerState an. */ public class LocationState extends BaseAppState { - private static final Logger log = LoggerFactory.getLogger(LocationState.class); + private static final Logger log = LoggerFactory.getLogger(LocationState.class); + private static final String PREFIX = "location."; - private final MainCharacter character; - private List locations; - private final Set active = new HashSet<>(); - - /** Referenz auf die Node/Control, von der wir die Spieler-Position lesen. */ + private final MainCharacter character; private final com.jme3.scene.Node playerNode; + private Application app; + private List zones; + private final Set active = new HashSet<>(); + private boolean warmStart = true; + public LocationState(MainCharacter character, com.jme3.scene.Node playerNode) { this.character = character; this.playerNode = playerNode; } + // ── Lifecycle ───────────────────────────────────────────────────────────── + @Override - protected void initialize(Application app) { + protected void initialize(Application application) { + app = application; try { - locations = LocationIO.load(); - log.info("{} Location(s) geladen.", locations.size()); + zones = LocationZoneIO.load(); + log.info("{} Location-Zone(n) geladen.", zones.size()); } catch (Exception e) { - log.error("Locations nicht ladbar", e); - locations = List.of(); + log.error("Location-Zones nicht ladbar", e); + zones = List.of(); } } + @Override protected void cleanup(Application application) {} + @Override protected void onEnable() {} + @Override protected void onDisable() {} + + // ── Update ──────────────────────────────────────────────────────────────── + @Override public void update(float tpf) { - if (locations.isEmpty() || playerNode == null) return; + if (zones.isEmpty() || playerNode == null) return; Vector3f pos = playerNode.getWorldTranslation(); float px = pos.x, pz = pos.z; - for (Location loc : locations) { - boolean inside = loc.contains(px, pz); - boolean wasInside = active.contains(loc.getId()); - if (inside && !wasInside) { - active.add(loc.getId()); - loc.entered(character); - log.debug("Location betreten: {}", loc.getId()); - } else if (!inside) { - active.remove(loc.getId()); + for (PlacedLocationZone zone : zones) { + String id = zone.nameId(); + boolean inside = pointInPolygon(px, pz, zone.pointsX(), zone.pointsZ()); + boolean wasInside = active.contains(id); + if (inside) { + active.add(id); + if (!wasInside && !warmStart) { + zone.triggers().stream() + .filter(t -> t.isTriggarable(character)) + .forEach(t -> t.fire(character)); + showName(id); + log.debug("Location betreten: {}", id); + } + } else { + active.remove(id); } } + warmStart = false; } - @Override protected void cleanup(Application app) {} - @Override protected void onEnable() {} - @Override protected void onDisable() {} + // ── Name display ────────────────────────────────────────────────────────── + + private void showName(String nameId) { + String shortId = nameId.startsWith(PREFIX) ? nameId.substring(PREFIX.length()) : nameId; + String key = nameId + ".name"; + String resolved = TextResolver.get().resolveOrId(key); + String name = resolved.equals(key) ? shortId : resolved; + NameBannerState banner = app.getStateManager().getState(NameBannerState.class); + if (banner != null) banner.show(name, NameBannerState.PRIORITY_LOCATION); + } + + // ── Helpers ─────────────────────────────────────────────────────────────── + + private static boolean pointInPolygon(float px, float pz, float[] xs, float[] zs) { + int n = xs.length; + boolean inside = false; + for (int i = 0, j = n - 1; i < n; j = i++) { + float xi = xs[i], zi = zs[i]; + float xj = xs[j], zj = zs[j]; + if ((zi > pz) != (zj > pz) && (px < (xj - xi) * (pz - zi) / (zj - zi) + xi)) { + inside = !inside; + } + } + return inside; + } } diff --git a/blight-game/src/main/java/de/blight/game/state/MusicSystem.java b/blight-game/src/main/java/de/blight/game/state/MusicSystem.java index 6dfea0c..9b53a38 100644 --- a/blight-game/src/main/java/de/blight/game/state/MusicSystem.java +++ b/blight-game/src/main/java/de/blight/game/state/MusicSystem.java @@ -7,19 +7,12 @@ import com.jme3.asset.AssetManager; import com.jme3.audio.AudioData; import com.jme3.audio.AudioNode; import com.jme3.audio.AudioSource; -import com.jme3.font.BitmapFont; -import com.jme3.font.BitmapText; -import com.jme3.material.Material; -import com.jme3.math.ColorRGBA; import com.jme3.math.Vector3f; -import com.jme3.scene.Geometry; import com.jme3.scene.Node; -import com.jme3.scene.Spatial; import de.blight.common.AreaDefinition; import de.blight.common.AreaDefinitionIO; import de.blight.common.AreaIO; import de.blight.common.PlacedArea; -import de.blight.game.config.NinePatch; import de.blight.lang.TextResolver; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -40,12 +33,9 @@ import java.util.Map; */ public class MusicSystem extends BaseAppState { - private static final Logger log = LoggerFactory.getLogger(MusicSystem.class); - private static final float CHECK_INTERVAL = 0.25f; - private static final float FADE_DURATION = 3f; - private static final float AREA_NAME_SHOW = 10f; - private static final float AREA_NAME_FADE = 1.5f; - private static final float AREA_NAME_SIZE = 24f; + private static final Logger log = LoggerFactory.getLogger(MusicSystem.class); + private static final float CHECK_INTERVAL = 0.25f; + private static final float FADE_DURATION = 3f; private static final int SLOT_DAY = 0; private static final int SLOT_NIGHT = 1; @@ -70,13 +60,6 @@ public class MusicSystem extends BaseAppState { private float checkTimer = 0f; private boolean isDaytime = true; - private BitmapText areaNameText; - private Node areaNamePanel = null; - private Material areaNamePanelMat = null; - private float areaNameTimer = 0f; - private boolean areaNameFadingIn = false; - private float areaNameFadeInElapsed = 0f; - // ── Lifecycle ───────────────────────────────────────────────────────────── @Override @@ -86,13 +69,6 @@ public class MusicSystem extends BaseAppState { rootNode = app.getRootNode(); audioSettings = app.getStateManager().getState(AudioSettingsState.class); - BitmapFont font = assets.loadFont("Interface/Fonts/Default.fnt"); - areaNameText = new BitmapText(font); - areaNameText.setSize(AREA_NAME_SIZE * 2f); - areaNameText.setLocalScale(0.5f, 0.5f, 1f); - areaNameText.setColor(new ColorRGBA(1f, 0.95f, 0.8f, 0f)); - app.getGuiNode().attachChild(areaNameText); - try { Map defs = new java.util.HashMap<>(); try { @@ -133,8 +109,6 @@ public class MusicSystem extends BaseAppState { phases.clear(); activeSlot.clear(); pendingSlot.clear(); - if (areaNamePanel != null) { app.getGuiNode().detachChild(areaNamePanel); areaNamePanel = null; } - if (areaNameText != null) app.getGuiNode().detachChild(areaNameText); } @Override protected void onEnable() {} @@ -160,25 +134,6 @@ public class MusicSystem extends BaseAppState { @Override public void update(float tpf) { - // area name display: fade-in → visible → fade-out - if (areaNameFadingIn) { - areaNameFadeInElapsed += tpf; - float alpha = Math.min(areaNameFadeInElapsed / AREA_NAME_FADE, 1f); - setAreaNameAlpha(alpha); - if (areaNameFadeInElapsed >= AREA_NAME_FADE) { - areaNameFadingIn = false; - setAreaNameAlpha(1f); - } - } else if (areaNameTimer > 0f) { - areaNameTimer -= tpf; - if (areaNameTimer <= 0f) { - areaNameTimer = 0f; - setAreaNameAlpha(0f); - } else if (areaNameTimer < AREA_NAME_FADE) { - setAreaNameAlpha(areaNameTimer / AREA_NAME_FADE); - } - } - if (data.isEmpty()) return; // per-area fade/finish handling + live volume update for active tracks @@ -304,47 +259,12 @@ public class MusicSystem extends BaseAppState { // ── Area-Name-Anzeige ───────────────────────────────────────────────────── private void showAreaName(int i) { - String key = i < areaNameKeys.size() ? areaNameKeys.get(i) : ""; - String shortId = i < areaShortIds.size() ? areaShortIds.get(i) : key; + String key = i < areaNameKeys.size() ? areaNameKeys.get(i) : ""; + String shortId = i < areaShortIds.size() ? areaShortIds.get(i) : key; String resolved = TextResolver.get().resolveOrId(key); String name = resolved.equals(key) ? shortId : resolved; - if (name.isBlank()) return; - - areaNameText.setText(name); - float tw = areaNameText.getLineWidth() * 0.5f; - float th = areaNameText.getLineHeight() * 0.5f; - float sw = app.getCamera().getWidth(); - float sh = app.getCamera().getHeight(); - - float padX = 20f, padY = 10f; - float textX = Math.round((sw - tw) / 2f); - float textY = sh - 40f; - float panelX = Math.round(textX - padX); - float panelY = Math.round(textY - th - padY); - float panelW = Math.round(tw + padX * 2f); - float panelH = Math.round(th + padY * 2f); - - areaNameText.setLocalTranslation(textX, textY, 0f); - - if (areaNamePanel != null) app.getGuiNode().detachChild(areaNamePanel); - areaNamePanel = NinePatch.panel(assets).build(panelX, panelY, panelW, panelH, -1f); - areaNamePanelMat = null; - for (Spatial s : areaNamePanel.getChildren()) { - if (s instanceof Geometry g) { areaNamePanelMat = g.getMaterial(); break; } - } - app.getGuiNode().attachChild(areaNamePanel); - - setAreaNameAlpha(0f); - areaNameFadingIn = true; - areaNameFadeInElapsed = 0f; - areaNameTimer = AREA_NAME_SHOW; - } - - private void setAreaNameAlpha(float alpha) { - areaNameText.setColor(new ColorRGBA(1f, 0.95f, 0.8f, alpha)); - if (areaNamePanelMat != null) { - areaNamePanelMat.setColor("Color", new ColorRGBA(1f, 1f, 1f, alpha)); - } + NameBannerState banner = app.getStateManager().getState(NameBannerState.class); + if (banner != null) banner.show(name, NameBannerState.PRIORITY_AREA); } // ── Helpers ─────────────────────────────────────────────────────────────── diff --git a/blight-game/src/main/java/de/blight/game/state/NameBannerState.java b/blight-game/src/main/java/de/blight/game/state/NameBannerState.java new file mode 100644 index 0000000..e3d0d2e --- /dev/null +++ b/blight-game/src/main/java/de/blight/game/state/NameBannerState.java @@ -0,0 +1,140 @@ +package de.blight.game.state; + +import com.jme3.app.Application; +import com.jme3.app.SimpleApplication; +import com.jme3.app.state.BaseAppState; +import com.jme3.font.BitmapFont; +import com.jme3.font.BitmapText; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import de.blight.game.config.NinePatch; + +import java.util.Comparator; +import java.util.PriorityQueue; + +/** + * Zeigt einen Bereichs- oder Ortsnamen als eingeblendetes Banner (Fade-in → sichtbar → Fade-out). + * Mehrere gleichzeitige Aufrufe werden in einer Priority-Queue gepuffert: + * Priorität 0 = Area (zuerst), Priorität 1 = Location (danach). + */ +public class NameBannerState extends BaseAppState { + + public static final int PRIORITY_AREA = 0; + public static final int PRIORITY_LOCATION = 1; + + private static final float SHOW_DURATION = 10f; + private static final float FADE_DURATION = 1.5f; + private static final float FONT_SIZE = 24f; + + private record QueuedName(String name, int priority) {} + + private SimpleApplication app; + private BitmapText text; + private Node panel = null; + private Material panelMat = null; + private float showTimer = 0f; + private boolean fadingIn = false; + private float fadeInElapsed = 0f; + private final PriorityQueue queue = + new PriorityQueue<>(Comparator.comparingInt(QueuedName::priority)); + + // ── Lifecycle ───────────────────────────────────────────────────────────── + + @Override + protected void initialize(Application application) { + app = (SimpleApplication) application; + BitmapFont font = app.getAssetManager().loadFont("Interface/Fonts/Default.fnt"); + text = new BitmapText(font); + text.setSize(FONT_SIZE * 2f); + text.setLocalScale(0.5f, 0.5f, 1f); + text.setColor(new ColorRGBA(1f, 0.95f, 0.8f, 0f)); + app.getGuiNode().attachChild(text); + } + + @Override + protected void cleanup(Application application) { + if (panel != null) { app.getGuiNode().detachChild(panel); panel = null; } + if (text != null) app.getGuiNode().detachChild(text); + } + + @Override protected void onEnable() {} + @Override protected void onDisable() {} + + // ── Update ──────────────────────────────────────────────────────────────── + + @Override + public void update(float tpf) { + if (fadingIn) { + fadeInElapsed += tpf; + setAlpha(Math.min(fadeInElapsed / FADE_DURATION, 1f)); + if (fadeInElapsed >= FADE_DURATION) { + fadingIn = false; + setAlpha(1f); + } + } else if (showTimer > 0f) { + showTimer -= tpf; + if (showTimer <= 0f) { + showTimer = 0f; + setAlpha(0f); + if (!queue.isEmpty()) { + showNow(queue.poll().name()); + } + } else if (showTimer < FADE_DURATION) { + setAlpha(showTimer / FADE_DURATION); + } + } + } + + // ── API ─────────────────────────────────────────────────────────────────── + + public void show(String name, int priority) { + if (name == null || name.isBlank()) return; + if (!fadingIn && showTimer <= 0f) { + showNow(name); + } else { + queue.offer(new QueuedName(name, priority)); + } + } + + // ── Internals ───────────────────────────────────────────────────────────── + + private void showNow(String name) { + text.setText(name); + float tw = text.getLineWidth() * 0.5f; + float th = text.getLineHeight() * 0.5f; + float sw = app.getCamera().getWidth(); + float sh = app.getCamera().getHeight(); + + float padX = 20f, padY = 10f; + float textX = Math.round((sw - tw) / 2f); + float textY = sh - 40f; + + text.setLocalTranslation(textX, textY, 0f); + + if (panel != null) app.getGuiNode().detachChild(panel); + panel = NinePatch.panel(app.getAssetManager()).build( + Math.round(textX - padX), + Math.round(textY - th - padY), + Math.round(tw + padX * 2f), + Math.round(th + padY * 2f), + -1f); + panelMat = null; + for (Spatial s : panel.getChildren()) { + if (s instanceof Geometry g) { panelMat = g.getMaterial(); break; } + } + app.getGuiNode().attachChild(panel); + + setAlpha(0f); + fadingIn = true; + fadeInElapsed = 0f; + showTimer = SHOW_DURATION; + } + + private void setAlpha(float alpha) { + text.setColor(new ColorRGBA(1f, 0.95f, 0.8f, alpha)); + if (panelMat != null) panelMat.setColor("Color", new ColorRGBA(1f, 1f, 1f, alpha)); + } +} diff --git a/blight-lang/src/main/resources/lang/messages_de.properties b/blight-lang/src/main/resources/lang/messages_de.properties index ae72045..85ea0dd 100644 --- a/blight-lang/src/main/resources/lang/messages_de.properties +++ b/blight-lang/src/main/resources/lang/messages_de.properties @@ -238,3 +238,8 @@ quest.blight_wuehler.success=Der Blight-Wühler ist besiegt. Der Stollen ist wie quest.magnetiterz.name=Magnetiterz quest.magnetiterz.description=Schürfe 5 Einheiten reines Magnetiterz aus dem alten Stollen in den Bergen. Björnson braucht es für das Schwert. quest.magnetiterz.success=Du hast genug Magnetiterz gesammelt. Bring es zu Björnson. +location.neu_1787424294831.name=Neu_1787424294831 +location.silas.name=Silas +location.silas_.name=Silas +location.silas_haus.name=Silas Haus +location.silas_heim.name=Silas Heim diff --git a/blight-lang/src/main/resources/lang/messages_en.properties b/blight-lang/src/main/resources/lang/messages_en.properties index 8eba328..94bbee9 100644 --- a/blight-lang/src/main/resources/lang/messages_en.properties +++ b/blight-lang/src/main/resources/lang/messages_en.properties @@ -93,3 +93,8 @@ key.walk=Walk key.interact=Interact key.inventory=Inventory key.quicksave=Quick Save +location.neu_1787424294831.name=Neu_1787424294831 +location.silas.name=Silas +location.silas_.name=Silas +location.silas_haus.name=Silas Haus +location.silas_heim.name=Silas Heim diff --git a/blight-lang/src/main/resources/lang/text_keys.txt b/blight-lang/src/main/resources/lang/text_keys.txt index 43a6f90..93ceb40 100644 --- a/blight-lang/src/main/resources/lang/text_keys.txt +++ b/blight-lang/src/main/resources/lang/text_keys.txt @@ -132,6 +132,11 @@ hero.name location.neu_1786533928723 location.neu_1786546178407 location.neu_1786606437840 +location.neu_1787424294831 +location.silas +location.silas_ +location.silas_haus +location.silas_heim location.test quest.blight_wuehler.description quest.blight_wuehler.name diff --git a/blight-map/src/main/map/blight_location_zones.blz b/blight-map/src/main/map/blight_location_zones.blz index a7e9071..95ab349 100644 --- a/blight-map/src/main/map/blight_location_zones.blz +++ b/blight-map/src/main/map/blight_location_zones.blz @@ -1 +1,2 @@ # polygon nameId triggersJson +267.905,-829.243;276.075,-861.410;240.825,-877.135;233.375,-864.779 location.silas_heim [] diff --git a/blight-map/src/main/map/blight_locations.blo b/blight-map/src/main/map/blight_locations.blo new file mode 100644 index 0000000..1d2310f --- /dev/null +++ b/blight-map/src/main/map/blight_locations.blo @@ -0,0 +1,2 @@ +# nameId centerX centerZ radius triggersJson +location.silas_heim 0.000 0.000 0.000 []