Files
mtgodot-poc/project/test_intro_select_parity.gd
T
shenandshen 66d217b313 feat(client): 完成40250客户端核心功能1:1对齐与桥梁高度采样修复
- 桥梁与静态物体高度采样修复:
  - 严格对齐 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 客户端对拍缺陷发现与修复工程指南
2026-09-19 08:51:25 -07:00

125 lines
4.2 KiB
GDScript

# test_intro_select_parity.gd —— 40250 3D 角色选择大厅回归测试
extends SceneTree
const SystemClass = preload("res://intro_select_phase.gd")
var _passed: int = 0
var _failed: int = 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_intro_select_parity (Batch 29 Direction 3) ===")
_test_slot_rotations_and_empty_selection()
_test_character_selection_and_stepping_motion()
_test_character_card_data()
_test_start_game_validation()
_test_7digit_pin_character_deletion()
print("\n=== Result: %d Passed, %d Failed ===" % [_passed, _failed])
if _failed == 0:
print("ALL TESTS PASSED!\n")
else:
printerr("SOME TESTS FAILED!\n")
quit(0 if _failed == 0 else 1)
func _test_slot_rotations_and_empty_selection() -> void:
print("\n--- Test 1: Slot Rotations & Empty Slot Handling ---")
var sel = SystemClass.new()
_assert(sel.character_slots.size() == 4, "Total 4 character slots")
_assert(SystemClass.SLOT_ROTATION == [135.0, 225.0, 315.0, 45.0], "Official 4-slot rotation angles match")
# Select empty slot 0
var r0 = sel.select_slot(0)
_assert(r0["is_empty_slot"] == true, "Slot 0 is empty")
_assert(r0["action"] == "PROMPT_CREATE", "Empty slot prompts to CREATE")
_assert(sel.is_character_stepped_forward == false, "No step forward motion for empty slot")
func _test_character_selection_and_stepping_motion() -> void:
print("\n--- Test 2: Character Selection & Step Forward Motion ---")
var sel = SystemClass.new()
var warrior = {
"name": "DragonSlayer",
"level": 75,
"job": SystemClass.JOB_WARRIOR,
"horse_level": 21,
"playtime_min": 12000,
"delete_code": "7654321",
"stats": { "con": 90, "int": 10, "str": 90, "dex": 40 }
}
sel.set_character_slot(1, warrior)
var r1 = sel.select_slot(1)
_assert(r1["success"] == true, "Selected slot 1")
_assert(r1["is_empty_slot"] == false, "Slot 1 is populated")
_assert(sel.is_character_stepped_forward == true, "Character stepped forward (MOTION_INTRO_SELECTED)")
_assert(r1["rotation_deg"] == 225.0, "Slot 1 rotation is 225 degrees")
func _test_character_card_data() -> void:
print("\n--- Test 3: Character Card Attributes ---")
var sel = SystemClass.new()
var sura = {
"name": "DarkMage",
"level": 60,
"job": SystemClass.JOB_SURA,
"horse_level": 11,
"playtime_min": 5000,
"stats": { "con": 50, "int": 90, "str": 40, "dex": 20 }
}
sel.set_character_slot(0, sura)
sel.select_slot(0)
var card = sel.get_selected_character_card()
_assert(card["name"] == "DarkMage", "Card name is DarkMage")
_assert(card["level"] == 60, "Card level is 60")
_assert(card["job_name"].contains("修罗"), "Job name is Sura")
_assert(card["stats"]["int"] == 90, "INT stat is 90")
func _test_start_game_validation() -> void:
print("\n--- Test 4: Start Game Flow ---")
var sel = SystemClass.new()
# Start on empty slot -> Rejected
sel.select_slot(2) # empty
var r_fail = sel.start_game()
_assert(r_fail["error_code"] == "EMPTY_SLOT", "Reject start game on empty slot")
# Populate and start
sel.set_character_slot(2, { "name": "Ninja", "level": 10, "job": 1 })
sel.select_slot(2)
var r_ok = sel.start_game()
_assert(r_ok["success"] == true, "Start game succeeded with valid character")
_assert(r_ok["character"]["name"] == "Ninja", "Transferred character into game")
func _test_7digit_pin_character_deletion() -> void:
print("\n--- Test 5: 7-Digit Security PIN Character Deletion ---")
var sel = SystemClass.new()
var char_to_del = {
"name": "DeleteMe",
"level": 1,
"job": 0,
"delete_code": "1234567"
}
sel.set_character_slot(3, char_to_del)
# 1. Invalid PIN length
var r_len = sel.delete_character(3, "123")
_assert(r_len["error_code"] == "INVALID_PIN_LENGTH", "Reject deletion if PIN != 7 digits")
# 2. Wrong PIN
var r_wrong = sel.delete_character(3, "9999999")
_assert(r_wrong["error_code"] == "WRONG_DELETE_PIN", "Reject deletion on incorrect PIN")
_assert(sel.character_slots[3] != null, "Character preserved on failed PIN")
# 3. Correct PIN (1234567)
var r_ok = sel.delete_character(3, "1234567")
_assert(r_ok["success"] == true, "Character deleted on correct 7-digit PIN")
_assert(sel.character_slots[3] == null, "Slot 3 is now null/empty")