- 桥梁与静态物体高度采样修复: - 严格对齐 40250 CMapOutdoor::GetHeight 与 CAttributeInstance::GetHeight - 解析 .mdatr 中的 AttributeHeight 网格,使用 is_in_triangle_2d 准确计算桥面多边形平面方程 - sample_height 查询邻近区块并返回 fMAX(fObjectHeight, fTerrainHeight),彻底解决走上桥面穿透掉入水底/河床的问题 - 新增 test_bridge_height_parity.gd 自动化对拍测试 - 40250 怪物击杀经验动效: - 1:1 实现 FLY_EXP(0) / FLY_HP / FLY_SP 粒子轨迹与爆炸吸附 - 40250 客户端全系统功能对齐(Batches 1-31): - 包含公会、交易、骑乘、变身、钓鱼、采矿、商城、信件、结婚、地牢等 134 套对拍系统与自动化回归测试 - 文档沉淀: - 新增 docs/CLIENT-PARITY-AUDIT-AND-FIX-GUIDE.md 客户端对拍缺陷发现与修复工程指南
127 lines
4.8 KiB
GDScript
127 lines
4.8 KiB
GDScript
# test_weather_daynight_parity.gd —— 40250 昼夜交替与地图天候环境 1:1 回归测试套件
|
|
extends SceneTree
|
|
|
|
const WeatherDayNightSystem = preload("res://weather_daynight_system.gd")
|
|
|
|
var _passed := 0
|
|
var _failed := 0
|
|
|
|
func _assert(cond: bool, msg: String) -> void:
|
|
if cond:
|
|
_passed += 1
|
|
print(" [PASS] %s" % msg)
|
|
else:
|
|
_failed += 1
|
|
printerr(" [FAIL] %s" % msg)
|
|
|
|
func _init() -> void:
|
|
print("\n=== Running test_weather_daynight_parity (Direction 4: Day/Night & Weather 1:1) ===")
|
|
_test_default_state()
|
|
_test_phase_transitions()
|
|
_test_time_progression_and_wrap()
|
|
_test_weather_modes_and_maps()
|
|
_finish()
|
|
|
|
func _test_default_state() -> void:
|
|
print("\n--- Test 1: Default Noon State & Formatted Time ---")
|
|
var w := WeatherDayNightSystem.new()
|
|
_assert(w.current_phase == WeatherDayNightSystem.PHASE_NOON, "Defaults to NOON")
|
|
_assert(w.current_weather == WeatherDayNightSystem.WEATHER_CLEAR, "Defaults to CLEAR weather")
|
|
_assert(w.get_time_string() == "12:00:00", "Default time is 12:00:00")
|
|
_assert(w.sun_energy == 1.2, "Noon sun energy is 1.2")
|
|
|
|
func _test_phase_transitions() -> void:
|
|
print("\n--- Test 2: Phase Transitions (Dawn, Noon, Dusk, Night) ---")
|
|
var w := WeatherDayNightSystem.new()
|
|
|
|
var phase_sig := {"fired": false, "old": "", "new": ""}
|
|
w.phase_changed.connect(func(o: String, n: String):
|
|
phase_sig["fired"] = true
|
|
phase_sig["old"] = o
|
|
phase_sig["new"] = n
|
|
)
|
|
|
|
# Transition to DAWN (06:00)
|
|
w.set_phase(WeatherDayNightSystem.PHASE_DAWN)
|
|
_assert(w.current_phase == WeatherDayNightSystem.PHASE_DAWN, "Phase is DAWN")
|
|
_assert(phase_sig["fired"] == true and phase_sig["new"] == "dawn", "phase_changed emitted dawn")
|
|
_assert(w.sun_color.r > 0.9 and w.sun_color.g > 0.7, "Dawn has warm golden light")
|
|
|
|
# Transition to DUSK (18:30)
|
|
phase_sig["fired"] = false
|
|
w.set_phase(WeatherDayNightSystem.PHASE_DUSK)
|
|
_assert(w.current_phase == WeatherDayNightSystem.PHASE_DUSK, "Phase is DUSK")
|
|
_assert(phase_sig["fired"] == true and phase_sig["new"] == "dusk", "phase_changed emitted dusk")
|
|
|
|
# Transition to NIGHT (23:00)
|
|
phase_sig["fired"] = false
|
|
w.set_phase(WeatherDayNightSystem.PHASE_NIGHT)
|
|
_assert(w.current_phase == WeatherDayNightSystem.PHASE_NIGHT, "Phase is NIGHT")
|
|
_assert(phase_sig["fired"] == true and phase_sig["new"] == "night", "phase_changed emitted night")
|
|
_assert(w.sun_energy <= 0.3, "Night has low moon energy")
|
|
|
|
func _test_time_progression_and_wrap() -> void:
|
|
print("\n--- Test 3: Time Flow, Freezing, and Midnight Wrap ---")
|
|
var w := WeatherDayNightSystem.new()
|
|
w.set_time_of_day(12.0, 0.0) # 12:00:00
|
|
w.time_scale = 60.0 # 1 real sec = 60 game sec
|
|
|
|
# Advance 1 second -> should become 12:01:00
|
|
w.update(1.0)
|
|
_assert(w.get_time_string() == "12:01:00", "Advanced 1 minute of game time")
|
|
|
|
# Freeze time
|
|
w.is_frozen = true
|
|
w.update(5.0)
|
|
_assert(w.get_time_string() == "12:01:00", "Time remains frozen")
|
|
|
|
# Midnight wrap test: 23:59:30 + 60s -> 00:00:30
|
|
w.is_frozen = false
|
|
w.time_scale = 1.0
|
|
w.set_time_of_day(23.0, 59.0)
|
|
w.time_of_day += 30.0 # 23:59:30
|
|
w.update(60.0) # +60s
|
|
_assert(w.time_of_day < 3600.0, "Wrapped cleanly past midnight")
|
|
_assert(w.current_phase == WeatherDayNightSystem.PHASE_NIGHT, "Still NIGHT after midnight wrap")
|
|
|
|
func _test_weather_modes_and_maps() -> void:
|
|
print("\n--- Test 4: Map Weather Presets & Environment Atmospheres ---")
|
|
var w := WeatherDayNightSystem.new()
|
|
|
|
var weather_sig := {"fired": false, "old": "", "new": ""}
|
|
w.weather_changed.connect(func(o: String, n: String):
|
|
weather_sig["fired"] = true
|
|
weather_sig["old"] = o
|
|
weather_sig["new"] = n
|
|
)
|
|
|
|
# Switch map to Mount Sohan (Ice Mountain) -> Snow
|
|
w.set_map_environment("sohan")
|
|
_assert(w.current_weather == WeatherDayNightSystem.WEATHER_SNOW, "Mount Sohan auto-activates SNOW")
|
|
_assert(weather_sig["fired"] == true and weather_sig["new"] == "snow", "weather_changed emitted snow")
|
|
|
|
# Switch map to Yongbi Desert -> Sandstorm
|
|
w.set_map_environment("desert")
|
|
_assert(w.current_weather == WeatherDayNightSystem.WEATHER_SANDSTORM, "Desert auto-activates SANDSTORM")
|
|
_assert(w.fog_density >= 0.005, "Sandstorm substantially raises fog density")
|
|
|
|
# Switch map to Doyyumhwan (Flame field) -> Cinders
|
|
w.set_map_environment("flame")
|
|
_assert(w.current_weather == WeatherDayNightSystem.WEATHER_CINDERS, "Flame field auto-activates CINDERS")
|
|
|
|
# Switch back to Village -> Clear
|
|
w.set_map_environment("village")
|
|
_assert(w.current_weather == WeatherDayNightSystem.WEATHER_CLEAR, "Village reverts to CLEAR sky")
|
|
|
|
func _finish() -> void:
|
|
print("\n==========================================")
|
|
print("Weather Day/Night Parity Tests Finished:")
|
|
print("Passed: %d, Failed: %d" % [_passed, _failed])
|
|
print("==========================================")
|
|
if _failed > 0:
|
|
printerr("FAILED: Some tests did not pass.")
|
|
quit(1)
|
|
else:
|
|
print("SUCCESS: All Weather Day/Night parity tests passed!")
|
|
quit(0)
|