Soundsystem weiter ausgebaut

This commit is contained in:
2026-07-05 10:39:32 +02:00
parent 63aa7aa104
commit 66d7956a28
273 changed files with 6045 additions and 2625 deletions

View File

@@ -129,6 +129,9 @@ public final class MapData {
/** Spawnpunkt Z-Koordinate in Welteinheiten (default: 0 = Kartenmitte). */
public float spawnZ = 0f;
/** Blickrichtung am permanenten Spawnpunkt in Grad (0 = +Z, 90 = +X, Uhrzeigersinn von oben). */
public float spawnYaw = 0f;
/** Terrain-Slot (0-7) für flache Voxel-Flächen (TexFlat), -1 = nicht gesetzt. */
public int voxelFlatSlot = -1;
/** Terrain-Slot (0-7) für steile Wände (TexSteep), -1 = nicht gesetzt. */

View File

@@ -63,7 +63,7 @@ public final class MapIO {
}
private static final int MAGIC = 0x424C4947; // "BLIG"
private static final int VERSION = 14;
private static final int VERSION = 15;
// Größen älterer Saves (v≤9) für Migrations-Upsampling
private static final int OLD_TERRAIN_VERTS = 4097;
@@ -124,6 +124,8 @@ public final class MapIO {
// v4: spawnpunkt
out.writeFloat(data.spawnX);
out.writeFloat(data.spawnZ);
// v15: spawn-blickrichtung
out.writeFloat(data.spawnYaw);
// v5: splatA + texturpfade + gebirge-splatmap
out.write(data.splatA);
writeStrings(out, data.terrainTextures);
@@ -232,6 +234,9 @@ public final class MapIO {
data.spawnX = in.readFloat();
data.spawnZ = in.readFloat();
}
if (version >= 15) {
data.spawnYaw = in.readFloat();
}
if (version >= 5) {
if (version >= 10) {
in.readFully(data.splatA);

View File

@@ -32,7 +32,8 @@ public record ModelMeta(
float interactableOffsetX,
float interactableOffsetY,
float interactableOffsetZ,
float interactableRotY
float interactableRotY,
String footstepSurface
) {
/** Lichtquelle relativ zum Modell-Ursprung. */
public record AttachedLight(
@@ -52,6 +53,6 @@ public record ModelMeta(
"", "", 30f, 80f, 120f,
List.of(), List.of(),
de.blight.common.model.InteractableType.NONE,
0f, 0.5f, 0f, 0f);
0f, 0.5f, 0f, 0f, "");
}
}

View File

@@ -39,6 +39,7 @@ public final class ModelMetaIO {
p.setProperty("interactableOffsetY", String.valueOf(m.interactableOffsetY()));
p.setProperty("interactableOffsetZ", String.valueOf(m.interactableOffsetZ()));
p.setProperty("interactableRotY", String.valueOf(m.interactableRotY()));
p.setProperty("footstepSurface", m.footstepSurface() != null ? m.footstepSurface() : "");
// Anhänge: Lichter
List<ModelMeta.AttachedLight> lights = m.attachedLights();
@@ -138,7 +139,8 @@ public final class ModelMetaIO {
parseFloat(p, "interactableOffsetX", 0f),
parseFloat(p, "interactableOffsetY", 0.5f),
parseFloat(p, "interactableOffsetZ", 0f),
parseFloat(p, "interactableRotY", 0f)
parseFloat(p, "interactableRotY", 0f),
p.getProperty("footstepSurface", "")
);
}

View File

@@ -40,4 +40,10 @@ public class Bed implements Interactable {
public String getDisplayText() {
return TextRegistry.resolve(name, id != null ? id : "Bett");
}
@Override
public String getLabelKey() {
if (name != null && name.id() != null && !name.id().isBlank()) return name.id();
return "interactable.bed.name";
}
}

View File

@@ -41,4 +41,10 @@ public class Bench implements Interactable {
public String getDisplayText() {
return TextRegistry.resolve(name, id != null ? id : "Bank");
}
@Override
public String getLabelKey() {
if (name != null && name.id() != null && !name.id().isBlank()) return name.id();
return "interactable.bench.name";
}
}

View File

@@ -2,5 +2,8 @@ package de.blight.common.model;
public interface Interactable {
public String getDisplayText();
String getDisplayText();
/** Gibt den Lokalisierungsschlüssel für das HUD-Label zurück (z.B. "item.driftwood.name"). */
default String getLabelKey() { return ""; }
}

View File

@@ -30,4 +30,10 @@ public class Item implements Interactable {
public String getDisplayText() {
return TextRegistry.resolve(name, itemId != null ? itemId : "?");
}
@Override
public String getLabelKey() {
if (name != null && name.id() != null && !name.id().isBlank()) return name.id();
return itemId != null ? "item." + itemId + ".name" : "";
}
}

View File

@@ -1,7 +1,9 @@
package de.blight.common.model;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -11,7 +13,7 @@ import lombok.Setter;
@Getter
@Setter
public class NPC extends GameCharacter {
public class NPC extends GameCharacter implements Interactable {
private static final Logger LOG = LoggerFactory.getLogger(NPC.class);
@@ -23,6 +25,15 @@ public class NPC extends GameCharacter {
private List<DialogOption> currentOptions;
/** Nur im Editor relevant: Optionen die nicht mit currentOptions verbunden sind, aber erhalten werden sollen. */
private List<DialogOption> editorOnlyOptions;
/**
* Standard-Nachrichten je Status, die angezeigt werden wenn keine Dialog-Optionen
* verfügbar sind. Schlüssel = Status-Wert des NPCs zum Gesprächszeitpunkt.
*/
private Map<Status, TextReference> defaultMessages = new EnumMap<>(Status.class);
/** Tagesabläufe dieses NPCs. Die erste Routine gilt standardmäßig als aktiv. */
private List<NpcRoutine> routines = new ArrayList<>();
@@ -58,6 +69,35 @@ public class NPC extends GameCharacter {
this.activeRoutineName = routineName;
}
// ── Interactable ─────────────────────────────────────────────────────────
@Override
public String getDisplayText() {
return TextRegistry.resolve(getName(), getCharacterId() != null ? getCharacterId() : "NPC");
}
@Override
public String getLabelKey() {
TextReference nameRef = getName();
if (nameRef != null && nameRef.id() != null && !nameRef.id().isBlank()) return nameRef.id();
return getCharacterId() != null ? "npc." + getCharacterId() + ".name" : "";
}
/**
* Gibt die Default-Nachricht für den aktuellen Status zurück.
* Fällt auf den nächst-freundlicheren Status zurück wenn kein Eintrag gefunden wird.
*/
public TextReference getDefaultMessage() {
if (defaultMessages == null || defaultMessages.isEmpty()) return null;
Status s = status != null ? status : Status.NEUTRAL;
Status[] fallback = {s, Status.NEUTRAL, Status.FRIENDLY, Status.ENRAGED, Status.ENEMY};
for (Status candidate : fallback) {
TextReference ref = defaultMessages.get(candidate);
if (ref != null) return ref;
}
return null;
}
// ── Dialog-Methoden ──────────────────────────────────────────────────────
public List<DialogOption> getAvailableOptions(MainCharacter character) {