scopedvr-map-editor/tests/test_loadout.gd
2026-11-01 19:34:05 +01:00

175 lines
8.5 KiB
GDScript
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.

extends SceneTree
## Editor-Test (headless): Map-Loadout (V18) — Katalog, Validierung, Panel mit
## Undo/Redo und Speichern/Laden. Ausführen:
## godot --headless --path . --script res://tests/test_loadout.gd
var failures := 0
var checks := 0
var main: Control
func _initialize() -> void:
_run_all.call_deferred()
func _check(cond: bool, label: String) -> void:
checks += 1
if cond:
print(" ok: %s" % label)
else:
failures += 1
print(" FAIL: %s" % label)
func _run_all() -> void:
_test_katalog()
await _test_panel()
if failures == 0:
print("ALL OK: %d checks" % checks)
quit(0)
else:
print("FAILED: %d/%d checks" % [failures, checks])
quit(1)
func _test_katalog() -> void:
print("Testgruppe: Katalog + Validierung")
_check(LoadoutKatalog.waffen_ids().size() >= 50, "Katalog hat Waffen")
_check(LoadoutKatalog.hat_waffe("m40") and LoadoutKatalog.hat_waffe("pistol1"), "m40 + pistol1 bekannt")
_check(LoadoutKatalog.validate(null).is_empty(), "fehlend gültig")
_check(LoadoutKatalog.validate({"mode": "player"}).is_empty(), "player gültig")
_check(not LoadoutKatalog.validate({"mode": "fixed"}).is_empty(), "fixed ohne Primär ungültig")
_check(not LoadoutKatalog.validate({"mode": "fixed", "primary": "nix"}).is_empty(), "unbekannte Waffe ungültig")
_check(not LoadoutKatalog.validate({"mode": "x"}).is_empty(), "unbekannter Modus ungültig")
_check(LoadoutKatalog.validate({"mode": "fixed", "primary": "sr1", "secondary": ""}).is_empty(), "fixed ohne Sekundär gültig")
_check(not LoadoutKatalog.validate({"mode": "fixed", "primary": "sr1",
"attachments": {"ar1": ""}}).is_empty(), "Aufsatz für Fremdwaffe ungültig")
_check(not LoadoutKatalog.validate({"mode": "fixed", "primary": "sr1",
"attachments": {"sr1": "sight=nix"}}).is_empty(), "unbekanntes Teil ungültig")
var sel := LoadoutKatalog.auswahl("sr1", "")
sel["muzzle"] = "muzzle_suppressor_01"
var wire := LoadoutKatalog.encode("sr1", sel)
_check(wire == "muzzle=muzzle_suppressor_01", "encode nur Abweichungen: " + wire)
_check(LoadoutKatalog.pruefe_aufsaetze("sr1", wire) == "", "encodierter Text gültig")
# Rotpunktvisier statt Zielfernrohr: wählbar, gültig, deutscher Name
var rot := LoadoutKatalog.auswahl("sr1", "")
rot["sight"] = "sight_collimator"
var rot_wire := LoadoutKatalog.encode("sr1", rot)
_check(rot_wire == "sight=sight_collimator", "Rotpunkt-Draht: " + rot_wire)
_check(LoadoutKatalog.validate({"mode": "fixed", "primary": "sr1", "secondary": "",
"attachments": {"sr1": rot_wire}}).is_empty(), "Rotpunkt im festen Loadout gültig")
_check(LoadoutKatalog.auswahl("sr1", rot_wire)["sight"] == "sight_collimator", "Rotpunkt Rundlauf")
_check(LoadoutKatalog.teil_name("sight_collimator") == "Rotpunktvisier", "Rotpunkt-Name deutsch")
_check(LoadoutKatalog.teil_name("") == "— nichts —", "leerer Slot benannt")
func _test_panel() -> void:
print("Testgruppe: Panel")
var scene: PackedScene = load("res://core/scenes/main.tscn")
main = scene.instantiate()
root.add_child(main)
await process_frame
await process_frame
main.doc = SvmapDocument.create_new("LoadoutTest", 512.0, "mittag")
main.history.doc = main.doc
main.call("_refresh_all")
var panel: Node = main.map_mod.sections_host().get_node_or_null("loadout")
_check(panel != null, "Loadout-Panel hängt im Map-Tab")
if panel == null:
return
_check(not panel.is_fixed() and not main.doc.has("loadout"), "Start: Spieler-Loadout, kein Block")
_check(not panel.fixed_box.visible, "Waffen-Auswahl verborgen")
panel.set_fixed(true)
_check(panel.is_fixed() and main.doc["loadout"]["primary"] == "m40", "fest: M40 als Start")
_check(panel.fixed_box.visible, "Waffen-Auswahl sichtbar")
panel.set_weapons("sr1", "")
_check(main.doc["loadout"]["primary"] == "sr1" and main.doc["loadout"]["secondary"] == "", "Waffen gesetzt, Sekundär leer")
panel.set_part("sr1", "muzzle", "muzzle_suppressor_01")
_check(main.doc["loadout"]["attachments"].get("sr1", "") == "muzzle=muzzle_suppressor_01", "Aufsatz gespeichert")
panel.set_part("ar1", "muzzle", "muzzle_suppressor_01")
_check(not main.doc["loadout"]["attachments"].has("ar1"), "Aufsatz für Nicht-Loadout-Waffe ignoriert")
_check(SvmapIO.validate_map(_signed(main.doc)).is_empty(), "Map mit Loadout besteht V1–V18")
# Rotpunktvisier: in der Auswahl deutsch benannt, wird gespeichert, besteht die Prüfung
var visier := panel.attach_box.find_child("Teil_sr1_sight", true, false) as OptionButton
var eintraege: Array[String] = []
if visier != null:
for i in visier.item_count:
eintraege.append(visier.get_item_text(i))
_check(eintraege.has("Rotpunktvisier"), "Rotpunktvisier in der Visier-Auswahl")
panel.set_part("sr1", "sight", "sight_collimator")
_check(main.doc["loadout"]["attachments"]["sr1"] == "muzzle=muzzle_suppressor_01;sight=sight_collimator", "Rotpunkt gespeichert")
_check(SvmapIO.validate_map(_signed(main.doc)).is_empty(), "Map mit Rotpunkt besteht V1–V18")
main.history.undo()
main.call("_refresh_all")
panel.set_weapons("ar1", "")
_check(not main.doc["loadout"]["attachments"].has("sr1"), "Waffenwechsel verwirft Aufsätze der alten Waffe")
# Undo/Redo
main.history.undo()
main.call("_refresh_all")
_check(main.doc["loadout"]["primary"] == "sr1" and main.doc["loadout"]["attachments"].has("sr1"), "Undo: Waffenwechsel zurück")
main.history.undo()
main.history.undo()
main.history.undo()
main.call("_refresh_all")
_check(not main.doc.has("loadout") and not panel.fixed_box.visible, "Undo bis Start: Block weg, UI nachgezogen")
main.history.redo()
main.call("_refresh_all")
_check(main.doc.has("loadout") and panel.is_fixed(), "Redo: fest wieder da")
# Zurück auf Spieler-Loadout entfernt den Block
panel.set_fixed(false)
_check(not main.doc.has("loadout"), "Spieler-Loadout entfernt den Block")
# Granaten + Minen: Undo, Spieler-Modus, Validierung
_check(not panel.vorrat_check.button_pressed and not panel.vorrat_box.visible, "Vorrat aus: Server-Standard")
panel.set_vorrat_aktiv(true)
_check(main.doc["loadout"]["mode"] == "player" and main.doc["loadout"]["mines"] == 2, "Vorrat an: Block im Spieler-Modus, Standard 2 Minen")
_check(panel.vorrat_box.visible and panel.minen_spin.value == 2, "Eingabefelder sichtbar")
panel.set_granaten("he1", 3)
panel.set_minen(1)
_check(main.doc["loadout"]["grenades"]["he1"] == 3 and main.doc["loadout"]["mines"] == 1, "Anzahlen gespeichert")
panel.set_granaten("smoke1", 0)
_check(not main.doc["loadout"]["grenades"].has("smoke1"), "0 entfernt die Art")
main.history.undo()
main.call("_refresh_all")
_check(main.doc["loadout"]["grenades"]["smoke1"] == 1 and panel.granaten_spins["smoke1"].value == 1, "Undo holt die Art zurück, UI folgt")
panel.granaten_spins["blend1"].value = 4
_check(main.doc["loadout"]["grenades"]["blend1"] == 4, "Eingabefeld schreibt den Wert")
_check(LoadoutKatalog.validate(main.doc["loadout"]).is_empty(), "Vorrat gültig")
panel.set_fixed(true)
_check(panel.is_fixed() and main.doc["loadout"]["mines"] == 1, "Wechsel auf fest behält den Vorrat")
panel.set_fixed(false)
_check(main.doc["loadout"]["mode"] == "player" and main.doc["loadout"]["mines"] == 1, "Wechsel auf Spieler behält den Vorrat")
_check(not LoadoutKatalog.validate({"mode": "player", "mines": 4}).is_empty(), "zu viele Minen ungültig")
_check(not LoadoutKatalog.validate({"mode": "player", "grenades": {"he1": 6}}).is_empty(), "zu viele Granaten ungültig")
_check(not LoadoutKatalog.validate({"mode": "player", "grenades": {"nix": 1}}).is_empty(), "unbekannte Granate ungültig")
_check(not LoadoutKatalog.validate({"mode": "player", "grenades": 3}).is_empty(), "grenades ohne Objekt ungültig")
panel.set_vorrat_aktiv(false)
_check(not main.doc.has("loadout"), "Vorrat aus im Spieler-Modus entfernt den Block")
# Speichern/Laden
panel.set_fixed(true)
panel.set_weapons("sr2", "pistol2")
var path := "user://loadout_test.svmap"
var doc2: Dictionary = main.doc.duplicate(true)
SvmapIO.sign_map(doc2)
var res := SvmapIO.save_to_file(path, doc2)
_check(res["ok"], "Speichern ok: " + str(res["errors"]))
var back := SvmapIO.load_from_file(path)
_check(back["ok"] and back["data"]["loadout"]["primary"] == "sr2", "Laden: Loadout bleibt erhalten")
panel.set_vorrat_aktiv(true)
panel.set_minen(3)
var doc3: Dictionary = main.doc.duplicate(true)
SvmapIO.sign_map(doc3)
res = SvmapIO.save_to_file(path, doc3)
back = SvmapIO.load_from_file(path)
_check(res["ok"] and back["ok"] and back["data"]["loadout"]["mines"] == 3, "Laden: Vorrat bleibt erhalten")
func _signed(d: Dictionary) -> Dictionary:
var c := d.duplicate(true)
SvmapIO.sign_map(c)
return c