# test_mysterious_merchant_blackmarket_parity.gd —— 40250 野外神秘游商与黑市折扣系统 1:1 回归测试套件 extends SceneTree const MysteriousMerchantBlackmarketSystem = preload("res://mysterious_merchant_blackmarket_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_mysterious_merchant_blackmarket_parity (Direction 4: Mysterious Merchant Blackmarket 1:1) ===") _test_merchant_spawn_and_lifecycle() _test_blackmarket_goods_and_discount_purchase() _test_high_price_buyback_and_antiflag() _test_serialization_and_persistence() _finish() func _test_merchant_spawn_and_lifecycle() -> void: print("\n--- Test 1: Merchant Spawn & Lifecycle ---") var sys := MysteriousMerchantBlackmarketSystem.new() _assert(not sys.is_active, "Initially merchant is not active") var spawn_sig := {"fired": false, "map": "", "pos": Vector2.ZERO, "dur": 0.0} sys.merchant_appeared.connect(func(m: String, p: Vector2, d: float): spawn_sig["fired"] = true spawn_sig["map"] = m spawn_sig["pos"] = p spawn_sig["dur"] = d ) var depart_sig := {"fired": false} sys.merchant_departed.connect(func(): depart_sig["fired"] = true ) # Spawn at fixed location index 0 (Desert) var spawn_res = sys.spawn_random_merchant(1800.0, 0) _assert(spawn_res["ok"] == true, "Spawn result ok") _assert(sys.is_active == true, "System active flag is true") _assert(sys.current_map == "Desert", "Spawned at Desert") _assert(sys.current_pos == Vector2(120, 350), "Spawn pos matches Desert Oasis") _assert(spawn_sig["fired"] == true, "merchant_appeared signal fired") _assert(spawn_sig["dur"] == 1800.0, "Signal duration is 1800.0s") # Update heartbeat - advance 600s sys.update(600.0) _assert(is_equal_approx(sys.time_remaining, 1200.0), "Time remaining decremented to 1200s") _assert(sys.is_active == true, "Still active after 600s") # Update heartbeat - advance remaining 1200s to timeout sys.update(1200.0) _assert(sys.is_active == false, "Merchant despawned after timeout") _assert(depart_sig["fired"] == true, "merchant_departed signal fired on timeout") _assert(sys.get_stock().is_empty(), "Stock cleared after merchant departed") func _test_blackmarket_goods_and_discount_purchase() -> void: print("\n--- Test 2: Black Market Goods & Discount Purchases ---") var sys := MysteriousMerchantBlackmarketSystem.new() sys.spawn_random_merchant(1800.0, 1) # Mount_Sohan _assert(sys.current_map == "Mount_Sohan", "Spawned at Mount Sohan") var stock = sys.get_stock() _assert(stock.size() == 5, "Stock has 5 unique blackmarket items") # Check item 0 (Cor Draconis): base 2M, blackmarket price 1M (50% off) _assert(stock[0]["vnum"] == 51501, "First item is Cor Draconis (51501)") _assert(stock[0]["price"] == 1000000, "Half-price discount 1,000,000 gold") _assert(stock[0]["base_price"] == 2000000, "Base price 2,000,000 gold") _assert(stock[0]["stock"] == 5, "Initial stock is 5") var player := {"gold": 500000} # Only 500k, not enough for 1M var inv: Array = [null, null, null] # Attempt buy with insufficient gold var buy_fail = sys.buy_item(0, player, inv) _assert(buy_fail["ok"] == false, "Buy failed with insufficient gold") _assert(buy_fail["reason"] == "NOT_ENOUGH_GOLD", "Failure reason is NOT_ENOUGH_GOLD") # Give enough gold player["gold"] = 3000000 var bought_sig := {"fired": false, "name": "", "cost": 0} sys.item_bought.connect(func(n: String, c: int): bought_sig["fired"] = true bought_sig["name"] = n bought_sig["cost"] = c ) var buy_succ = sys.buy_item(0, player, inv) _assert(buy_succ["ok"] == true, "Buy succeeded with sufficient gold") _assert(buy_succ["cost"] == 1000000, "Cost is 1,000,000 gold") _assert(player["gold"] == 2000000, "Player gold deducted properly to 2,000,000") _assert(inv[0] != null and inv[0]["vnum"] == 51501, "Cor Draconis placed into slot 0") _assert(bought_sig["fired"] == true, "item_bought signal fired") _assert(bought_sig["cost"] == 1000000, "Signal reported correct cost") # Check remaining stock var updated_stock = sys.get_stock() _assert(updated_stock[0]["stock"] == 4, "Stock decremented from 5 to 4") # Test inventory full inv[1] = {"vnum": 1, "name": "Item 1"} inv[2] = {"vnum": 2, "name": "Item 2"} var buy_full = sys.buy_item(0, player, inv) _assert(buy_full["ok"] == false, "Buy failed when inventory full") _assert(buy_full["reason"] == "INVENTORY_FULL", "Failure reason is INVENTORY_FULL") # Test out of stock by depleting item 4 (Legendary Elixir, stock=2) var big_inv: Array = [null, null, null, null, null] player["gold"] = 10000000 var b1 = sys.buy_item(4, player, big_inv) _assert(b1["ok"] == true, "Bought 1st Legendary Elixir") var b2 = sys.buy_item(4, player, big_inv) _assert(b2["ok"] == true, "Bought 2nd Legendary Elixir") var b3 = sys.buy_item(4, player, big_inv) _assert(b3["ok"] == false, "3rd buy rejected") _assert(b3["reason"] == "OUT_OF_STOCK", "Reason is OUT_OF_STOCK") func _test_high_price_buyback_and_antiflag() -> void: print("\n--- Test 3: High-Price Buyback (+30% Markup) & Anti-Flags ---") var sys := MysteriousMerchantBlackmarketSystem.new() sys.spawn_random_merchant(1800.0, 2) # Doyyumhwan var player := {"gold": 100000} # Base price 10,000. Standard sell (1/5) = 2,000. # High-price buyback (+30%) = 2,000 * 1.3 = 2,600. var test_rare_item := { "vnum": 70005, "name": "极品黑铁矿", "count": 2, "shop_buy_price": 10000, "anti_flags": 0 } # For count=2: unit=2600 * 2 = 5200. var calculated_price = sys.calculate_sell_price(test_rare_item) _assert(calculated_price == 5200, "High-price buyback calculated 5200 gold (2600 * 2)") var inv: Array = [test_rare_item, null] var sold_sig := {"fired": false, "name": "", "earned": 0} sys.item_sold.connect(func(n: String, e: int): sold_sig["fired"] = true sold_sig["name"] = n sold_sig["earned"] = e ) var sell_res = sys.sell_item(0, player, inv) _assert(sell_res["ok"] == true, "Sold rare item to wandering merchant") _assert(sell_res["earned"] == 5200, "Earned 5200 gold") _assert(player["gold"] == 105200, "Player gold increased to 105,200") _assert(inv[0] == null, "Inventory slot 0 cleared") _assert(sold_sig["fired"] == true, "item_sold signal fired") _assert(sold_sig["earned"] == 5200, "Signal reported earned gold") # Test unsellable item with ITEM_ANTIFLAG_SELL (256) var unsellable_item := { "vnum": 90001, "name": "绑定专属神兵", "count": 1, "shop_buy_price": 500000, "anti_flags": 256 } inv[0] = unsellable_item var sell_unsellable = sys.sell_item(0, player, inv) _assert(sell_unsellable["ok"] == false, "Unsellable item rejected") _assert(sell_unsellable["reason"] == "ITEM_ANTIFLAG_SELL", "Reason is ITEM_ANTIFLAG_SELL") _assert(inv[0] != null, "Unsellable item not removed from inventory") # Test merchant inactive sys.despawn_merchant() var sell_inactive = sys.sell_item(0, player, inv) _assert(sell_inactive["ok"] == false, "Sell rejected when merchant inactive") _assert(sell_inactive["reason"] == "MERCHANT_NOT_ACTIVE", "Reason is MERCHANT_NOT_ACTIVE") func _test_serialization_and_persistence() -> void: print("\n--- Test 4: Serialization & Save/Load Parity ---") var sys1 := MysteriousMerchantBlackmarketSystem.new() sys1.spawn_merchant("Desert", Vector2(120, 350), 1500.0) sys1.update(300.0) # 1200s left # Buy 1 Cor Draconis so stock changes var player := {"gold": 5000000} var inv: Array = [null] sys1.buy_item(0, player, inv) _assert(sys1.get_stock()[0]["stock"] == 4, "Sys1 stock of item 0 is 4") var save_data = sys1.serialize() _assert(save_data["is_active"] == true, "Serialized is_active true") _assert(save_data["current_map"] == "Desert", "Serialized map matches") _assert(save_data["stock"][0]["stock"] == 4, "Serialized stock of item 0 is 4") var sys2 := MysteriousMerchantBlackmarketSystem.new() sys2.deserialize(save_data) _assert(sys2.is_active == true, "Sys2 restored is_active") _assert(sys2.current_map == "Desert", "Sys2 restored current_map") _assert(sys2.current_pos == Vector2(120, 350), "Sys2 restored current_pos") _assert(is_equal_approx(sys2.time_remaining, 1200.0), "Sys2 restored time_remaining") _assert(sys2.get_stock()[0]["stock"] == 4, "Sys2 restored stock count 4") func _finish() -> void: print("\n=======================================================") print("Mysterious Merchant & Blackmarket Parity Tests: %d Passed, %d Failed" % [_passed, _failed]) print("=======================================================\n") if _failed > 0: quit(1) else: quit(0)