Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7f458b0139 | ||
|
|
9d19df407a | ||
|
|
202bdbbfbc |
No files matched your search
@@ -7,8 +7,9 @@ import random
|
||||
from sprites import Canvas, C, key, MODELS
|
||||
|
||||
BW, BH = 192, 128
|
||||
FANS = ((68, 51), (142, 51))
|
||||
FR = 30 # 风扇半径
|
||||
# 风扇布局(按风扇数):中心与半径;FANS / FR 保留为双风扇的值,给叠加图模块当默认
|
||||
FAN_LAYOUT = {1: ([(105, 55)], 34), 2: ([(68, 51), (142, 51)], 30), 3: ([(52, 51), (96, 51), (140, 51)], 21)}
|
||||
FANS, FR = FAN_LAYOUT[2][0], FAN_LAYOUT[2][1]
|
||||
SH0, SH1 = (24, 14), (186, 96) # 散热罩 左上 / 右下
|
||||
FING_Y0, FING_Y1 = 109, 122
|
||||
NOTCH_X = 112
|
||||
@@ -94,9 +95,9 @@ def bracket(c):
|
||||
c.rect(9, 10, 14, 12, 'k')
|
||||
|
||||
|
||||
def fan(c, cx, cy, accent, accent_dark):
|
||||
def fan(c, cx, cy, accent, accent_dark, R=None):
|
||||
"""风扇:九片弯曲扇叶(前缘高光、叶面渐变、叶尖暗边),外圈带四个固定螺丝,轴心带品牌圆标。"""
|
||||
R = FR
|
||||
R = R or FR
|
||||
for y in range(cy - R - 1, cy + R + 2):
|
||||
for x in range(cx - R - 1, cx + R + 2):
|
||||
dx, dy = x - cx, y - cy
|
||||
@@ -135,7 +136,10 @@ def fan(c, cx, cy, accent, accent_dark):
|
||||
c.put(sx, sy, 'g')
|
||||
|
||||
|
||||
def gpu_front(accent, accent_dark, brand_text, burnt=False):
|
||||
def gpu_front(accent, accent_dark, brand_text, tier=1, burnt=False):
|
||||
"""tier 决定实物特征:风扇数(1/2/3/3)与供电口(6 针 / 8 针 / 8 针 / 双 8 针)。"""
|
||||
count = (1, 2, 3, 3)[tier]
|
||||
fans, R = FAN_LAYOUT[count]
|
||||
c = Canvas(BW, BH)
|
||||
bracket(c)
|
||||
x0, y0 = SH0
|
||||
@@ -161,21 +165,26 @@ def gpu_front(accent, accent_dark, brand_text, burnt=False):
|
||||
c.put(x, y, 'x' if (x - (x1 - 18)) % 3 == 0 else 'g' if (x - (x1 - 18)) % 3 == 1 else 'n')
|
||||
c.rect(x1 - 20, y0 + 10, x1 - 19, y1 - 4, 'x')
|
||||
# 风扇之间的中筋
|
||||
c.rect(105, y0 + 8, 106, y1 - 5, 'k'); c.rect(107, y0 + 8, 107, y1 - 5, 'x')
|
||||
for cx, cy in FANS:
|
||||
fan(c, cx, cy, accent, accent_dark)
|
||||
for a, b in zip(fans, fans[1:]):
|
||||
mx = (a[0] + b[0]) // 2 + 1
|
||||
c.rect(mx - 1, y0 + 8, mx, y1 - 5, 'k'); c.rect(mx + 1, y0 + 8, mx + 1, y1 - 5, 'x')
|
||||
for cx, cy in fans:
|
||||
fan(c, cx, cy, accent, accent_dark, R)
|
||||
# 前沿斜切装饰条:品牌色 + 品牌字
|
||||
for x in range(x0 + 4, x1 - 20):
|
||||
c.rect(x, y1 - 5, x, y1 - 3, accent if x % 11 else accent_dark)
|
||||
text57(c, 112, 84, brand_text, 'h')
|
||||
text57(c, 136 if count == 1 else 112, 84, brand_text, 'h')
|
||||
# 顶沿:四根铜热管端头与 8 针供电口
|
||||
for i in range(4):
|
||||
x = 38 + i * 9
|
||||
c.rect(x, 7, x + 6, y0 - 1, 'p'); c.rect(x, 7, x + 1, y0 - 1, 'h' if i == 0 else 'p')
|
||||
c.rect(x + 5, 7, x + 6, y0 - 1, 'q'); c.rect(x, 7, x + 6, 7, 'q')
|
||||
c.rect(112, 5, 154, y0 - 1, 'n'); c.rect(112, 5, 154, 6, 'z')
|
||||
for i in range(8):
|
||||
c.rect(114 + i * 5, 7, 116 + i * 5, 9, 'k'); c.put(115 + i * 5, 8, 'Y')
|
||||
# 供电口:低端 6 针;中端、高端 8 针;旗舰两个 8 针
|
||||
for left, pins in ((((118, 6),) if tier == 0 else ((112, 8),) if tier < 3 else ((78, 8), (126, 8)))):
|
||||
right = left + pins * 5 + 2
|
||||
c.rect(left, 5, right, y0 - 1, 'n'); c.rect(left, 5, right, 6, 'z')
|
||||
for i in range(pins):
|
||||
c.rect(left + 2 + i * 5, 7, left + 4 + i * 5, 9, 'k'); c.put(left + 3 + i * 5, 8, 'Y')
|
||||
# PCB:阻焊绿、边缘高光、元件与走线
|
||||
for y in range(y1 + 1, FING_Y0):
|
||||
for x in range(x0, x1 + 1):
|
||||
@@ -248,8 +257,6 @@ def sticker(c, seed):
|
||||
w = 1 + ((x * 7 + seed) % 3)
|
||||
if (x * 5 + seed) % 4 != 0:
|
||||
c.rect(x, 70, x, 84, 'n')
|
||||
text57(c, 118, 88, "0X5A70", 'n')
|
||||
c.rect(150, 88, 166, 94, 'm')
|
||||
|
||||
|
||||
def seal(c):
|
||||
@@ -407,19 +414,12 @@ def ov_sticker(kind):
|
||||
|
||||
BIG = {}
|
||||
for _b, (_a, _ad, _t) in {'probidia': ('G', 'g2', 'PROBIDIA'), 'pmd': ('R', 'r2', 'PMD')}.items():
|
||||
BIG['gpu_big_%s_f' % _b] = (lambda a=_a, ad=_ad, t=_t: gpu_front(a, ad, t))
|
||||
for _tier in range(4):
|
||||
BIG['gpu_big_%s_f_t%d' % (_b, _tier)] = (lambda a=_a, ad=_ad, t=_t, k=_tier: gpu_front(a, ad, t, k))
|
||||
BIG['gpu_big_%s_b' % _b] = (lambda a=_a, ad=_ad: gpu_back(a, ad))
|
||||
BIG['gpu_big_burnt_f'] = lambda: gpu_front('e', 'c', 'PROBIDIA', burnt=True)
|
||||
BIG['gpu_big_burnt_f'] = lambda: gpu_front('e', 'c', 'PROBIDIA', 1, burnt=True)
|
||||
BIG['gpu_big_burnt_b'] = lambda: gpu_back('e', 'c', burnt=True)
|
||||
BIG_OV = {
|
||||
'gpu_big_ov_fan1': lambda: ov_fan(1), 'gpu_big_ov_fan2': lambda: ov_fan(2),
|
||||
'gpu_big_ov_fin1': lambda: ov_fingers(1), 'gpu_big_ov_fin2': lambda: ov_fingers(2),
|
||||
'gpu_big_ov_brk1': lambda: ov_bracket(1), 'gpu_big_ov_brk2': lambda: ov_bracket(2),
|
||||
'gpu_big_ov_stk1': lambda: ov_sticker(1), 'gpu_big_ov_stk2': lambda: ov_sticker(2),
|
||||
}
|
||||
for _m in MODELS:
|
||||
BIG_OV['gpu_big_ov_txt_' + key(_m)] = (lambda m=_m: ov_text(m, False))
|
||||
BIG_OV['gpu_big_ov_txs_' + key(_m)] = (lambda m=_m: ov_text(m, True))
|
||||
BIG_OV = {}
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys, os
|
||||
@@ -435,7 +435,5 @@ if __name__ == '__main__':
|
||||
b.px[y][x] = oc.px[y][x]
|
||||
return b
|
||||
bg = (0x6A, 0x72, 0x70)
|
||||
stack('gpu_big_probidia_f').png(os.path.join(d, 'big_f.png'), scale=5, bg=bg)
|
||||
stack('gpu_big_pmd_f', 'gpu_big_ov_fan1', 'gpu_big_ov_fin2', 'gpu_big_ov_brk2').png(os.path.join(d, 'big_f_fake.png'), scale=5, bg=bg)
|
||||
stack('gpu_big_pmd_b', 'gpu_big_ov_txs_rz6800', 'gpu_big_ov_stk1').png(os.path.join(d, 'big_b_fake.png'), scale=5, bg=bg)
|
||||
stack('gpu_big_probidia_b', 'gpu_big_ov_txt_rzx80ti').png(os.path.join(d, 'big_b.png'), scale=5, bg=bg)
|
||||
for t in range(4):
|
||||
stack('gpu_big_probidia_f_t%d' % t).png(os.path.join(d, 'big_f_t%d.png' % t), scale=3, bg=bg)
|
||||
@@ -137,13 +137,14 @@ def bracket(c):
|
||||
c.put(2, 27, 'h'); c.put(4, 27, 'd')
|
||||
|
||||
|
||||
def fan(c, cx, cy, accent, burnt=False):
|
||||
def fan(c, cx, cy, accent, burnt=False, R=7):
|
||||
"""风扇:深色风道里六片弯曲扇叶(前缘高光、叶面按受光渐变),外圈细边,轴心带品牌色点;光从左上来。"""
|
||||
import math
|
||||
for y in range(cy - 7, cy + 8):
|
||||
for x in range(cx - 7, cx + 8):
|
||||
k = 7.0 / R # 按半径折算到 R=7 的画法
|
||||
for y in range(cy - R, cy + R + 1):
|
||||
for x in range(cx - R, cx + R + 1):
|
||||
dx, dy = x - cx, y - cy
|
||||
r = math.hypot(dx, dy)
|
||||
r = math.hypot(dx, dy) * k
|
||||
if r > 7.4:
|
||||
continue
|
||||
ang = (math.atan2(dy, dx) / (2 * math.pi)) % 1.0
|
||||
@@ -164,7 +165,10 @@ def fan(c, cx, cy, accent, burnt=False):
|
||||
c.put(cx - 1, cy - 1, 'w')
|
||||
|
||||
|
||||
def gpu_front(accent, accent_dark, burnt=False):
|
||||
FAN_LAYOUT_SMALL = {1: ([(26, 13)], 9), 2: ([(17, 13), (34, 13)], 7), 3: ([(14, 13), (26, 13), (38, 13)], 5)}
|
||||
|
||||
|
||||
def gpu_front(accent, accent_dark, burnt=False, tier=1):
|
||||
"""显卡正面(48×32,3×2 格),略微俯视:石墨色散热罩带斜切角与品牌色斜条,两个七叶风扇,
|
||||
右端露出鳍片,顶沿露出铜热管和 8 针供电口,前沿是带元件的 PCB 和逐根画出的金手指。每格中心都不透明。"""
|
||||
c = Canvas(W, H)
|
||||
@@ -182,26 +186,33 @@ def gpu_front(accent, accent_dark, burnt=False):
|
||||
for y in range(TOP0 + 2, TOP1):
|
||||
c.put(x, y, 'g' if (x - (R - 4)) % 2 == 0 else 'k')
|
||||
c.rect(R - 5, TOP0 + 2, R - 5, TOP1 - 1, 'x')
|
||||
# 中间的筋条(两个风扇之间)与上下沿的槽
|
||||
for y in range(TOP0 + 3, TOP1 - 2):
|
||||
c.put(25, y, 'k'); c.put(26, y, 'x')
|
||||
count = (1, 2, 3, 3)[tier]
|
||||
fans, fr = FAN_LAYOUT_SMALL[count]
|
||||
# 风扇之间的筋条
|
||||
for a, b in zip(fans, fans[1:]):
|
||||
mx = (a[0] + b[0]) // 2
|
||||
for y in range(TOP0 + 3, TOP1 - 2):
|
||||
c.put(mx, y, 'k'); c.put(mx + 1, y, 'x')
|
||||
# 品牌色斜条(从前沿向左上延伸)与前沿色条
|
||||
for x in range(L + 1, R - 5):
|
||||
c.put(x, TOP1 - 1, accent if x % 9 else accent_dark)
|
||||
c.put(x, TOP1, accent_dark)
|
||||
for cx, cy in FANS:
|
||||
fan(c, cx, cy, accent)
|
||||
for dx, dy in ((-7, -7), (7, -7), (-7, 7), (7, 7)): # 风扇四角的固定孔
|
||||
c.put(cx + dx, cy + dy, 'n' if dx + dy else 'k')
|
||||
for cx, cy in fans:
|
||||
fan(c, cx, cy, accent, R=fr)
|
||||
if count < 3:
|
||||
for dx, dy in ((-7, -7), (7, -7), (-7, 7), (7, 7)): # 风扇四角的固定孔
|
||||
c.put(cx + dx, cy + dy, 'n' if dx + dy else 'k')
|
||||
# 顶沿:铜热管端头 + 8 针供电口(带针脚)
|
||||
for x0 in (L + 6, L + 8, L + 10, L + 12):
|
||||
c.put(x0, TOP0 - 1, 'p'); c.put(x0 + 1, TOP0 - 1, 'q')
|
||||
for x in range(L + 18, L + 28):
|
||||
c.put(x, TOP0 - 1, 'n')
|
||||
for x in range(L + 18, L + 28, 2):
|
||||
c.put(x, TOP0 - 2, 'k')
|
||||
for x in range(L + 19, L + 28, 2):
|
||||
c.put(x, TOP0 - 2, 'Y')
|
||||
# 供电口:低端 6 针;中端、高端 8 针;旗舰两个 8 针(每针占两像素)
|
||||
for left, pins in (((L + 22, 6),) if tier == 0 else ((L + 18, 8),) if tier < 3 else ((L + 8, 8), (L + 25, 8))):
|
||||
for x in range(left, left + pins * 2):
|
||||
c.put(x, TOP0 - 1, 'n')
|
||||
for x in range(left, left + pins * 2, 2):
|
||||
c.put(x, TOP0 - 2, 'k')
|
||||
for x in range(left + 1, left + pins * 2, 2):
|
||||
c.put(x, TOP0 - 2, 'Y')
|
||||
# 前沿:PCB(绿)带元件,之后金手指
|
||||
for x in range(L, R + 1):
|
||||
c.put(x, TOP1 + 1, 'G' if x % 7 else 'g2'); c.put(x, TOP1 + 2, 'g2')
|
||||
@@ -221,7 +232,7 @@ def gpu_front(accent, accent_dark, burnt=False):
|
||||
c.put(x, y, 'c')
|
||||
for x in range(L + 1, R - 5):
|
||||
c.put(x, TOP1 - 1, 'e')
|
||||
for cx, cy in FANS:
|
||||
for cx, cy in fans:
|
||||
for dx, dy in ((0, 0), (1, 1), (-1, 1), (2, -2), (-2, -2)):
|
||||
c.put(cx + dx, cy + dy, 'c')
|
||||
outline(c)
|
||||
@@ -298,10 +309,10 @@ def overlay():
|
||||
return Canvas(W, H)
|
||||
|
||||
|
||||
def ov_fan(kind):
|
||||
def ov_fan(kind, count=2):
|
||||
"""风扇叠加:1 积灰(叶片上一层灰),2 叶片缺角(边缘缺一块并露出黑底)。"""
|
||||
c = overlay()
|
||||
for cx, cy in FANS:
|
||||
for cx, cy in FAN_LAYOUT_SMALL[count][0]:
|
||||
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')
|
||||
@@ -363,7 +374,7 @@ def ov_sticker(kind):
|
||||
return c
|
||||
|
||||
|
||||
MODELS = ['RZX 50', 'RZX 60', 'RZX 70', 'RZX 80 Ti', 'RZX 90', 'RZ 470', 'RZ 580', 'RZ 6800', 'RZ 7900']
|
||||
MODELS = ['RZX 60', 'RZX 70', 'RZX 80', 'RZX 90', 'RZ 70', 'RZ 80', 'RZ 800', 'RZ 900']
|
||||
|
||||
|
||||
def rig():
|
||||
@@ -503,24 +514,43 @@ def key(model):
|
||||
return model.replace(' ', '').lower()
|
||||
|
||||
|
||||
def guide():
|
||||
"""鉴定手册(16×16,一格):竖放的小册子,封面带品牌色条,书脊在左。"""
|
||||
c = Canvas(16, 16)
|
||||
c.box(2, 1, 13, 14, 'b')
|
||||
c.rect(3, 2, 4, 13, 'd') # 书脊
|
||||
c.rect(5, 2, 12, 2, 'h')
|
||||
c.rect(6, 4, 11, 5, 'G') # 封面色块
|
||||
c.rect(6, 4, 11, 4, 'g2')
|
||||
for y in (7, 9, 11): # 文字行
|
||||
c.rect(6, y, 11 if y != 11 else 9, y, 'm')
|
||||
c.put(12, 13, 'd')
|
||||
outline(c)
|
||||
return c
|
||||
|
||||
|
||||
SPRITES = {
|
||||
'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_guide': guide,
|
||||
'gpu_burnt_f': lambda: gpu_front('e', 'c', burnt=True),
|
||||
'gpu_burnt_b': lambda: gpu_back('e', 'c', burnt=True),
|
||||
'gpu_probidia_b': lambda: gpu_back('G', 'g2'),
|
||||
'gpu_pmd_b': lambda: gpu_back('R', 'r2'),
|
||||
'rig': rig,
|
||||
'terminal': terminal,
|
||||
}
|
||||
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))
|
||||
|
||||
# 叠加图:和底图同尺寸,位置 (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),
|
||||
'gpu_ov_brk1': lambda: ov_bracket(1),
|
||||
'gpu_ov_stk2': lambda: ov_sticker(2),
|
||||
}
|
||||
for _n in (1, 2, 3):
|
||||
OVERLAYS['gpu_ov_fan1_%d' % _n] = (lambda n=_n: ov_fan(1, n))
|
||||
OVERLAYS['gpu_ov_fan2_%d' % _n] = (lambda n=_n: ov_fan(2, n))
|
||||
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))
|
||||
@@ -551,13 +581,13 @@ if __name__ == '__main__':
|
||||
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))
|
||||
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:
|
||||
out = os.path.normpath(os.path.join(here, '..', 'src', 'Decentralized', 'ModFiles', 'Textures', 'Items'))
|
||||
for f in os.listdir(out): # 清掉旧的显卡图,避免留下不再使用的文件
|
||||
if f.startswith('gpu_'):
|
||||
os.remove(os.path.join(out, f))
|
||||
for name, make in SPRITES.items():
|
||||
canvas = make()
|
||||
check_cells(canvas, name)
|
||||
@@ -568,8 +598,16 @@ if __name__ == '__main__':
|
||||
for name, make in big.BIG.items():
|
||||
make().png(os.path.join(out, name + '.png'))
|
||||
for name, make in big_cases.CASES.items():
|
||||
if not name.startswith('gpu_big_ov_print_'):
|
||||
if name.startswith('gpu_big_ov_fan_'):
|
||||
continue
|
||||
if not name.startswith('gpu_big_ov_print_') and name in ('gpu_big_ov_fin_dim', 'gpu_big_ov_fin_oxide', 'gpu_big_ov_brk_scratch', 'gpu_big_ov_seal_missing'):
|
||||
make().png(os.path.join(out, name + '.png'))
|
||||
# 风扇叠加按风扇数各出一套:叠加模块里的风扇位置是模块级变量,换成对应布局后再画
|
||||
for count, (centres, radius) in big.FAN_LAYOUT.items():
|
||||
big_cases.FANS = list(centres) if len(centres) > 1 else [centres[0], centres[0]]
|
||||
big_cases.FR = radius
|
||||
for fname, short in (('fan_dust1', 'fan_dust1'), ('fan_dust2', 'fan_dust2'), ('fan_chip', 'fan_chip')):
|
||||
getattr(big_cases, fname)().png(os.path.join(out, 'gpu_big_ov_%s_%d.png' % (short, count)))
|
||||
for m in MODELS:
|
||||
for style in ('normal', 'skew', 'stamp'):
|
||||
big_cases.print_overlay(m, style).png(os.path.join(out, 'gpu_big_ov_print_%s_%s.png' % (style, key(m))))
|
||||
|
||||
@@ -3,52 +3,56 @@ using System.Linq;
|
||||
|
||||
namespace Decentralized.Domain
|
||||
{
|
||||
/// <summary>卖家的说法:每个标签一项。型号是文字,其余五项取值与 <see cref="CardLook"/> 的取值一致。</summary>
|
||||
/// <summary>卖家的说法:每个标签一项。型号是文字,其余取值与 <see cref="CardLook"/> 一致;「供电与风扇」由说法里的型号决定档次。</summary>
|
||||
public struct Claim
|
||||
{
|
||||
public string Model;
|
||||
public int Fan, Fingers, Bracket, Print, Sticker;
|
||||
public int Fan, Fingers, Bracket, Print, Sticker, Serial;
|
||||
|
||||
public int Get(int row) => row == CardLabels.RowFan ? Fan : row == CardLabels.RowFingers ? Fingers : row == CardLabels.RowBracket ? Bracket : row == CardLabels.RowPrint ? Print : Sticker;
|
||||
public int Tier => Hardware.Specs[Model].Tier;
|
||||
|
||||
public int Get(int row) => row == CardLabels.RowBuild ? Tier : row == CardLabels.RowFan ? Fan : row == CardLabels.RowFingers ? Fingers
|
||||
: row == CardLabels.RowBracket ? Bracket : row == CardLabels.RowPrint ? Print : row == CardLabels.RowSerial ? Serial : Sticker;
|
||||
|
||||
public Claim With(int row, int value)
|
||||
{
|
||||
var c = this;
|
||||
if (row == CardLabels.RowFan) c.Fan = value; else if (row == CardLabels.RowFingers) c.Fingers = value;
|
||||
else if (row == CardLabels.RowBracket) c.Bracket = value; else if (row == CardLabels.RowPrint) c.Print = value; else c.Sticker = value;
|
||||
else if (row == CardLabels.RowBracket) c.Bracket = value; else if (row == CardLabels.RowPrint) c.Print = value;
|
||||
else if (row == CardLabels.RowSerial) c.Serial = value; else if (row == CardLabels.RowSeal) c.Sticker = value;
|
||||
return c;
|
||||
}
|
||||
|
||||
public string Encode() => $"{Model}:{Fan}{Fingers}{Bracket}{Print}{Sticker}";
|
||||
public string Encode() => $"{Model}:{Fan}{Fingers}{Bracket}{Print}{Sticker}{Serial}";
|
||||
|
||||
public static Claim Decode(string s)
|
||||
{
|
||||
var p = (s ?? "").Split(':');
|
||||
if (p.Length != 2 || p[1].Length != 5 || !Hardware.Specs.ContainsKey(p[0])) return default;
|
||||
if (p.Length != 2 || p[1].Length != 6 || !Hardware.Specs.ContainsKey(p[0])) return default;
|
||||
int D(int i) => Math.Max(0, Math.Min(2, p[1][i] - '0'));
|
||||
return new Claim { Model = p[0], Fan = D(0), Fingers = D(1), Bracket = D(2), Print = D(3), Sticker = D(4) };
|
||||
return new Claim { Model = p[0], Fan = D(0), Fingers = D(1), Bracket = D(2), Print = D(3), Sticker = D(4), Serial = D(5) };
|
||||
}
|
||||
|
||||
/// <summary>按真实情况写出的说法(没有隐瞒)。</summary>
|
||||
public static Claim Truth(Unit u)
|
||||
{
|
||||
var l = u.Appearance;
|
||||
return new Claim { Model = u.FakeOf ?? u.Model, Fan = l.Fan, Fingers = l.Fingers, Bracket = l.Bracket, Print = l.Print, Sticker = l.Sticker };
|
||||
return new Claim { Model = u.FakeOf ?? u.Model, Fan = l.Fan, Fingers = l.Fingers, Bracket = l.Bracket, Print = l.Print, Sticker = l.Sticker, Serial = l.Serial };
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 标签栏的数据:六个标签(型号、风扇、金手指、挡板、丝印、贴纸),每个标签有卖家的说法和真实情况。
|
||||
/// 标签栏的数据:八个标签(型号、供电与风扇、风扇叶片、金手指、挡板、背面丝印、序列号、封条),每个标签有卖家的说法和真实情况。
|
||||
/// 一个标签被指出(拆穿)之后,说法改回真实情况;价格按「已指出的标签取真实情况,其余取说法」算,
|
||||
/// 所以卖家隐瞒的问题要玩家一项项指出来才能把价格拉回真实价值。
|
||||
/// 所以卖家隐瞒的问题要玩家一项项指出来才能把价格拉回真实价值。指出假货的证据(供电与风扇、丝印、序列号)会连带把型号改回真实型号。
|
||||
/// </summary>
|
||||
public static class CardLabels
|
||||
{
|
||||
public const int RowSpec = 1, RowFan = 2, RowFingers = 4, RowBracket = 8, RowPrint = 16, RowSticker = 32, AllRows = 63;
|
||||
public static readonly int[] Rows = { RowSpec, RowFan, RowFingers, RowBracket, RowPrint, RowSticker };
|
||||
public const int RowSpec = 1, RowBuild = 2, RowFan = 4, RowFingers = 8, RowBracket = 16, RowPrint = 32, RowSerial = 64, RowSeal = 128, AllRows = 255;
|
||||
public static readonly int[] Rows = { RowSpec, RowBuild, RowFan, RowFingers, RowBracket, RowPrint, RowSerial, RowSeal };
|
||||
|
||||
/// <summary>各标签各取值对价格的影响(百分比,相加):风扇积灰 −4%、缺角 −12%;金手指发暗 −4%、氧化 −12%;挡板划痕 −2%;封条缺失 −6%。
|
||||
/// 接口数不对、丝印、手写序列号本身不扣价,它们是假货的证据。</summary>
|
||||
/// <summary>各标签各取值对价格的影响(百分比,相加):风扇叶片积灰 −4%、缺角 −12%;金手指发暗 −4%、氧化 −12%;挡板划痕 −2%;封条缺失 −6%。
|
||||
/// 型号、供电与风扇、丝印、序列号本身不扣价,它们决定的是这块卡是什么芯片。</summary>
|
||||
public static double Pct(int row, int value)
|
||||
{
|
||||
switch (row)
|
||||
@@ -56,14 +60,22 @@ namespace Decentralized.Domain
|
||||
case RowFan: return value == 1 ? -4 : value == 2 ? -12 : 0;
|
||||
case RowFingers: return value == 1 ? -4 : value == 2 ? -12 : 0;
|
||||
case RowBracket: return value == 1 ? -2 : 0;
|
||||
case RowSticker: return value == 2 ? -6 : 0;
|
||||
case RowSeal: return value == 2 ? -6 : 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>这一项的真实取值是不是假货的证据。</summary>
|
||||
public static bool IsFakeSign(int row, int realValue) =>
|
||||
(row == RowBracket && realValue == 2) || (row == RowPrint && realValue != 0) || (row == RowSticker && realValue == 1);
|
||||
/// <summary>这一行是不是假货的证据:说法与真实情况不同,并且真实情况本身不该出现在真卡上。</summary>
|
||||
public static bool IsEvidence(int row, Claim claim, Claim real)
|
||||
{
|
||||
switch (row)
|
||||
{
|
||||
case RowBuild: return claim.Tier != real.Tier;
|
||||
case RowPrint: return real.Print != 0 && claim.Print != real.Print;
|
||||
case RowSerial: return real.Serial != 0 && claim.Serial != real.Serial;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 价值:claim 为空表示没有人说过什么,一律按真实情况;exposed 里的位表示已指出的标签(取真实情况)。
|
||||
@@ -74,9 +86,8 @@ namespace Decentralized.Domain
|
||||
var real = Claim.Truth(u);
|
||||
Claim believed = claim == null ? real : claim.Value;
|
||||
double sum = 0;
|
||||
foreach (int r in Rows)
|
||||
foreach (int r in new[] { RowFan, RowFingers, RowBracket, RowSeal })
|
||||
{
|
||||
if (r == RowSpec) continue;
|
||||
int v = claim == null || (exposed & r) != 0 ? real.Get(r) : believed.Get(r);
|
||||
sum += Pct(r, v);
|
||||
}
|
||||
@@ -85,24 +96,23 @@ namespace Decentralized.Domain
|
||||
return Math.Max(1, (long)Math.Round(value));
|
||||
}
|
||||
|
||||
/// <summary>指出一个标签:返回 0 没问题(说法属实)、1 隐瞒了对价格不利的情况、2 拆穿了假货。
|
||||
/// 指出假货的证据(接口数、丝印、手写序列号)时,型号标签一并拆穿。</summary>
|
||||
/// <summary>指出一个标签:返回 0 没问题(说法属实)、1 隐瞒了对价格不利的情况、2 拆穿了假货(型号一并改回真实型号)。</summary>
|
||||
public static int Point(Unit u, Claim claim, int row, ref int exposed)
|
||||
{
|
||||
var real = Claim.Truth(u);
|
||||
bool wasExposed = (exposed & row) != 0;
|
||||
exposed |= row;
|
||||
if (row == RowSpec) return claim.Model != real.Model ? 2 : 0;
|
||||
if (IsFakeSign(row, real.Get(row)) && claim.Get(row) != real.Get(row))
|
||||
if (IsEvidence(row, claim, real))
|
||||
{
|
||||
exposed |= RowSpec;
|
||||
exposed |= RowSpec | RowBuild;
|
||||
return 2;
|
||||
}
|
||||
if (wasExposed) return 0;
|
||||
return claim.Get(row) != real.Get(row) ? 1 : 0;
|
||||
}
|
||||
|
||||
/// <summary>说法里隐瞒了什么:说法比真实情况价值高的标签,以及型号不符。</summary>
|
||||
/// <summary>说法里隐瞒了什么:说法比真实情况价值高的标签,型号不符,以及假货的证据。</summary>
|
||||
public static int Lies(Unit u, Claim claim, int exposed)
|
||||
{
|
||||
var real = Claim.Truth(u);
|
||||
@@ -111,24 +121,58 @@ namespace Decentralized.Domain
|
||||
{
|
||||
if ((exposed & r) != 0) continue;
|
||||
if (r == RowSpec) { if (claim.Model != real.Model) lies |= r; }
|
||||
else if (claim.Get(r) != real.Get(r) && (Pct(r, claim.Get(r)) > Pct(r, real.Get(r)) || IsFakeSign(r, real.Get(r)))) lies |= r;
|
||||
else if (IsEvidence(r, claim, real)) lies |= r;
|
||||
else if (claim.Get(r) != real.Get(r) && Pct(r, claim.Get(r)) > Pct(r, real.Get(r))) lies |= r;
|
||||
}
|
||||
return lies;
|
||||
}
|
||||
|
||||
/// <summary>卖家怎么说:老实人如实说;中间商每项有三成概率隐瞒;骗子全部说成没问题。假卡的型号一律说成标称型号。</summary>
|
||||
/// <summary>卖家怎么说:老实人如实说;中间商每项有七成概率说成没问题;骗子全部说成没问题。假卡的型号一律说成标称型号。</summary>
|
||||
public static Claim DealerClaim(Unit u, DealerKind kind, Rng rng)
|
||||
{
|
||||
var c = Claim.Truth(u);
|
||||
if (kind == DealerKind.Honest) return c;
|
||||
c.Model = u.Model;
|
||||
if (kind == DealerKind.Honest) { c.Model = u.FakeOf ?? u.Model; return c; }
|
||||
double hide = kind == DealerKind.Scammer ? 1.0 : 0.7;
|
||||
foreach (int r in Rows)
|
||||
{
|
||||
if (r == RowSpec) continue;
|
||||
foreach (int r in new[] { RowFan, RowFingers, RowBracket, RowPrint, RowSerial, RowSeal })
|
||||
if (rng.Chance(hide)) c = c.With(r, 0);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
// ---------- 序列号 ----------
|
||||
|
||||
/// <summary>各牌子的序列号前缀与合法工厂码。序列号格式:前缀 + 档次码(1 到 4)+ "-" + 工厂码(两位)+ "-" + 四位流水。</summary>
|
||||
public static string BrandCode(string brand) => brand == Hardware.Probidia ? "PB" : "MD";
|
||||
public static readonly int[] ProbidiaFactories = { 11, 12, 21, 34, 47 }, PmdFactories = { 13, 22, 35, 41, 58 };
|
||||
public static int[] Factories(string brand) => brand == Hardware.Probidia ? ProbidiaFactories : PmdFactories;
|
||||
|
||||
private static uint Mix(uint seed, int salt)
|
||||
{
|
||||
uint x = seed * 2654435761u + (uint)salt * 40503u + 777u;
|
||||
x ^= x >> 15; x *= 2246822519u; x ^= x >> 13; x *= 3266489917u; x ^= x >> 16;
|
||||
return x;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 卡上贴纸的序列号。合规:前缀(牌子)+ 标称型号的档次码 + 合法工厂码 + 四位流水。
|
||||
/// 不合规(贴纸是后补的):工厂码不在合法范围,或流水只有三位。档次码不符:贴的是原芯片的序列号,档次码是真实芯片的档次。
|
||||
/// </summary>
|
||||
public static string SerialText(Unit u)
|
||||
{
|
||||
var label = Hardware.Specs[u.Model];
|
||||
var chip = Hardware.Specs[u.FakeOf ?? u.Model];
|
||||
uint seed = u.Look.Seed == 0 ? 12345u : u.Look.Seed;
|
||||
int kind = u.Appearance.Serial;
|
||||
int[] ok = Factories(label.Brand);
|
||||
int tier = (kind == 2 ? chip.Tier : label.Tier) + 1;
|
||||
int factory = ok[(int)(Mix(seed, 1) % (uint)ok.Length)];
|
||||
int number = 1000 + (int)(Mix(seed, 2) % 9000);
|
||||
if (kind == 1)
|
||||
{
|
||||
if (Mix(seed, 3) % 2 == 0) { int[] bad = { 0, 9, 66, 77, 88, 99 }; factory = bad[(int)(Mix(seed, 4) % (uint)bad.Length)]; }
|
||||
else number = 100 + (int)(Mix(seed, 5) % 900);
|
||||
}
|
||||
return $"{BrandCode(label.Brand)}{tier}-{factory:00}-{number}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,12 +13,15 @@ namespace Decentralized.Domain
|
||||
public int Fan;
|
||||
/// <summary>金手指:0 光亮,1 发暗,2 氧化发绿(老化)。</summary>
|
||||
public int Fingers;
|
||||
/// <summary>挡板:0 完好,1 划痕(老化),2 接口数量不对(假卡)。</summary>
|
||||
/// <summary>挡板:0 完好,1 划痕(老化)。</summary>
|
||||
public int Bracket;
|
||||
/// <summary>背面丝印:0 与标称型号一致,1 印的是真实芯片的型号(假卡),2 重新印过、字歪(假卡)。</summary>
|
||||
public int Print;
|
||||
/// <summary>背面贴纸与封条:0 印刷序列号、封条完好,1 手写序列号(假卡),2 封条缺失(旧卡或翻新卡)。</summary>
|
||||
/// <summary>封条:0 完好,2 缺失(开过封的旧卡或翻新卡)。</summary>
|
||||
public int Sticker;
|
||||
/// <summary>序列号:0 合规(格式对、工厂码在合法范围、档次码与型号一致),1 不合规(工厂码不在合法范围或位数不对,贴纸是后补的),
|
||||
/// 2 档次码与标称型号不符(贴的是原芯片的序列号)。后两种只出现在假卡上。</summary>
|
||||
public int Serial;
|
||||
|
||||
public const int Variants = 3;
|
||||
|
||||
@@ -43,7 +46,7 @@ namespace Decentralized.Domain
|
||||
double fan = worn + (U(Seed, 1) - 0.5) * 0.3, fin = worn + (U(Seed, 2) - 0.5) * 0.3, brk = worn + (U(Seed, 3) - 0.5) * 0.3;
|
||||
l.Fan = fan >= 0.55 ? 2 : fan >= 0.25 ? 1 : 0;
|
||||
l.Fingers = fin >= 0.60 ? 2 : fin >= 0.30 ? 1 : 0;
|
||||
if (Bracket != 2) l.Bracket = brk >= 0.45 ? 1 : 0;
|
||||
l.Bracket = brk >= 0.45 ? 1 : 0;
|
||||
return l;
|
||||
}
|
||||
|
||||
@@ -52,14 +55,14 @@ namespace Decentralized.Domain
|
||||
/// <summary>算力倍数:风扇积灰 ×0.97、缺角 ×0.92(降频);金手指发暗 ×0.98、氧化 ×0.94(接触不良掉速)。</summary>
|
||||
public double HashFactor => FanHash[Fan] * FingerHash[Fingers];
|
||||
|
||||
/// <summary>五位数字,存在物品标签上:风扇、金手指、挡板、丝印、贴纸。</summary>
|
||||
public string Encode() => $"{Fan}{Fingers}{Bracket}{Print}{Sticker}";
|
||||
/// <summary>六位数字,存在物品标签上:风扇、金手指、挡板、丝印、封条、序列号。</summary>
|
||||
public string Encode() => $"{Fan}{Fingers}{Bracket}{Print}{Sticker}{Serial}";
|
||||
|
||||
public static CardLook Decode(string s)
|
||||
{
|
||||
if (s == null || s.Length != 5) return default;
|
||||
if (s == null || (s.Length != 5 && s.Length != 6)) 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) };
|
||||
return new CardLook { Fan = D(0), Fingers = D(1), Bracket = D(2), Print = D(3), Sticker = D(4), Serial = s.Length > 5 ? D(5) : 0 };
|
||||
}
|
||||
|
||||
// 外观维度对应卡的真实状态:损耗、暴毙概率随之变化,价值走标签(见 CardLabels)
|
||||
@@ -73,7 +76,7 @@ namespace Decentralized.Domain
|
||||
public double DeathFactor => FanDeath[Fan] * FingerDeath[Fingers];
|
||||
|
||||
/// <summary>只在假卡上出现的取值:玩家一旦看到,就能肯定是假的。</summary>
|
||||
public bool HasFakeSign => Bracket == 2 || Print != 0 || Sticker == 1;
|
||||
public bool HasFakeSign => Print != 0 || Serial != 0;
|
||||
|
||||
/// <summary>
|
||||
/// 生成外观。真卡:老化维度按健康度出现,封条缺失在二手卡上很常见,不会出现破绽类取值。
|
||||
@@ -84,26 +87,12 @@ namespace Decentralized.Domain
|
||||
var look = new CardLook { Seed = rng.NextUInt() | 1, Sticker = rng.Chance(fake ? 0.35 : 0.15 + 0.30 * (1 - Math.Max(0, Math.Min(100, health)) / 100.0)) ? 2 : 0 };
|
||||
if (fake)
|
||||
{
|
||||
int signs = rng.Chance(0.55) ? 1 : rng.Chance(0.6) ? 2 : 3;
|
||||
var order = new[] { 0, 1, 2 };
|
||||
for (int i = order.Length - 1; i > 0; i--)
|
||||
{
|
||||
int j = rng.Range(0, i);
|
||||
(order[i], order[j]) = (order[j], order[i]);
|
||||
}
|
||||
for (int k = 0; k < signs; k++)
|
||||
{
|
||||
switch (order[k])
|
||||
{
|
||||
case 0: look.Bracket = 2; break;
|
||||
case 1: look.Print = rng.Chance(0.6) ? 1 : 2; break;
|
||||
default: look.Sticker = 1; break;
|
||||
}
|
||||
}
|
||||
// 假卡本身就带着实物上的破绽(低档次的板子:供电口和风扇数对不上),此外骗子还可能重印丝印、补贴序列号
|
||||
if (rng.Chance(0.55)) look.Print = rng.Chance(0.6) ? 1 : 2;
|
||||
if (rng.Chance(0.65)) look.Serial = rng.Chance(0.55) ? 2 : 1;
|
||||
}
|
||||
return look.Appearance(health);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -9,9 +9,9 @@ namespace Decentralized.Domain
|
||||
{
|
||||
public const string Rig = "RIG";
|
||||
|
||||
public static readonly string[] Basic = { "RZX50", "RZX60", "RZ470", "RZ580" };
|
||||
public static readonly string[] Advanced = { "RZX70", "RZX80Ti", "RZ6800" };
|
||||
public static readonly string[] Flagship = { "RZX90", "RZ7900" };
|
||||
public static readonly string[] Basic = { "RZX60", "RZ70" };
|
||||
public static readonly string[] Advanced = { "RZX70", "RZ80", "RZX80", "RZ800" };
|
||||
public static readonly string[] Flagship = { "RZX90", "RZ900" };
|
||||
|
||||
public const int AdvancedFromDay = 10, FlagshipFromDay = 30, SpecialFlagshipFromDay = 20;
|
||||
public const double RigRestockChance = 0.30, AdvancedChance = 0.60, AdvancedSecondChance = 0.30, FlagshipChance = 0.25;
|
||||
|
||||
@@ -13,6 +13,8 @@ namespace Decentralized.Domain
|
||||
public double Kj;
|
||||
public int Price;
|
||||
/// <summary>暴毙概率的品牌系数。</summary>
|
||||
/// <summary>档次:0 低端、1 中端、2 高端、3 旗舰(显卡)。实物特征(供电口、风扇数)只看档次。</summary>
|
||||
public int Tier;
|
||||
public double DeathFactor;
|
||||
/// <summary>每天损耗的系数。</summary>
|
||||
public double WearFactor;
|
||||
@@ -25,20 +27,25 @@ namespace Decentralized.Domain
|
||||
|
||||
public static class Hardware
|
||||
{
|
||||
/// <summary>各档次的实物特征:供电口针数(旗舰是两个 8 针)与风扇数量。</summary>
|
||||
public static readonly string[] PowerPins = { "6", "8", "8", "8+8" };
|
||||
public static readonly int[] FanCount = { 1, 2, 3, 3 };
|
||||
|
||||
public const string Probidia = "Probidia", Pmd = "PMD", RatDigg = "RatDigg";
|
||||
|
||||
public static readonly IReadOnlyDictionary<string, HardwareSpec> Specs = new[]
|
||||
{
|
||||
Gpu("RZX50", Probidia, 1.0, 4, 220), Gpu("RZX60", Probidia, 1.5, 5, 330), Gpu("RZX70", Probidia, 5.0, 12, 800),
|
||||
Gpu("RZX80Ti", Probidia, 8.0, 18, 1300), Gpu("RZX90", Probidia, 20.0, 30, 5000),
|
||||
Gpu("RZ470", Pmd, 0.8, 2.5, 170), Gpu("RZ580", Pmd, 1.2, 3, 250), Gpu("RZ6800", Pmd, 4.0, 8, 680),
|
||||
Gpu("RZ7900", Pmd, 15.0, 20, 4000),
|
||||
// 四个档次(低端、中端、高端、旗舰),两个牌子通用:型号只是显示名,性能和价格由「牌子 + 档次」决定
|
||||
Gpu("RZX60", Probidia, 0, 1.0, 4, 220), Gpu("RZX70", Probidia, 1, 5.0, 12, 800),
|
||||
Gpu("RZX80", Probidia, 2, 8.0, 18, 1300), Gpu("RZX90", Probidia, 3, 20.0, 30, 5000),
|
||||
Gpu("RZ70", Pmd, 0, 0.8, 2.5, 170), Gpu("RZ80", Pmd, 1, 4.0, 8, 680),
|
||||
Gpu("RZ800", Pmd, 2, 8.0, 12, 1500), Gpu("RZ900", Pmd, 3, 15.0, 20, 4000),
|
||||
Asic("M1", 50, 60, 11000), Asic("M2", 120, 110, 27000), Asic("M3", 300, 220, 72000),
|
||||
}.ToDictionary(s => s.Model);
|
||||
|
||||
private static HardwareSpec Gpu(string model, string brand, double h, double kj, int price) => new HardwareSpec
|
||||
private static HardwareSpec Gpu(string model, string brand, int tier, double h, double kj, int price) => new HardwareSpec
|
||||
{
|
||||
Model = model, Brand = brand, Hash = h, Kj = kj, Price = price,
|
||||
Model = model, Brand = brand, Tier = tier, Hash = h, Kj = kj, Price = price,
|
||||
DeathFactor = brand == Probidia ? 0.7 : 1.0, WearFactor = brand == Probidia ? 1.0 : 1.2,
|
||||
};
|
||||
|
||||
|
||||
@@ -19,10 +19,10 @@ namespace Decentralized
|
||||
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));
|
||||
Items.Give(Items.NewCard("RZX80", 40, null, rng));
|
||||
Items.Give(Items.NewCard("RZX80", 70, "RZX60", rng));
|
||||
Items.Give(Items.NewCard("RZ800", 30, "RZ70", rng));
|
||||
Items.Give(Items.NewCard("RZ900", 90, "RZ70", rng));
|
||||
});
|
||||
ModHelper.AddDebugFunction(ModInfo.Id, ModInfo.Name, "Dump inspection UI (test)", () => Log.Guard("检视界面结构", () =>
|
||||
{
|
||||
|
||||
@@ -16,7 +16,8 @@ namespace Decentralized
|
||||
/// </summary>
|
||||
public sealed class GpuInspectView : MonoBehaviour
|
||||
{
|
||||
private const float RowH = 30f, CardScale = 3f;
|
||||
private const float RowH = 27f, CardScale = 2.7f, PanelTop = -86f;
|
||||
private const int RowCount = 8;
|
||||
private static GpuInspectView instance;
|
||||
private RectTransform root, cardRoot;
|
||||
private Button flip;
|
||||
@@ -26,9 +27,10 @@ namespace Decentralized
|
||||
private bool hidGlass;
|
||||
private Transform buttonTemplate;
|
||||
private TMP_FontAsset font;
|
||||
private readonly TextMeshProUGUI[] rowName = new TextMeshProUGUI[6], rowText = new TextMeshProUGUI[6];
|
||||
private readonly Button[] rowButton = new Button[6];
|
||||
private readonly TextMeshProUGUI[] rowButtonText = new TextMeshProUGUI[6];
|
||||
private readonly TextMeshProUGUI[] rowName = new TextMeshProUGUI[RowCount], rowText = new TextMeshProUGUI[RowCount];
|
||||
private readonly Button[] rowButton = new Button[RowCount];
|
||||
private readonly TextMeshProUGUI[] rowButtonText = new TextMeshProUGUI[RowCount];
|
||||
private TextMeshProUGUI serialText;
|
||||
|
||||
public static void Ensure()
|
||||
{
|
||||
@@ -83,18 +85,17 @@ namespace Decentralized
|
||||
string P = "gpu_big_ov_";
|
||||
if (!Items.IsBack(item))
|
||||
{
|
||||
if (l.Fan == 1) o.Add(P + "fan_dust2");
|
||||
if (l.Fan == 2) { o.Add(P + "fan_dust1"); o.Add(P + "fan_chip"); }
|
||||
int n = Items.FansOf(u);
|
||||
if (l.Fan == 1) o.Add(P + "fan_dust2_" + n);
|
||||
if (l.Fan == 2) { o.Add(P + "fan_dust1_" + n); o.Add(P + "fan_chip_" + n); }
|
||||
if (l.Fingers == 1) o.Add(P + "fin_dim");
|
||||
if (l.Fingers == 2) o.Add(P + "fin_oxide");
|
||||
if (l.Bracket == 1) o.Add(P + "brk_scratch");
|
||||
if (l.Bracket == 2) o.Add(P + "brk_port");
|
||||
}
|
||||
else
|
||||
{
|
||||
string model = (l.Print == 1 && u.FakeOf != null ? u.FakeOf : u.Model).ToLowerInvariant();
|
||||
o.Add(P + "print_" + (l.Print == 2 ? "skew_" : l.Print == 1 ? "stamp_" : "normal_") + model);
|
||||
if (l.Sticker == 1) o.Add(P + "sticker_hand");
|
||||
if (l.Sticker == 2) o.Add(P + "seal_missing");
|
||||
}
|
||||
return o;
|
||||
@@ -160,30 +161,40 @@ namespace Decentralized
|
||||
root.localPosition = Vector3.zero;
|
||||
cardRoot = new GameObject("Card", typeof(RectTransform)).GetComponent<RectTransform>();
|
||||
cardRoot.SetParent(root, false);
|
||||
cardRoot.localPosition = new Vector3(0, 85, 0);
|
||||
cardRoot.localPosition = new Vector3(0, 95, 0);
|
||||
buttonTemplate = m.appraisalPanel.transform.Find("buttonSend");
|
||||
// 贴纸上的序列号:随卡变化,运行时用文字写在贴纸的空白处
|
||||
serialText = MakeText(root, "Serial", Vector2.zero, new Vector2(48 * CardScale, 8 * CardScale), TextAlignmentOptions.Center, 20);
|
||||
serialText.color = new Color(0.1f, 0.1f, 0.13f);
|
||||
serialText.fontStyle = FontStyles.Bold;
|
||||
serialText.overflowMode = TextOverflowModes.Overflow;
|
||||
serialText.rectTransform.sizeDelta = new Vector2(48 * CardScale, 14 * CardScale);
|
||||
if (buttonTemplate == null) return;
|
||||
font = buttonTemplate.GetComponentInChildren<TextMeshProUGUI>()?.font;
|
||||
if (font != null) serialText.font = font;
|
||||
// 标签区:深色底加浅色边框,和上面的大图分开
|
||||
MakeRect(root, "LabelFrame", new Vector2(0, -201), new Vector2(648, 194), new Color(0.78f, 0.68f, 0.45f, 1f));
|
||||
MakeRect(root, "LabelBack", new Vector2(0, -201), new Vector2(640, 186), new Color(0.10f, 0.11f, 0.14f, 0.96f));
|
||||
flip = MakeButton(root, "Flip", new Vector2(0, -326), new Vector2(200, 34), out flipText);
|
||||
float panelH = RowCount * RowH + 10f, panelY = PanelTop - panelH / 2;
|
||||
MakeRect(root, "LabelFrame", new Vector2(0, panelY), new Vector2(648, panelH + 8), new Color(0.78f, 0.68f, 0.45f, 1f));
|
||||
MakeRect(root, "LabelBack", new Vector2(0, panelY), new Vector2(640, panelH), new Color(0.10f, 0.11f, 0.14f, 0.96f));
|
||||
flip = MakeButton(root, "Flip", new Vector2(0, PanelTop - panelH - 24), new Vector2(200, 30), out flipText);
|
||||
flip.onClick.AddListener(() => { if (shown != null) Items.Flip(shown); });
|
||||
for (int i = 0; i < 6; i++)
|
||||
for (int i = 0; i < RowCount; i++)
|
||||
{
|
||||
int row = CardLabels.Rows[i];
|
||||
float y = -126 - i * RowH;
|
||||
rowName[i] = MakeText(root, "RowName" + i, new Vector2(-255, y), new Vector2(110, RowH), TextAlignmentOptions.Left, 24);
|
||||
rowText[i] = MakeText(root, "RowText" + i, new Vector2(-30, y), new Vector2(330, RowH), TextAlignmentOptions.Left, 24);
|
||||
rowButton[i] = MakeButton(root, "RowButton" + i, new Vector2(245, y), new Vector2(110, RowH - 4), out rowButtonText[i]);
|
||||
float y = PanelTop - 5 - RowH * (i + 0.5f);
|
||||
rowName[i] = MakeText(root, "RowName" + i, new Vector2(-255, y), new Vector2(110, RowH), TextAlignmentOptions.Left, 22);
|
||||
rowText[i] = MakeText(root, "RowText" + i, new Vector2(-30, y), new Vector2(330, RowH), TextAlignmentOptions.Left, 22);
|
||||
rowButton[i] = MakeButton(root, "RowButton" + i, new Vector2(245, y), new Vector2(110, RowH - 3), out rowButtonText[i]);
|
||||
rowButton[i].onClick.AddListener(() => Log.Guard("标签栏", () => OnRowButton(row)));
|
||||
}
|
||||
}
|
||||
|
||||
private static string ValueText(int row, int value) =>
|
||||
row == CardLabels.RowSpec ? "" : L.T("lbl." + (row == CardLabels.RowFan ? "fan" : row == CardLabels.RowFingers ? "fingers" : row == CardLabels.RowBracket ? "bracket" : row == CardLabels.RowPrint ? "print" : "sticker") + "." + value);
|
||||
private static string RowKey(int row) => row == CardLabels.RowSpec ? "spec" : row == CardLabels.RowBuild ? "build" : row == CardLabels.RowFan ? "fan" : row == CardLabels.RowFingers ? "fingers"
|
||||
: row == CardLabels.RowBracket ? "bracket" : row == CardLabels.RowPrint ? "print" : row == CardLabels.RowSerial ? "serial" : "seal";
|
||||
|
||||
private static string RowName(int row) => L.T("lbl.row." + (row == CardLabels.RowSpec ? "spec" : row == CardLabels.RowFan ? "fan" : row == CardLabels.RowFingers ? "fingers" : row == CardLabels.RowBracket ? "bracket" : row == CardLabels.RowPrint ? "print" : "sticker"));
|
||||
private static string ValueText(int row, int value) => row == CardLabels.RowSpec ? "" : L.T("lbl." + RowKey(row) + "." + (row == CardLabels.RowSeal && value == 1 ? 0 : value));
|
||||
|
||||
private static string RowName(int row) => L.T("lbl.row." + RowKey(row));
|
||||
|
||||
/// <summary>现场有没有卖家 / 鉴定客户在:决定"指出"按钮是否出现。</summary>
|
||||
private static bool CanPoint(GameItem item)
|
||||
@@ -203,37 +214,38 @@ namespace Decentralized
|
||||
int exposed = Items.Exposed(item);
|
||||
bool owned = GeneralHelper.IsItemOwned(item);
|
||||
bool canPoint = CanPoint(item), canEdit = owned && HasLabeler();
|
||||
for (int i = 0; i < 6; i++)
|
||||
for (int i = 0; i < RowCount; i++)
|
||||
{
|
||||
int row = CardLabels.Rows[i];
|
||||
rowName[i].text = RowName(row);
|
||||
rowName[i].color = new Color(1f, 0.85f, 0.45f);
|
||||
string text;
|
||||
Color color = new Color(0.96f, 0.98f, 1f);
|
||||
if (claim == null)
|
||||
{
|
||||
text = row == CardLabels.RowSpec ? DisplayModel(real.Model) : ValueText(row, real.Get(row));
|
||||
}
|
||||
string Show(Claim c) => row == CardLabels.RowSpec ? DisplayModel(c.Model) : ValueText(row, c.Get(row));
|
||||
if (claim == null) text = Show(real);
|
||||
else if ((exposed & row) != 0)
|
||||
{
|
||||
int r = row == CardLabels.RowSpec ? 0 : real.Get(row);
|
||||
text = row == CardLabels.RowSpec ? DisplayModel(real.Model) : ValueText(row, r);
|
||||
bool lied = row == CardLabels.RowSpec ? claim.Value.Model != real.Model : claim.Value.Get(row) != r;
|
||||
if (lied) { color = new Color(1f, 0.45f, 0.4f); text += L.T("lbl.said", row == CardLabels.RowSpec ? DisplayModel(claim.Value.Model) : ValueText(row, claim.Value.Get(row))); }
|
||||
text = Show(real);
|
||||
bool lied = row == CardLabels.RowSpec ? claim.Value.Model != real.Model : claim.Value.Get(row) != real.Get(row);
|
||||
if (lied) { color = new Color(1f, 0.45f, 0.4f); text += L.T("lbl.said", row == CardLabels.RowBuild ? L.T("lbl.tier." + claim.Value.Tier) : Show(claim.Value)); }
|
||||
else color = new Color(0.5f, 1f, 0.55f);
|
||||
}
|
||||
else
|
||||
{
|
||||
text = row == CardLabels.RowSpec ? DisplayModel(claim.Value.Model) : ValueText(row, claim.Value.Get(row));
|
||||
}
|
||||
else text = Show(claim.Value);
|
||||
rowText[i].text = text;
|
||||
rowText[i].color = color;
|
||||
bool show = row != CardLabels.RowSpec && ((canPoint && claim != null && (exposed & row) == 0) || canEdit || (canPoint && claim == null));
|
||||
bool point = canPoint && !canEdit;
|
||||
rowButton[i].gameObject.SetActive(row != CardLabels.RowSpec ? ((canPoint && (exposed & row) == 0) || canEdit) : canEdit);
|
||||
bool editable = row != CardLabels.RowBuild;
|
||||
rowButton[i].gameObject.SetActive(canEdit ? editable : canPoint && (exposed & row) == 0);
|
||||
rowButtonText[i].text = L.T(canEdit ? "lbl.edit" : "lbl.point");
|
||||
}
|
||||
if (flipText != null) flipText.text = L.T(Items.IsBack(item) ? "inspect.flip.front" : "inspect.flip.back");
|
||||
// 贴纸上的序列号:只在背面显示
|
||||
if (serialText != null)
|
||||
{
|
||||
serialText.gameObject.SetActive(Items.IsBack(item) && !u.Dead);
|
||||
serialText.text = CardLabels.SerialText(u);
|
||||
// 贴纸空白处中心在大图 (142, 91):卡片坐标以图中心为原点,y 向上
|
||||
serialText.rectTransform.localPosition = new Vector3((142 - 96) * CardScale, 95 + (64 - 91) * CardScale, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private static string DisplayModel(string model) => Items.DisplayModel(model);
|
||||
@@ -244,7 +256,7 @@ namespace Decentralized
|
||||
var item = shown;
|
||||
if (GeneralHelper.IsItemOwned(item))
|
||||
{
|
||||
// 标签机:改说法,每按一次换下一个取值(型号是在九个型号里轮换)
|
||||
// 标签机:改说法,每按一次换下一个取值(型号是在八个型号里轮换)
|
||||
var u = Items.ToUnit(item);
|
||||
var cur = Items.GetClaim(item) ?? Claim.Truth(u);
|
||||
if (row == CardLabels.RowSpec)
|
||||
@@ -252,7 +264,7 @@ namespace Decentralized
|
||||
var models = Hardware.Specs.Values.Where(s => !s.Asic).Select(s => s.Model).ToList();
|
||||
Items.EditClaim(item, row, 0, models[(models.IndexOf(cur.Model) + 1) % models.Count]);
|
||||
}
|
||||
else Items.EditClaim(item, row, (cur.Get(row) + 1) % 3);
|
||||
else Items.EditClaim(item, row, row == CardLabels.RowSeal ? (cur.Get(row) == 0 ? 2 : 0) : row == CardLabels.RowBracket ? (cur.Get(row) + 1) % 2 : (cur.Get(row) + 1) % 3);
|
||||
EmporiumAudioPlayer.Instance?.audioLabeler?.Play();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ namespace Decentralized
|
||||
{
|
||||
public const string Terminal = "pd_terminal";
|
||||
public const string Rig = "pd_rig";
|
||||
public const string Guide = "pd_gpu_guide";
|
||||
public const string GpuPrefix = "pd_gpu_";
|
||||
|
||||
public const string HealthTag = "PD_HEALTH";
|
||||
@@ -36,6 +37,7 @@ namespace Decentralized
|
||||
{
|
||||
dir.Add(Terminal, CreateTerminal);
|
||||
dir.Add(Rig, CreateRig);
|
||||
dir.Add(Guide, CreateGuide);
|
||||
foreach (var spec in Hardware.Specs.Values.Where(s => !s.Asic))
|
||||
{
|
||||
var s = spec;
|
||||
@@ -61,9 +63,23 @@ namespace Decentralized
|
||||
return item;
|
||||
}
|
||||
|
||||
/// <summary>显卡鉴定手册:档次对照、序列号规则、外观折扣。和游戏里的鉴定手册一样,是一件物品,说明里就是内容。</summary>
|
||||
private static GameItem CreateGuide()
|
||||
{
|
||||
var item = ItemDirectory.CreateEmptyItem(Guide);
|
||||
item.SetSpriteAndShapeFromMod(ModInfo.Id, "gpu_guide");
|
||||
item.name = L.T("item.guide.name");
|
||||
item.shortDescription = L.T("item.guide.desc");
|
||||
item.unitValue = 0;
|
||||
item.EnableTag(GeneralHelper.IMPORTANT_TAG);
|
||||
item.EnableTag(TypeHelper.NOT_FOR_RESALE);
|
||||
ModHelper.SetSource(item, ModInfo.Id, ModInfo.Name);
|
||||
return item;
|
||||
}
|
||||
|
||||
// ---------- 显卡 ----------
|
||||
|
||||
/// <summary>RZX70 → "RZX 70",RZX80Ti → "RZX 80 Ti",RZ6800 → "RZ 6800"。</summary>
|
||||
/// <summary>RZX70 → "RZX 70",RZ800 → "RZ 800"。</summary>
|
||||
public static string DisplayModel(string model) => Regex.Replace(Regex.Replace(model, @"(?<=[A-Za-z])(?=\d)", " "), @"(?<=\d)(?=[A-Z])", " ");
|
||||
|
||||
private static GameItem CreateGpu(HardwareSpec spec)
|
||||
@@ -129,7 +145,7 @@ namespace Decentralized
|
||||
if ((lies & r) != 0 && rng.Chance(CustomerSpotChance))
|
||||
{
|
||||
found |= r;
|
||||
if (r != CardLabels.RowSpec && CardLabels.IsFakeSign(r, Claim.Truth(u).Get(r))) found |= CardLabels.RowSpec;
|
||||
if (r != CardLabels.RowSpec && CardLabels.IsEvidence(r, claim.Value, Claim.Truth(u))) found |= CardLabels.RowSpec | CardLabels.RowBuild;
|
||||
}
|
||||
if (found == 0) return;
|
||||
item.ModifyTag(ExposedTag, t => t.Enable().SetInt(exposed | found));
|
||||
@@ -217,7 +233,7 @@ namespace Decentralized
|
||||
public static Unit ToUnit(GameItem item)
|
||||
{
|
||||
string model = item.identifier.Substring(GpuPrefix.Length);
|
||||
model = Hardware.Specs.Keys.First(k => k.ToLowerInvariant() == model);
|
||||
model = Hardware.Specs.Keys.FirstOrDefault(k => k.ToLowerInvariant() == model) ?? "RZX60"; // 旧版本存档里的型号已改名,当作低端卡
|
||||
var u = new Unit { Model = model, Health = 100 };
|
||||
if (item.IsTag(HealthTag)) u.Health = item.GetTagReadonly(HealthTag).GetDouble();
|
||||
if (item.IsTag(FakeTag)) u.FakeOf = item.GetTagReadonly(FakeTag).GetString();
|
||||
@@ -253,7 +269,7 @@ namespace Decentralized
|
||||
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.SetSpriteAndShapeFromMod(ModInfo.Id, LookKeys(item, new List<string>()));
|
||||
SyncValue(item);
|
||||
}
|
||||
|
||||
@@ -266,6 +282,9 @@ namespace Decentralized
|
||||
}
|
||||
|
||||
/// <summary>当前面的底图名与叠加图名:正面三个维度,背面丝印与贴纸;烧毁的卡不叠。</summary>
|
||||
/// <summary>实物上的风扇数:由真实芯片的档次决定(低档次的板子套高档次的壳,风扇数露馅)。</summary>
|
||||
public static int FansOf(Unit u) => Hardware.FanCount[Hardware.Specs[u.FakeOf ?? u.Model].Tier];
|
||||
|
||||
public static string LookKeys(GameItem item, List<string> overlays)
|
||||
{
|
||||
var u = ToUnit(item);
|
||||
@@ -275,18 +294,18 @@ namespace Decentralized
|
||||
if (u.Dead) return back ? "gpu_burnt_b" : "gpu_burnt_f";
|
||||
if (!back)
|
||||
{
|
||||
if (l.Fan > 0) overlays.Add("gpu_ov_fan" + l.Fan);
|
||||
if (l.Fan > 0) overlays.Add($"gpu_ov_fan{l.Fan}_{FansOf(u)}");
|
||||
if (l.Fingers > 0) overlays.Add("gpu_ov_fin" + l.Fingers);
|
||||
if (l.Bracket > 0) overlays.Add("gpu_ov_brk" + l.Bracket);
|
||||
if (l.Bracket > 0) overlays.Add("gpu_ov_brk1");
|
||||
}
|
||||
else
|
||||
{
|
||||
// 丝印:0 标称型号;1 印的是真实芯片型号;2 标称型号但字歪(重印过)
|
||||
string model = l.Print == 1 && u.FakeOf != null ? u.FakeOf : u.Model;
|
||||
overlays.Add((l.Print == 2 ? "gpu_ov_txs_" : "gpu_ov_txt_") + model.ToLowerInvariant());
|
||||
if (l.Sticker > 0) overlays.Add("gpu_ov_stk" + l.Sticker);
|
||||
if (l.Sticker == 2) overlays.Add("gpu_ov_stk2");
|
||||
}
|
||||
return brand + (back ? "_b" : "_f");
|
||||
return brand + (back ? "_b" : "_f_t" + Hardware.Specs[u.FakeOf ?? u.Model].Tier);
|
||||
}
|
||||
|
||||
public static Sprite ModSprite(string key)
|
||||
|
||||
@@ -78,27 +78,15 @@ point.worn.1,"...Fine, it has that. I'll knock something off."
|
||||
point.worn.2,"Sharp eyes. All right, this price."
|
||||
point.fake.1,"...You caught it. It's a reflashed one. I'll price it for what it is."
|
||||
point.fake.2,"Tch, not the original chip. Fine, the real chip's price."
|
||||
lbl.row.spec,"Model"
|
||||
lbl.row.fan,"Fans"
|
||||
lbl.row.fingers,"Contacts"
|
||||
lbl.row.bracket,"Bracket"
|
||||
lbl.row.print,"Back print"
|
||||
lbl.row.sticker,"Sticker"
|
||||
lbl.fan.0,"Blades clean"
|
||||
lbl.fan.1,"Blades dusty"
|
||||
lbl.fan.2,"Blade chipped"
|
||||
lbl.fingers.0,"Bright"
|
||||
lbl.fingers.1,"Dull"
|
||||
lbl.fingers.2,"Oxidised"
|
||||
lbl.bracket.0,"Intact, three ports"
|
||||
lbl.bracket.1,"Scratched"
|
||||
lbl.bracket.2,"Wrong port count"
|
||||
lbl.print.0,"Matches the model"
|
||||
lbl.print.1,"Another model printed"
|
||||
lbl.print.2,"Reprinted, crooked"
|
||||
lbl.sticker.0,"Printed serial, seal intact"
|
||||
lbl.sticker.1,"Handwritten serial"
|
||||
lbl.sticker.2,"Seal missing"
|
||||
lbl.said," (seller said: {0})"
|
||||
lbl.point,"Point out"
|
||||
lbl.edit,"Edit"
|
||||
@@ -106,3 +94,28 @@ cust.fake.1,"That's not what the label says. You trying to pass off a fake?"
|
||||
cust.fake.2,"The model doesn't match. That isn't the chip it claims."
|
||||
cust.worn.1,"That's not what you wrote. You left out the flaws."
|
||||
cust.worn.2,"The condition on the label is false. Not at this price."
|
||||
lbl.row.spec,"Model"
|
||||
lbl.row.build,"Power & fans"
|
||||
lbl.row.fan,"Blades"
|
||||
lbl.row.fingers,"Contacts"
|
||||
lbl.row.bracket,"Bracket"
|
||||
lbl.row.print,"Back print"
|
||||
lbl.row.serial,"Serial"
|
||||
lbl.row.seal,"Seal"
|
||||
lbl.build.0,"Entry: 6-pin, single fan"
|
||||
lbl.build.1,"Mid: 8-pin, two fans"
|
||||
lbl.build.2,"High: 8-pin, three fans"
|
||||
lbl.build.3,"Flagship: dual 8-pin, three fans"
|
||||
lbl.bracket.0,"Intact"
|
||||
lbl.bracket.1,"Scratched"
|
||||
lbl.serial.0,"Valid"
|
||||
lbl.serial.1,"Bad factory code or length"
|
||||
lbl.serial.2,"Tier code does not match"
|
||||
lbl.seal.0,"Intact"
|
||||
lbl.seal.2,"Missing"
|
||||
lbl.tier.0,"Entry"
|
||||
lbl.tier.1,"Mid"
|
||||
lbl.tier.2,"High"
|
||||
lbl.tier.3,"Flagship"
|
||||
item.guide.name,"Graphics card appraisal guide"
|
||||
item.guide.desc,"Tiers: entry has a 6-pin connector and one fan; mid 8-pin and two fans; high 8-pin and three fans; flagship dual 8-pin and three fans. Model names are display only: Probidia RZX 60 / 70 / 80 / 90, PMD RZ 70 / 80 / 800 / 900, lowest to highest tier. Serial: prefix PB (Probidia) or MD (PMD), tier code 1 to 4, a dash, a two-digit factory code, a dash, four digits. Valid factory codes: PB 11, 12, 21, 34, 47; MD 13, 22, 35, 41, 58. A tier code that does not match the model, or a bad factory code or length, means a fake. Appearance discounts: dusty blades -4%, chipped -12%; dull contacts -4%, oxidised -12%; scratched bracket -2%; missing seal -6%."
|
||||
|
@@ -77,27 +77,15 @@ point.worn.1,"……行,这点毛病是有,算你便宜点。"
|
||||
point.worn.2,"眼睛挺毒。好吧,这个价。"
|
||||
point.fake.1,"……被你看出来了。是翻新的货,按真的价给你。"
|
||||
point.fake.2,"啧,不是原装的。那就按芯片本来的价吧。"
|
||||
lbl.row.spec,"型号"
|
||||
lbl.row.fan,"风扇"
|
||||
lbl.row.fingers,"金手指"
|
||||
lbl.row.bracket,"挡板"
|
||||
lbl.row.print,"背面丝印"
|
||||
lbl.row.sticker,"贴纸封条"
|
||||
lbl.fan.0,"叶片干净"
|
||||
lbl.fan.1,"叶片积灰"
|
||||
lbl.fan.2,"叶片缺角"
|
||||
lbl.fingers.0,"光亮"
|
||||
lbl.fingers.1,"发暗"
|
||||
lbl.fingers.2,"氧化发绿"
|
||||
lbl.bracket.0,"完好,接口三个"
|
||||
lbl.bracket.1,"有划痕"
|
||||
lbl.bracket.2,"接口数不对"
|
||||
lbl.print.0,"与型号一致"
|
||||
lbl.print.1,"印着另一个型号"
|
||||
lbl.print.2,"重印过,字歪"
|
||||
lbl.sticker.0,"印刷序列号,封条完好"
|
||||
lbl.sticker.1,"手写序列号"
|
||||
lbl.sticker.2,"封条已缺失"
|
||||
lbl.said,"(卖家说:{0})"
|
||||
lbl.point,"指出"
|
||||
lbl.edit,"改"
|
||||
@@ -105,3 +93,28 @@ cust.fake.1,"这不是它标的那块。你拿假货糊弄我?"
|
||||
cust.fake.2,"型号对不上,里面的芯片根本不是这个。"
|
||||
cust.worn.1,"跟你写的不一样,毛病你没说。"
|
||||
cust.worn.2,"标签上的成色是假的吧,这个价我不要。"
|
||||
lbl.row.spec,"型号"
|
||||
lbl.row.build,"供电与风扇"
|
||||
lbl.row.fan,"叶片"
|
||||
lbl.row.fingers,"金手指"
|
||||
lbl.row.bracket,"挡板"
|
||||
lbl.row.print,"背面丝印"
|
||||
lbl.row.serial,"序列号"
|
||||
lbl.row.seal,"封条"
|
||||
lbl.build.0,"低端:6针,单风扇"
|
||||
lbl.build.1,"中端:8针,双风扇"
|
||||
lbl.build.2,"高端:8针,三风扇"
|
||||
lbl.build.3,"旗舰:双8针,三风扇"
|
||||
lbl.bracket.0,"完好"
|
||||
lbl.bracket.1,"有划痕"
|
||||
lbl.serial.0,"合规"
|
||||
lbl.serial.1,"工厂码或位数不合规"
|
||||
lbl.serial.2,"档次码与型号不符"
|
||||
lbl.seal.0,"完好"
|
||||
lbl.seal.2,"已缺失"
|
||||
lbl.tier.0,"低端"
|
||||
lbl.tier.1,"中端"
|
||||
lbl.tier.2,"高端"
|
||||
lbl.tier.3,"旗舰"
|
||||
item.guide.name,"显卡鉴定手册"
|
||||
item.guide.desc,"档次:低端 6 针供电、单风扇;中端 8 针、双风扇;高端 8 针、三风扇;旗舰双 8 针、三风扇。型号只是显示名:Probidia 为 RZX 60 / 70 / 80 / 90,PMD 为 RZ 70 / 80 / 800 / 900,按档次从低到高。序列号:前缀 PB(Probidia)或 MD(PMD),接档次码 1 至 4,一道横杠,两位工厂码,一道横杠,四位流水。合法工厂码:PB 为 11、12、21、34、47;MD 为 13、22、35、41、58。档次码与型号不符,或工厂码、位数不对,都是假的。外观折扣:叶片积灰 -4%,缺角 -12%;金手指发暗 -4%,氧化 -12%;挡板划痕 -2%;封条缺失 -6%。"
|
||||
|
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 409 B |
|
After Width: | Height: | Size: 397 B |
|
After Width: | Height: | Size: 340 B |
|
After Width: | Height: | Size: 462 B |
|
After Width: | Height: | Size: 569 B |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 432 B |
|
Before Width: | Height: | Size: 437 B |
|
Before Width: | Height: | Size: 431 B |
|
Before Width: | Height: | Size: 428 B |
|
After Width: | Height: | Size: 402 B |
|
Before Width: | Height: | Size: 447 B |
|
After Width: | Height: | Size: 388 B |
|
After Width: | Height: | Size: 405 B |
|
After Width: | Height: | Size: 424 B |
|
Before Width: | Height: | Size: 451 B |
|
After Width: | Height: | Size: 428 B |
|
Before Width: | Height: | Size: 488 B |
|
Before Width: | Height: | Size: 569 B |
|
Before Width: | Height: | Size: 574 B |
|
Before Width: | Height: | Size: 634 B |
|
After Width: | Height: | Size: 502 B |
|
Before Width: | Height: | Size: 626 B |
|
After Width: | Height: | Size: 507 B |
|
After Width: | Height: | Size: 582 B |
|
After Width: | Height: | Size: 593 B |
|
Before Width: | Height: | Size: 592 B |
|
After Width: | Height: | Size: 592 B |
|
Before Width: | Height: | Size: 689 B |
|
Before Width: | Height: | Size: 865 B |
|
Before Width: | Height: | Size: 876 B |
|
Before Width: | Height: | Size: 929 B |
|
After Width: | Height: | Size: 805 B |
|
Before Width: | Height: | Size: 905 B |
|
After Width: | Height: | Size: 848 B |
|
After Width: | Height: | Size: 903 B |
|
After Width: | Height: | Size: 883 B |
|
Before Width: | Height: | Size: 859 B |
|
After Width: | Height: | Size: 881 B |
|
Before Width: | Height: | Size: 966 B |
|
Before Width: | Height: | Size: 364 B |
|
Before Width: | Height: | Size: 419 B |
|
Before Width: | Height: | Size: 345 B |
|
Before Width: | Height: | Size: 441 B |
|
Before Width: | Height: | Size: 420 B |
|
Before Width: | Height: | Size: 1011 B |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 607 B After Width: | Height: | Size: 607 B |
|
After Width: | Height: | Size: 137 B |
|
Before Width: | Height: | Size: 108 B |
|
After Width: | Height: | Size: 139 B |
|
After Width: | Height: | Size: 157 B |
|
After Width: | Height: | Size: 113 B |
|
After Width: | Height: | Size: 118 B |
|
Before Width: | Height: | Size: 160 B |
|
Before Width: | Height: | Size: 155 B |
|
Before Width: | Height: | Size: 150 B |
|
Before Width: | Height: | Size: 162 B |
|
After Width: | Height: | Size: 142 B |
|
Before Width: | Height: | Size: 156 B |
|
After Width: | Height: | Size: 145 B |
|
After Width: | Height: | Size: 152 B |
|
After Width: | Height: | Size: 150 B |
|
Before Width: | Height: | Size: 154 B |
|
After Width: | Height: | Size: 152 B |
|
Before Width: | Height: | Size: 164 B |
|
Before Width: | Height: | Size: 149 B |
|
Before Width: | Height: | Size: 141 B |
|
Before Width: | Height: | Size: 144 B |
|
After Width: | Height: | Size: 136 B |
|
Before Width: | Height: | Size: 145 B |