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