From 42608a4acdd33acb823162e90552534a9b55cd45 Mon Sep 17 00:00:00 2001 From: ZHU MINCHAO <48154958+MinchaoZhu@users.noreply.github.com> Date: Tue, 3 Nov 2026 11:26:11 +0800 Subject: [PATCH] Cards: 3x2 front/back sprites, appearance overlays, flip via the Toggle menu Co-Authored-By: Claude Sonnet 5.5 --- art/sprites.py | 298 ++++++++++++++---- src/Decentralized.Domain/CardLook.cs | 10 + src/Decentralized.Domain/Mining.cs | 2 + src/Decentralized.Domain/RigSlots.cs | 4 +- src/Decentralized/DealerStock.cs | 8 + src/Decentralized/Items.cs | 65 +++- .../ModFiles/Textures/Items/gpu_burnt.png | Bin 375 -> 0 bytes .../ModFiles/Textures/Items/gpu_burnt_b.png | Bin 0 -> 256 bytes .../ModFiles/Textures/Items/gpu_burnt_f.png | Bin 0 -> 390 bytes .../ModFiles/Textures/Items/gpu_ov_brk1.png | Bin 0 -> 118 bytes .../ModFiles/Textures/Items/gpu_ov_brk2.png | Bin 0 -> 108 bytes .../ModFiles/Textures/Items/gpu_ov_fan1.png | Bin 0 -> 155 bytes .../ModFiles/Textures/Items/gpu_ov_fan2.png | Bin 0 -> 116 bytes .../ModFiles/Textures/Items/gpu_ov_fin1.png | Bin 0 -> 129 bytes .../ModFiles/Textures/Items/gpu_ov_fin2.png | Bin 0 -> 126 bytes .../ModFiles/Textures/Items/gpu_ov_stk1.png | Bin 0 -> 133 bytes .../ModFiles/Textures/Items/gpu_ov_stk2.png | Bin 0 -> 116 bytes .../Textures/Items/gpu_ov_txs_rz470.png | Bin 0 -> 155 bytes .../Textures/Items/gpu_ov_txs_rz580.png | Bin 0 -> 150 bytes .../Textures/Items/gpu_ov_txs_rz6800.png | Bin 0 -> 162 bytes .../Textures/Items/gpu_ov_txs_rz7900.png | Bin 0 -> 156 bytes .../Textures/Items/gpu_ov_txs_rzx50.png | Bin 0 -> 154 bytes .../Textures/Items/gpu_ov_txs_rzx60.png | Bin 0 -> 154 bytes .../Textures/Items/gpu_ov_txs_rzx70.png | Bin 0 -> 153 bytes .../Textures/Items/gpu_ov_txs_rzx80ti.png | Bin 0 -> 164 bytes .../Textures/Items/gpu_ov_txs_rzx90.png | Bin 0 -> 153 bytes .../Textures/Items/gpu_ov_txt_rz470.png | Bin 0 -> 149 bytes .../Textures/Items/gpu_ov_txt_rz580.png | Bin 0 -> 141 bytes .../Textures/Items/gpu_ov_txt_rz6800.png | Bin 0 -> 144 bytes .../Textures/Items/gpu_ov_txt_rz7900.png | Bin 0 -> 145 bytes .../Textures/Items/gpu_ov_txt_rzx50.png | Bin 0 -> 144 bytes .../Textures/Items/gpu_ov_txt_rzx60.png | Bin 0 -> 146 bytes .../Textures/Items/gpu_ov_txt_rzx70.png | Bin 0 -> 144 bytes .../Textures/Items/gpu_ov_txt_rzx80ti.png | Bin 0 -> 153 bytes .../Textures/Items/gpu_ov_txt_rzx90.png | Bin 0 -> 144 bytes .../ModFiles/Textures/Items/gpu_pmd.png | Bin 329 -> 0 bytes .../ModFiles/Textures/Items/gpu_pmd_b.png | Bin 0 -> 235 bytes .../ModFiles/Textures/Items/gpu_pmd_f.png | Bin 0 -> 354 bytes .../ModFiles/Textures/Items/gpu_probidia.png | Bin 328 -> 0 bytes .../Textures/Items/gpu_probidia_b.png | Bin 0 -> 237 bytes .../Textures/Items/gpu_probidia_f.png | Bin 0 -> 353 bytes tests/Decentralized.Domain.Tests/Program.cs | 2 +- 42 files changed, 315 insertions(+), 74 deletions(-) delete mode 100644 src/Decentralized/ModFiles/Textures/Items/gpu_burnt.png create mode 100644 src/Decentralized/ModFiles/Textures/Items/gpu_burnt_b.png create mode 100644 src/Decentralized/ModFiles/Textures/Items/gpu_burnt_f.png create mode 100644 src/Decentralized/ModFiles/Textures/Items/gpu_ov_brk1.png create mode 100644 src/Decentralized/ModFiles/Textures/Items/gpu_ov_brk2.png create mode 100644 src/Decentralized/ModFiles/Textures/Items/gpu_ov_fan1.png create mode 100644 src/Decentralized/ModFiles/Textures/Items/gpu_ov_fan2.png create mode 100644 src/Decentralized/ModFiles/Textures/Items/gpu_ov_fin1.png create mode 100644 src/Decentralized/ModFiles/Textures/Items/gpu_ov_fin2.png create mode 100644 src/Decentralized/ModFiles/Textures/Items/gpu_ov_stk1.png create mode 100644 src/Decentralized/ModFiles/Textures/Items/gpu_ov_stk2.png create mode 100644 src/Decentralized/ModFiles/Textures/Items/gpu_ov_txs_rz470.png create mode 100644 src/Decentralized/ModFiles/Textures/Items/gpu_ov_txs_rz580.png create mode 100644 src/Decentralized/ModFiles/Textures/Items/gpu_ov_txs_rz6800.png create mode 100644 src/Decentralized/ModFiles/Textures/Items/gpu_ov_txs_rz7900.png create mode 100644 src/Decentralized/ModFiles/Textures/Items/gpu_ov_txs_rzx50.png create mode 100644 src/Decentralized/ModFiles/Textures/Items/gpu_ov_txs_rzx60.png create mode 100644 src/Decentralized/ModFiles/Textures/Items/gpu_ov_txs_rzx70.png create mode 100644 src/Decentralized/ModFiles/Textures/Items/gpu_ov_txs_rzx80ti.png create mode 100644 src/Decentralized/ModFiles/Textures/Items/gpu_ov_txs_rzx90.png create mode 100644 src/Decentralized/ModFiles/Textures/Items/gpu_ov_txt_rz470.png create mode 100644 src/Decentralized/ModFiles/Textures/Items/gpu_ov_txt_rz580.png create mode 100644 src/Decentralized/ModFiles/Textures/Items/gpu_ov_txt_rz6800.png create mode 100644 src/Decentralized/ModFiles/Textures/Items/gpu_ov_txt_rz7900.png create mode 100644 src/Decentralized/ModFiles/Textures/Items/gpu_ov_txt_rzx50.png create mode 100644 src/Decentralized/ModFiles/Textures/Items/gpu_ov_txt_rzx60.png create mode 100644 src/Decentralized/ModFiles/Textures/Items/gpu_ov_txt_rzx70.png create mode 100644 src/Decentralized/ModFiles/Textures/Items/gpu_ov_txt_rzx80ti.png create mode 100644 src/Decentralized/ModFiles/Textures/Items/gpu_ov_txt_rzx90.png delete mode 100644 src/Decentralized/ModFiles/Textures/Items/gpu_pmd.png create mode 100644 src/Decentralized/ModFiles/Textures/Items/gpu_pmd_b.png create mode 100644 src/Decentralized/ModFiles/Textures/Items/gpu_pmd_f.png delete mode 100644 src/Decentralized/ModFiles/Textures/Items/gpu_probidia.png create mode 100644 src/Decentralized/ModFiles/Textures/Items/gpu_probidia_b.png create mode 100644 src/Decentralized/ModFiles/Textures/Items/gpu_probidia_f.png diff --git a/art/sprites.py b/art/sprites.py index 02747c1..1277bd0 100644 --- a/art/sprites.py +++ b/art/sprites.py @@ -77,79 +77,208 @@ class Canvas: f.write(data) -def gpu(accent, accent_dark, burnt=False): - """显卡(32×32,2×2 格),略微俯视:顶面是带两个风扇的散热罩,左端金属挡板(带接口), - 前沿露出 PCB 和金手指,右端一道暗侧面,顶上一排供电口。每格中心都不透明。""" - c = Canvas(32, 32) - TOP0, TOP1 = 4, 22 # 顶面行范围 - L, R = 6, 29 # 顶面左右(左边是挡板) - # 金属 I/O 挡板(左端竖条,带两个接口孔) - c.rect(1, 2, 5, 27, 'b') - c.rect(1, 2, 1, 27, 'h'); c.rect(5, 2, 5, 27, 'd') - for y in (6, 12): # 两个视频接口(深色矩形孔,带高光边) - c.rect(2, y, 4, y + 3, 'k') - c.rect(2, y, 4, y, 'g') - c.put(3, 20, 'k'); c.put(3, 22, 'k'); c.put(3, 24, 'k') # 下部散热孔 - # 散热罩顶面 - for y in range(TOP0, TOP1 + 1): - for x in range(L, R + 1): - c.put(x, y, 'm') - c.put(R, y, 'd'); c.put(R - 1, y, 'd') - for x in range(L, R + 1): - c.put(x, TOP0, 'l'); c.put(x, TOP0 + 1, 'b') - # 品牌色条(沿罩顶前沿) - for x in range(L + 1, R - 1): - c.put(x, TOP1 - 1, accent) - c.put(L + 1, TOP1, accent_dark); c.put(R - 2, TOP1, accent_dark) - # 两个风扇(圆形,叶片用十字 + 斜线) - for cx in (11, 22): - cy = 13 - for y in range(cy - 6, cy + 7): - for x in range(cx - 6, cx + 7): - d2 = (x - cx) ** 2 + (y - cy) ** 2 - if d2 <= 36: - c.put(x, y, 'k') - if 20 <= d2 <= 30: - c.put(x, y, 'g') - for k in range(-4, 5): - if abs(k) >= 1: - c.put(cx + k, cy, 'g'); c.put(cx, cy + k, 'g') - c.put(cx - 2, cy - 2, 'g'); c.put(cx + 2, cy + 2, 'g'); c.put(cx + 2, cy - 2, 'g'); c.put(cx - 2, cy + 2, 'g') - c.rect(cx - 1, cy - 1, cx + 1, cy + 1, 'b') - c.put(cx, cy, 'h') - # 前沿:PCB 绿色薄边 + 金手指 - for x in range(L, R + 1): - c.put(x, TOP1 + 1, 'g2') - c.put(x, TOP1 + 2, 'g2') - for x in range(L, R + 1): # 金手指:连续金色带,中间一道缺口(PCIe 键位),带深色触点线 - c.put(x, TOP1 + 3, 'Y'); c.put(x, TOP1 + 4, 'Y' if x % 2 == 0 else 'e') - for y in (TOP1 + 3, TOP1 + 4): - c.put(L + 13, y, 'k'); c.put(L + 14, y, 'k') - # 顶上一排供电口(两个黑色插口) - for x0 in (L + 3, L + 9): - c.rect(x0, TOP0 - 1, x0 + 4, TOP0 - 1, 'k') - # 保证每格中心不透明:下半部(第二行格子,y 16..31 的中心 y=24)落在金手指/PCB 上 - for x in range(L, R + 1): - for y in range(TOP1 + 1, 28): - if c.px[y][x] is None: - c.put(x, y, 'k') - if burnt: - for x, y in [(9, 8), (10, 9), (13, 17), (24, 8), (25, 9), (27, 18), (17, 12), (18, 11)]: - c.put(x, y, 'c') - for x in range(L + 1, R - 1): - c.put(x, TOP1 - 1, 'e') - for x, y in [(15, 5), (16, 5), (20, 21), (26, 14)]: - c.put(x, y, 'c') - # 轮廓 +FONT = { # 3×5 像素字(丝印用) + 'R': '110101110101101', 'Z': '111001010100111', 'X': '101101010101101', 'P': '110101110100100', + 'M': '101111111101101', 'D': '110101101101110', 'T': '111010010010010', 'i': '010000010010010', + '0': '111101101101111', '1': '010110010010111', '2': '110001010100111', '3': '110001010001110', + '4': '101101111001001', '5': '111100110001110', '6': '011100111101111', '7': '111001010010010', + '8': '111101111101111', '9': '111101111001110', +} + + +def text(c, x, y, s, color, skew=False): + """在画布上写 3×5 像素字;skew 为重新印过的效果:字一高一低、间距不匀。""" + i = 0 + for ch in s: + if ch == ' ': + x += 2 + continue + dy = (i % 2) if skew else 0 + for k, bit in enumerate(FONT[ch]): + if bit == '1': + c.put(x + k % 3, y + k // 3 + dy, color) + x += 4 + (1 if skew and i % 3 == 2 else 0) + i += 1 + + +W, H = 48, 32 +TOP0, TOP1 = 4, 22 # 顶面行范围 +L, R = 6, 45 # 顶面左右(左边是挡板) +FANS = ((17, 13), (34, 13)) # 两个风扇中心 + + +def outline(c): solid = lambda v: v is not None get = lambda x, y: c.px[y][x] if 0 <= x < c.w and 0 <= y < c.h else None edge = [(x, y) for y in range(c.h) for x in range(c.w) if solid(get(x, y)) and any(not solid(get(x + dx, y + dy)) for dx, dy in ((1, 0), (-1, 0), (0, 1), (0, -1)))] for x, y in edge: c.put(x, y, 'O') + + +def bracket(c): + """左端金属挡板,三个接口孔。""" + c.rect(1, 2, 5, 27, 'b') + c.rect(1, 2, 1, 27, 'h'); c.rect(5, 2, 5, 27, 'd') + for y in (5, 11, 17): + c.rect(2, y, 4, y + 3, 'k') + c.rect(2, y, 4, y, 'g') + c.put(3, 22, 'k'); c.put(3, 24, 'k') + + +def gpu_front(accent, accent_dark, burnt=False): + """显卡正面(48×32,3×2 格),略微俯视:顶面是带两个风扇的散热罩,左端金属挡板(三个接口), + 前沿露出 PCB 和金手指,右端一道暗侧面。每格中心都不透明。""" + c = Canvas(W, H) + bracket(c) + for y in range(TOP0, TOP1 + 1): + for x in range(L, R + 1): + c.put(x, y, 'm') + c.put(R, y, 'd'); c.put(R - 1, y, 'd') + for x in range(L, R + 1): + c.put(x, TOP0, 'l'); c.put(x, TOP0 + 1, 'b') + for x in range(L + 1, R - 1): + c.put(x, TOP1 - 1, accent) + c.put(L + 1, TOP1, accent_dark); c.put(R - 2, TOP1, accent_dark) + for cx, cy in FANS: + for y in range(cy - 7, cy + 8): + for x in range(cx - 7, cx + 8): + d2 = (x - cx) ** 2 + (y - cy) ** 2 + if d2 <= 49: + c.put(x, y, 'k') + if 26 <= d2 <= 38: + c.put(x, y, 'g') + for k in range(-5, 6): + if abs(k) >= 1: + c.put(cx + k, cy, 'g'); c.put(cx, cy + k, 'g') + for dx, dy in ((-3, -3), (3, 3), (3, -3), (-3, 3)): + c.put(cx + dx, cy + dy, 'g') + c.rect(cx - 1, cy - 1, cx + 1, cy + 1, 'b') + c.put(cx, cy, 'h') + for x in range(L, R + 1): + c.put(x, TOP1 + 1, 'g2'); c.put(x, TOP1 + 2, 'g2') + for x in range(L, R + 1): + c.put(x, TOP1 + 3, 'Y'); c.put(x, TOP1 + 4, 'Y' if x % 2 == 0 else 'e') + for y in (TOP1 + 3, TOP1 + 4): + c.put(L + 17, y, 'k'); c.put(L + 18, y, 'k') + for x0 in (L + 4, L + 12): # 顶上供电口 + c.rect(x0, TOP0 - 1, x0 + 4, TOP0 - 1, 'k') + for x in range(L, R + 1): + for y in range(TOP1 + 1, 28): + if c.px[y][x] is None: + c.put(x, y, 'k') + if burnt: + for x, y in [(12, 8), (13, 9), (18, 17), (35, 8), (36, 9), (40, 18), (24, 12), (25, 11)]: + c.put(x, y, 'c') + for x in range(L + 1, R - 1): + c.put(x, TOP1 - 1, 'e') + outline(c) return c +def gpu_back(accent, accent_dark, burnt=False): + """显卡背面(翻面后):左端仍是挡板;黑色背板,上面一行丝印(型号用叠加图画), + 右下一张序列号贴纸,贴纸边上一道封条。""" + c = Canvas(W, H) + bracket(c) + for y in range(TOP0, 28): + for x in range(L, R + 1): + c.put(x, y, 'd') + c.put(R, y, 'k'); c.put(R - 1, y, 'k') + for x in range(L, R + 1): + c.put(x, TOP0, 'm'); c.put(x, TOP0 + 1, 'm') + for x in range(L + 1, R - 1): + c.put(x, 16, accent) + c.put(L + 1, 17, accent_dark); c.put(R - 2, 17, accent_dark) + for x in range(L + 2, R - 2, 5): # 背板螺丝 + for y in (22, 25): + c.put(x, y, 'b'); c.put(x + 1, y, 'k') + c.rect(26, 18, 41, 21, 'h') # 序列号贴纸(印刷条码) + for x in range(27, 41, 2): + c.rect(x, 19, x, 20, 'k') + c.rect(44, 17, 44, 22, 'R') # 封条(红色) + c.rect(43, 17, 43, 22, 'r2') + for x in range(L, R + 1): + for y in range(28, 28): + pass + if burnt: + for x, y in [(14, 9), (15, 10), (30, 11), (36, 13), (20, 14)]: + c.put(x, y, 'c') + outline(c) + return c + + +def overlay(): + return Canvas(W, H) + + +def ov_fan(kind): + """风扇叠加:1 积灰(叶片上一层灰),2 叶片缺角(边缘缺一块并露出黑底)。""" + c = overlay() + for cx, cy in FANS: + if kind == 1: + for dx, dy in ((-4, -2), (-2, -4), (3, -3), (4, 1), (-3, 3), (2, 4), (-5, 0), (0, 5), (1, -5), (-1, 2), (5, -1), (3, 2)): + c.put(cx + dx, cy + dy, 'l') + for dx, dy in ((-4, -1), (-1, -4), (4, -2), (2, 3), (-3, 4)): + c.put(cx + dx, cy + dy, 'h') + else: + for dx, dy in ((4, -4), (5, -4), (5, -3), (4, -3), (3, -4), (5, -5), (6, -3)): + c.put(cx + dx, cy + dy, 'k') + c.put(cx - 5, cy + 4, 'k'); c.put(cx - 4, cy + 5, 'k'); c.put(cx - 5, cy + 5, 'k') + return c + + +def ov_fingers(kind): + """金手指叠加:1 发暗(触点变褐),2 氧化发绿。""" + c = overlay() + for x in range(L, R + 1): + for y in (TOP1 + 3, TOP1 + 4): + if x in (L + 17, L + 18): + continue + if kind == 1: + c.put(x, y, 'e' if (x + y) % 3 else 'Y') + else: + c.put(x, y, 'g2' if (x + y) % 2 else 'G') + return c + + +def ov_bracket(kind): + """挡板叠加:1 划痕;2 接口数量不对(第三个接口被封成一块平板,只剩两个)。""" + c = overlay() + if kind == 1: + for x, y in ((2, 9), (3, 10), (4, 11), (2, 15), (3, 15), (3, 16), (2, 20), (3, 21), (4, 22), (4, 25), (3, 25)): + c.put(x, y, 'l' if (x + y) % 2 else 'd') + else: + c.rect(2, 17, 4, 20, 'b') + c.rect(2, 17, 4, 17, 'h') + return c + + +def ov_text(model, skew): + """背面丝印叠加:写型号。skew 为重新印过的版本(字高低不齐)。""" + c = overlay() + text(c, 10, 8, model, 'l' if skew else 'h', skew) + return c + + +def ov_sticker(kind): + """贴纸叠加:1 手写序列号(条码被盖住、写了歪歪扭扭的字);2 封条缺失(只剩撕过的残胶)。""" + c = overlay() + if kind == 1: + c.rect(26, 18, 41, 21, 'h') + for x, y in ((27, 20), (28, 19), (29, 20), (30, 19), (32, 20), (33, 19), (33, 21), (35, 19), (36, 20), (37, 19), (38, 21), (39, 20), (40, 19)): + c.put(x, y, 'O') + else: + c.rect(43, 17, 44, 22, 'd') + for y in (17, 19, 21, 22): + c.put(44, y, 'm') + c.put(43, 18, 'm'); c.put(43, 20, 'm') + return c + + +MODELS = ['RZX 50', 'RZX 60', 'RZX 70', 'RZX 80 Ti', 'RZX 90', 'RZ 470', 'RZ 580', 'RZ 6800', 'RZ 7900'] + + def rig(): """矿架(48×48,3×3 格):和游戏里其他机器一样的略微俯视(3/4 视角)——顶面是上窄下宽的梯形, 下面是正面,正面里四层显卡位,左下角电源;光从左上来,左亮右暗;轮廓统一深紫、削掉尖角、底下两只脚和一圈阴影。""" @@ -283,14 +412,33 @@ def terminal(): return c +def key(model): + return model.replace(' ', '').lower() + + SPRITES = { - 'gpu_probidia': lambda: gpu('G', 'g2'), - 'gpu_pmd': lambda: gpu('R', 'r2'), - 'gpu_burnt': lambda: gpu('e', 'c', burnt=True), + 'gpu_probidia_f': lambda: gpu_front('G', 'g2'), + 'gpu_probidia_b': lambda: gpu_back('G', 'g2'), + 'gpu_pmd_f': lambda: gpu_front('R', 'r2'), + 'gpu_pmd_b': lambda: gpu_back('R', 'r2'), + 'gpu_burnt_f': lambda: gpu_front('e', 'c', burnt=True), + 'gpu_burnt_b': lambda: gpu_back('e', 'c', burnt=True), 'rig': rig, 'terminal': terminal, } +# 叠加图:和底图同尺寸,位置 (0,0) 对齐,只画变化的像素,不参与判格 +OVERLAYS = { + 'gpu_ov_fan1': lambda: ov_fan(1), 'gpu_ov_fan2': lambda: ov_fan(2), + 'gpu_ov_fin1': lambda: ov_fingers(1), 'gpu_ov_fin2': lambda: ov_fingers(2), + 'gpu_ov_brk1': lambda: ov_bracket(1), 'gpu_ov_brk2': lambda: ov_bracket(2), + 'gpu_ov_stk1': lambda: ov_sticker(1), 'gpu_ov_stk2': lambda: ov_sticker(2), +} +for _m in MODELS: + OVERLAYS['gpu_ov_txt_' + key(_m)] = (lambda m=_m: ov_text(m, False)) + OVERLAYS['gpu_ov_txs_' + key(_m)] = (lambda m=_m: ov_text(m, True)) + + def check_cells(canvas, name): """游戏按 mod 物品图每格的中心像素是否不透明来判断占格(行从图的下沿往上数)。有空格就报错。""" cols, rows = canvas.w // 16, canvas.h // 16 @@ -306,6 +454,20 @@ if __name__ == '__main__': canvas = make() check_cells(canvas, name) canvas.png(os.path.join(sys.argv[2], name + '.png'), scale=6, bg=(0xA0, 0xA8, 0x9C)) + # 预览:把各种叠加图叠在底图上 + def stack(base, *ovs): + b = SPRITES[base]() + for o in ovs: + oc = OVERLAYS[o]() + for y in range(oc.h): + for x in range(oc.w): + if oc.px[y][x] is not None: + b.px[y][x] = oc.px[y][x] + return b + stack('gpu_probidia_f', 'gpu_ov_fan1', 'gpu_ov_fin1', 'gpu_ov_brk1').png(os.path.join(sys.argv[2], 'prev_front_worn.png'), scale=6, bg=(0xA0, 0xA8, 0x9C)) + stack('gpu_pmd_f', 'gpu_ov_fan2', 'gpu_ov_fin2', 'gpu_ov_brk2').png(os.path.join(sys.argv[2], 'prev_front_fake.png'), scale=6, bg=(0xA0, 0xA8, 0x9C)) + stack('gpu_probidia_b', 'gpu_ov_txt_rzx80ti').png(os.path.join(sys.argv[2], 'prev_back_ok.png'), scale=6, bg=(0xA0, 0xA8, 0x9C)) + stack('gpu_pmd_b', 'gpu_ov_txs_rz6800', 'gpu_ov_stk1', 'gpu_ov_stk2').png(os.path.join(sys.argv[2], 'prev_back_fake.png'), scale=6, bg=(0xA0, 0xA8, 0x9C)) print(sys.argv[2]) else: out = os.path.normpath(os.path.join(here, '..', 'src', 'Decentralized', 'ModFiles', 'Textures', 'Items')) @@ -313,4 +475,6 @@ if __name__ == '__main__': canvas = make() check_cells(canvas, name) canvas.png(os.path.join(out, name + '.png')) + for name, make in OVERLAYS.items(): + make().png(os.path.join(out, name + '.png')) print(out) diff --git a/src/Decentralized.Domain/CardLook.cs b/src/Decentralized.Domain/CardLook.cs index ebce2e1..d05f80d 100644 --- a/src/Decentralized.Domain/CardLook.cs +++ b/src/Decentralized.Domain/CardLook.cs @@ -22,6 +22,16 @@ namespace Decentralized.Domain public const int Variants = 3; + /// 五位数字,存在物品标签上:风扇、金手指、挡板、丝印、贴纸。 + public string Encode() => $"{Fan}{Fingers}{Bracket}{Print}{Sticker}"; + + public static CardLook Decode(string s) + { + if (s == null || s.Length != 5) return default; + int D(int i) => Math.Max(0, Math.Min(Variants - 1, s[i] - '0')); + return new CardLook { Fan = D(0), Fingers = D(1), Bracket = D(2), Print = D(3), Sticker = D(4) }; + } + /// 只在假卡上出现的取值:玩家一旦看到,就能肯定是假的。 public bool HasFakeSign => Bracket == 2 || Print != 0 || Sticker == 1; diff --git a/src/Decentralized.Domain/Mining.cs b/src/Decentralized.Domain/Mining.cs index 5360761..50b3a82 100644 --- a/src/Decentralized.Domain/Mining.cs +++ b/src/Decentralized.Domain/Mining.cs @@ -84,6 +84,8 @@ namespace Decentralized.Domain public double Health = 100; public bool Dead; public bool Refurbished; + /// 外观;新卡(正规渠道)没有记录,按全新画。 + public CardLook Look; public HardwareSpec Label => Hardware.Specs[Model]; public HardwareSpec Chip => Hardware.Specs[FakeOf ?? Model]; diff --git a/src/Decentralized.Domain/RigSlots.cs b/src/Decentralized.Domain/RigSlots.cs index 8f7a9a2..0e459f6 100644 --- a/src/Decentralized.Domain/RigSlots.cs +++ b/src/Decentralized.Domain/RigSlots.cs @@ -9,7 +9,7 @@ namespace Decentralized.Domain public static class RigSlots { public const int Base = 2, Max = 5; - public const int CellWidth = 2, CellsPerSlot = 2; + public const int CellWidth = 3, CellsPerSlot = 2; /// 升级到第 n 个槽需要的电子元件(物品 id,件数)。n 从 3 开始。 public static (string Item, int Count) Cost(int slot) @@ -45,7 +45,7 @@ namespace Decentralized.Domain return take; } - /// 显卡格子的形状字符串:宽 2,高 2 × 最大槽数;前 slots × 2 行可放(0),其余不可放(1)。 + /// 显卡格子的形状字符串:宽 3(一张卡 3×2 格),高 2 × 最大槽数;前 slots × 2 行可放(0),其余不可放(1)。 public static string Shape(int slots) { var sb = new System.Text.StringBuilder(); diff --git a/src/Decentralized/DealerStock.cs b/src/Decentralized/DealerStock.cs index 1099abd..c2f687c 100644 --- a/src/Decentralized/DealerStock.cs +++ b/src/Decentralized/DealerStock.cs @@ -15,6 +15,14 @@ namespace Decentralized ModHook.OnPlaceInventorInventoryItemLate += OnPlace; // 开发者模式(F9)里的测试入口:像到了杰克逊店里一样,清空并扩大柜台后上货 ModHelper.AddDebugFunction(ModInfo.Id, ModInfo.Name, "Give rig x3 (test)", () => { for (int i = 0; i < 3; i++) Items.Give(ModHelper.SpawnItem(Items.Rig)); }); + ModHelper.AddDebugFunction(ModInfo.Id, ModInfo.Name, "Used cards x4 (test)", () => + { + var rng = Session.Data.Rng; + Items.Give(Items.NewCard("RZX80Ti", 40, null, rng)); + Items.Give(Items.NewCard("RZX80Ti", 70, "RZX60", rng)); + Items.Give(Items.NewCard("RZ6800", 30, "RZ580", rng)); + Items.Give(Items.NewCard("RZ7900", 90, "RZ470", rng)); + }); ModHelper.AddDebugFunction(ModInfo.Id, ModInfo.Name, "Dr. Jackson stock (test)", () => { EmporiumEntry.Instance.ClearFrontInv(); diff --git a/src/Decentralized/Items.cs b/src/Decentralized/Items.cs index 01b50e4..7a354e0 100644 --- a/src/Decentralized/Items.cs +++ b/src/Decentralized/Items.cs @@ -21,6 +21,7 @@ namespace Decentralized public const string FakeTag = "PD_FAKE_OF"; public const string RefurbTag = "PD_REFURBISHED"; public const string DeadTag = "PD_DEAD"; + public const string LookTag = "PD_LOOK", BackTag = "PD_BACK"; public static Action OpenTerminal; @@ -68,14 +69,32 @@ namespace Decentralized private static GameItem CreateGpu(HardwareSpec spec) { var item = ItemDirectory.CreateEmptyItem(GpuId(spec.Model)); - item.SetSpriteAndShapeFromMod(ModInfo.Id, spec.Brand == Hardware.Probidia ? "gpu_probidia" : "gpu_pmd"); item.SetGameItemType("ELECTRONIC"); item.onLoaded = Refresh; + // 右键"切换"翻面;外观差异用叠加图画在同一张底图上 + item.EnableTag(ToggleAppearanceHelper.TOGGLE_APPEARANCE_TAG); + item.mayToggleSlotItemFunc = (_, _, _) => true; + item.canToggleSlotItemFunc = (_, _, _) => true; + item.onToggleSlotItemFunc = (toggled, _, _) => Log.Guard("显卡翻面", () => + { + if (toggled.IsTag(BackTag)) toggled.ModifyTag(BackTag, t => t.Disable()); else toggled.EnableTag(BackTag); + Refresh(toggled); + }); + item.getItemSpriteModifierForItemFunc = Overlays; ModHelper.SetSource(item, ModInfo.Id, ModInfo.Name); Refresh(item); return item; } + /// 按给定的状态造一张卡(二手卡、假卡):写入标签并生成外观。 + public static GameItem NewCard(string model, double health, string fakeOf, Rng rng) + { + var item = ModHelper.SpawnItem(GpuId(model)); + var u = new Unit { Model = model, FakeOf = fakeOf, Health = health, Look = CardLook.Generate(rng, health, fakeOf != null) }; + Store(item, u); + return item; + } + public static Unit ToUnit(GameItem item) { string model = item.identifier.Substring(GpuPrefix.Length); @@ -85,6 +104,7 @@ namespace Decentralized if (item.IsTag(FakeTag)) u.FakeOf = item.GetTagReadonly(FakeTag).GetString(); u.Refurbished = item.IsTag(RefurbTag); u.Dead = item.IsTag(DeadTag); + if (item.IsTag(LookTag)) u.Look = CardLook.Decode(item.GetTagReadonly(LookTag).GetString()); return u; } @@ -94,6 +114,7 @@ namespace Decentralized if (u.FakeOf != null) item.ModifyTag(FakeTag, s => s.Enable().SetString(u.FakeOf)); if (u.Refurbished) item.EnableTag(RefurbTag); if (u.Dead) item.EnableTag(DeadTag); + item.ModifyTag(LookTag, s => s.Enable().SetString(u.Look.Encode())); Refresh(item); } @@ -107,12 +128,48 @@ namespace Decentralized item.name = L.T("item.gpu.burnt.name", label.Brand, DisplayModel(label.Model)); item.shortDescription = L.T("item.gpu.burnt.desc"); item.unitValue = Math.Max(1, label.Price / 20); - item.SetSpriteAndShapeFromMod(ModInfo.Id, "gpu_burnt"); + item.SetSpriteAndShapeFromMod(ModInfo.Id, item.IsTag(BackTag) ? "gpu_burnt_b" : "gpu_burnt_f"); return; } + item.SetSpriteAndShapeFromMod(ModInfo.Id, (label.Brand == Hardware.Probidia ? "gpu_probidia" : "gpu_pmd") + (item.IsTag(BackTag) ? "_b" : "_f")); item.name = L.T("item.gpu.name", label.Brand, DisplayModel(label.Model)); item.shortDescription = L.T("item.gpu.desc", Fmt.Num(label.DisplayHash), Fmt.Num(label.Kj), Mathf.RoundToInt((float)u.Health)); - item.unitValue = Math.Max(1, (long)Math.Round(label.Price * u.Health / 100)); + item.unitValue = CardValue.True(u); + } + + private static Sprite ModSprite(string key) + { + var mod = ModLoader.Mods.Find(m => m.Manifest.ID.Equals(ModInfo.Id)); + return mod != null && mod.Sprites.TryGetValue(key, out var sprite) ? sprite : null; + } + + /// 外观叠加图:正面三个维度,背面丝印与贴纸;烧毁的卡不叠。 + private static List Overlays(GameItem item) + { + var list = new List(); + if (item.IsTag(DeadTag)) return list; + var u = ToUnit(item); + var keys = new List(); + if (!item.IsTag(BackTag)) + { + if (u.Look.Fan > 0) keys.Add("gpu_ov_fan" + u.Look.Fan); + if (u.Look.Fingers > 0) keys.Add("gpu_ov_fin" + u.Look.Fingers); + if (u.Look.Bracket > 0) keys.Add("gpu_ov_brk" + u.Look.Bracket); + } + else + { + // 丝印:0 标称型号;1 印的是真实芯片型号;2 标称型号但字歪(重印过) + string model = u.Look.Print == 1 && u.FakeOf != null ? u.FakeOf : u.Model; + keys.Add((u.Look.Print == 2 ? "gpu_ov_txs_" : "gpu_ov_txt_") + model.ToLowerInvariant()); + if (u.Look.Sticker > 0) keys.Add("gpu_ov_stk" + u.Look.Sticker); + } + int priority = 0; + foreach (var k in keys) + { + var sprite = ModSprite(k); + if (sprite != null) list.Add(new ItemSpriteModifier(sprite, Vector2.zero, 0, false, priority++, false, Color.white)); + } + return list; } // ---------- 矿架 ---------- @@ -126,7 +183,7 @@ namespace Decentralized var battery = new GameSlotInventory(); var upgrade = new GameSlotInventory(); var modules = new GameGridInventory(MachineHelper.DEFAULT_MODULE_BAY_CONFIG, 7); - // 显卡每张 2×2 格:一列 2 格宽的格子,每个槽两行;未解锁的行不可放 + // 显卡每张 3×2 格:3 格宽的格子,每张卡 3×2 格,每个槽两行;未解锁的行不可放 var cards = new GameGridInventory(RigSlots.Shape(RigSlots.Base), RigSlots.CellWidth); var window = MachineHelper.CreateMachineryWindow(true, MachineHelper.PowerPanel(battery), diff --git a/src/Decentralized/ModFiles/Textures/Items/gpu_burnt.png b/src/Decentralized/ModFiles/Textures/Items/gpu_burnt.png deleted file mode 100644 index aeff9bf24233d0edafe82078a02e377c256edc8e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 375 zcmV--0f_#IP)$;dI21P*!NIlA7ZGP4LBUCUhz`D$dVwqFHJ98$TM-)g2uZ(Q zemO2FO_IKS+Hf#_adi%GJfA9Y012=$a1O9qZ@z-w?$??^^BP3~=vdMyO`SB}P=+1A zcDJtt0EawpMVQ?hz-+RtBmuxP?Lv~*3;<(DGtCglw*bs>AG}MwCIA``A?O?p%;#xO zAw&RPgfs{$G}e060Mc%F&r==qiU9l+@EuS*bqRgUqfF8ifnEc zq&f85lmQ6VBM|$04N$uj{q^B7ocnPzk_|l_6F!c Vl*Mxw8C3uP002ovPDHLkV1iU#nA89O diff --git a/src/Decentralized/ModFiles/Textures/Items/gpu_burnt_b.png b/src/Decentralized/ModFiles/Textures/Items/gpu_burnt_b.png new file mode 100644 index 0000000000000000000000000000000000000000..7f86961d7a5ccdce3af9bc62af66535f07ac6258 GIT binary patch literal 256 zcmV+b0ssDqP)XeycfN5@0X107Sk;CRS;z{SnyKekvIOc=uh!4c7L4DvvHM#iAUSUq5F>Ilam z4-8fea^I*22BinkGch5or=>NtJupz7!07?>Qi#@=T+feY;(?ACntOoO`GTsMc+i(Z z*L5^np2af<_gsQ@^$-ILlcdrql??>vp}b8VS^%2FbsYl) z9zpKADR}N3JV2a>2ml-70JzV(0HhvT09u7?N6vH)mYvkYOAgRPQ^GSxJBM{G_3#3q zOI+1yQQY5GQ$qXj`1uU@_VAX(->lz8bKozkP+bkjdxK;jFnM@6N;I_-a~`yc#j{Yb zr%^76^K=%RY5|}o0{~rrZA-;tJp=Q660EFdppyW21|H{BEGP;-ys)eRRMJSU03h|D kR~DdaihoDO7Tc%206?vv!{(4XtN;K207*qoM6N<$f;K0jd;kCd literal 0 HcmV?d00001 diff --git a/src/Decentralized/ModFiles/Textures/Items/gpu_ov_brk1.png b/src/Decentralized/ModFiles/Textures/Items/gpu_ov_brk1.png new file mode 100644 index 0000000000000000000000000000000000000000..750d49d01a020a58c962695decff5b5490eda702 GIT binary patch literal 118 zcmeAS@N?(olHy`uVBq!ia0vp^20*O9!3HEluKbn(QnsEhjv*Dd-d^3v$)F&>?9eW( zeO+Wt%tzfh2fX6mnQ^Er5n=doFh;pWfazY@{%vw>Jf2JCHwYBGdVGc&t;uc GLK6V*gdleS literal 0 HcmV?d00001 diff --git a/src/Decentralized/ModFiles/Textures/Items/gpu_ov_fan1.png b/src/Decentralized/ModFiles/Textures/Items/gpu_ov_fan1.png new file mode 100644 index 0000000000000000000000000000000000000000..8b0254eba359006591986553ecc4b9d665902c5d GIT binary patch literal 155 zcmeAS@N?(olHy`uVBq!ia0vp^20*O9!3HEluKbn(Qc0dJjv*Dd-d^6wdq9E5CGgvQ z=1wldmhVcnvl3o&aQ-nrAej^E#lXNZW!7(TqdUxJqvGcl-cy~&){_%5QSjR}=H)Su zrl;QhHTk>a#DiTtC)@TM4Nmdsesgz@QgaeB14F`G?h9(^(-)UrT?Dj^!PC{xWt~$( F699i}IvxN3 literal 0 HcmV?d00001 diff --git a/src/Decentralized/ModFiles/Textures/Items/gpu_ov_fan2.png b/src/Decentralized/ModFiles/Textures/Items/gpu_ov_fan2.png new file mode 100644 index 0000000000000000000000000000000000000000..2a62cc00fe071e576de4e479612c4fd6c18555cb GIT binary patch literal 116 zcmeAS@N?(olHy`uVBq!ia0vp^20*O9!3HEluKbn(Qr4a>jv*Dd-d^3v$)Lc)azID* z+B^FxVcRrWI#0+h`K#_L#K<82#q1fkr2EopEn^+V2aZd>@3dlOXyDh`yGXGx;_2pE PpfL=du6{1-oD!M<{URer literal 0 HcmV?d00001 diff --git a/src/Decentralized/ModFiles/Textures/Items/gpu_ov_fin1.png b/src/Decentralized/ModFiles/Textures/Items/gpu_ov_fin1.png new file mode 100644 index 0000000000000000000000000000000000000000..447e6a69a1fd919f719ac5d91962b4ee3d86a237 GIT binary patch literal 129 zcmeAS@N?(olHy`uVBq!ia0vp^20*O9!3HEluKbn(QXZZzjv*Dd-k#sc$)G5};_!MC zOY}zF?w{*Kn%nt#o|p!vJ$SHa?`;8~Qica=mPc;4!l}up8frE cFl&Rc$pV*U5)-&gK7bT@y85}Sb4q9e0OBSsVE_OC literal 0 HcmV?d00001 diff --git a/src/Decentralized/ModFiles/Textures/Items/gpu_ov_fin2.png b/src/Decentralized/ModFiles/Textures/Items/gpu_ov_fin2.png new file mode 100644 index 0000000000000000000000000000000000000000..70bec062de22a12c5262411e9752d27ef4ba0df3 GIT binary patch literal 126 zcmeAS@N?(olHy`uVBq!ia0vp^20*O9!3HEluKbn(Qm&pZjv*Dd-d@_E$f=1B-DCWWmk6G_dl7uK(!2IMRx9Y-iywB6MJ)Bjv*Dd-d^0u%b>u+?AYcU z^2TBIUvY+|OP6=-n0?^dcA(+|)wO5#DwW-2wzTutSa4uH>nVALhTDw6e;AB^X&>4?uK+ff3;)|$TkK~S3j3^P69JMC}H)jhlKc%9Q{J~G2}qN!+cvdpf=oQBm4 z+xP{#?P@2#Gz-v-yX){>x}vxv*o23H;lOb|d*Qi| z+^MPID&>>TsYUAjTfbz>jaf@s7#f^c?(BWq8@zGe40YBuyS63YETehaCl$e zzhM2kh%ehYPDw2kG*&pIwdwV05eAPN{cra~=i7Xnxz(sRUU$K}WTCxGZqNMe8zr(; zLyk`uz2I$8%rsx?!O3;o*4@A4Zu=>twiRf6eGy~ByotA&H=maP@)$f_{an^LB{Ts5 DS8O=K literal 0 HcmV?d00001 diff --git a/src/Decentralized/ModFiles/Textures/Items/gpu_ov_txs_rzx60.png b/src/Decentralized/ModFiles/Textures/Items/gpu_ov_txs_rzx60.png new file mode 100644 index 0000000000000000000000000000000000000000..744cce5c6de269a69e3a9dfe4c4010fadec39974 GIT binary patch literal 154 zcmeAS@N?(olHy`uVBq!ia0vp^20*O9!3HEluKbn(Qi+}}jv*Dd-d=X(YETehaQOef ze?f4(&Mw`?)vnXpB?Vkv%OiDJ8LZaa-ZWn~y1({(q-}M)?}J;%6{0xr-29!%`Y1;1 z&*d!M)egBa-bGzpDbu$LotSrj{rsw1{@e@<2NKwSDNR3bkkYIRw2Z;i)z4*}Q$iB} D(C9Z; literal 0 HcmV?d00001 diff --git a/src/Decentralized/ModFiles/Textures/Items/gpu_ov_txs_rzx70.png b/src/Decentralized/ModFiles/Textures/Items/gpu_ov_txs_rzx70.png new file mode 100644 index 0000000000000000000000000000000000000000..8e4f770fc40910a344fe25b0203dcd346763a7b0 GIT binary patch literal 153 zcmeAS@N?(olHy`uVBq!ia0vp^20*O9!3HEluKbn(QVE_ejv*Dd-d=X(Vo>C0efX}v ze?e%t&aF=FV6EGK{tDnm{r-UW|^D8&L literal 0 HcmV?d00001 diff --git a/src/Decentralized/ModFiles/Textures/Items/gpu_ov_txs_rzx80ti.png b/src/Decentralized/ModFiles/Textures/Items/gpu_ov_txs_rzx80ti.png new file mode 100644 index 0000000000000000000000000000000000000000..616e5561230ebfe4b226c38c1989305ce7e30d36 GIT binary patch literal 164 zcmeAS@N?(olHy`uVBq!ia0vp^20*O9!3HEluKbn(QrVs^jv*Dd-d^$MI-tPg8u)!b z|G|mTA#+j_zI4h9ykp#WV}ja}Tn+{Xj-bA!YcJOB*4{ZK!gTqZBk#6#1Tts6$x3!t zOE|xWy}I@Mr`Wj-<$H}Am-Bu(X0Lsq`tLlG4WAX)9s6{e1!z%&dc> wJ7aFa>b-y2_L+U?W^v1}oN{2AJzopr0CCthkN^Mx literal 0 HcmV?d00001 diff --git a/src/Decentralized/ModFiles/Textures/Items/gpu_ov_txt_rz580.png b/src/Decentralized/ModFiles/Textures/Items/gpu_ov_txt_rz580.png new file mode 100644 index 0000000000000000000000000000000000000000..5d91b8e592a740b10265d0f672a385b942ca547e GIT binary patch literal 141 zcmeAS@N?(olHy`uVBq!ia0vp^20*O9!3HEluKbn(QJyZ2Ar-gYUN+=ApuoZ4@c;iT zyF>L?ON^Iw#daNzP2%uTSSZ49Bj9zZeg2u>x1w!N)yppEPqsakZkWrwS#6Q;QoavM n8(%!{mq;jO-fhkZG}2S5ylz#>ju|;>Kn{batDnm{r-UW|S%xt| literal 0 HcmV?d00001 diff --git a/src/Decentralized/ModFiles/Textures/Items/gpu_ov_txt_rz6800.png b/src/Decentralized/ModFiles/Textures/Items/gpu_ov_txt_rz6800.png new file mode 100644 index 0000000000000000000000000000000000000000..71f95666522553e4dc6cedce136f6a693c386f3e GIT binary patch literal 144 zcmeAS@N?(olHy`uVBq!ia0vp^20*O9!3HEluKbn(QsJI1jv*Dd-d;Y)c|d`O!QuP- zWzIXom)c8h}%6RFo$M%K(d&N}S^EGr{@BF<7ax$JB s+par7^2e8B+w}~pr^f$d1e&@dyIB5uT1L7=50Jy)>FVdQ&MBb@0RCq*dH?_b literal 0 HcmV?d00001 diff --git a/src/Decentralized/ModFiles/Textures/Items/gpu_ov_txt_rz7900.png b/src/Decentralized/ModFiles/Textures/Items/gpu_ov_txt_rz7900.png new file mode 100644 index 0000000000000000000000000000000000000000..47e13be7938db7d7db589a33b6ce841583f2b281 GIT binary patch literal 145 zcmeAS@N?(olHy`uVBq!ia0vp^20*O9!3HEluKbn(QW2gmjv*Dd-d;YjM` zWzIXomzq!Xxa@rOaJ9lDjf_82m>4*>#(lqhY{z-mpX)!aXZ`YbM*ZyhZ>QgNNc+55 w_jM` zWzIXMFKv%w%6xn@<{qjM` zV~TfHUvlQ>?Rx22UBT}n!u&HqlVQSzsJ-t*&!3OIlfKa~FPm{OOE~MAd-Ag#)NZby te9NjaCq2DzzlOr)n-_O0*8`1ZxM#(mwD_CJsptM6o~Nsy%Q~loCIDv_G>HHJ literal 0 HcmV?d00001 diff --git a/src/Decentralized/ModFiles/Textures/Items/gpu_ov_txt_rzx70.png b/src/Decentralized/ModFiles/Textures/Items/gpu_ov_txt_rzx70.png new file mode 100644 index 0000000000000000000000000000000000000000..7c4bafcc5ef717f96b3c76714d7c7266046fabfc GIT binary patch literal 144 zcmeAS@N?(olHy`uVBq!ia0vp^20*O9!3HEluKbn(QsJI1jv*Dd-d;Y)c|d`OHQ@XF zWzIXom$u7EnY?h-+{3PvC15`(h#|pg?e)JsJLbP0l+XkK^ye}_ literal 0 HcmV?d00001 diff --git a/src/Decentralized/ModFiles/Textures/Items/gpu_ov_txt_rzx80ti.png b/src/Decentralized/ModFiles/Textures/Items/gpu_ov_txt_rzx80ti.png new file mode 100644 index 0000000000000000000000000000000000000000..7fc2af90a99399a366fa2077dd5f34824ca78be6 GIT binary patch literal 153 zcmeAS@N?(olHy`uVBq!ia0vp^20*O9!3HEluKbn(QVE_ejv*Dd-d;YjM` zWzIXoz4>iTuJD`QyT>fJ*du9!2*Zqk*M;|#*UgWZQ~mr=?Ai*O%`pzz2kn2ypIoYD z^U6X0W*~bS_l;YP7roO<5~>+z)&mKk=^x4%Z>ya>7{B6>Bap}7>FVdQ&MBb@0O|KP Aga7~l literal 0 HcmV?d00001 diff --git a/src/Decentralized/ModFiles/Textures/Items/gpu_ov_txt_rzx90.png b/src/Decentralized/ModFiles/Textures/Items/gpu_ov_txt_rzx90.png new file mode 100644 index 0000000000000000000000000000000000000000..326619a9590f0e8e84b691cafca82f0670508083 GIT binary patch literal 144 zcmeAS@N?(olHy`uVBq!ia0vp^20*O9!3HEluKbn(QsJI1jv*Dd-d;YjM` zWzIXMFKv%w%A75C=Bcefr+v>sLxu;d^)3`CpOWCG+dc)I$ztaD0e0sxroHmm>u literal 0 HcmV?d00001 diff --git a/src/Decentralized/ModFiles/Textures/Items/gpu_pmd.png b/src/Decentralized/ModFiles/Textures/Items/gpu_pmd.png deleted file mode 100644 index 7d340b465d0b019844a020d56fad92f7c4ccce05..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 329 zcmV-P0k-~$P)Iq72Y}>=wFsA5k{tlzBZm$QW3zx5wIn$J*+3W@T@0J$ z_|)Qb0D2-sHUx(8@rhMSv;%PY2Al6lQH#?7=(zyh2gnXY_ZcZ_iAn?5dmla7g%mIYdVRZn#@o0B& b6us&HUqj z-1!`{Z1AoJ6(_0>96kHoep`g3kHlf-gMt?ecs@DQxE)(?G{QC^?-j>!1%93|o}&9J z*x8n{Uoif-g8ju?#xFq`Cj32B30p*@*yL_JNHu?9;JGwl>c)EuxN0XeJbx|4~&lR|rQP0u^V89x#Pq%TM;@V0HxWoxVPwV5&L!iPLB j9#b1D8A~oVMivH!ldSR{pYM8sJi*}U>gTe~DWM4fXeycfN5@0X107Sk;24_+2zhcq0|DIwE^a;;j#;s8DF!A*p4u401Hlo|a18PQ zvWEs6#_9ocQ%5)kc_2O`gJ=xWLyCGz%z&j1iah{RiyU(>F;W~&su@)A0J^25rx zYX(japl4!279)EY7oQepP~-t*gOM%7#>V9UO3lFO0rXOc*pMS6Mr|`F$^+;b4TO;@gi>j7Aq4D&#hu^z=COHB-N579ATmu)s^F;OuvBt3u}11FYvQH)`Q0yWG+ z#zcD{+sld~8s-5?%|WNJdSIyG(c#EZFbW_507-tZ6i?hV2LJ#707*qoM6N<$f|9O* AVE_OC literal 0 HcmV?d00001 diff --git a/src/Decentralized/ModFiles/Textures/Items/gpu_probidia.png b/src/Decentralized/ModFiles/Textures/Items/gpu_probidia.png deleted file mode 100644 index 247a3fc766368152777c23698482d3c54d49273b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 328 zcmV-O0k{5%P)Iq72Y}>=wFsA5k{tlzBZm$QW3zx5wIn$J*+3W@T@0J$ z_|)Qb0D2-sHUx(8@rhMSv;%PY2Al6lQH#?7=(zyh2gnXY_ZcZ_iAn?5dXeycfN5@0X107Sk;CRS;z{SnyKekvIOc=uh!4c7L4DvvHM#iAUSUq5F>Ilam z4-8fea^I*22BinkGx4Yg=}jCx?S6dDE|h@0a#=rBp8kX^RfpbGseW4-?y zyzB-h4;(qNfg(I8JODDA9C~DUfYzlD&65zw;UFKQdjKXr7{mrN2Ix``V2gnvUlR|e nBs9F65XeycfN5@0X107Sk;24_+2zhcq0|DIwE^a;;j#;s8DF!A*p4u401Hlo|a18PQ zvWEs6#_9ocQ%5)kc_2O`gJ=xWLyCGz%z&j1iah{RiyU(>F;W~&su@)A0J^25rx zYX(japl4!279)EY7oQepP~-t*gOM%7#>V9UO3lFO0rXOc*pMS6Mr|`F$^+;b4TOj7Aq4D*0pwi(4COHB-N5799IQao5OQ86$iJ%AhoCzg0ojA4ZWHOxZB zM0+6H%Zefz<^f90L8q~LV5s5I;mA=i3LpRgwu-WBcWu|{00000NkvXXu0mjf2p@ua literal 0 HcmV?d00001 diff --git a/tests/Decentralized.Domain.Tests/Program.cs b/tests/Decentralized.Domain.Tests/Program.cs index d125ef8..0469e13 100644 --- a/tests/Decentralized.Domain.Tests/Program.cs +++ b/tests/Decentralized.Domain.Tests/Program.cs @@ -170,7 +170,7 @@ internal static class Program Check(RigSlots.Next(4) == ("rare_electronic", 2) && RigSlots.Insert(ref slots, ref prog, "rare_electronic", 1) == 1 && slots == 4 && prog == 1, "第 5 槽:2 个稀有元件,先投 1 个进度 1/2"); Check(RigSlots.Insert(ref slots, ref prog, "rare_electronic", 1) == 1 && slots == 5, "投满解锁第 5 槽"); Check(RigSlots.Next(5) == null && RigSlots.Insert(ref slots, ref prog, "rare_electronic", 1) == 0, "满 5 槽后不再收"); - Check(RigSlots.Shape(2) == "0000" + "0000" + new string('1', 12) && RigSlots.Shape(5) == new string('0', 20) && RigSlots.Shape(3).Length == 20, "形状:宽 2、共 10 行,前 2 × 槽数行可放"); + Check(RigSlots.Shape(2) == "000000" + "000000" + new string('1', 18) && RigSlots.Shape(5) == new string('0', 30) && RigSlots.Shape(3).Length == 30, "形状:宽 3、共 10 行,前 2 × 槽数行可放"); }); Test("模块:折算系数 4,算力 +20%、省电 25%、损耗 −30% 封顶;性能加成提高损耗与暴毙", () =>