Black market: useful goods only, player selling with price-dependent speed and taint
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
5b57f3eedc
commit
502366e7c4
10 files changed
+363
-21
No files matched your search
@@ -48,6 +48,31 @@ namespace Decentralized
|
||||
return n;
|
||||
}
|
||||
|
||||
// ---- 玩家出售:从储藏区挑能上架的货 ----
|
||||
|
||||
/// <summary>这件物品在黑市上的货 id(显卡是 "gpu:型号",其余是物品 id);不能上架返回 null。</summary>
|
||||
public static string SellId(GameItem it)
|
||||
{
|
||||
if (it == null || it.identifier == null) return null;
|
||||
if (Items.IsGpu(it)) return "gpu:" + Items.ToUnit(it).Model;
|
||||
string id = it.identifier;
|
||||
return BlackMarket.Pool.Any(x => x.Key == id) || BlackMarket.TechPool.Contains(id) ? id : null;
|
||||
}
|
||||
|
||||
public static System.Collections.Generic.List<GameItem> Sellable() =>
|
||||
GraphUtils.FindAllChildrenType<GameItem>(EmporiumEntry.Instance.invElement, i => GeneralHelper.IsItemOwned(i) && SellId(i) != null, i => i.identifier != Items.Rig);
|
||||
|
||||
/// <summary>参考价:显卡按标称型号与成色,其余按游戏基础价。</summary>
|
||||
public static long RefValue(GameItem it)
|
||||
{
|
||||
string id = SellId(it);
|
||||
if (id == null) return 0;
|
||||
if (Items.IsGpu(it)) { var u = Items.ToUnit(it); return CardValue.Of(u.Model, u.Health); }
|
||||
return Value(id);
|
||||
}
|
||||
|
||||
public static GoodKind KindOf(string id) => id.StartsWith("gpu:") ? GoodKind.Gpu : BlackMarket.TechPool.Contains(id) ? GoodKind.Tech : GoodKind.Contraband;
|
||||
|
||||
/// <summary>每周刷新:现货与订单目录一起。返回是否刷新了。</summary>
|
||||
public static bool Restock(SaveData d, int day, bool force = false)
|
||||
{
|
||||
@@ -62,8 +87,25 @@ 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, StoreReputation.GetSecReputation()))
|
||||
foreach (var e in d.Black.Night(day, crackdown, d.Hot, d.Rng, StoreReputation.GetSecReputation(), Session.Price))
|
||||
{
|
||||
if (e.Sale != null)
|
||||
{
|
||||
string sname = ItemName(e.Sale.Item);
|
||||
Log.Info($"黑市出售事件:{e.Kind} {e.Sale.Item} ×{e.Sale.Mult} 货款 {e.Amount:0} 污点 {e.Sale.Taint:0}");
|
||||
switch (e.Kind)
|
||||
{
|
||||
case "sale_sold": ps.AddNightLog(L.T("nightlog.bm.sale_sold", sname, Fmt.Num(e.Amount), e.Sale.PayDay), "99bb66"); break;
|
||||
case "sale_paid": ps.AddNightLog(L.T("nightlog.bm.sale_paid", sname, Fmt.Num(e.Amount), Fmt.Num(e.Sale.Taint)), "99bb66"); break;
|
||||
case "sale_fake":
|
||||
Items.Give(Make(e.Sale.Item, e.Sale.Model, e.Sale.FakeOf, e.Sale.Health));
|
||||
ps.AddNightLog(L.T("nightlog.bm.sale_fake", sname), "cc7755");
|
||||
break;
|
||||
case "sale_rug": ps.AddNightLog(L.T("nightlog.bm.sale_rug", sname, Fmt.Num(e.Amount)), "cc7755"); break;
|
||||
}
|
||||
if (e.Kind == "sale_rug") News.Show("pd_news_bmrug_" + day, L.T("news.bmrug.title"), L.T("news.bmrug.desc"), 4);
|
||||
continue;
|
||||
}
|
||||
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)
|
||||
|
||||
@@ -270,7 +270,7 @@ 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, 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."
|
||||
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. Selling: on the black market's Sell page, list contraband, high-tech goods and GPUs from storage at 0.6x to 1.8x the reference price. The higher the multiplier, the slower the sale (below 0.9x about a day, 1.0x about two, 1.8x about fourteen), and the likelier and larger the taint on the payout; 5% listing fee, 8% commission, payout held 3 days before reaching your wallet; a fake card may be spotted and returned, hurting your rating; if the platform rugs, listed goods and unreleased payouts are gone. 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
|
||||
@@ -286,3 +286,26 @@ nightlog.bm.trap.seller,"Black market: a seller was arrested and the order recor
|
||||
web3.sub.mining,Mining
|
||||
courier.sign.say,I'll sign.
|
||||
courier.refuse.say,Not taking it. Send it back.
|
||||
black.forum.busted_buyer,"Word is a batch of buyers got arrested, and the sale records are still on the platform."
|
||||
nightlog.bm.sale_sold,"Black market: your {0} sold for {1}; payout on day {2}."
|
||||
nightlog.bm.sale_paid,"Black market: payout of {1} for {0} arrived (CRT), taint {2}."
|
||||
nightlog.bm.sale_fake,"Black market: the buyer saw that {0} is a fake and returned it; your rating dropped."
|
||||
nightlog.bm.sale_rug,"Black market: the platform rugged; your {0} and the payout ({1}) are gone."
|
||||
black.sub.sell,Sell
|
||||
black.sell.h,Sell
|
||||
black.sell.mult,"Price x{0}"
|
||||
black.sell.info,"Price {0} ~{1} days to sell payout tainted {2}% of the time ({3}% of it)"
|
||||
black.sell.list,List
|
||||
black.sell.none,Nothing sellable in storage.
|
||||
black.sell.ref,"Ref {0}"
|
||||
black.sell.listed,"Listed: {0} at {1}."
|
||||
black.sell.delist,Take down
|
||||
black.sell.rating,"Rating {0}%"
|
||||
black.mine.sales,My listings
|
||||
black.mine.sale,"{0} x{1}: {2}"
|
||||
black.sale.Listed,listed
|
||||
black.sale.Sold,"sold, payout day {0}"
|
||||
black.sale.Paid,paid
|
||||
black.sale.Lost,platform rugged, gone
|
||||
black.sale.Delisted,taken down
|
||||
black.sale.Delisted.fake,buyer spotted the fake and returned it
|
||||
|
@@ -269,7 +269,7 @@ 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 单以上的卖家接受;平台自己也可能跑路,也可能被执法接管,或者卖家落网,之后你的订单会被追查、记罪证;论坛上的传闻可以当预兆。被截获的包裹有时会变成执法人员上门:签收当场记罪证并查封,拒签只损失货款。出售:在黑市的出售页把储藏区里的违禁品、高科技物品和显卡上架,标价是参考价的 0.6 到 1.8 倍。倍率越高成交越慢(0.9 以下约一天,1.0 约两天,1.8 约十四天),货款带污点的可能性和比例也越高;上架收 5% 上架费,成交扣 8% 抽成,货款托管 3 天后进钱包;卖假卡可能被买家看穿而退货,拉低好评;平台跑路时上架的货和未放款的货款都没了。Ponero 兑换处:Ponero 是隐私币,兑入时这部分价值的污点被清除;兑入、兑出各收 8% 手续费,每天有额度;从 Ponero 兑出的币来路不明,出金审查会加重。"
|
||||
courier.odd1,……东西到了。
|
||||
courier.odd2,"(他的手一直放在口袋里)在这儿签个字。"
|
||||
courier.sign,签收
|
||||
@@ -285,3 +285,26 @@ nightlog.bm.trap.seller,"黑市:卖家落网,他留存的订单记录连累
|
||||
web3.sub.mining,挖矿
|
||||
courier.sign.say,签收。
|
||||
courier.refuse.say,不收,退回去。
|
||||
black.forum.busted_buyer,"有人说最近一批买家被抓了,成交记录还在平台上。"
|
||||
nightlog.bm.sale_sold,"黑市:你上架的 {0} 卖出了,货款 {1},第 {2} 天放款。"
|
||||
nightlog.bm.sale_paid,"黑市:{0} 的货款 {1} 到账(CRT),其中污点 {2}。"
|
||||
nightlog.bm.sale_fake,"黑市:买家看穿了 {0} 是假卡,退了货,你的好评下降。"
|
||||
nightlog.bm.sale_rug,"黑市:平台跑路,你的 {0} 和货款({1})没了。"
|
||||
black.sub.sell,出售
|
||||
black.sell.h,出售
|
||||
black.sell.mult,"标价 ×{0}"
|
||||
black.sell.info,"标价 {0} 约 {1} 天成交 货款带污点 {2}%(比例 {3}%)"
|
||||
black.sell.list,上架
|
||||
black.sell.none,储藏区里没有能卖的货。
|
||||
black.sell.ref,"参考价 {0}"
|
||||
black.sell.listed,"已上架:{0},标价 {1}。"
|
||||
black.sell.delist,撤下
|
||||
black.sell.rating,"好评 {0}%"
|
||||
black.mine.sales,我的上架
|
||||
black.mine.sale,"{0} ×{1}:{2}"
|
||||
black.sale.Listed,上架中
|
||||
black.sale.Sold,"已成交,第 {0} 天放款"
|
||||
black.sale.Paid,已到账
|
||||
black.sale.Lost,平台跑路,没了
|
||||
black.sale.Delisted,已撤下
|
||||
black.sale.Delisted.fake,买家看穿假卡退货
|
||||
|
@@ -267,7 +267,7 @@ namespace Decentralized
|
||||
});
|
||||
}
|
||||
|
||||
private enum BlackTab { Shop, Orders, Mine, Desk }
|
||||
private enum BlackTab { Shop, Orders, Sell, Mine, Desk }
|
||||
private static BlackTab _blackTab = BlackTab.Shop;
|
||||
private static PayMode _mode = PayMode.Escrow;
|
||||
private static string _deskAsset = Assets.PSC;
|
||||
@@ -312,6 +312,7 @@ namespace Decentralized
|
||||
if (d.Black.Closed(day)) { b.AddLabel(L.T("black.rugged", d.Black.ClosedUntil - day + 1)); return; }
|
||||
if (_blackTab == BlackTab.Desk && desk) { DeskPage(b, rep, day); return; }
|
||||
if (_blackTab == BlackTab.Mine) { MinePage(b, day); return; }
|
||||
if (_blackTab == BlackTab.Sell) { SellPage(b, day); return; }
|
||||
bool orders = _blackTab == BlackTab.Orders;
|
||||
var w = d.Hot;
|
||||
b.AddLabel(L.T("black.rep", rep, BlackMarket.MaxLevel(rep)) + " " + L.T("mixer.balance", _payAsset, Fmt.Num(w.Avail(_payAsset))) + (w.Taint > 0.5 ? " " + L.T("wallet.taint", Fmt.Credits(w.Taint)) : ""));
|
||||
@@ -358,6 +359,60 @@ namespace Decentralized
|
||||
}
|
||||
}
|
||||
|
||||
private static double _sellMult = 1.0;
|
||||
private static readonly double[] SellMults = { 0.6, 0.8, 0.9, 1.0, 1.2, 1.5, 1.8 };
|
||||
|
||||
/// <summary>出售:储藏区里能上架的货做成货架,选标价倍率后上架。</summary>
|
||||
private static void SellPage(CustomUIBuilder b, int day)
|
||||
{
|
||||
var d = Session.Data;
|
||||
b.BeginRow();
|
||||
foreach (var m in SellMults)
|
||||
{
|
||||
double mult = m;
|
||||
string n = m.ToString("0.0", CultureInfo.InvariantCulture);
|
||||
b.AddButton(Math.Abs(mult - _sellMult) < 1e-9 ? $"[×{n}]" : "×" + n, () => { _sellMult = mult; Open(); });
|
||||
}
|
||||
b.End();
|
||||
b.AddLabel(L.T("black.sell.info", "×" + _sellMult.ToString("0.0", CultureInfo.InvariantCulture), (int)Math.Round(BlackMarket.ExpectedDays(_sellMult)), (int)Math.Round(BlackMarket.TaintChance(_sellMult) * 100), (int)Math.Round(BlackMarket.TaintRatio(_sellMult) * 100)) + " " + L.T("black.sell.rating", d.Black.Rating));
|
||||
b.AddLabel(L.T("mixer.balance", _payAsset, Fmt.Num(d.Hot.Avail(_payAsset))));
|
||||
b.AddSeparator();
|
||||
var items = BlackDelivery.Sellable();
|
||||
if (items.Count == 0) { b.AddLabel(L.T("black.sell.none")); return; }
|
||||
Shelf(b, items.Select(it =>
|
||||
{
|
||||
string id = BlackDelivery.SellId(it);
|
||||
var kind = BlackDelivery.KindOf(id);
|
||||
var g = new BmGood { Item = id, Kind = kind, Level = kind == GoodKind.Contraband ? BlackMarket.Pool.First(x => x.Key == id).Value : 3 };
|
||||
if (kind == GoodKind.Gpu) g.Health = Items.ToUnit(it).Health;
|
||||
g.Price = BlackMarket.ListPriceOf(BlackDelivery.RefValue(it), _sellMult);
|
||||
return new { g, it };
|
||||
}).Select(x => { SellCards[x.g] = x.it; return x.g; }).ToList(), (c, g) =>
|
||||
{
|
||||
var it = SellCards[g];
|
||||
GoodHead(c, g, L.T("black.sell.ref", BlackDelivery.RefValue(it)));
|
||||
c.AddLabel(L.T("black.price", g.Price));
|
||||
c.AddFlexibleSpace();
|
||||
c.AddButton(L.T("black.sell.list"), () => ListItem(it));
|
||||
});
|
||||
}
|
||||
|
||||
private static readonly System.Collections.Generic.Dictionary<BmGood, GameItem> SellCards = new System.Collections.Generic.Dictionary<BmGood, GameItem>();
|
||||
|
||||
private static void ListItem(GameItem it)
|
||||
{
|
||||
var d = Session.Data;
|
||||
string id = BlackDelivery.SellId(it);
|
||||
if (id == null) { Open(); return; }
|
||||
var u = Items.IsGpu(it) ? Items.ToUnit(it) : null;
|
||||
var s = d.Black.List(id, u?.Model, u?.FakeOf, u?.Health ?? 0, BlackDelivery.RefValue(it), _sellMult, d.Hot, _payAsset, StoreStation.GetDayCounter(), Session.Price);
|
||||
if (s == null) { _message = L.T("msg.balance"); Open(); return; }
|
||||
it.Destroy();
|
||||
_message = L.T("black.sell.listed", ItemName(id), s.ListPrice);
|
||||
Session.Save();
|
||||
Open();
|
||||
}
|
||||
|
||||
private const int ShelfCols = 4;
|
||||
private const float CardW = 172f, CardH = 268f;
|
||||
|
||||
@@ -411,6 +466,15 @@ namespace Decentralized
|
||||
Open();
|
||||
}
|
||||
|
||||
private static void Delist(BmSale s)
|
||||
{
|
||||
var d = Session.Data;
|
||||
d.Black.Delist(s);
|
||||
Items.Give(BlackDelivery.Make(s.Item, s.Model, s.FakeOf, s.Health));
|
||||
Session.Save();
|
||||
Open();
|
||||
}
|
||||
|
||||
/// <summary>我的订单与论坛情报。</summary>
|
||||
private static void MinePage(CustomUIBuilder b, int day)
|
||||
{
|
||||
@@ -418,7 +482,14 @@ namespace Decentralized
|
||||
Columns(b, l =>
|
||||
{
|
||||
l.AddHeader(L.T("black.mine.h"));
|
||||
if (d.Black.Orders.Count == 0) l.AddLabel(L.T("black.mine.none"));
|
||||
if (d.Black.Orders.Count == 0 && d.Black.Sales.Count == 0) l.AddLabel(L.T("black.mine.none"));
|
||||
foreach (var sl in d.Black.Sales.Where(x => x.State != SaleState.Delisted || x.Why == "fake").OrderByDescending(x => x.ListedDay))
|
||||
{
|
||||
var sale = sl;
|
||||
string st = sale.State == SaleState.Sold ? L.T("black.sale.Sold", sale.PayDay) : L.T("black.sale." + sale.State + (sale.State == SaleState.Delisted && sale.Why != null ? "." + sale.Why : ""));
|
||||
l.AddLabel(L.T("black.mine.sale", ItemName(sale.Item), sale.Mult.ToString("0.0", CultureInfo.InvariantCulture), st));
|
||||
if (sale.State == SaleState.Listed) l.AddButton(L.T("black.sell.delist"), () => Delist(sale));
|
||||
}
|
||||
foreach (var o in d.Black.Orders.OrderByDescending(x => x.PlacedDay))
|
||||
l.AddLabel(L.T("black.mine.line", ItemName(o.Item), o.Seller, L.T("black.mode." + o.Mode), L.T("black.state." + o.State + (o.Why != null && o.State != OrderState.Done ? "." + o.Why : "")), o.DueDay));
|
||||
}, r =>
|
||||
|
||||
Reference in new issue
Block a user