Compare commits

...

2 Commits

Author SHA1 Message Date
d0f33a5b4b Anzeige von Area und Location Namen korrigiert 2026-08-22 21:18:53 +02:00
756304f621 Anzeige von Areas aktualisiert 2026-08-22 20:36:44 +02:00
14 changed files with 382 additions and 80 deletions

View File

@@ -14,7 +14,8 @@ import javafx.scene.layout.*;
import javafx.util.Duration; import javafx.util.Duration;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Path; import java.nio.charset.StandardCharsets;
import java.nio.file.*;
public class AreaEditorView extends BorderPane { public class AreaEditorView extends BorderPane {
@@ -57,6 +58,7 @@ public class AreaEditorView extends BorderPane {
current = saved; current = saved;
reloading = false; reloading = false;
persist(); persist();
writeDefaultLocalisation(saved.id());
} }
// ── Form panel ──────────────────────────────────────────────────────────── // ── Form panel ────────────────────────────────────────────────────────────
@@ -185,6 +187,7 @@ public class AreaEditorView extends BorderPane {
private void createArea() { private void createArea() {
AreaDefinition d = new AreaDefinition(PREFIX + "neu_" + System.currentTimeMillis(), "", "", ""); AreaDefinition d = new AreaDefinition(PREFIX + "neu_" + System.currentTimeMillis(), "", "", "");
areas.add(d); areas.add(d);
writeDefaultLocalisation(d.id());
onSelected(current, d); onSelected(current, d);
} }
@@ -229,6 +232,54 @@ public class AreaEditorView extends BorderPane {
catch (IOException e) { areas.clear(); } catch (IOException e) { areas.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<String> 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 ─────────────────────────────────────────────────────────────── // ── Helpers ───────────────────────────────────────────────────────────────
private static Label sectionTitle(String text) { private static Label sectionTitle(String text) {

View File

@@ -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();
}
}

View File

@@ -3,6 +3,7 @@ package de.blight.editor.ui;
import de.blight.common.LocationIO; import de.blight.common.LocationIO;
import de.blight.common.model.Location; import de.blight.common.model.Location;
import de.blight.common.model.TextReference; import de.blight.common.model.TextReference;
import de.blight.editor.ProjectRoot;
import javafx.animation.PauseTransition; import javafx.animation.PauseTransition;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
@@ -14,6 +15,8 @@ import javafx.scene.layout.*;
import javafx.util.Duration; import javafx.util.Duration;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.util.List; import java.util.List;
public class LocationEditorView extends BorderPane { public class LocationEditorView extends BorderPane {
@@ -49,6 +52,7 @@ public class LocationEditorView extends BorderPane {
saveFormToLocation(current); saveFormToLocation(current);
if (current.getId() == null || current.getId().isBlank()) return; if (current.getId() == null || current.getId().isBlank()) return;
persist(); persist();
writeDefaultLocalisation(current.getId());
} }
// ── Form panel ──────────────────────────────────────────────────────────── // ── Form panel ────────────────────────────────────────────────────────────
@@ -133,6 +137,7 @@ public class LocationEditorView extends BorderPane {
Location loc = new Location(); Location loc = new Location();
loc.setName(new TextReference(PREFIX + "neu_" + System.currentTimeMillis())); loc.setName(new TextReference(PREFIX + "neu_" + System.currentTimeMillis()));
locations.add(loc); locations.add(loc);
writeDefaultLocalisation(loc.getId());
onSelected(current, loc); onSelected(current, loc);
} }
@@ -177,6 +182,54 @@ public class LocationEditorView extends BorderPane {
catch (IOException e) { locations.clear(); } 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<String> 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 ─────────────────────────────────────────────────────────────── // ── Helpers ───────────────────────────────────────────────────────────────
private static Label sectionTitle(String text) { private static Label sectionTitle(String text) {

View File

@@ -986,6 +986,7 @@ public class WorldScene extends BaseAppState {
ambientSounds = new de.blight.game.state.AmbientSoundSystem(); ambientSounds = new de.blight.game.state.AmbientSoundSystem();
app.getStateManager().attach(ambientSounds); app.getStateManager().attach(ambientSounds);
app.getStateManager().attach(new de.blight.game.state.NameBannerState());
musicSystem = new de.blight.game.state.MusicSystem(); musicSystem = new de.blight.game.state.MusicSystem();
app.getStateManager().attach(musicSystem); app.getStateManager().attach(musicSystem);
} }

View File

@@ -3,9 +3,10 @@ package de.blight.game.state;
import com.jme3.app.Application; import com.jme3.app.Application;
import com.jme3.app.state.BaseAppState; import com.jme3.app.state.BaseAppState;
import com.jme3.math.Vector3f; import com.jme3.math.Vector3f;
import de.blight.common.LocationIO; import de.blight.common.LocationZoneIO;
import de.blight.common.model.Location; import de.blight.common.PlacedLocationZone;
import de.blight.common.model.MainCharacter; import de.blight.common.model.MainCharacter;
import de.blight.lang.TextResolver;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -15,55 +16,95 @@ import java.util.Set;
/** /**
* Verfolgt die Spieler-Position und feuert Location-Trigger wenn der Charakter * 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 { 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 final MainCharacter character;
private List<Location> locations;
private final Set<String> active = new HashSet<>();
/** Referenz auf die Node/Control, von der wir die Spieler-Position lesen. */
private final com.jme3.scene.Node playerNode; private final com.jme3.scene.Node playerNode;
private Application app;
private List<PlacedLocationZone> zones;
private final Set<String> active = new HashSet<>();
private boolean warmStart = true;
public LocationState(MainCharacter character, com.jme3.scene.Node playerNode) { public LocationState(MainCharacter character, com.jme3.scene.Node playerNode) {
this.character = character; this.character = character;
this.playerNode = playerNode; this.playerNode = playerNode;
} }
// ── Lifecycle ─────────────────────────────────────────────────────────────
@Override @Override
protected void initialize(Application app) { protected void initialize(Application application) {
app = application;
try { try {
locations = LocationIO.load(); zones = LocationZoneIO.load();
log.info("{} Location(s) geladen.", locations.size()); log.info("{} Location-Zone(n) geladen.", zones.size());
} catch (Exception e) { } catch (Exception e) {
log.error("Locations nicht ladbar", e); log.error("Location-Zones nicht ladbar", e);
locations = List.of(); zones = List.of();
} }
} }
@Override protected void cleanup(Application application) {}
@Override protected void onEnable() {}
@Override protected void onDisable() {}
// ── Update ────────────────────────────────────────────────────────────────
@Override @Override
public void update(float tpf) { public void update(float tpf) {
if (locations.isEmpty() || playerNode == null) return; if (zones.isEmpty() || playerNode == null) return;
Vector3f pos = playerNode.getWorldTranslation(); Vector3f pos = playerNode.getWorldTranslation();
float px = pos.x, pz = pos.z; float px = pos.x, pz = pos.z;
for (Location loc : locations) { for (PlacedLocationZone zone : zones) {
boolean inside = loc.contains(px, pz); String id = zone.nameId();
boolean wasInside = active.contains(loc.getId()); boolean inside = pointInPolygon(px, pz, zone.pointsX(), zone.pointsZ());
if (inside && !wasInside) { boolean wasInside = active.contains(id);
active.add(loc.getId()); if (inside) {
loc.entered(character); active.add(id);
log.debug("Location betreten: {}", loc.getId()); if (!wasInside && !warmStart) {
} else if (!inside) { zone.triggers().stream()
active.remove(loc.getId()); .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) {} // ── Name display ──────────────────────────────────────────────────────────
@Override protected void onEnable() {}
@Override protected void onDisable() {} 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;
}
} }

View File

@@ -7,9 +7,6 @@ import com.jme3.asset.AssetManager;
import com.jme3.audio.AudioData; import com.jme3.audio.AudioData;
import com.jme3.audio.AudioNode; import com.jme3.audio.AudioNode;
import com.jme3.audio.AudioSource; import com.jme3.audio.AudioSource;
import com.jme3.font.BitmapFont;
import com.jme3.font.BitmapText;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f; import com.jme3.math.Vector3f;
import com.jme3.scene.Node; import com.jme3.scene.Node;
import de.blight.common.AreaDefinition; import de.blight.common.AreaDefinition;
@@ -39,9 +36,6 @@ public class MusicSystem extends BaseAppState {
private static final Logger log = LoggerFactory.getLogger(MusicSystem.class); private static final Logger log = LoggerFactory.getLogger(MusicSystem.class);
private static final float CHECK_INTERVAL = 0.25f; private static final float CHECK_INTERVAL = 0.25f;
private static final float FADE_DURATION = 3f; 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 int SLOT_DAY = 0; private static final int SLOT_DAY = 0;
private static final int SLOT_NIGHT = 1; private static final int SLOT_NIGHT = 1;
@@ -66,9 +60,6 @@ public class MusicSystem extends BaseAppState {
private float checkTimer = 0f; private float checkTimer = 0f;
private boolean isDaytime = true; private boolean isDaytime = true;
private BitmapText areaNameText;
private float areaNameTimer = 0f;
// ── Lifecycle ───────────────────────────────────────────────────────────── // ── Lifecycle ─────────────────────────────────────────────────────────────
@Override @Override
@@ -78,13 +69,6 @@ public class MusicSystem extends BaseAppState {
rootNode = app.getRootNode(); rootNode = app.getRootNode();
audioSettings = app.getStateManager().getState(AudioSettingsState.class); 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 { try {
Map<String, AreaDefinition> defs = new java.util.HashMap<>(); Map<String, AreaDefinition> defs = new java.util.HashMap<>();
try { try {
@@ -97,7 +81,6 @@ public class MusicSystem extends BaseAppState {
if (def == null) continue; if (def == null) continue;
AudioNode day = loadTrack(def.dayTrack()); AudioNode day = loadTrack(def.dayTrack());
AudioNode night = loadTrack(def.nightTrack()); AudioNode night = loadTrack(def.nightTrack());
if (day == null && night == null) continue;
String rawId = def.id(); String rawId = def.id();
String shortId = rawId.startsWith("area.") ? rawId.substring("area.".length()) : rawId; String shortId = rawId.startsWith("area.") ? rawId.substring("area.".length()) : rawId;
data.add(area); data.add(area);
@@ -126,7 +109,6 @@ public class MusicSystem extends BaseAppState {
phases.clear(); phases.clear();
activeSlot.clear(); activeSlot.clear();
pendingSlot.clear(); pendingSlot.clear();
if (areaNameText != null) app.getGuiNode().detachChild(areaNameText);
} }
@Override protected void onEnable() {} @Override protected void onEnable() {}
@@ -152,18 +134,6 @@ public class MusicSystem extends BaseAppState {
@Override @Override
public void update(float tpf) { public void update(float tpf) {
// area name display timer
if (areaNameTimer > 0f) {
areaNameTimer -= tpf;
if (areaNameTimer <= 0f) {
areaNameText.setColor(new ColorRGBA(1f, 0.95f, 0.8f, 0f));
areaNameTimer = 0f;
} else if (areaNameTimer < AREA_NAME_FADE) {
float alpha = areaNameTimer / AREA_NAME_FADE;
areaNameText.setColor(new ColorRGBA(1f, 0.95f, 0.8f, alpha));
}
}
if (data.isEmpty()) return; if (data.isEmpty()) return;
// per-area fade/finish handling + live volume update for active tracks // per-area fade/finish handling + live volume update for active tracks
@@ -205,7 +175,7 @@ public class MusicSystem extends BaseAppState {
private void startArea(int i) { private void startArea(int i) {
int slot = desiredSlot(i); int slot = desiredSlot(i);
AudioNode n = nodes.get(i)[slot]; AudioNode n = nodes.get(i)[slot];
if (n == null) return; if (n != null) {
n.setVolume(0f); n.setVolume(0f);
n.setLooping(true); n.setLooping(true);
rootNode.attachChild(n); rootNode.attachChild(n);
@@ -214,6 +184,9 @@ public class MusicSystem extends BaseAppState {
pendingSlot.set(i, -1); pendingSlot.set(i, -1);
phases.set(i, Phase.FADING_IN); phases.set(i, Phase.FADING_IN);
log.info("[MusicSystem] Area {} → slot {} gestartet", i, slot == SLOT_DAY ? "Tag" : "Nacht"); log.info("[MusicSystem] Area {} → slot {} gestartet", i, slot == SLOT_DAY ? "Tag" : "Nacht");
} else {
phases.set(i, Phase.ACTIVE);
}
showAreaName(i); showAreaName(i);
} }
@@ -290,15 +263,8 @@ public class MusicSystem extends BaseAppState {
String shortId = i < areaShortIds.size() ? areaShortIds.get(i) : key; String shortId = i < areaShortIds.size() ? areaShortIds.get(i) : key;
String resolved = TextResolver.get().resolveOrId(key); String resolved = TextResolver.get().resolveOrId(key);
String name = resolved.equals(key) ? shortId : resolved; String name = resolved.equals(key) ? shortId : resolved;
if (name.isBlank()) return; NameBannerState banner = app.getStateManager().getState(NameBannerState.class);
if (banner != null) banner.show(name, NameBannerState.PRIORITY_AREA);
areaNameText.setText(name);
float tw = areaNameText.getLineWidth() * 0.5f;
float sw = app.getCamera().getWidth();
float sh = app.getCamera().getHeight();
areaNameText.setLocalTranslation((sw - tw) / 2f, sh - 40f, 0f);
areaNameText.setColor(new ColorRGBA(1f, 0.95f, 0.8f, 1f));
areaNameTimer = AREA_NAME_SHOW;
} }
// ── Helpers ─────────────────────────────────────────────────────────────── // ── Helpers ───────────────────────────────────────────────────────────────

View File

@@ -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<QueuedName> 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));
}
}

View File

@@ -238,3 +238,8 @@ quest.blight_wuehler.success=Der Blight-Wühler ist besiegt. Der Stollen ist wie
quest.magnetiterz.name=Magnetiterz 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.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. 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

View File

@@ -93,3 +93,8 @@ key.walk=Walk
key.interact=Interact key.interact=Interact
key.inventory=Inventory key.inventory=Inventory
key.quicksave=Quick Save 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

View File

@@ -132,6 +132,11 @@ hero.name
location.neu_1786533928723 location.neu_1786533928723
location.neu_1786546178407 location.neu_1786546178407
location.neu_1786606437840 location.neu_1786606437840
location.neu_1787424294831
location.silas
location.silas_
location.silas_haus
location.silas_heim
location.test location.test
quest.blight_wuehler.description quest.blight_wuehler.description
quest.blight_wuehler.name quest.blight_wuehler.name

View File

@@ -0,0 +1,2 @@
# id dayTrack nightTrack combatTrack
area.strand

View File

@@ -1 +1,2 @@
# polygon areaId triggersJson # polygon areaId triggersJson
255.852,-828.388;281.186,-815.228;272.373,-782.936;237.423,-778.259;223.212,-812.720;227.232,-839.121 area.strand []

View File

@@ -1 +1,2 @@
# polygon nameId triggersJson # polygon nameId triggersJson
267.905,-829.243;276.075,-861.410;240.825,-877.135;233.375,-864.779 location.silas_heim []

View File

@@ -0,0 +1,2 @@
# nameId centerX centerZ radius triggersJson
location.silas_heim 0.000 0.000 0.000 []