- 桥梁与静态物体高度采样修复: - 严格对齐 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 客户端对拍缺陷发现与修复工程指南
141 lines
5.1 KiB
GDScript
141 lines
5.1 KiB
GDScript
# test_biologist_quest_parity.gd —— 40250 生物学研究家任务链 1:1 纯净回归测试套件
|
|
extends SceneTree
|
|
|
|
const BiologistQuestSystem = preload("res://biologist_quest_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_biologist_quest_parity (Direction 1: Biologist Quests 1:1) ===")
|
|
_test_level_unlock()
|
|
_test_item_submission_and_potion()
|
|
_test_soul_stone_completion_and_bonuses()
|
|
_test_full_chain_progression()
|
|
_finish()
|
|
|
|
func _test_level_unlock() -> void:
|
|
print("\n--- Test 1: Level Requirement & Stage Unlock ---")
|
|
var bio := BiologistQuestSystem.new()
|
|
bio.init_for_player(25) # Level 25
|
|
_assert(bio.current_stage_idx == -1, "Level 25 cannot start Lv30 Orc Tooth quest")
|
|
|
|
bio.init_for_player(30) # Level 30
|
|
_assert(bio.current_stage_idx == 0, "Level 30 unlocks Stage 0 (Orc Tooth)")
|
|
var stage: Dictionary = bio.get_current_stage()
|
|
_assert(stage["collect_vnum"] == 30006, "Stage 0 requires Orc Tooth (30006)")
|
|
_assert(stage["collect_count"] == 10, "Stage 0 requires 10 teeth")
|
|
|
|
func _test_item_submission_and_potion() -> void:
|
|
print("\n--- Test 2: Item Submission & Spiral Potion (71035) ---")
|
|
var bio := BiologistQuestSystem.new()
|
|
bio.init_for_player(30)
|
|
|
|
var inv: Array = [
|
|
{"vnum": 30006}, # slot 0: Orc Tooth
|
|
{"vnum": 71035}, # slot 1: Spiral Potion
|
|
null
|
|
]
|
|
|
|
# Test missing item error
|
|
var empty_inv: Array = [null, null]
|
|
var res = bio.submit_item(empty_inv)
|
|
_assert(res["ok"] == false and res["reason"] == "MISSING_ITEM", "Fails when missing tooth in inventory")
|
|
|
|
# Test successful submission with Spiral Potion
|
|
res = bio.submit_item(inv, true, true)
|
|
_assert(res["ok"] == true and res["success"] == true, "Submission succeeds with potion")
|
|
_assert(bio.delivered_count == 1, "Delivered count incremented to 1")
|
|
_assert(inv[0] == null, "Tooth consumed from slot 0")
|
|
_assert(inv[1] == null, "Spiral Potion consumed from slot 1")
|
|
_assert(bio.cooldown_remaining == 0.0, "Cooldown is 0 with potion")
|
|
|
|
func _test_soul_stone_completion_and_bonuses() -> void:
|
|
print("\n--- Test 3: Soul Stone Phase & Permanent Stat Bonus ---")
|
|
var bio := BiologistQuestSystem.new()
|
|
bio.init_for_player(30)
|
|
bio.delivered_count = 10
|
|
bio.soul_stone_phase = true
|
|
|
|
var inv: Array = [
|
|
{"vnum": 30220}, # Jinunggyi's Soul Stone
|
|
null
|
|
]
|
|
|
|
# Test without soul stone
|
|
var res = bio.submit_soul_stone([null])
|
|
_assert(res["ok"] == false and res["reason"] == "MISSING_SOUL_STONE", "Fails without soul stone")
|
|
|
|
# Submit soul stone
|
|
res = bio.submit_soul_stone(inv)
|
|
_assert(res["ok"] == true, "Soul stone submitted successfully")
|
|
_assert(res["completed_stage"] == 0, "Stage 0 completed")
|
|
_assert(bio.permanent_bonuses["move_speed"] == 10, "Permanent move speed +10 granted")
|
|
_assert(inv[0] == null, "Soul stone consumed from inventory")
|
|
|
|
func _test_full_chain_progression() -> void:
|
|
print("\n--- Test 4: Full Quest Progression Lv30 -> Lv80 ---")
|
|
var bio := BiologistQuestSystem.new()
|
|
bio.init_for_player(85) # High level to test through all stages
|
|
|
|
# Stage 0: Orc Tooth (Lv30)
|
|
_assert(bio.current_stage_idx == 0, "Current stage is 0 (Lv30)")
|
|
bio.delivered_count = 10
|
|
bio.soul_stone_phase = true
|
|
bio.submit_soul_stone([{"vnum": 30220}])
|
|
_assert(bio.permanent_bonuses["move_speed"] == 10, "Lv30 Bonus: Move speed +10")
|
|
|
|
# Stage 1: Curse Book (Lv40)
|
|
_assert(bio.current_stage_idx == 1, "Advanced to stage 1 (Lv40 Curse Book)")
|
|
bio.delivered_count = 15
|
|
bio.soul_stone_phase = true
|
|
bio.submit_soul_stone([{"vnum": 30221}])
|
|
_assert(bio.permanent_bonuses["att_speed"] == 5, "Lv40 Bonus: Attack speed +5")
|
|
|
|
# Stage 2: Demon Keepsake (Lv50)
|
|
_assert(bio.current_stage_idx == 2, "Advanced to stage 2 (Lv50 Demon Keepsake)")
|
|
bio.delivered_count = 15
|
|
bio.soul_stone_phase = true
|
|
bio.submit_soul_stone([{"vnum": 30222}])
|
|
_assert(bio.permanent_bonuses["def_grade"] == 60, "Lv50 Bonus: Defense +60")
|
|
|
|
# Stage 3: Ice Marble (Lv60)
|
|
_assert(bio.current_stage_idx == 3, "Advanced to stage 3 (Lv60 Ice Marble)")
|
|
bio.delivered_count = 20
|
|
bio.soul_stone_phase = true
|
|
bio.submit_soul_stone([{"vnum": 30223}])
|
|
_assert(bio.permanent_bonuses["att_grade"] == 50, "Lv60 Bonus: Attack power +50")
|
|
|
|
# Stage 4: Zelkova Branch (Lv70)
|
|
_assert(bio.current_stage_idx == 4, "Advanced to stage 4 (Lv70 Zelkova Branch)")
|
|
bio.delivered_count = 25
|
|
bio.soul_stone_phase = true
|
|
bio.submit_soul_stone([{"vnum": 30224}])
|
|
_assert(bio.permanent_bonuses["damage_reduction"] == 10, "Lv70 Bonus: Damage reduction 10%")
|
|
|
|
# Stage 5: Tugyi's Tablet (Lv80)
|
|
_assert(bio.current_stage_idx == 5, "Advanced to stage 5 (Lv80 Tugyi Tablet)")
|
|
bio.delivered_count = 30
|
|
bio.soul_stone_phase = true
|
|
bio.submit_soul_stone([{"vnum": 30225}])
|
|
_assert(bio.permanent_bonuses["att_grade_pct"] == 10, "Lv80 Bonus: Attack power +10%")
|
|
|
|
_assert(bio.completed_stages.size() == 6, "All 6 biologist quest stages completed")
|
|
|
|
func _finish() -> void:
|
|
print("\n=== SUMMARY: %d passed, %d failed ===" % [_passed, _failed])
|
|
if _failed == 0:
|
|
print("ALL TESTS PASSED!\n")
|
|
quit(0)
|
|
else:
|
|
printerr("SOME TESTS FAILED!\n")
|
|
quit(1)
|