# test_costume_system_parity.gd —— 40250 独立时装衣柜系统 1:1 纯净回归测试套件 extends SceneTree const CostumeSystem = preload("res://costume_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_costume_system_parity (Direction 1: Costume System 1:1) ===") _test_slot_type_validation() _test_costume_equip_and_unequip() _test_stat_stacking_and_appearance() _test_costume_expiration() _finish() func _test_slot_type_validation() -> void: print("\n--- Test 1: Slot Type & Item Category Validation ---") var cs := CostumeSystem.new() var body_costume := {"vnum": 41001, "name": "沙漠战袍", "costume_type": "body", "model_id": 101} var hair_costume := {"vnum": 45001, "name": "头巾发型", "costume_type": "hair", "model_id": 201} # Invalid slot var r_bad = cs.equip_costume(99, body_costume) _assert(r_bad["ok"] == false and r_bad["reason"] == "INVALID_SLOT", "Invalid slot rejected") # Put body costume into hair slot var r_mismatch1 = cs.equip_costume(CostumeSystem.CostumeSlot.COSTUME_HAIR, body_costume) _assert(r_mismatch1["ok"] == false and r_mismatch1["reason"] == "SLOT_TYPE_MISMATCH", "Body costume rejected in Hair slot") # Put hair costume into weapon slot var r_mismatch2 = cs.equip_costume(CostumeSystem.CostumeSlot.COSTUME_WEAPON, hair_costume) _assert(r_mismatch2["ok"] == false and r_mismatch2["reason"] == "SLOT_TYPE_MISMATCH", "Hair costume rejected in Weapon slot") func _test_costume_equip_and_unequip() -> void: print("\n--- Test 2: Equip & Unequip Operations ---") var cs := CostumeSystem.new() var body_item := { "vnum": 41001, "name": "黑骑士战袍", "costume_type": "body", "model_id": 105, "bonuses": {"max_hp": 1000} } var equip_signal := {"fired": false, "slot": -1} cs.costume_equipped.connect(func(s: int, _it: Dictionary): equip_signal["fired"] = true equip_signal["slot"] = s ) var unequip_signal := {"fired": false, "slot": -1} cs.costume_unequipped.connect(func(s: int): unequip_signal["fired"] = true unequip_signal["slot"] = s ) # Equip var r_eq = cs.equip_costume(CostumeSystem.CostumeSlot.COSTUME_BODY, body_item) _assert(r_eq["ok"] == true, "Body costume equipped successfully") _assert(cs.equipped_costumes[CostumeSystem.CostumeSlot.COSTUME_BODY] != null, "Body slot occupied") _assert(equip_signal["fired"] == true and equip_signal["slot"] == CostumeSystem.CostumeSlot.COSTUME_BODY, "costume_equipped signal fired") # Unequip var r_uneq = cs.unequip_costume(CostumeSystem.CostumeSlot.COSTUME_BODY) _assert(r_uneq["ok"] == true, "Body costume unequipped") _assert(cs.equipped_costumes[CostumeSystem.CostumeSlot.COSTUME_BODY] == null, "Body slot now null") _assert(unequip_signal["fired"] == true and unequip_signal["slot"] == CostumeSystem.CostumeSlot.COSTUME_BODY, "costume_unequipped signal fired") # Unequip empty slot var r_empty = cs.unequip_costume(CostumeSystem.CostumeSlot.COSTUME_BODY) _assert(r_empty["ok"] == false and r_empty["reason"] == "SLOT_EMPTY", "Unequipping empty slot rejected") func _test_stat_stacking_and_appearance() -> void: print("\n--- Test 3: Stat Stacking & 3D Appearance Overrides ---") var cs := CostumeSystem.new() var body := {"vnum": 41001, "costume_type": "body", "model_id": 101, "bonuses": {"max_hp": 1000, "att_pct": 5}} var hair := {"vnum": 45001, "costume_type": "hair", "model_id": 202, "bonuses": {"max_hp": 500, "cast_speed": 10}} var weapon := {"vnum": 49001, "costume_type": "weapon", "model_id": 303, "bonuses": {"monster_dmg_pct": 10}} cs.equip_costume(CostumeSystem.CostumeSlot.COSTUME_BODY, body) cs.equip_costume(CostumeSystem.CostumeSlot.COSTUME_HAIR, hair) cs.equip_costume(CostumeSystem.CostumeSlot.COSTUME_WEAPON, weapon) # Verify Stat Stacking var bonuses = cs.get_costume_bonuses() _assert(bonuses["max_hp"] == 1500, "Stacked Max HP is 1500 (1000 + 500)") _assert(bonuses["att_pct"] == 5, "ATK is +5%") _assert(bonuses["cast_speed"] == 10, "Casting Speed is +10") _assert(bonuses["monster_dmg_pct"] == 10, "Monster Dmg is +10%") # Verify 3D Model Overrides var models = cs.get_appearance_overrides() _assert(models["body_model"] == 101, "Body model is 101") _assert(models["hair_model"] == 202, "Hair model is 202") _assert(models["weapon_model"] == 303, "Weapon model is 303") func _test_costume_expiration() -> void: print("\n--- Test 4: Duration Decay & Expiration Auto-Unequip ---") var cs := CostumeSystem.new() var temp_body := { "vnum": 41002, "name": "限时战袍", "costume_type": "body", "remaining_time": 10.0, "bonuses": {"max_hp": 800} } cs.equip_costume(CostumeSystem.CostumeSlot.COSTUME_BODY, temp_body) var expire_signal := {"fired": false, "name": ""} cs.costume_expired.connect(func(_s: int, iname: String): expire_signal["fired"] = true expire_signal["name"] = iname ) # Update 5.0 seconds -> still active cs.update(5.0) _assert(cs.equipped_costumes[CostumeSystem.CostumeSlot.COSTUME_BODY] != null, "Still active after 5s") _assert(cs.get_costume_bonuses()["max_hp"] == 800, "Bonus HP still active") # Update 6.0 seconds -> expired! var expired = cs.update(6.0) _assert(expired.size() == 1, "1 item expired") _assert(cs.equipped_costumes[CostumeSystem.CostumeSlot.COSTUME_BODY] == null, "Auto-unequipped on expiration") _assert(expire_signal["fired"] == true and expire_signal["name"] == "限时战袍", "costume_expired signal fired") _assert(cs.get_costume_bonuses().is_empty(), "Bonuses cleared after expiration") func _finish() -> void: print("\n==========================================") print("Costume System Parity Test Results: %d Passed, %d Failed" % [_passed, _failed]) print("==========================================") if _failed > 0: quit(1) else: quit(0)