From 9441d4d1bd754ff5b4ac2c3764de01ad44250b26 Mon Sep 17 00:00:00 2001 From: ZHU MINCHAO <48154958+MinchaoZhu@users.noreply.github.com> Date: Tue, 3 Nov 2026 15:23:15 +0800 Subject: [PATCH] Terminal: home with three entries (Bank, Poinbase, Web3) plus report; entry icons Bank shows real credits, rent and deposits/withdrawals; Poinbase is the compliant exchange; Web3 is the wallet and decentralised trading. Co-Authored-By: Claude Sonnet 5.5 --- art/__pycache__/sprites.cpython-314.pyc | Bin 48727 -> 55586 bytes art/sprites.py | 81 +++++++++++++ .../ModFiles/Localization/en.csv | 23 +++- .../ModFiles/Localization/zh.csv | 23 +++- .../ModFiles/Textures/Items/ui_bank.png | Bin 0 -> 247 bytes .../ModFiles/Textures/Items/ui_poinbase.png | Bin 0 -> 260 bytes .../ModFiles/Textures/Items/ui_web3.png | Bin 0 -> 297 bytes src/Decentralized/TerminalWindow.cs | 107 ++++++++++++++---- 8 files changed, 211 insertions(+), 23 deletions(-) create mode 100644 src/Decentralized/ModFiles/Textures/Items/ui_bank.png create mode 100644 src/Decentralized/ModFiles/Textures/Items/ui_poinbase.png create mode 100644 src/Decentralized/ModFiles/Textures/Items/ui_web3.png diff --git a/art/__pycache__/sprites.cpython-314.pyc b/art/__pycache__/sprites.cpython-314.pyc index 7fc7d1b1b56c259fc59d45124a0e025fc08e3f40..c0d9531744ec791a4deadf55c910d3ab4fa7f45b 100644 GIT binary patch delta 14039 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 delta 8974 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 diff --git a/art/sprites.py b/art/sprites.py index 426dc21..bdfbd0e 100644 --- a/art/sprites.py +++ b/art/sprites.py @@ -30,6 +30,11 @@ C = { 'Y': (0xC8, 0xA4, 0x4A), # 金手指 'c': (0x2E, 0x2A, 0x2A), # 焦黑 'e': (0x6B, 0x4A, 0x3A), # 焦痕 + 'u': (0x4F, 0x86, 0xD0), # 蓝 + 'U': (0x2B, 0x4A, 0x82), # 深蓝 + 'v': (0x9B, 0x76, 0xD6), # 紫 + 'V': (0x5E, 0x45, 0x8F), # 深紫 + 'y': (0xF0, 0xCF, 0x64), # 亮金 'p': (0xC0, 0x7A, 0x4A), # 铜 'q': (0x8A, 0x4F, 0x34), # 暗铜 'w': (0xE6, 0xE2, 0xD0), # 白 @@ -514,6 +519,76 @@ def key(model): return model.replace(' ', '').lower() +def ui_bank(): + """银行图标(32×32):带山花的石柱建筑,门前一枚金币。""" + c = Canvas(32, 32) + for k in range(0, 14): # 山花(三角) + c.rect(16 - k, 4 + k // 2, 16 + k, 4 + k // 2, 'h' if k < 3 else 'l') + c.rect(2, 11, 29, 12, 'b'); c.rect(2, 13, 29, 13, 'd') # 檐口 + for x0 in (4, 10, 16, 22): # 四根柱子 + c.rect(x0, 14, x0 + 3, 24, 'l') + c.rect(x0, 14, x0, 24, 'h'); c.rect(x0 + 3, 14, x0 + 3, 24, 'd') + c.rect(x0 - 1, 14, x0 + 4, 14, 'b'); c.rect(x0 - 1, 24, x0 + 4, 24, 'b') + c.rect(1, 25, 30, 26, 'b'); c.rect(0, 27, 31, 28, 'm'); c.rect(0, 29, 31, 29, 'd') + c.rect(14, 8, 17, 9, 'y'); c.put(15, 8, 'w') # 山花里的小徽标 + for yy in range(19, 27): # 金币 + for xx in range(23, 31): + d = (xx - 26.5) ** 2 + (yy - 22.5) ** 2 + if d <= 14: + c.put(xx, yy, 'e' if d > 9 else 'y') + c.put(25, 21, 'w'); c.put(26, 21, 'w'); c.put(26, 22, 'y') + outline(c) + return c + + +def ui_poinbase(): + """Poinbase 图标(32×32):蓝色盾牌,中间一枚金色 P 币,两侧一上一下的箭头。""" + c = Canvas(32, 32) + for y in range(3, 29): # 盾牌 + half = 12 if y < 16 else max(0, 12 - (y - 16) * 12 // 12) + for x in range(16 - half, 16 + half + 1): + c.put(x, y, 'u' if x < 16 else 'U') + c.put(16 - half, y, 'h') if half else None + for x in range(4, 29): + c.put(x, 3, 'h'); c.put(x, 4, 'l') + for y in range(7, 21): # 币 + for x in range(9, 24): + d = (x - 16) ** 2 + (y - 13.5) ** 2 + if d <= 36: + c.put(x, y, 'e' if d > 28 else 'y') + c.put(12, 9, 'w'); c.put(13, 8, 'w'); c.put(12, 10, 'w') + c.rect(13, 9, 14, 18, 'U'); c.rect(15, 9, 18, 10, 'U'); c.rect(18, 11, 19, 13, 'U'); c.rect(15, 14, 18, 15, 'U') # P + for k in range(4): # 下方两个箭头:买入、卖出 + c.put(9 + k, 24 - k, 'w') if k < 3 else None + for x in range(8, 13): c.put(x, 22, 'w') + for x in range(19, 24): c.put(x, 22, 'w') + c.put(19, 23, 'w'); c.put(20, 24, 'w'); c.put(23, 23, 'w'); c.put(22, 24, 'w') + outline(c) + return c + + +def ui_web3(): + """Web3 图标(32×32):六边形节点网络,紫色底。""" + c = Canvas(32, 32) + nodes = [(16, 7), (7, 14), (25, 14), (11, 24), (21, 24), (16, 16)] + edges = [(0, 1), (0, 2), (1, 3), (2, 4), (3, 4), (5, 0), (5, 1), (5, 2), (5, 3), (5, 4)] + for (a, b) in edges: + (x0, y0), (x1, y1) = nodes[a], nodes[b] + n = max(abs(x1 - x0), abs(y1 - y0)) + for i in range(n + 1): + px, py = x0 + (x1 - x0) * i // n, y0 + (y1 - y0) * i // n + c.put(px, py, 'v'); c.put(px + 1, py, 'v'); c.put(px, py + 1, 'v') + for i, (x, y) in enumerate(nodes): + r = 3 if i == 5 else 2 + for dy in range(-r, r + 1): + for dx in range(-r, r + 1): + if dx * dx + dy * dy <= r * r + 1: + c.put(x + dx, y + dy, 'V' if (dx + dy) > 0 else 'h' if i != 5 else 'y') + c.put(x, y, 'w') + outline(c) + return c + + def guide(): """鉴定手册(16×16,一格):竖放的小册子,封面带品牌色条,书脊在左。""" c = Canvas(16, 16) @@ -542,6 +617,8 @@ for _tier in range(4): SPRITES['gpu_probidia_f_t%d' % _tier] = (lambda t=_tier: gpu_front('G', 'g2', tier=t)) SPRITES['gpu_pmd_f_t%d' % _tier] = (lambda t=_tier: gpu_front('R', 'r2', tier=t)) +UI_ICONS = {'ui_bank': ui_bank, 'ui_poinbase': ui_poinbase, 'ui_web3': ui_web3} + # 叠加图:和底图同尺寸,位置 (0,0) 对齐,只画变化的像素,不参与判格 OVERLAYS = { 'gpu_ov_fin1': lambda: ov_fingers(1), 'gpu_ov_fin2': lambda: ov_fingers(2), @@ -581,6 +658,8 @@ if __name__ == '__main__': if oc.px[y][x] is not None: b.px[y][x] = oc.px[y][x] return b + for name, make in UI_ICONS.items(): + make().png(os.path.join(sys.argv[2], name + '.png'), scale=8, bg=(0x2a, 0x2c, 0x34)) stack('gpu_probidia_f_t1', 'gpu_ov_fan2_2', 'gpu_ov_fin1', 'gpu_ov_brk1').png(os.path.join(sys.argv[2], 'prev_front_worn.png'), scale=6, bg=(0xA0, 0xA8, 0x9C)) print(sys.argv[2]) else: @@ -594,6 +673,8 @@ if __name__ == '__main__': canvas.png(os.path.join(out, name + '.png')) for name, make in OVERLAYS.items(): make().png(os.path.join(out, name + '.png')) + for name, make in UI_ICONS.items(): + make().png(os.path.join(out, name + '.png')) import big, big_cases for name, make in big.BIG.items(): make().png(os.path.join(out, name + '.png')) diff --git a/src/Decentralized/ModFiles/Localization/en.csv b/src/Decentralized/ModFiles/Localization/en.csv index 8551bc3..9081b60 100644 --- a/src/Decentralized/ModFiles/Localization/en.csv +++ b/src/Decentralized/ModFiles/Localization/en.csv @@ -18,8 +18,6 @@ item.gpu.desc,"Rated hashrate {0} MH/s. Rated draw {1} kJ per day. Condition: {2 item.gpu.burnt.name,Burnt {0} {1} item.gpu.burnt.desc,This card no longer works. term.title,Trading Terminal -tab.wallet,Wallet -tab.trade,Trade tab.report,Report wallet.line,"{0}: {1} (about {2} credits)" wallet.empty,The wallet is empty. @@ -129,3 +127,24 @@ lbl.ev.print.1,"Print shows another model" lbl.ev.print.2,"Print was redone" news.prehalving.title,"PSC Halving Ahead" news.prehalving.desc,"Miners will receive half as many coins per night in three days. Holders expect the price to rise." +tab.home,"Home" +tab.bank,"Bank" +tab.poinbase,"Poinbase" +tab.web3,"Web3" +home.enter,"Enter" +home.summary,"Credits {0} | On-chain assets about {1} credits" +home.lastnight,"Night of day {0}: mined {1} PSC, {2} / {3} rigs powered" +entry.bank,"Bank" +entry.bank.l1,"Deposits, withdrawals, rent" +entry.bank.l2,"Credits {0}" +entry.poinbase,"Poinbase" +entry.poinbase.l1,"Compliant exchange" +entry.poinbase.l2,"PSC {0} credits" +entry.web3,"Web3" +entry.web3.l1,"Wallet and decentralised trading" +entry.web3.l2,"About {0} credits" +bank.cash,"Credits: {0}" +bank.rent,"Rent: {0} credits, due in {1} days" +bank.crc,"Poinbase account (CRC): {0}" +bank.hint,"Deposit turns credits into CRC; withdrawing turns CRC back into credits and passes compliance review." +poin.account,"Poinbase account: CRC {0}, PSC {1}" diff --git a/src/Decentralized/ModFiles/Localization/zh.csv b/src/Decentralized/ModFiles/Localization/zh.csv index 82822ba..6f85c3b 100644 --- a/src/Decentralized/ModFiles/Localization/zh.csv +++ b/src/Decentralized/ModFiles/Localization/zh.csv @@ -17,8 +17,6 @@ item.gpu.desc,标称算力 {0} MH/s。标称耗电 {1} kJ/天。成色 {2}。 item.gpu.burnt.name,烧毁的 {0} {1} item.gpu.burnt.desc,此显卡已无法工作。 term.title,交易终端 -tab.wallet,钱包 -tab.trade,交易 tab.report,报告 wallet.line,{0}:{1}(约 {2} 信用点) wallet.empty,钱包为空。 @@ -128,3 +126,24 @@ lbl.ev.print.1,"丝印印着另一个型号" lbl.ev.print.2,"丝印重印过" news.prehalving.title,"PSC 即将减半" news.prehalving.desc,"三天后矿工每晚获得的币减半。持币者预期币价上行。" +tab.home,"首页" +tab.bank,"银行" +tab.poinbase,"Poinbase" +tab.web3,"Web3" +home.enter,"进入" +home.summary,"信用点 {0} | 链上资产约 {1} 信用点" +home.lastnight,"第 {0} 天夜间:挖出 {1} PSC,{2} / {3} 个矿架有电" +entry.bank,"银行" +entry.bank.l1,"信用点存取、房租" +entry.bank.l2,"信用点 {0}" +entry.poinbase,"Poinbase" +entry.poinbase.l1,"合规交易所" +entry.poinbase.l2,"PSC {0} 信用点" +entry.web3,"Web3" +entry.web3.l1,"钱包与去中心化交易" +entry.web3.l2,"约 {0} 信用点" +bank.cash,"信用点:{0}" +bank.rent,"房租:{0} 信用点,{1} 天后支付" +bank.crc,"Poinbase 账户(CRC):{0}" +bank.hint,"存入把信用点换成 CRC,提取把 CRC 换回信用点,提取要过合规审查。" +poin.account,"Poinbase 账户:CRC {0},PSC {1}" diff --git a/src/Decentralized/ModFiles/Textures/Items/ui_bank.png b/src/Decentralized/ModFiles/Textures/Items/ui_bank.png new file mode 100644 index 0000000000000000000000000000000000000000..c06305c58dd5f0cdcb70639dfca6ff1404b9b91f GIT binary patch literal 247 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=ffJeV#6kAr-fh6C_v{H!v+&nes`# zjs3_Y(bv-s8OF*qolPq75pEYqHuRNgI{%3OdGJ5`>JmnuW`j^!r=I>qG2tQxPd-KU z6`n^eWSNBC%(&z#Zc`!q;L$VZV4n>S4vBFY@Lmy6w_;aNm&oeww@OH{Vz6YtaF_9B zT$qNdnPYpvZN?2=+&dpFn$3KnwqH)D`8?wm4bIL@GSd^U9Jt}csM7X`qv}eFg14i@ s;yeb!N5)2MEX}fp8ZrhGDz;R!GrYVj8v5#@Cdi8np00i_>zopr07_j|p#T5? literal 0 HcmV?d00001 diff --git a/src/Decentralized/ModFiles/Textures/Items/ui_poinbase.png b/src/Decentralized/ModFiles/Textures/Items/ui_poinbase.png new file mode 100644 index 0000000000000000000000000000000000000000..82f6d6bcc0a2e42b688f59a2325c90528b29e9fc GIT binary patch literal 260 zcmV+f0sH=mP)e12AponW zU=~x&0mufSI|5g*Q`PtQ(gfAxoK!~)h~>zR7%- literal 0 HcmV?d00001 diff --git a/src/Decentralized/ModFiles/Textures/Items/ui_web3.png b/src/Decentralized/ModFiles/Textures/Items/ui_web3.png new file mode 100644 index 0000000000000000000000000000000000000000..ea60ced292202e34aac257588a103b30ddababf4 GIT binary patch literal 297 zcmV+^0oMMBP)mc_6oI%JEHLkX99vU3Hl)Qs#1Vl1ah z_QMrI_=1;e4!{)($fY689DuK|!RJV-mWJrrk5Iuw69>Qw5<&$NOrENB0VyRTO&TeL vN=AxHK1xbPs+D}yYJd)CLv<940&)NV7G%=kwHk;l00000NkvXXu0mjff5~)B literal 0 HcmV?d00001 diff --git a/src/Decentralized/TerminalWindow.cs b/src/Decentralized/TerminalWindow.cs index e91f087..9ce6825 100644 --- a/src/Decentralized/TerminalWindow.cs +++ b/src/Decentralized/TerminalWindow.cs @@ -6,13 +6,16 @@ using Decentralized.Domain; namespace Decentralized { - /// 交易终端窗口:钱包、交易、报告三页。每次操作后按当前页重建窗口。 + /// + /// 交易终端窗口:首页三个入口(银行、Poinbase、Web3)加报告。银行是真实的信用点(存取、房租); + /// Poinbase 是合规交易所;Web3 是去中心化交易和链上钱包。每次操作后按当前页重建窗口。 + /// public static class TerminalWindow { public const string Id = "pd_terminal"; - private enum Page { Wallet, Trade, Report } + private enum Page { Home, Bank, Poinbase, Web3, Report } - private static Page _page = Page.Wallet; + private static Page _page = Page.Home; private static string _amount = ""; private static string _message; @@ -21,7 +24,7 @@ namespace Decentralized if (Session.Data == null) return; var b = CustomUIManager.Window(Id, L.T("term.title")); if (b == null) return; - b.SetSize(620, 560).SetDraggable(true).SetCloseOnEscape(true).UseMachineryStyle(); + b.SetSize(640, 580).SetDraggable(true).SetCloseOnEscape(true).UseMachineryStyle(); b.BeginRow(); foreach (Page p in Enum.GetValues(typeof(Page))) { @@ -31,11 +34,13 @@ namespace Decentralized } b.End(); b.AddSeparator(); - b.BeginScroll(440); + b.BeginScroll(450); switch (_page) { - case Page.Wallet: WalletPage(b); break; - case Page.Trade: TradePage(b); break; + case Page.Home: HomePage(b); break; + case Page.Bank: BankPage(b); break; + case Page.Poinbase: ExchangePage(b, Venue.Exchange); break; + case Page.Web3: Web3Page(b); break; default: ReportPage(b); break; } b.End(); @@ -43,32 +48,67 @@ namespace Decentralized b.Show(); } - private static void WalletPage(CustomUIBuilder b) + private static void Go(Page p) { _page = p; _message = null; Open(); } + + private static void Entry(CustomUIBuilder b, string icon, string name, string line1, string line2, Page target) { - var w = Session.Data.Hot; - if (w.Balances.Count == 0) b.AddLabel(L.T("wallet.empty")); - foreach (var kv in w.Balances.OrderBy(k => k.Key)) - b.AddLabel(L.T("wallet.line", kv.Key, Fmt.Num(kv.Value), Fmt.Credits(kv.Value * Session.Price(kv.Key)))); - b.AddSeparator(); - b.AddLabel(L.T("wallet.total", Fmt.Credits(w.Value(Session.Price)))); - if (w.Taint > 0.5) b.AddLabel(L.T("wallet.taint", Fmt.Credits(w.Taint))); + b.BeginPanel(190f, 250f, TextAnchor.UpperCenter, 10f, 6f); + b.AddImage(ModInfo.Id + ":" + icon, 96f, 96f); + b.AddHeader(name); + b.AddLabel(line1); + b.AddLabel(line2); + b.AddFlexibleSpace(); + b.AddButton(L.T("home.enter"), () => Go(target)); + b.End(); } - private static void TradePage(CustomUIBuilder b) + private static void HomePage(CustomUIBuilder b) + { + var d = Session.Data; + double chain = d.Hot.Value(Session.Price); + b.AddLabel(L.T("home.summary", PlayerStore.Instance.playerCash, Fmt.Credits(chain))); + b.AddSpace(6f); + b.BeginRow(8f, TextAnchor.UpperCenter); + Entry(b, "ui_bank", L.T("entry.bank"), L.T("entry.bank.l1"), L.T("entry.bank.l2", PlayerStore.Instance.playerCash), Page.Bank); + Entry(b, "ui_poinbase", L.T("entry.poinbase"), L.T("entry.poinbase.l1"), L.T("entry.poinbase.l2", Fmt.Num(d.Market.Price)), Page.Poinbase); + Entry(b, "ui_web3", L.T("entry.web3"), L.T("entry.web3.l1"), L.T("entry.web3.l2", Fmt.Credits(chain)), Page.Web3); + b.End(); + b.AddSpace(8f); + b.AddSeparator(); + var r = d.LastNight; + b.AddLabel(r == null ? L.T("report.none") : L.T("home.lastnight", r.Day, Fmt.Num(r.Mined), r.PoweredRigs, r.Rigs)); + } + + private static void AmountRow(CustomUIBuilder b) { - b.AddLabel(L.T("trade.hint")); b.BeginRow(); b.AddLabel(L.T("trade.amount")); b.BeginPanel(240f, -1f, TextAnchor.MiddleCenter, 0f, 0f); // 给输入框一个固定宽度,容得下大额数字 b.AddInput("0", _amount, s => _amount = s, "amount", s => _amount = s); b.End(); b.End(); + } + + /// 银行:真实的信用点。现金、房租,以及信用点与 Poinbase 账户(CRC)之间的存取。 + private static void BankPage(CustomUIBuilder b) + { + var ps = PlayerStore.Instance; + b.AddHeader(L.T("entry.bank")); + b.AddLabel(L.T("bank.cash", ps.playerCash)); + b.AddLabel(L.T("bank.rent", Session.Rent(), ps.GetRentDayCounter())); + b.AddLabel(L.T("bank.crc", Fmt.Num(Session.Data.Hot.Get(Assets.CRC)))); + b.AddSeparator(); + b.AddLabel(L.T("bank.hint")); + AmountRow(b); b.BeginRow(); b.AddButton(L.T("trade.deposit"), Deposit); b.AddButton(L.T("trade.withdraw"), Withdraw); b.End(); - b.AddSeparator(); - foreach (var pool in Session.Data.Market.Pools) + } + + private static void TradeRows(CustomUIBuilder b, Venue venue) + { + foreach (var pool in Session.Data.Market.Pools.Where(x => x.Venue == venue)) { var p = pool; b.AddLabel(L.T("trade.pair", p.Base, p.Quote, L.T("venue." + p.Venue)) + " " + L.T("trade.price", Fmt.Num(p.Price))); @@ -79,6 +119,35 @@ namespace Decentralized } } + /// Poinbase:合规交易所。账户余额与交易对;信用点的存取在银行。 + private static void ExchangePage(CustomUIBuilder b, Venue venue) + { + var w = Session.Data.Hot; + b.AddHeader(L.T("entry.poinbase")); + b.AddLabel(L.T("poin.account", Fmt.Num(w.Get(Assets.CRC)), Fmt.Num(w.Get(Assets.PSC)))); + b.AddLabel(L.T("trade.hint")); + AmountRow(b); + b.AddSeparator(); + TradeRows(b, venue); + } + + /// Web3:链上钱包与去中心化交易。 + private static void Web3Page(CustomUIBuilder b) + { + var w = Session.Data.Hot; + b.AddHeader(L.T("entry.web3")); + if (w.Balances.Count == 0) b.AddLabel(L.T("wallet.empty")); + foreach (var kv in w.Balances.OrderBy(k => k.Key)) + b.AddLabel(L.T("wallet.line", kv.Key, Fmt.Num(kv.Value), Fmt.Credits(kv.Value * Session.Price(kv.Key)))); + b.AddLabel(L.T("wallet.total", Fmt.Credits(w.Value(Session.Price)))); + if (w.Taint > 0.5) b.AddLabel(L.T("wallet.taint", Fmt.Credits(w.Taint))); + b.AddSeparator(); + b.AddLabel(L.T("trade.hint")); + AmountRow(b); + b.AddSeparator(); + TradeRows(b, Venue.Dex); + } + private static void ReportPage(CustomUIBuilder b) { var r = Session.Data.LastNight;