Label bar: one model-authenticity row with a hint line; evidence listed after exposure

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
ZHU MINCHAOandClaude Sonnet 5.5 committed 2026-11-03 14:30:47 +08:00
1 parent d6a456c986
commit f564a895d0
5 files changed
+53 -16

No files matched your search

+6 -6
View File
@@ -42,16 +42,17 @@ namespace Decentralized.Domain
}
/// <summary>
/// 标签栏的数据:八个标签(型号、供电与风扇、风扇叶片、金手指、挡板、背面丝印、序列号、封条),每个标签有卖家的说法和真实情况。
/// 标签栏的数据:五个标签(型号真伪、风扇叶片、金手指、挡板、封条),每个标签有卖家的说法和真实情况;
/// 供电与风扇、背面丝印、序列号三项是型号真伪的依据,只存状态,不单独成行。
/// 一个标签被指出(拆穿)之后,说法改回真实情况;价格按「已指出的标签取真实情况,其余取说法」算,
/// 所以卖家隐瞒的问题要玩家一项项指出来才能把价格拉回真实价值。指出假货的证据(供电与风扇、丝印、序列号)会连带把型号改回真实型号。
/// 所以卖家隐瞒的问题要玩家一项项指出来才能把价格拉回真实价值。指出型号有问题,型号自动改回真实型号。
/// </summary>
public static class CardLabels
{
public const int RowSpec = 1, RowBuild = 2, RowFan = 4, RowFingers = 8, RowBracket = 16, RowPrint = 32, RowSerial = 64, RowSeal = 128, AllRows = 255;
/// <summary>标签栏的顺序:前四行鉴定真伪(型号、供电与风扇、序列号条形码、丝印),后四行鉴定成色。</summary>
public static readonly int[] Rows = { RowSpec, RowBuild, RowSerial, RowPrint, RowFan, RowFingers, RowBracket, RowSeal };
public const int AuthRows = 4;
/// <summary>标签栏的顺序:第一行鉴定真伪(型号;依据是供电口与风扇数、序列号、背面丝印,玩家对着大图自己看),后四行鉴定成色。</summary>
public static readonly int[] Rows = { RowSpec, RowFan, RowFingers, RowBracket, RowSeal };
public const int AuthRows = 1;
/// <summary>各标签各取值对价格的影响(百分比,相加):风扇叶片积灰 −4%、缺角 −12%;金手指发暗 −4%、氧化 −12%;挡板划痕 −2%;封条缺失 −6%。
/// 型号、供电与风扇、丝印、序列号本身不扣价,它们决定的是这块卡是什么芯片。</summary>
@@ -123,7 +124,6 @@ namespace Decentralized.Domain
{
if ((exposed & r) != 0) continue;
if (r == RowSpec) { if (claim.Model != real.Model) 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;
+28 -7
View File
@@ -16,8 +16,9 @@ namespace Decentralized
/// </summary>
public sealed class GpuInspectView : MonoBehaviour
{
private const float RowH = 27f, CardScale = 2.7f, PanelTop = -86f, GroupGap = 8f;
private const int RowCount = 8;
private const float RowH = 30f, CardScale = 3f, PanelTop = -112f, DetailH = 26f, GroupGap = 8f;
private const int RowCount = 5;
private TextMeshProUGUI detailText;
private static GpuInspectView instance;
private RectTransform root, cardRoot;
private Button flip;
@@ -161,7 +162,7 @@ namespace Decentralized
root.localPosition = Vector3.zero;
cardRoot = new GameObject("Card", typeof(RectTransform)).GetComponent<RectTransform>();
cardRoot.SetParent(root, false);
cardRoot.localPosition = new Vector3(0, 95, 0);
cardRoot.localPosition = new Vector3(0, 85, 0);
buttonTemplate = m.appraisalPanel.transform.Find("buttonSend");
// 贴纸上的序列号:随卡变化,运行时用文字写在贴纸的空白处
serialText = MakeText(root, "Serial", Vector2.zero, new Vector2(48 * CardScale, 8 * CardScale), TextAlignmentOptions.Center, 20);
@@ -173,16 +174,17 @@ namespace Decentralized
font = buttonTemplate.GetComponentInChildren<TextMeshProUGUI>()?.font;
if (font != null) serialText.font = font;
// 标签区:深色底加浅色边框,和上面的大图分开
float panelH = RowCount * RowH + 10f + GroupGap, panelY = PanelTop - panelH / 2;
float panelH = RowCount * RowH + 10f + DetailH + GroupGap, 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));
MakeRect(root, "LabelDivider", new Vector2(0, PanelTop - 5 - RowH * CardLabels.AuthRows - GroupGap / 2), new Vector2(620, 2), new Color(0.78f, 0.68f, 0.45f, 0.8f));
MakeRect(root, "LabelDivider", new Vector2(0, PanelTop - 5 - RowH * CardLabels.AuthRows - DetailH - GroupGap / 2), new Vector2(620, 2), new Color(0.78f, 0.68f, 0.45f, 0.8f));
detailText = MakeText(root, "Detail", new Vector2(-15, PanelTop - 5 - RowH * CardLabels.AuthRows - DetailH / 2), new Vector2(600, DetailH), TextAlignmentOptions.Left, 17);
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 < RowCount; i++)
{
int row = CardLabels.Rows[i];
float y = PanelTop - 5 - RowH * (i + 0.5f) - (i >= CardLabels.AuthRows ? GroupGap : 0f);
float y = PanelTop - 5 - RowH * (i + 0.5f) - (i >= CardLabels.AuthRows ? DetailH + GroupGap : 0f);
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]);
@@ -220,6 +222,7 @@ namespace Decentralized
int row = CardLabels.Rows[i];
rowName[i].text = RowName(row);
rowName[i].color = i < CardLabels.AuthRows ? new Color(1f, 0.85f, 0.45f) : new Color(0.6f, 0.85f, 1f); // 真伪行金黄,成色行浅蓝
rowName[i].fontSize = 22;
string text;
Color color = new Color(0.96f, 0.98f, 1f);
string Show(Claim c) => row == CardLabels.RowSpec ? DisplayModel(c.Model) : ValueText(row, c.Get(row));
@@ -238,6 +241,14 @@ namespace Decentralized
rowButton[i].gameObject.SetActive(canEdit ? editable : canPoint && (exposed & row) == 0);
rowButtonText[i].text = L.T(canEdit ? "lbl.edit" : "lbl.point");
}
// 型号真伪的依据:没拆穿之前提示去看哪里;拆穿之后列出实际查到的问题
if (detailText != null)
{
bool spec = (exposed & CardLabels.RowSpec) != 0;
string detail = claim == null ? "" : !spec ? L.T("lbl.hint") : Evidence(u, claim.Value, real);
detailText.text = detail;
detailText.color = spec ? new Color(1f, 0.7f, 0.6f) : new Color(0.75f, 0.78f, 0.85f);
}
if (flipText != null) flipText.text = L.T(Items.IsBack(item) ? "inspect.flip.front" : "inspect.flip.back");
// 贴纸上的序列号:只在背面显示
if (serialText != null)
@@ -245,10 +256,20 @@ namespace Decentralized
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);
serialText.rectTransform.localPosition = new Vector3((142 - 96) * CardScale, 85 + (64 - 91) * CardScale, 0);
}
}
/// <summary>型号真伪的依据:实物与卖家说法对不上的地方(供电口与风扇数、序列号、背面丝印)。</summary>
private static string Evidence(Unit u, Claim claim, Claim real)
{
var parts = new List<string>();
if (claim.Tier != real.Tier) parts.Add(L.T("lbl.ev.build", L.T("lbl.tier." + real.Tier), Hardware.PowerPins[real.Tier], Hardware.FanCount[real.Tier]));
if (real.Serial != 0) parts.Add(L.T("lbl.ev.serial." + real.Serial));
if (real.Print != 0) parts.Add(L.T("lbl.ev.print." + real.Print));
return parts.Count == 0 ? L.T("lbl.ev.none") : L.T("lbl.ev.prefix") + string.Join(";", parts);
}
private static string DisplayModel(string model) => Items.DisplayModel(model);
private void OnRowButton(int row)
@@ -94,7 +94,6 @@ 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"
@@ -119,3 +118,12 @@ 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%."
lbl.row.spec,"Model authenticity"
lbl.hint,"Check: power connector and fan count, serial, back print"
lbl.ev.prefix,"Evidence: "
lbl.ev.none,"Everything matches the model"
lbl.ev.build,"Hardware is {0} ({1}-pin, {2} fans)"
lbl.ev.serial.1,"Serial: bad factory code or length"
lbl.ev.serial.2,"Serial: tier code does not match"
lbl.ev.print.1,"Print shows another model"
lbl.ev.print.2,"Print was redone"
1 # Probably Decentralized localization table: English (en)
94 cust.fake.2
95 cust.worn.1
96 cust.worn.2
lbl.row.spec
97 lbl.row.build
98 lbl.row.fan
99 lbl.row.fingers
118 lbl.tier.3
119 item.guide.name
120 item.guide.desc
121 lbl.row.spec
122 lbl.hint
123 lbl.ev.prefix
124 lbl.ev.none
125 lbl.ev.build
126 lbl.ev.serial.1
127 lbl.ev.serial.2
128 lbl.ev.print.1
129 lbl.ev.print.2
@@ -93,7 +93,6 @@ cust.fake.1,"这不是它标的那块。你拿假货糊弄我?"
cust.fake.2,"型号对不上,里面的芯片根本不是这个。"
cust.worn.1,"跟你写的不一样,毛病你没说。"
cust.worn.2,"标签上的成色是假的吧,这个价我不要。"
lbl.row.spec,"型号"
lbl.row.build,"供电与风扇"
lbl.row.fan,"叶片"
lbl.row.fingers,"金手指"
@@ -118,3 +117,12 @@ 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%。"
lbl.row.spec,"型号真伪"
lbl.hint,"依据:供电口与风扇数、序列号、背面丝印"
lbl.ev.prefix,"依据:"
lbl.ev.none,"各项依据都与型号相符"
lbl.ev.build,"实物是{0}({1} 针,{2} 风扇)"
lbl.ev.serial.1,"序列号工厂码或位数不合规"
lbl.ev.serial.2,"序列号档次码与型号不符"
lbl.ev.print.1,"丝印印着另一个型号"
lbl.ev.print.2,"丝印重印过"
1 # Probably Decentralized 本地化表:简体中文(zh)
93 cust.fake.2
94 cust.worn.1
95 cust.worn.2
lbl.row.spec
96 lbl.row.build
97 lbl.row.fan
98 lbl.row.fingers
117 lbl.tier.3
118 item.guide.name
119 item.guide.desc
120 lbl.row.spec
121 lbl.hint
122 lbl.ev.prefix
123 lbl.ev.none
124 lbl.ev.build
125 lbl.ev.serial.1
126 lbl.ev.serial.2
127 lbl.ev.print.1
128 lbl.ev.print.2
+1 -1
View File
@@ -370,7 +370,7 @@ internal static class Program
int ex2 = 0;
var honestUnit = new Unit { Model = "RZX70", Health = 60, Look = new CardLook { Fan = 1 } };
Check(CardLabels.Point(honestUnit, CardLabels.DealerClaim(honestUnit, DealerKind.Honest, new Rng(1)), CardLabels.RowFan, ref ex2) == 0, "老实人说的是实话,指出去没用");
Check(CardLabels.Lies(u, claim, 0) == (CardLabels.RowSpec | CardLabels.RowBuild | CardLabels.RowFan | CardLabels.RowFingers | CardLabels.RowPrint), "骗子隐瞒了型号、供电与风扇、风扇叶片、金手指、丝印");
Check(CardLabels.Lies(u, claim, 0) == (CardLabels.RowSpec | CardLabels.RowFan | CardLabels.RowFingers), "骗子隐瞒了型号、叶片、金手指");
Check(CardLabels.Lies(u, claim, ex) == 0, "指出之后不再算隐瞒");
Check(Claim.Decode(claim.Encode()).Encode() == claim.Encode(), "说法能存取");
});