Stage 4: Web3 black market spot counter and Ponero desk

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
ZHU MINCHAOandClaude Sonnet 5.5 committed 2026-11-03 19:35:48 +08:00
1 parent 74f0dac57e
commit f43cd487e5
11 files changed
+366 -1

No files matched your search

+117 -1
View File
@@ -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, Black, Report }
private static Page _page = Page.Home;
private static string _amount = "";
@@ -28,6 +28,7 @@ namespace Decentralized
b.BeginRow();
foreach (Page p in Enum.GetValues(typeof(Page)))
{
if (p == Page.Black && !Unlock.BlackUnlocked) continue;
var page = p;
string name = L.T("tab." + p.ToString().ToLowerInvariant());
b.AddButton(page == _page ? $"[{name}]" : name, () => { _page = page; _message = null; Open(); });
@@ -41,6 +42,7 @@ namespace Decentralized
case Page.Bank: BankPage(b); break;
case Page.Poinbase: ExchangePage(b, Venue.Exchange); break;
case Page.Web3: Web3Page(b); break;
case Page.Black: BlackPage(b); break;
default: ReportPage(b); break;
}
b.End();
@@ -262,6 +264,120 @@ namespace Decentralized
});
}
private static bool _blackDesk;
private static string _deskAsset = Assets.PSC;
private static bool _deskIn = true;
private static string _payAsset = Assets.CRT;
/// <summary>Web3 黑市:黑市派系的链上实体。现货柜台(只收币)与 Ponero 兑换处。</summary>
private static void BlackPage(CustomUIBuilder b)
{
int rep = StoreReputation.GetBMReputation();
int day = StoreStation.GetDayCounter();
var d = Session.Data;
if (d.ActiveEvents.Contains(MarketEvent.Crackdown)) { b.AddLabel(L.T("black.offline")); return; }
if (!BlackMarket.Open(rep)) { b.AddLabel(L.T("black.closed", Tuning.BmOpenRep, rep)); return; }
bool desk = BlackMarket.DeskOpen(rep);
if (desk)
{
b.BeginRow();
b.AddButton(_blackDesk ? L.T("black.sub.shop") : $"[{L.T("black.sub.shop")}]", () => { _blackDesk = false; _message = null; Open(); });
b.AddButton(_blackDesk ? $"[{L.T("black.sub.desk")}]" : L.T("black.sub.desk"), () => { _blackDesk = true; _message = null; Open(); });
b.End();
}
if (desk && _blackDesk) { DeskPage(b, rep, day); return; }
var w = d.Hot;
Columns(b, l =>
{
l.AddHeader(L.T("black.shop.h"));
l.AddLabel(L.T("black.rep", rep, BlackMarket.MaxLevel(rep)));
if (d.Black.Offers.Count == 0) l.AddLabel(L.T("black.empty"));
foreach (var o in d.Black.Offers.ToList())
{
var offer = o;
l.AddLabel(L.T("black.offer", ItemName(offer.Item), offer.Qty, offer.Price));
l.AddButton(L.T("black.buy", offer.Price), () => BuyOffer(offer));
}
}, r =>
{
r.AddHeader(L.T("black.pay.h"));
foreach (var line in L.T("black.hint").Split('|')) r.AddLabel(line);
r.BeginRow();
foreach (var a in new[] { Assets.PSC, Assets.CRT, Assets.CRA, Assets.Ponero })
{
var asset = a;
r.AddButton(asset == _payAsset ? $"[{asset}]" : asset, () => { _payAsset = asset; Open(); });
}
r.End();
r.AddLabel(L.T("mixer.balance", _payAsset, Fmt.Num(w.Avail(_payAsset))));
if (w.Taint > 0.5) r.AddLabel(L.T("wallet.taint", Fmt.Credits(w.Taint)));
});
}
private static string ItemName(string id)
{
var it = ModHelper.SpawnItem(id);
if (it == null) return id;
string n = it.name;
it.Destroy();
return n;
}
private static void BuyOffer(BmOffer o)
{
var d = Session.Data;
if (!d.Black.Buy(o, d.Hot, _payAsset, Session.Price)) { _message = L.T("msg.balance"); Open(); return; }
Items.Give(ModHelper.SpawnItem(o.Item));
_message = L.T("black.bought", ItemName(o.Item));
Session.Save();
Open();
}
private static void DeskPage(CustomUIBuilder b, int rep, int day)
{
var d = Session.Data;
var w = d.Hot;
Columns(b, l =>
{
l.AddHeader(L.T("black.desk.h"));
foreach (var line in L.T("black.desk.hint", (int)Math.Round(Tuning.PoneroFee * 100)).Split('|')) l.AddLabel(line);
l.AddLabel(L.T("black.desk.left", Fmt.Credits(d.Black.DeskLeft(day)), Fmt.Credits(Tuning.PoneroDailyCap)));
l.AddLabel(L.T("black.desk.price", Fmt.Num(Session.Price(Assets.Ponero))));
Holdings(l, w, a => a == Assets.Ponero || a == _deskAsset);
}, r =>
{
r.AddHeader(L.T("black.desk.swap"));
r.BeginRow();
r.AddButton(_deskIn ? $"[{L.T("black.desk.in")}]" : L.T("black.desk.in"), () => { _deskIn = true; Open(); });
r.AddButton(_deskIn ? L.T("black.desk.out") : $"[{L.T("black.desk.out")}]", () => { _deskIn = false; Open(); });
r.End();
r.BeginRow();
foreach (var a in new[] { Assets.PSC, Assets.CRT, Assets.CRA })
{
var asset = a;
r.AddButton(asset == _deskAsset ? $"[{asset}]" : asset, () => { _deskAsset = asset; Open(); });
}
r.End();
r.AddLabel(_deskIn ? L.T("mixer.balance", _deskAsset, Fmt.Num(w.Avail(_deskAsset))) : L.T("mixer.balance", Assets.Ponero, Fmt.Num(w.Avail(Assets.Ponero))));
AmountRow(r);
r.AddButton(L.T("black.desk.go"), DeskSwap);
});
}
private static void DeskSwap()
{
if (!ReadAmount(out double v)) return;
var d = Session.Data;
int day = StoreStation.GetDayCounter();
double got = _deskIn ? d.Black.ToPonero(d.Hot, _deskAsset, v, day, Session.Price) : d.Black.FromPonero(d.Hot, _deskAsset, v, day, Session.Price);
if (got < 0) { _message = L.T("black.desk.fail"); Open(); return; }
// 从 Ponero 出来的币来源不明:出金审查按"来自混币器"加重
if (!_deskIn) d.Mixer.LastReturnDay = day;
_message = _deskIn ? L.T("msg.trade", Fmt.Num(v), _deskAsset, Fmt.Num(got), Assets.Ponero) : L.T("msg.trade", Fmt.Num(v), Assets.Ponero, Fmt.Num(got), _deskAsset);
Session.Save();
Open();
}
private static bool _web3Mixer;
private static string _mixAsset = Assets.PSC;
private static int _mixRounds = 2;