From 5b57f3eedc39fec387c0f4fac1eaea876233efc3 Mon Sep 17 00:00:00 2001 From: ZHU MINCHAO <48154958+MinchaoZhu@users.noreply.github.com> Date: Tue, 3 Nov 2026 20:13:18 +0800 Subject: [PATCH] Stage 4: honeypot, seller busts, controlled delivery; mining report moved into Web3 page Co-Authored-By: Claude Sonnet 5.5 --- CHANGELOG.md | 5 +- src/Decentralized.Domain/BmOrders.cs | 49 ++++++++++++++++++- src/Decentralized.Domain/Tuning.cs | 4 ++ src/Decentralized/BlackDelivery.cs | 43 +++++++++++++--- src/Decentralized/CoinCustomers.cs | 7 +++ .../ModFiles/Localization/en.csv | 17 ++++++- .../ModFiles/Localization/zh.csv | 17 ++++++- src/Decentralized/TerminalWindow.cs | 10 ++-- tests/Decentralized.Domain.Tests/Program.cs | 20 ++++++++ 9 files changed, 156 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a32c298..31705ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,10 @@ - 商城改成货架式:每行 4 张商品卡(游戏物品贴图、名称、类别、库存或卖家、价格、按钮);删掉死投点,只剩送货上门;货架上除违禁品外偶尔有高科技物品(声望 ≥ 40,加价 50%)和显卡(加价 20%,20% 是假卡)。 - 界面不放说明文字:银行、交易、混币器、黑市、Ponero 的规则说明都移进新物品"Web3 手册"(购买 Web3 治理社区时一并交付)。 - 游戏内验证:货架显示贴图与成色,用 CRT 买一张 RTX 60(232)进储藏区。 -- 还没做:蜜罐、受控交付(第三批)。 +- 第三批:执法蜜罐——每晚有概率接管平台(1% + 治安声望 × 0.04%,封顶 6%),持续 6 天,期间下的单和之后 4 天到期记罪证(违禁品 / 高科技记 `CONTRABAND_TRAFFICKING`,显卡记 `FENCING`,金额 = 货款,上限 400),论坛出现"最近太顺了"。卖家落网——近期成交的卖家每晚 0.8% 被抓,他留存的订单 4 天后连累买家,论坛有传闻。 +- 受控交付:被截获的包裹有 35% 变成执法人员上门:快递员神色异常,出现"签收。/不收,退回去。"两个选项;签收当场记罪证并查封,拒签只损失货款。 +- 挖矿报告并进 Web3 页的"挖矿"子页,终端顶栏不再有"报告"。 +- 游戏内验证:受控交付的对话与两个选项显示,拒签后快递员离开、下一位顾客进来。没在游戏里验证:签收的罪证、蜜罐与落网的夜间追查(只有单元测试)。 ### 第三阶段:数值调优(进行中) diff --git a/src/Decentralized.Domain/BmOrders.cs b/src/Decentralized.Domain/BmOrders.cs index 530c33d..3b6340b 100644 --- a/src/Decentralized.Domain/BmOrders.cs +++ b/src/Decentralized.Domain/BmOrders.cs @@ -38,11 +38,22 @@ namespace Decentralized.Domain /// 付款时留在卖家那边的污点与成本:退款时一并还回,免得"付脏币再退款"洗钱。 public double Taint, Basis; public int PlacedDay, DueDay; + /// 被截获后执法选择了上门:到货时快递员是执法人员,签收即记罪证。 + public bool Controlled; public OrderState State = OrderState.Pending; /// 终态的原因:done / scam / rug / intercept / theft / refund。 public string Why; } + /// 一笔会被追查的交易:到期日、金额(信用点)、来源(honeypot / seller / controlled)。 + public sealed class BmTrap + { + public int Day; + public double Amount; + public string Why; + public string Item; + } + /// 夜间发生的订单事件,供日志与新闻使用。 public sealed class BmEvent { @@ -59,6 +70,13 @@ namespace Decentralized.Domain public List Forum = new List(); /// 平台跑路后关闭到这一天(含)。 public int ClosedUntil = -1; + /// 执法接管平台的最后一天(含);期间的交易之后会被追查。 + public int HoneypotUntil = -1; + public List Traps = new List(); + + public bool Honeypot(int day) => day <= HoneypotUntil; + + public static double HoneypotChance(int secRep) => Math.Min(Tuning.BmHoneypotMax, Tuning.BmHoneypotBase + Math.Max(0, secRep) * Tuning.BmHoneypotPerSecRep); private static readonly string[] NameA = { "rat", "grey", "static", "null", "dust", "iron", "pale", "wire", "salt", "ghost" }; private static readonly string[] NameB = { "king", "mule", "broker", "hand", "cat", "fox", "tooth", "lamp", "nine", "dealer" }; @@ -122,6 +140,7 @@ namespace Decentralized.Domain Taint = taint, Basis = basis, PlacedDay = day, DueDay = day + Tuning.BmDoorDays, }; Orders.Add(o); + if (Honeypot(day)) Traps.Add(new BmTrap { Day = day + Tuning.BmTrapDelay, Amount = credits, Why = "honeypot", Item = l.Item }); return o; } @@ -132,9 +151,10 @@ namespace Decentralized.Domain } /// 每晚推进订单:平台跑路、到期的订单(卖家跑路、被截获、死投被挖走)、转入可取状态。镇压期间到期顺延一天。 - public List Night(int day, bool crackdown, Wallet w, Rng rng) + public List Night(int day, bool crackdown, Wallet w, Rng rng, int secRep = 0) { var ev = new List(); + if (!Honeypot(day) && rng.Chance(HoneypotChance(secRep))) { HoneypotUntil = day + Tuning.BmHoneypotDays; if (!Forum.Contains("easy")) Forum.Add("easy"); } if (ClosedUntil == day) ev.Add(new BmEvent { Kind = "reopen" }); if (!Closed(day) && Orders.Any(o => o.State == OrderState.Pending) && rng.Chance(RugChance)) { @@ -158,14 +178,39 @@ namespace Decentralized.Domain continue; } double ic = Tuning.BmInterceptDoor + (crackdown ? Tuning.BmInterceptCrackdown : 0); - if (rng.Chance(ic)) { o.State = OrderState.Lost; o.Why = "intercept"; ev.Add(new BmEvent { Kind = "intercept", Order = o, Amount = o.Price }); continue; } + if (rng.Chance(ic)) + { + if (rng.Chance(Tuning.BmControlled)) { o.Controlled = true; o.State = OrderState.Ready; ev.Add(new BmEvent { Kind = "ready", Order = o }); continue; } + o.State = OrderState.Lost; o.Why = "intercept"; ev.Add(new BmEvent { Kind = "intercept", Order = o, Amount = o.Price }); continue; + } o.State = OrderState.Ready; ev.Add(new BmEvent { Kind = "ready", Order = o }); } + // 卖家落网:近期成交过的卖家各有小概率被抓,他们留存的订单记录之后会连累买家 + foreach (var name in Orders.Where(x => x.State == OrderState.Done && day - x.DueDay <= 14).Select(x => x.Seller).Distinct().ToList()) + { + if (!rng.Chance(Tuning.BmSellerBust)) continue; + foreach (var o in Orders.Where(x => x.State == OrderState.Done && x.Seller == name && day - x.DueDay <= 14)) + Traps.Add(new BmTrap { Day = day + Tuning.BmTrapDelay, Amount = o.Price, Why = "seller", Item = o.Item }); + Forum.Add("busted:" + name); + } + foreach (var t in Traps.Where(x => day >= x.Day).ToList()) + { + Traps.Remove(t); + ev.Add(new BmEvent { Kind = "trap", Amount = t.Amount, Order = new BmOrder { Item = t.Item, Seller = t.Why } }); + } Orders.RemoveAll(o => o.State != OrderState.Pending && o.State != OrderState.Ready && day - o.DueDay > 14); return ev; } + /// 受控交付:签收则当场记罪证(返回金额)并查封,不交货;拒签则损失货款,不留罪证。 + public double Sign(BmOrder o, bool accept) + { + o.State = OrderState.Lost; + o.Why = accept ? "seized" : "refused"; + return accept ? o.Price : 0; + } + public void Deliver(BmOrder o) { o.State = OrderState.Done; o.Why = "done"; } public IEnumerable Ready => Orders.Where(o => o.State == OrderState.Ready); diff --git a/src/Decentralized.Domain/Tuning.cs b/src/Decentralized.Domain/Tuning.cs index d9c985b..144a6ef 100644 --- a/src/Decentralized.Domain/Tuning.cs +++ b/src/Decentralized.Domain/Tuning.cs @@ -94,6 +94,10 @@ namespace Decentralized.Domain public const double BmOrderDiscount = 0.15, BmEscrowFee = 0.05, BmAdvanceDiscount = 0.10, BmInterceptDoor = 0.08, BmInterceptCrackdown = 0.15; public const double BmScamSellerShare = 0.15, BmRugBase = 0.002, BmRugPerTenK = 0.004, BmRugMax = 0.05; public const int BmAdvanceMinTrades = 30, BmDoorDays = 3, BmRugClosedDays = 10, BmSellerCount = 4; + /// 蜜罐:每晚平台被执法接管的基础概率、每点治安声望加的概率、封顶、持续天数;之后订单被追查的延迟天数; + /// 订单被截获时变成受控交付的概率;每晚某个近期卖家落网的概率。 + public const double BmHoneypotBase = 0.01, BmHoneypotPerSecRep = 0.0004, BmHoneypotMax = 0.06, BmControlled = 0.35, BmSellerBust = 0.008; + public const int BmHoneypotDays = 6, BmTrapDelay = 4; /// 货架上除违禁品外的两类货:高科技物品(需中档声望)和显卡的出现概率、加价(在现货溢价 / 订单价之外再加),显卡里夹假卡的比例。 public const double BmTechChance = 0.15, BmGpuChance = 0.20, BmTechMarkup = 0.5, BmGpuMarkup = 0.2, BmGpuFake = 0.20; /// 黑市人脉升级的价格。 diff --git a/src/Decentralized/BlackDelivery.cs b/src/Decentralized/BlackDelivery.cs index 34f8e7d..9914295 100644 --- a/src/Decentralized/BlackDelivery.cs +++ b/src/Decentralized/BlackDelivery.cs @@ -1,3 +1,4 @@ +using System; using System.Linq; using Decentralized.Domain; @@ -61,10 +62,10 @@ namespace Decentralized public static void Night(SaveData d, int day, bool crackdown) { var ps = PlayerStore.Instance; - foreach (var e in d.Black.Night(day, crackdown, d.Hot, d.Rng)) + foreach (var e in d.Black.Night(day, crackdown, d.Hot, d.Rng, StoreReputation.GetSecReputation())) { - string name = e.Order != null ? ItemName(e.Order.Item) : null; - Log.Info($"黑市订单事件:{e.Kind} {e.Order?.Item} {e.Order?.Seller} {e.Order?.Mode} 金额 {e.Amount:0}"); + string name = e.Order != null && e.Kind != "trap" ? ItemName(e.Order.Item) : null; + Log.Info($"黑市订单事件:{e.Kind} {e.Order?.Item} {e.Order?.Seller} {e.Order?.Mode} 受控 {e.Order?.Controlled} 金额 {e.Amount:0}"); switch (e.Kind) { case "ready": ps.AddNightLog(L.T("nightlog.bm.ready", name), "99bb66"); break; @@ -72,6 +73,13 @@ namespace Decentralized case "scam_loss": ps.AddNightLog(L.T("nightlog.bm.scam_loss", e.Order.Seller, name, Fmt.Num(e.Amount)), "cc7755"); break; case "intercept": ps.AddNightLog(L.T("nightlog.bm.intercept", name, Fmt.Num(e.Amount)), "cc7755"); break; case "rug": ps.AddNightLog(L.T("nightlog.bm.rug", name, Fmt.Num(e.Amount)), "cc7755"); break; + case "trap": + { + int amount = (int)Math.Min(Tuning.CrimeEventCap, e.Amount); + ps.secData.CommitCrime(e.Order.Item != null && e.Order.Item.StartsWith("gpu:") ? "FENCING" : "CONTRABAND_TRAFFICKING", amount); + ps.AddNightLog(L.T("nightlog.bm.trap." + e.Order.Seller, ItemName(e.Order.Item), amount), "cc7755"); + break; + } case "reopen": ps.AddNightLog(L.T("nightlog.bm.reopen"), "99bb66"); break; } if (e.Kind == "rug") Night_RugNews(day); @@ -107,8 +115,31 @@ namespace Decentralized clientIntent = StoreClient.ClientIntent.SELL, }; StoreClientFactionSetup.InitScav(c); - c.mainDialogue.SetText(c.displayName, L.T("courier.line1." + rng.Range(1, 2))).NextDialogue().SetText(c.displayName, L.T("courier.line2." + rng.Range(1, 2))) - .SetEndAction(() => Log.Guard("黑市快递交货", () => { DeliverDoor(); PlayerStore.Instance.DismissCurrentClient(); })); + var trap = Session.Data.Black.Ready.FirstOrDefault(o => o.Controlled); + Action finish = () => { PlayerStore.Instance.DismissCurrentClient(); }; + if (trap == null) + { + c.mainDialogue.SetText(c.displayName, L.T("courier.line1." + rng.Range(1, 2))).NextDialogue().SetText(c.displayName, L.T("courier.line2." + rng.Range(1, 2))) + .SetEndAction(() => Log.Guard("黑市快递交货", () => { DeliverDoor(); finish(); })); + } + else + { + // 受控交付:快递员神色异常,签收就是当场记罪证并查封,拒签只损失货款 + var sign = new Dialogue(); + sign.SetText("PLAYER", L.T("courier.sign.say")); + sign.NextDialogue().SetText(c.displayName, L.T("courier.signed")).SetEndAction(() => Log.Guard("受控交付签收", () => + { + int amount = (int)Math.Min(Tuning.CrimeEventCap, Session.Data.Black.Sign(trap, true)); + PlayerStore.Instance.secData.CommitCrime(trap.Item.StartsWith("gpu:") ? "FENCING" : "CONTRABAND_TRAFFICKING", amount); + DeliverDoor(); finish(); + })); + var refuse = new Dialogue(); + refuse.SetText("PLAYER", L.T("courier.refuse.say")); + refuse.NextDialogue().SetText(c.displayName, L.T("courier.refused")).SetEndAction(() => Log.Guard("受控交付拒签", () => { Session.Data.Black.Sign(trap, false); DeliverDoor(); finish(); })); + c.mainDialogue.SetText(c.displayName, L.T("courier.odd1")).NextDialogue().SetText(c.displayName, L.T("courier.odd2")) + .AddChoice(DirectoryMaster.Item("yes"), L.T("courier.sign"), "", sign, null) + .AddChoice(DirectoryMaster.Item("cancel"), L.T("courier.refuse"), "", refuse, null); + } c.AddBasicDialog(); c.CompleteClientCreation(); return c; @@ -117,7 +148,7 @@ namespace Decentralized private static void DeliverDoor() { var d = Session.Data; - foreach (var o in d.Black.Ready.ToList()) + foreach (var o in d.Black.Ready.Where(x => !x.Controlled).ToList()) { Items.Give(Make(o.Item, o.Model, o.FakeOf, o.Health)); d.Black.Deliver(o); diff --git a/src/Decentralized/CoinCustomers.cs b/src/Decentralized/CoinCustomers.cs index a85e7a9..9ab8df7 100644 --- a/src/Decentralized/CoinCustomers.cs +++ b/src/Decentralized/CoinCustomers.cs @@ -65,6 +65,13 @@ namespace Decentralized PlayerStore.Instance.storeClientManager.clientStack.Insert(0, BlackDelivery.CreateCourier()); PlayerStore.Instance.TryCallNextClient(); })); + ModHelper.AddDebugFunction(ModInfo.Id, ModInfo.Name, "Courier trap (test)", () => Log.Guard("受控交付(测试)", () => + { + foreach (var o in Session.Data.Black.Orders.Where(x => x.State == OrderState.Pending)) { o.State = OrderState.Ready; o.Controlled = true; } + PlayerStore.Instance.currentClientInstance = null; + PlayerStore.Instance.storeClientManager.clientStack.Insert(0, BlackDelivery.CreateCourier()); + PlayerStore.Instance.TryCallNextClient(); + })); ModHelper.AddDebugFunction(ModInfo.Id, ModInfo.Name, "Coin buyer (test)", () => Log.Guard("用币付款顾客(测试)", () => { var c = new StoreClient diff --git a/src/Decentralized/ModFiles/Localization/en.csv b/src/Decentralized/ModFiles/Localization/en.csv index cbee266..1d999a1 100644 --- a/src/Decentralized/ModFiles/Localization/en.csv +++ b/src/Decentralized/ModFiles/Localization/en.csv @@ -270,4 +270,19 @@ black.kind.Contraband.3,Contraband (high) black.kind.Tech,High-tech (markup) nightlog.bm.ready,"Black market: {0} arrived; a courier will come by once you open." item.web3guide.name,Web3 Handbook -item.web3guide.desc,"Bank: depositing turns credits into CRC; withdrawing turns CRC back into credits and goes through compliance screening. Trading: buys are paid in the quote coin, sells in the traded coin. Mixer: pick a coin, amount and rounds; each round takes a fee and lowers taint, rounds equal days of waiting, and the coins come back to the same address; the more you deposit, the worse the cleaning. Black market: coin only, no CRC, 30% above normal channels, with extra markup on high-tech goods and GPUs; the coin you pay leaves its share of taint with the seller and the goods carry no stolen tag; GPUs may be fake, inspect them yourself. Orders are cheaper than spot but take days and may be intercepted; escrow costs 5%, is released on delivery and refunded if the seller runs; advance release takes another 10% off, but a scammer keeps the money and only sellers with 30+ trades accept; the platform itself can rug. Ponero desk: Ponero is a privacy coin and swapping in wipes the taint on that value; 8% fee each way with a daily limit; coin swapped out of Ponero has no origin and cash-out screening gets stricter." +item.web3guide.desc,"Bank: depositing turns credits into CRC; withdrawing turns CRC back into credits and goes through compliance screening. Trading: buys are paid in the quote coin, sells in the traded coin. Mixer: pick a coin, amount and rounds; each round takes a fee and lowers taint, rounds equal days of waiting, and the coins come back to the same address; the more you deposit, the worse the cleaning. Black market: coin only, no CRC, 30% above normal channels, with extra markup on high-tech goods and GPUs; the coin you pay leaves its share of taint with the seller and the goods carry no stolen tag; GPUs may be fake, inspect them yourself. Orders are cheaper than spot but take days and may be intercepted; escrow costs 5%, is released on delivery and refunded if the seller runs; advance release takes another 10% off, but a scammer keeps the money and only sellers with 30+ trades accept; the platform itself can rug, be taken over by enforcement, or a seller can be arrested, after which your orders get traced and crime logged; forum rumors can be warnings. An intercepted parcel sometimes turns into enforcement at your door: signing logs the crime on the spot and seizes the goods, refusing only costs the payment. Ponero desk: Ponero is a privacy coin and swapping in wipes the taint on that value; 8% fee each way with a daily limit; coin swapped out of Ponero has no origin and cash-out screening gets stricter." +courier.odd1,...Package is here. +courier.odd2,"(His hand stays in his pocket.) Sign here." +courier.sign,Sign +courier.refuse,Refuse +courier.signed,"Good. Don't move, Security." +courier.refused,"...Fine, forget it." +black.state.Lost.seized,seized +black.state.Lost.refused,refused +black.forum.easy,"Too smooth lately: sellers ship faster than ever, and there are new accounts nobody has seen." +black.forum.busted,"Word is {0} got arrested, and the order records are still around." +nightlog.bm.trap.honeypot,"Black market: the platform was taken over by enforcement; your {0} was traced, crime logged {1}." +nightlog.bm.trap.seller,"Black market: a seller was arrested and the order records implicate you: {0}, crime logged {1}." +web3.sub.mining,Mining +courier.sign.say,I'll sign. +courier.refuse.say,Not taking it. Send it back. diff --git a/src/Decentralized/ModFiles/Localization/zh.csv b/src/Decentralized/ModFiles/Localization/zh.csv index 1ffe0bc..b4a08ad 100644 --- a/src/Decentralized/ModFiles/Localization/zh.csv +++ b/src/Decentralized/ModFiles/Localization/zh.csv @@ -269,4 +269,19 @@ black.kind.Contraband.3,违禁品(高) black.kind.Tech,高科技物品(加价) nightlog.bm.ready,"黑市:{0} 到货,开店后会有快递员上门。" item.web3guide.name,Web3 手册 -item.web3guide.desc,"银行:存入把信用点换成 CRC;提取把 CRC 换回信用点,提取要过合规审查。交易:买入按计价币的数量支付,卖出按所交易币的数量卖出。混币器:选币种、填数量和轮数,每轮扣手续费并降低污点,轮数即等待天数,到期提回同一个地址;存入越多,清洗越差。黑市:只收币,不收 CRC,价格比正常渠道贵 30%,高科技物品和显卡另有加价;付出去的币带着按比例的污点留在卖家那边,货不带赃物标签;显卡不保证真假,自己鉴定。订单比现货便宜,要等几天,路上可能被截获;托管多付 5% 托管费,收货后放款,卖家跑路时退款;提前放款再打九折,卖家若是骗子钱就没了,只有成交 30 单以上的卖家接受;平台自己也可能跑路。Ponero 兑换处:Ponero 是隐私币,兑入时这部分价值的污点被清除;兑入、兑出各收 8% 手续费,每天有额度;从 Ponero 兑出的币来路不明,出金审查会加重。" +item.web3guide.desc,"银行:存入把信用点换成 CRC;提取把 CRC 换回信用点,提取要过合规审查。交易:买入按计价币的数量支付,卖出按所交易币的数量卖出。混币器:选币种、填数量和轮数,每轮扣手续费并降低污点,轮数即等待天数,到期提回同一个地址;存入越多,清洗越差。黑市:只收币,不收 CRC,价格比正常渠道贵 30%,高科技物品和显卡另有加价;付出去的币带着按比例的污点留在卖家那边,货不带赃物标签;显卡不保证真假,自己鉴定。订单比现货便宜,要等几天,路上可能被截获;托管多付 5% 托管费,收货后放款,卖家跑路时退款;提前放款再打九折,卖家若是骗子钱就没了,只有成交 30 单以上的卖家接受;平台自己也可能跑路,也可能被执法接管,或者卖家落网,之后你的订单会被追查、记罪证;论坛上的传闻可以当预兆。被截获的包裹有时会变成执法人员上门:签收当场记罪证并查封,拒签只损失货款。Ponero 兑换处:Ponero 是隐私币,兑入时这部分价值的污点被清除;兑入、兑出各收 8% 手续费,每天有额度;从 Ponero 兑出的币来路不明,出金审查会加重。" +courier.odd1,……东西到了。 +courier.odd2,"(他的手一直放在口袋里)在这儿签个字。" +courier.sign,签收 +courier.refuse,拒签 +courier.signed,"好。别动,治安部的。" +courier.refused,"……那就算了。" +black.state.Lost.seized,被查封 +black.state.Lost.refused,拒签 +black.forum.easy,"最近太顺了,卖家发货比平时都快,还多了几个没见过的新号。" +black.forum.busted,"有人说 {0} 被抓了,他的订单记录还在。" +nightlog.bm.trap.honeypot,"黑市:平台曾被执法接管,你买的 {0} 被追查,记罪证 {1}。" +nightlog.bm.trap.seller,"黑市:卖家落网,他留存的订单记录连累了你:{0},记罪证 {1}。" +web3.sub.mining,挖矿 +courier.sign.say,签收。 +courier.refuse.say,不收,退回去。 diff --git a/src/Decentralized/TerminalWindow.cs b/src/Decentralized/TerminalWindow.cs index caac440..78ec3f4 100644 --- a/src/Decentralized/TerminalWindow.cs +++ b/src/Decentralized/TerminalWindow.cs @@ -13,7 +13,7 @@ namespace Decentralized public static class TerminalWindow { public const string Id = "pd_terminal"; - private enum Page { Home, Bank, Poinbase, Web3, Report } + private enum Page { Home, Bank, Poinbase, Web3 } private static Page _page = Page.Home; private static string _amount = ""; @@ -41,7 +41,7 @@ namespace Decentralized case Page.Bank: BankPage(b); break; case Page.Poinbase: ExchangePage(b, Venue.Exchange); break; case Page.Web3: Web3Page(b); break; - default: ReportPage(b); break; + default: break; } b.End(); if (!string.IsNullOrEmpty(_message)) b.AddLabel(_message); @@ -235,7 +235,6 @@ namespace Decentralized private static void Web3Page(CustomUIBuilder b) { var w = Session.Data.Hot; - if (Unlock.MixerUnlocked || Unlock.BlackUnlocked) { if (_web3Tab == Web3Tab.Mixer && !Unlock.MixerUnlocked) _web3Tab = Web3Tab.Trade; if (_web3Tab == Web3Tab.Black && !Unlock.BlackUnlocked) _web3Tab = Web3Tab.Trade; @@ -248,6 +247,7 @@ namespace Decentralized b.AddButton(tab == _web3Tab ? $"[{name}]" : name, () => { _web3Tab = tab; _message = null; Open(); }); } b.End(); + if (_web3Tab == Web3Tab.Mining) { ReportPage(b); return; } if (_web3Tab == Web3Tab.Mixer) { MixerPage(b); return; } if (_web3Tab == Web3Tab.Black) { BlackPage(b); return; } } @@ -426,7 +426,7 @@ namespace Decentralized r.AddHeader(L.T("black.forum.h")); if (d.Black.Forum.Count == 0) r.AddLabel(L.T("black.forum.quiet")); foreach (var f in d.Black.Forum) - r.AddLabel(f.StartsWith("scam:") ? L.T("black.forum.scam", f.Substring(5)) : L.T("black.forum." + f)); + r.AddLabel(f.StartsWith("scam:") ? L.T("black.forum.scam", f.Substring(5)) : f.StartsWith("busted:") ? L.T("black.forum.busted", f.Substring(7)) : L.T("black.forum." + f)); }); } @@ -474,7 +474,7 @@ namespace Decentralized Open(); } - private enum Web3Tab { Trade, Mixer, Black } + private enum Web3Tab { Trade, Mining, Mixer, Black } private static Web3Tab _web3Tab = Web3Tab.Trade; private static string _mixAsset = Assets.PSC; private static int _mixRounds = 2; diff --git a/tests/Decentralized.Domain.Tests/Program.cs b/tests/Decentralized.Domain.Tests/Program.cs index 66fb171..1110205 100644 --- a/tests/Decentralized.Domain.Tests/Program.cs +++ b/tests/Decentralized.Domain.Tests/Program.cs @@ -625,6 +625,26 @@ internal static class Program var co = c.Place(new BmListing { Seller = 0, Item = "x", Price = 100 }, PayMode.Escrow, cw, Assets.CRT, 1, price); c.Night(co.DueDay, true, cw, new Rng(1)); Check(co.State == OrderState.Pending && co.DueDay == 5, "镇压期间到期顺延一天"); + // 蜜罐期间下单会被追查;受控交付签收记罪证、拒签不记 + var h = new BlackMarket(); h.Sellers.Add(good); h.HoneypotUntil = 12; + var hw = new Wallet(); hw.Add(Assets.CRT, 5000); + var ho = h.Place(new BmListing { Seller = 0, Item = "x", Price = 100 }, PayMode.Escrow, hw, Assets.CRT, 10, price); + Check(h.Traps.Count == 1 && h.Traps[0].Day == 10 + Tuning.BmTrapDelay, "蜜罐期间下单:记一笔追查"); + Check(h.Night(h.Traps[0].Day, false, hw, new Rng(3)).Any(e => e.Kind == "trap" && Near(e.Amount, ho.Price, 1e-9)) && h.Traps.Count == 0, "追查到期:产生罪证事件"); + int ctrl = 0; + for (int i = 0; i < 600; i++) + { + var t2 = new BlackMarket(); t2.Sellers.Add(good); + var w2 = new Wallet(); w2.Add(Assets.CRT, 5000); + var o2b = t2.Place(new BmListing { Seller = 0, Item = "x", Price = 100 }, PayMode.Escrow, w2, Assets.CRT, 1, price); + t2.Night(o2b.DueDay, false, w2, new Rng((ulong)i + 99), 0); + if (o2b.Controlled) ctrl++; + } + Check(ctrl > 5 && ctrl < 50, $"被截获里一部分变成受控交付:{ctrl}/600"); + var co2 = new BmOrder { Item = "x", Price = 150, State = OrderState.Ready, Controlled = true }; + var cm = new BlackMarket(); + Check(Near(cm.Sign(co2, true), 150, 1e-9) && co2.State == OrderState.Lost && co2.Why == "seized" && Near(cm.Sign(new BmOrder { Price = 50 }, false), 0, 1e-9), "签收记罪证(金额)并查封,拒签不记"); + Check(BlackMarket.HoneypotChance(100) > BlackMarket.HoneypotChance(0) && BlackMarket.HoneypotChance(100000) <= Tuning.BmHoneypotMax, "治安声望越高越容易被接管,有封顶"); // 跑路:托管资金多则概率高;跑路后关闭 var r = new BlackMarket(); r.Sellers.Add(good); var rw = new Wallet(); rw.Add(Assets.CRT, 1000000);