# test_item_attr_parity.gd —— 验证方向 1:装备附魔、洗炼与祝福宝珠 40250 1:1 对齐 extends SceneTree const ItemAttrSystem = preload("res://item_attr_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_item_attr_parity (Direction 1: Item Add/Change Bonus 1:1) ===") test_scroll_detection() test_can_have_attributes() test_add_attribute_parity() test_change_attribute_parity() test_blessing_marble_parity() print("\n=== SUMMARY: %d passed, %d failed ===" % [_passed, _failed]) if _failed > 0: printerr("TEST FAILED!") quit(1) else: print("ALL TESTS PASSED!") quit(0) func test_scroll_detection() -> void: print("\n--- Test 1: Scroll Vnum Detection (71084, 71085, 70024) ---") _assert(ItemAttrSystem.is_attr_scroll(71085), "71085 is detected as Add Attribute Scroll") _assert(ItemAttrSystem.is_attr_scroll(71084), "71084 is detected as Change Attribute Scroll") _assert(ItemAttrSystem.is_attr_scroll(70024), "70024 is detected as Blessing Marble") _assert(not ItemAttrSystem.is_attr_scroll(27001), "Normal potion is not an attr scroll") _assert(not ItemAttrSystem.is_attr_scroll(10), "Sword is not an attr scroll") func test_can_have_attributes() -> void: print("\n--- Test 2: Target Equipment Compatibility (Weapon/Armor vs Arrow) ---") var weapon := {"type": ItemAttrSystem.ITEM_TYPE_WEAPON, "sub_type": 0} # 剑 var armor := {"type": ItemAttrSystem.ITEM_TYPE_ARMOR, "sub_type": 0} # 衣服 var arrow := {"type": ItemAttrSystem.ITEM_TYPE_WEAPON, "sub_type": 5} # 箭矢 var potion := {"type": 3, "sub_type": 0} # 消耗品 _assert(ItemAttrSystem.can_have_attributes(weapon), "Weapon can have attributes") _assert(ItemAttrSystem.can_have_attributes(armor), "Armor can have attributes") _assert(not ItemAttrSystem.can_have_attributes(arrow), "Arrow (WEAPON_ARROW) cannot have attributes") _assert(not ItemAttrSystem.can_have_attributes(potion), "Potion cannot have attributes") func test_add_attribute_parity() -> void: print("\n--- Test 3: 40250 Add Attribute Progression (1..4 Attrs & Cap) ---") var weapon_proto := {"type": ItemAttrSystem.ITEM_TYPE_WEAPON, "sub_type": 0} var sword_item := {"vnum": 10, "attrs": []} # 1st attribute var res1 := ItemAttrSystem.apply_add_attribute(sword_item, weapon_proto, true) _assert(res1.ok and res1.code == "SUCCESS", "1st attribute added successfully") _assert(sword_item.attrs.size() == 1, "Sword has 1 attribute now") # 2nd attribute var res2 := ItemAttrSystem.apply_add_attribute(sword_item, weapon_proto, true) _assert(res2.ok and res2.code == "SUCCESS", "2nd attribute added successfully") _assert(sword_item.attrs.size() == 2, "Sword has 2 attributes now") _assert(sword_item.attrs[0].type != sword_item.attrs[1].type, "1st and 2nd attribute types are distinct (no duplicate)") # 3rd attribute var res3 := ItemAttrSystem.apply_add_attribute(sword_item, weapon_proto, true) _assert(res3.ok and res3.code == "SUCCESS", "3rd attribute added successfully") _assert(sword_item.attrs.size() == 3, "Sword has 3 attributes now") # 4th attribute var res4 := ItemAttrSystem.apply_add_attribute(sword_item, weapon_proto, true) _assert(res4.ok and res4.code == "SUCCESS", "4th attribute added successfully") _assert(sword_item.attrs.size() == 4, "Sword has 4 attributes now") # 5th attempt with normal scroll 71085 MUST fail (40250 char_item.cpp:4665 item2->GetAttributeCount() < 4) var res5 := ItemAttrSystem.apply_add_attribute(sword_item, weapon_proto, true) _assert(not res5.ok and res5.code == "MAX_ATTR_REACHED", "Normal scroll cannot add 5th attribute (MAX_ATTR_REACHED)") _assert(sword_item.attrs.size() == 4, "Sword remains at 4 attributes") func test_change_attribute_parity() -> void: print("\n--- Test 4: 40250 Change Attribute (Reroll All Attributes) ---") var weapon_proto := {"type": ItemAttrSystem.ITEM_TYPE_WEAPON, "sub_type": 0} var empty_item := {"vnum": 10, "attrs": []} # Fails on item with 0 attributes (40250 char_item.cpp:4560 item2->GetAttributeCount() == 0) var res_empty := ItemAttrSystem.apply_change_attribute(empty_item, weapon_proto) _assert(not res_empty.ok and res_empty.code == "NO_ATTRIBUTES", "Change attribute fails when item has 0 attributes") var geared_item := { "vnum": 10, "attrs": [ {"type": 1, "value": 500}, {"type": 15, "value": 10}, {"type": 16, "value": 10} ] } var res_reroll := ItemAttrSystem.apply_change_attribute(geared_item, weapon_proto) _assert(res_reroll.ok and res_reroll.code == "SUCCESS", "Change attribute rerolls successfully") _assert(geared_item.attrs.size() == 3, "Item still has exactly 3 attributes after reroll") # Verify all rerolled attribute types are unique var types := {} var has_duplicate := false for a in geared_item.attrs: if types.has(a.type): has_duplicate = true types[a.type] = true _assert(not has_duplicate, "All rerolled attribute types are distinct") func test_blessing_marble_parity() -> void: print("\n--- Test 5: 40250 Blessing Marble 70024 (5th Attribute Lock) ---") var weapon_proto := {"type": ItemAttrSystem.ITEM_TYPE_WEAPON, "sub_type": 0} # Item with 3 attributes -> marble fails (40250 char_item.cpp:4738 item2->GetAttributeCount() == 4) var item_3_attrs := { "vnum": 10, "attrs": [ {"type": 1, "value": 500}, {"type": 2, "value": 200}, {"type": 3, "value": 4} ] } var res_marble_fail := ItemAttrSystem.apply_blessing_marble(item_3_attrs, weapon_proto, true) _assert(not res_marble_fail.ok and res_marble_fail.code == "NEED_FOUR_ATTRS", "Blessing marble fails on item with less than 4 attributes") # Item with 4 attributes -> marble succeeds and adds 5th item_3_attrs.attrs.append({"type": 4, "value": 4}) var res_marble_ok := ItemAttrSystem.apply_blessing_marble(item_3_attrs, weapon_proto, true) _assert(res_marble_ok.ok and res_marble_ok.code == "SUCCESS", "Blessing marble successfully unlocks 5th attribute") _assert(item_3_attrs.attrs.size() == 5, "Item now has 5 attributes") # Marble fails on item that already has 5 attributes var res_marble_cap := ItemAttrSystem.apply_blessing_marble(item_3_attrs, weapon_proto, true) _assert(not res_marble_cap.ok and res_marble_cap.code == "ALREADY_FIVE_ATTRS", "Blessing marble cannot exceed 5 attributes")