Terminal and graphics cards redrawn; rig slots 2 to 5 with electronics

Terminal: monitor with a top face and a trapezoid keyboard. Graphics card:
a metal bracket with ports, two fans, brand stripe, gold fingers with a PCIe
notch and power connectors on top, now 2x2 cells. Rig: two slots by default,
an upgrade slot that takes the next level's electronics (4 common, 1 rare,
2 rare) and consumes them at once; the card grid reshapes with the slot
count, which is kept on the rig's tags. Verified in game, including the
slot limit, the upgrade items, five cards, and save and reload.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
ZHU MINCHAOandClaude Sonnet 5.5 committed 2026-11-03 10:18:19 +08:00
1 parent 9d51c74f56
commit 3a4572efb6
12 files changed
+252 -40

No files matched your search

+58
View File
@@ -0,0 +1,58 @@
using System;
namespace Decentralized.Domain
{
/// <summary>
/// 矿架的显卡槽:默认 2 个,投入电子元件逐个升级,最多 5 个。每张显卡占 2×2 格,槽在矿架窗口里是一列 2 格宽的格子,
/// 每个槽两行;未解锁的行是不可放的格子。游戏里电子元件的价值是 33 / 350 / 2,500(普通 / 稀有 / 超科技)。
/// </summary>
public static class RigSlots
{
public const int Base = 2, Max = 5;
public const int CellWidth = 2, CellsPerSlot = 2;
/// <summary>升级到第 n 个槽需要的电子元件(物品 id,件数)。n 从 3 开始。</summary>
public static (string Item, int Count) Cost(int slot)
{
switch (slot)
{
case 3: return ("common_electronic", 4);
case 4: return ("rare_electronic", 1);
case 5: return ("rare_electronic", 2);
default: throw new ArgumentOutOfRangeException(nameof(slot));
}
}
/// <summary>当前槽数下,下一次升级需要什么;已满时返回 null。</summary>
public static (string Item, int Count)? Next(int slots) => slots >= Max ? ((string, int)?)null : Cost(slots + 1);
/// <summary>
/// 投入 count 件 item:只收下一级需要的那种;累计到够用就解锁一个槽,多出的留作下一级进度(若下一级是同一种元件)。
/// 返回实际收下的件数;其余退回(不收)。
/// </summary>
public static int Insert(ref int slots, ref int progress, string item, int count)
{
if (slots >= Max || count <= 0) return 0;
var need = Cost(slots + 1);
if (item != need.Item) return 0;
int take = Math.Min(count, need.Count - progress);
progress += take;
if (progress >= need.Count)
{
slots++;
progress = 0;
}
return take;
}
/// <summary>显卡格子的形状字符串:宽 2,高 2 × 最大槽数;前 slots × 2 行可放(0),其余不可放(1)。</summary>
public static string Shape(int slots)
{
var sb = new System.Text.StringBuilder();
for (int row = 0; row < Max * CellsPerSlot; row++)
for (int col = 0; col < CellWidth; col++)
sb.Append(row < slots * CellsPerSlot ? '0' : '1');
return sb.ToString();
}
}
}
+1 -1
View File
@@ -15,7 +15,7 @@ namespace Decentralized.Domain
public const double NpcTargetRatio = 3.5;
public const double NpcAdj = 0.05;
public const double PoolFee = 0.03;
public const int RigPrice = 400, RigKj = 2, RigSlots = 4;
public const int RigPrice = 400, RigKj = 2;
/// <summary>矿架上模块百分比的折算系数(原版机器用 2–4),以及各项上限。</summary>
public const double ModuleRatio = 4, ModuleHashCap = 0.20, ModuleKjCap = 0.25, ModuleWearCap = 0.30;
public const double DeathBase = 0.001, DeathWorn = 0.03, FakeDeathFactor = 2;
+53 -4
View File
@@ -117,15 +117,22 @@ namespace Decentralized
// ---------- 矿架 ----------
public const string SlotsTag = "PD_SLOTS", ProgressTag = "PD_SLOT_PROGRESS";
private static int SlotsOf(GameItem rig) => rig.IsTag(SlotsTag) ? rig.GetTagReadonly(SlotsTag).GetInt() : RigSlots.Base;
private static GameItem CreateRig()
{
var battery = new GameSlotInventory();
var upgrade = new GameSlotInventory();
var modules = new GameGridInventory(MachineHelper.DEFAULT_MODULE_BAY_CONFIG, 7);
var cards = new GameGridInventory(2, 4);
// 显卡每张 2×2 格:一列 2 格宽的格子,每个槽两行;未解锁的行不可放
var cards = new GameGridInventory(RigSlots.Shape(RigSlots.Base), RigSlots.CellWidth);
var window = MachineHelper.CreateMachineryWindow(true,
MachineHelper.PowerPanel(battery),
MachineHelper.Panel(L.T("rig.label.modules"), modules, "module"),
MachineHelper.Panel(L.T("rig.label.cards"), cards, "cards"));
MachineHelper.Panel(L.T("rig.label.cards"), cards, "cards"),
MachineHelper.Panel(L.T("rig.label.upgrade"), upgrade, "upgrade"));
var rig = ItemDirectory.CreateEmptyItem(Rig).SetContentWindow(window);
rig.SetSpriteAndShapeFromMod(ModInfo.Id, "rig");
rig.name = L.T("item.rig.name");
@@ -139,13 +146,48 @@ namespace Decentralized
cards.mayInventoryAddItemFunc = (item, _) => GeneralHelper.IsItemOwned(item) && IsGpu(item) && !item.IsTag(DeadTag);
cards.onSlotAddItemEndFunc = (_, _, _) => UpdateRig(rig, modules, cards);
cards.onSlotRemoveItemEndFunc = (_, _, _) => UpdateRig(rig, modules, cards);
rig.onLoaded = _ => UpdateRig(rig, modules, cards);
// 升级槽:只收下一级需要的电子元件,放进去立刻投入(计入进度),攒够解锁一个显卡槽
upgrade.mayInventoryAddItemFunc = (item, _) =>
{
var need = RigSlots.Next(SlotsOf(rig));
return GeneralHelper.IsItemOwned(item) && need != null && item.identifier == need.Value.Item;
};
upgrade.onSlotAddItemEndFunc = (item, _, _) => Log.Guard("矿架升级槽位", () => TakeUpgrade(rig, upgrade, cards, modules, item));
rig.onLoaded = _ => { ApplySlots(rig, cards); UpdateRig(rig, modules, cards); };
rig.onCycleEndEarlySlotItemFunc = (_, _, _) => Log.Guard("矿架扣电", () => NightDraw(rig, battery, modules, cards));
ModHelper.SetSource(rig, ModInfo.Id, ModInfo.Name);
ApplySlots(rig, cards);
UpdateRig(rig, modules, cards);
return rig;
}
/// <summary>按标签里的槽数设置显卡格子的形状(游戏自己扩展模块槽也是 SetShape 加 Validate)。</summary>
private static void ApplySlots(GameItem rig, GameGridInventory cards)
{
cards.SetShape(RigSlots.Shape(SlotsOf(rig)), RigSlots.CellWidth);
rig.contentWindow?.Validate();
}
private static void TakeUpgrade(GameItem rig, GameSlotInventory upgradeSlot, GameGridInventory cards, GameInventory modules, GameItem item)
{
int slots = SlotsOf(rig);
int progress = rig.IsTag(ProgressTag) ? rig.GetTagReadonly(ProgressTag).GetInt() : 0;
int before = slots;
int took = RigSlots.Insert(ref slots, ref progress, item.identifier, item.unitCount);
if (took <= 0) return;
rig.ModifyTag(SlotsTag, s => s.Enable().SetInt(slots));
rig.ModifyTag(ProgressTag, s => s.Enable().SetInt(progress));
// 消耗收下的件数;放不下的部分留在升级槽里(玩家取回)
if (took >= item.unitCount) { upgradeSlot.Expel(item); item.Destroy(); }
else item.GetSplitItem(took).Destroy();
if (slots != before)
{
ApplySlots(rig, cards);
EmporiumAudioPlayer.Instance?.ratchet?.Play();
}
UpdateRig(rig, (GameGridInventory)modules, cards);
}
public static List<GameItem> Cards(GameInventory cards) => cards.childItems.Where(IsGpu).ToList();
/// <summary>按模块槽里的模块重新汇总三项百分比(游戏自己的公式,含相邻效果),换算成本 mod 的模块效果。</summary>
@@ -167,7 +209,14 @@ namespace Decentralized
int kj = RigKj(cards, b);
rig.ModifyTag(MachineryHelper.MACHINERY_DRAWN_POWER, s => s.Enable().SetInt(kj));
double hash = Cards(cards).Select(ToUnit).Sum(u => u.Hash(b));
rig.shortDescription = L.T("item.rig.desc", Fmt.Num(hash * 10), kj);
int slots = SlotsOf(rig);
rig.shortDescription = L.T("item.rig.desc", slots, Fmt.Num(hash * 10), kj);
var next = RigSlots.Next(slots);
if (next != null)
{
int progress = rig.IsTag(ProgressTag) ? rig.GetTagReadonly(ProgressTag).GetInt() : 0;
rig.shortDescription += " " + L.T("item.rig.next", slots + 1, L.T("mat." + next.Value.Item), progress, next.Value.Count);
}
if (b.Hash != 1 || b.Kj != 1 || b.Wear != 1)
rig.shortDescription += " " + L.T("item.rig.modules", Pct(b.Hash), Pct(b.Kj), Pct(b.Wear));
}
@@ -5,9 +5,13 @@ upgrade.desc,Members receive a trading terminal and an RZX 50 graphics card. The
item.terminal.name,Trading Terminal
item.terminal.desc,Wallet, the Poinbase exchange and the nightly mining report.
item.rig.name,Mining Rig
item.rig.desc,"Holds up to four graphics cards. Hashrate {0} MH/s. Draws {1} kJ per day."
item.rig.desc,"Holds up to {0} graphics cards. Hashrate {1} MH/s. Draws {2} kJ per day."
rig.label.modules,Modules
item.rig.modules,"Modules: hashrate {0}, power draw {1}, wear {2}."
rig.label.upgrade,Upgrade slot
item.rig.next,"Slot {0}: put in {1} ({2}/{3})."
mat.common_electronic,Common electronics
mat.rare_electronic,Rare electronics
rig.label.cards,Graphics cards
item.gpu.name,{0} {1}
item.gpu.desc,"Hashrate {0} MH/s. Draws {1} kJ per day. Condition {2}%."
1 # Probably Decentralized localization table: English (en)
5 item.terminal.name
6 item.terminal.desc
7 item.rig.name
8 item.rig.desc
9 rig.label.modules
10 item.rig.modules
11 rig.label.upgrade
12 item.rig.next
13 mat.common_electronic
14 mat.rare_electronic
15 rig.label.cards
16 item.gpu.name
17 item.gpu.desc
@@ -4,9 +4,13 @@ upgrade.desc,成员可获得一台交易终端和一张 RZX 50 显卡。终端
item.terminal.name,交易终端
item.terminal.desc,钱包、Poinbase 交易所与夜间挖矿报告。
item.rig.name,矿架
item.rig.desc,可装 4 张显卡。算力 {0} MH/s。耗电 {1} kJ/天。
item.rig.desc,最多装 {0} 张显卡。算力 {1} MH/s。耗电 {2} kJ/天。
rig.label.modules,模块
item.rig.modules,模块:算力 {0},耗电 {1},损耗 {2}。
rig.label.upgrade,升级槽位
item.rig.next,第 {0} 槽:投入{1}({2}/{3})。
mat.common_electronic,普通电子元件
mat.rare_electronic,稀有电子元件
rig.label.cards,显卡
item.gpu.name,{0} {1}
item.gpu.desc,算力 {0} MH/s。耗电 {1} kJ/天。健康度 {2}%。
1 # Probably Decentralized 本地化表:简体中文(zh)
4 item.terminal.name,交易终端
5 item.terminal.desc,钱包、Poinbase 交易所与夜间挖矿报告。
6 item.rig.name,矿架
7 item.rig.desc,可装 4 张显卡。算力 {0} MH/s。耗电 {1} kJ/天。 item.rig.desc,最多装 {0} 张显卡。算力 {1} MH/s。耗电 {2} kJ/天。
8 rig.label.modules,模块
9 item.rig.modules,模块:算力 {0},耗电 {1},损耗 {2}。
10 rig.label.upgrade,升级槽位
11 item.rig.next,第 {0} 槽:投入{1}({2}/{3})。
12 mat.common_electronic,普通电子元件
13 mat.rare_electronic,稀有电子元件
14 rig.label.cards,显卡
15 item.gpu.name,{0} {1}
16 item.gpu.desc,算力 {0} MH/s。耗电 {1} kJ/天。健康度 {2}%。
Binary file not shown.

Before

Width:  |  Height:  |  Size: 229 B

After

Width:  |  Height:  |  Size: 375 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 185 B

After

Width:  |  Height:  |  Size: 329 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 185 B

After

Width:  |  Height:  |  Size: 328 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 229 B

After

Width:  |  Height:  |  Size: 259 B