Rig: game module bay with damped, capped effects

The rig gets the game's universal module bay (module adjacency included).
The machine's summed performance, efficiency and quality percentages are
divided by 4, like the ratios vanilla machines use, and capped: hashrate
at most +20%, power saving at most 25%, card wear at most -30%. Performance
also raises wear and burn-out chance by the same amount; negative
efficiency (overclock module, neural cores) raises power draw. Replaces the
planned mod-specific overclock module. Tested in game.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ZHU MINCHAOandClaude Opus 5.5 committed 2026-11-03 09:16:46 +08:00
1 parent 750b26e4b3
commit 79d4c686a0
9 files changed
+113 -44

No files matched your search

+42 -18
View File
@@ -120,9 +120,11 @@ namespace Decentralized
private static GameItem CreateRig()
{
var battery = new GameSlotInventory();
var modules = new GameGridInventory(MachineHelper.DEFAULT_MODULE_BAY_CONFIG, 7);
var cards = new GameGridInventory(2, 4);
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"));
var rig = ItemDirectory.CreateEmptyItem(Rig).SetContentWindow(window);
rig.SetSpriteAndShapeFromMod(ModInfo.Id, "rig");
@@ -132,41 +134,63 @@ namespace Decentralized
rig.EnableTag("CONTAINER_TAG");
rig.EnableTag("STANDARD_MACHINE_TAG");
MachineryHelper.InitMachinery(rig, Tuning.RigKj);
// 游戏的通用模块槽(含模块相邻效果);模块变动后游戏会按原版公式改写耗电,再由 UpdateRig 按本 mod 的规则重算
MachineHelper.SetupModuleBay(modules, rig, () => UpdateRig(rig, modules, cards));
cards.mayInventoryAddItemFunc = (item, _) => GeneralHelper.IsItemOwned(item) && IsGpu(item) && !item.IsTag(DeadTag);
cards.onSlotAddItemEndFunc = (_, _, _) => UpdateRig(rig, cards);
cards.onSlotRemoveItemEndFunc = (_, _, _) => UpdateRig(rig, cards);
rig.onLoaded = _ => UpdateRig(rig, cards);
rig.onCycleEndEarlySlotItemFunc = (_, _, _) => Log.Guard("矿架扣电", () => NightDraw(rig, battery, cards));
cards.onSlotAddItemEndFunc = (_, _, _) => UpdateRig(rig, modules, cards);
cards.onSlotRemoveItemEndFunc = (_, _, _) => UpdateRig(rig, modules, cards);
rig.onLoaded = _ => UpdateRig(rig, modules, cards);
rig.onCycleEndEarlySlotItemFunc = (_, _, _) => Log.Guard("矿架扣电", () => NightDraw(rig, battery, modules, cards));
ModHelper.SetSource(rig, ModInfo.Id, ModInfo.Name);
UpdateRig(rig, cards);
UpdateRig(rig, modules, cards);
return rig;
}
public static List<GameItem> Cards(GameInventory cards) => cards.childItems.Where(IsGpu).ToList();
private static int RigKj(GameInventory cards) =>
Tuning.RigKj + Mathf.CeilToInt((float)Cards(cards).Select(ToUnit).Sum(u => u.Kj(false)));
private static void UpdateRig(GameItem rig, GameInventory cards)
/// <summary>按模块槽里的模块重新汇总三项百分比(游戏自己的公式,含相邻效果),换算成本 mod 的模块效果。</summary>
public static ModuleBonus Bonus(GameItem rig, GameInventory modules)
{
int kj = RigKj(cards);
rig.ModifyTag(MachineryHelper.MACHINERY_DRAWN_POWER, s => s.Enable().SetInt(kj));
double hash = Cards(cards).Select(ToUnit).Sum(u => u.Hash(false));
rig.shortDescription = L.T("item.rig.desc", Fmt.Num(hash * 10), kj);
ModuleHelper.ComputeModuleEffect(modules.childItems, rig);
return ModuleBonus.From(
rig.GetTagReadonly(ModuleHelper.TOTAL_PERCENTAGE_PERFORMANCE_BONUS_INT).GetInt(),
rig.GetTagReadonly(ModuleHelper.TOTAL_PERCENTAGE_POWER_BONUS_INT).GetInt(),
rig.GetTagReadonly(ModuleHelper.TOTAL_PERCENTAGE_QUALITY_BONUS_INT).GetInt());
}
/// <summary>夜间早段:按矿架上的显卡总耗电从电池扣电;扣电成功,登记今晚参与挖矿的显卡。</summary>
private static void NightDraw(GameItem rig, GameSlotInventory battery, GameInventory cards)
private static int RigKj(GameInventory cards, ModuleBonus b) =>
Tuning.RigKj + Mathf.CeilToInt((float)Cards(cards).Select(ToUnit).Sum(u => u.Kj(b)));
private static void UpdateRig(GameItem rig, GameInventory modules, GameInventory cards)
{
var b = Bonus(rig, modules);
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);
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));
}
private static string Pct(double mult)
{
int p = (int)Math.Round((mult - 1) * 100);
return p > 0 ? "+" + p + "%" : p + "%";
}
/// <summary>夜间早段:按矿架上的显卡总耗电(含模块效果)从电池扣电;扣电成功,登记今晚参与挖矿的显卡和模块效果。</summary>
private static void NightDraw(GameItem rig, GameSlotInventory battery, GameInventory modules, GameInventory cards)
{
var list = Cards(cards).Where(c => !c.IsTag(DeadTag)).ToList();
Session.TonightRigs++;
if (list.Count == 0) return;
int kj = RigKj(cards);
var b = Bonus(rig, modules);
int kj = RigKj(cards, b);
if (battery.childItems.Count == 0 || !PowerHelper.DrawPowerSource(battery.childItem, kj)) return;
Session.TonightPoweredRigs++;
Session.TonightKj += kj;
Session.TonightCards.AddRange(list);
UpdateRig(rig, cards);
foreach (var c in list) Session.TonightCards.Add(new KeyValuePair<GameItem, ModuleBonus>(c, b));
UpdateRig(rig, modules, cards);
}
/// <summary>
@@ -7,6 +7,8 @@ item.terminal.name,Trading Terminal
item.terminal.desc,Wallet, 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."
rig.label.modules,Modules
item.rig.modules,"Modules: hashrate {0}, power draw {1}, wear {2}."
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)
7 item.terminal.desc
8 item.rig.name
9 item.rig.desc
10 rig.label.modules
11 item.rig.modules
12 rig.label.cards
13 item.gpu.name
14 item.gpu.desc
@@ -6,6 +6,8 @@ item.terminal.name,交易终端
item.terminal.desc,钱包、交易所与夜间挖矿报告。
item.rig.name,矿架
item.rig.desc,可装 4 张显卡。算力 {0} MH/s。耗电 {1} kJ/天。
rig.label.modules,模块
item.rig.modules,模块:算力 {0},耗电 {1},损耗 {2}。
rig.label.cards,显卡
item.gpu.name,{0} {1}
item.gpu.desc,算力 {0} MH/s。耗电 {1} kJ/天。健康度 {2}%。
1 # Probably Decentralized 本地化表:简体中文(zh)
6 item.terminal.desc,钱包、交易所与夜间挖矿报告。
7 item.rig.name,矿架
8 item.rig.desc,可装 4 张显卡。算力 {0} MH/s。耗电 {1} kJ/天。
9 rig.label.modules,模块
10 item.rig.modules,模块:算力 {0},耗电 {1},损耗 {2}。
11 rig.label.cards,显卡
12 item.gpu.name,{0} {1}
13 item.gpu.desc,算力 {0} MH/s。耗电 {1} kJ/天。健康度 {2}%。
+4 -4
View File
@@ -86,8 +86,8 @@ namespace Decentralized
d.ActiveEvents = events;
d.Network.Availability = (events.Contains(MarketEvent.Blackout) ? 0.8 : 1) * (events.Contains(MarketEvent.LowerUnrest) ? 0.9 : 1);
var units = Session.TonightCards.Select(c => (item: c, unit: Items.ToUnit(c))).ToList();
double hash = units.Sum(x => x.unit.Hash(false));
var units = Session.TonightCards.Select(c => (item: c.Key, unit: Items.ToUnit(c.Key), bonus: c.Value)).ToList();
double hash = units.Sum(x => x.unit.Hash(x.bonus));
double mined = d.Network.Mine(hash);
if (mined > 0) d.Hot.Add(Assets.PSC, mined);
@@ -96,9 +96,9 @@ namespace Decentralized
Day = day, Rigs = Session.TonightRigs, PoweredRigs = Session.TonightPoweredRigs, Kj = Session.TonightKj,
Hash = hash, NetworkHash = d.Network.NpcHash * d.Network.Availability + hash, Mined = mined,
};
foreach (var (item, unit) in units)
foreach (var (item, unit, bonus) in units)
{
bool died = unit.Night(false, d.Rng);
bool died = unit.Night(bonus, d.Rng);
Items.Store(item, unit);
if (died) report.Burnt.Add(item.name);
}
+1 -1
View File
@@ -37,7 +37,7 @@ namespace Decentralized
public static SaveData Data;
/// <summary>今晚有电的矿架上的显卡(矿架在夜间早段扣电时登记,结算时用)。</summary>
public static readonly List<GameItem> TonightCards = new List<GameItem>();
public static readonly List<KeyValuePair<GameItem, ModuleBonus>> TonightCards = new List<KeyValuePair<GameItem, ModuleBonus>>();
public static int TonightRigs, TonightPoweredRigs;
public static double TonightKj;