Add the optional Forward+ desktop HQ build
Package a Forward+ preset with volumetric fog, SDFGI and a volumetric flashlight for a separate Linux/Windows Desktop HQ zip. Gate the effects on a real RenderingDevice, tune LATE fog, and adapt local light falloff for Godot 4.7. Record the Compatibility/Forward+ A/B captures and metrics, add the artifact to the build/publish scripts, and keep the default Compatibility/Web path unchanged. Headless 231/231, Python 87/87; exported HQ binary boots with Vulkan.
This commit is contained in:
1 parent
64f0c6a198
commit
28f2a48811
23 files changed
+337
-46
No files matched your search
@@ -30,6 +30,9 @@ const HOODED_TYPES := [5, 6, 7] # TRESPASSER, VIOLENT_THREAT, MENTAL_CRISIS
|
||||
|
||||
## Optional `--portrait-type=N` picks the NpcType a portrait should feature.
|
||||
var _portrait_type := -1
|
||||
## Optional `--flashlight` turns the guard lamp on for night stages; the desktop
|
||||
## HQ A/B uses it to show the volumetric shaft.
|
||||
var _flashlight := false
|
||||
## Where the portrait subject is placed, relative to the guard's spawn.
|
||||
var _portrait_spot := Vector3(0.0, 0.5, 9.0)
|
||||
var _portrait_subject: Node3D = null
|
||||
@@ -114,6 +117,8 @@ func _parse_args() -> void:
|
||||
_only_stages[name.strip_edges()] = true
|
||||
elif text.begins_with("--portrait-type="):
|
||||
_portrait_type = int(text.substr(16))
|
||||
elif text == "--flashlight":
|
||||
_flashlight = true
|
||||
|
||||
func _pair(text: String, into: Dictionary) -> void:
|
||||
var cut := text.find("=", 6) # skip the "res://" scheme
|
||||
@@ -168,6 +173,10 @@ func _begin_stage() -> void:
|
||||
if venue != "" and venue != str(gm.get("active_scenario_id")):
|
||||
gm.call("switch_scenario", venue)
|
||||
gm.coordinator.elapsed_s = float(stage["elapsed"])
|
||||
if _flashlight:
|
||||
var want := bool(stage["night"])
|
||||
if want != bool(gm.flashlight_on):
|
||||
gm.call("_toggle_flashlight")
|
||||
_apply(swaps)
|
||||
if bool(stage["night"]):
|
||||
_apply(night_swaps)
|
||||
|
||||
@@ -43,8 +43,11 @@ func test_flashlight_aims_a_tight_forward_spot() -> bool:
|
||||
var c := TestUtils.check(lamp != null and lamp.spot_angle <= 20.0,
|
||||
"flashlight cone is narrow enough to read as a torch")
|
||||
var d := TestUtils.check(lamp != null and not lamp.visible, "flashlight starts off")
|
||||
var e := TestUtils.check(lamp != null
|
||||
and is_zero_approx(lamp.light_volumetric_fog_energy),
|
||||
"headless/compatibility builds leave the flashlight non-volumetric")
|
||||
root.free()
|
||||
return a and b and c and d
|
||||
return a and b and c and d and e
|
||||
|
||||
func test_flashlight_widens_perception() -> bool:
|
||||
## Without the flashlight, an NPC at AWARE_RADIUS + 3 m is unaware.
|
||||
|
||||
@@ -77,14 +77,19 @@ func test_environment_tuning_applies_phase_values() -> bool:
|
||||
var f := TestUtils.check(
|
||||
env.fog_light_color.is_equal_approx(late["fog_color"]),
|
||||
"phase fog colour is used")
|
||||
return a and b and c and d and e and f
|
||||
var advanced := Materials.forward_plus_active()
|
||||
var g := TestUtils.check(env.volumetric_fog_enabled == advanced,
|
||||
"volumetric fog is gated to Forward+ (advanced=%s)" % advanced)
|
||||
var h := TestUtils.check(env.sdfgi_enabled == advanced,
|
||||
"SDFGI is gated to Forward+ (advanced=%s)" % advanced)
|
||||
return a and b and c and d and e and f and g and h
|
||||
|
||||
func test_every_phase_has_environment_keys() -> bool:
|
||||
var ok := true
|
||||
for phase in [Rules.Phase.EARLY, Rules.Phase.MIDDAY, Rules.Phase.EVENING, Rules.Phase.LATE]:
|
||||
var cfg: Dictionary = GameManager.PHASE_LIGHTING.get(phase, {})
|
||||
for key in ["exposure", "glow", "fog_color", "fog_density", "fog_energy",
|
||||
"contrast", "saturation"]:
|
||||
"contrast", "saturation", "volumetric_density", "volumetric_energy"]:
|
||||
if not cfg.has(key):
|
||||
ok = false
|
||||
return TestUtils.check(ok, "all phases set exposure/glow/fog/grading")
|
||||
|
||||
Reference in new issue
Block a user