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>
141 lines
5.9 KiB
C#
141 lines
5.9 KiB
C#
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Decentralized.Domain;
|
|
|
|
namespace Decentralized
|
|
{
|
|
/// <summary>
|
|
/// 每天的推进:开门时日内波动和 NPC 大户;睡觉时(游戏 EndNight 的最后)挖矿、损耗与暴毙、全网、稳定币、行情结算,写晨间日志,存档。
|
|
/// 矿架自己在夜间早段扣电并登记显卡(Items.NightDraw),这里只结算。
|
|
/// </summary>
|
|
public static class Night
|
|
{
|
|
public static void Subscribe()
|
|
{
|
|
ModHook.OnShutterOpenedLate += OnOpen;
|
|
ModHook.OnGoingSleepEarly += OnSleepEarly;
|
|
ModHook.OnGoingSleepLate += OnSleepLate;
|
|
}
|
|
|
|
public static void Unsubscribe()
|
|
{
|
|
ModHook.OnShutterOpenedLate -= OnOpen;
|
|
ModHook.OnGoingSleepEarly -= OnSleepEarly;
|
|
ModHook.OnGoingSleepLate -= OnSleepLate;
|
|
}
|
|
|
|
private static bool Active => Session.Data != null && Unlock.IsUnlocked;
|
|
|
|
/// <summary>游戏新闻事件与派系行动 → 行情事件。</summary>
|
|
public static List<MarketEvent> ActiveEvents()
|
|
{
|
|
var list = new List<MarketEvent>();
|
|
var mgr = StoreStation.Instance?.storeEventManager;
|
|
if (mgr == null) return list;
|
|
foreach (var e in mgr.GetActiveEvents())
|
|
{
|
|
switch (e.identifier)
|
|
{
|
|
case "stationWideBlackout": case "powerShortage": case "powerPlantMaintenance": list.Add(MarketEvent.Blackout); break;
|
|
case "crackdown": case "sec_martial_law": list.Add(MarketEvent.Crackdown); break;
|
|
case "bm_gang_war": list.Add(MarketEvent.GangWar); break;
|
|
case "rev_raid_upper_level": list.Add(MarketEvent.RevRaidUpper); break;
|
|
case "ll_riot": case "ll_worker_strike": list.Add(MarketEvent.LowerUnrest); break;
|
|
}
|
|
}
|
|
return list.Distinct().ToList();
|
|
}
|
|
|
|
private static void OnOpen()
|
|
{
|
|
if (!Active) return;
|
|
Log.Guard("开门行情", () =>
|
|
{
|
|
var d = Session.Data;
|
|
int day = StoreStation.GetDayCounter();
|
|
d.Market.Open(ActiveEvents(), d.Rng, day);
|
|
d.Market.Whale(d.Rng);
|
|
if (!d.OpeningNewsShown)
|
|
{
|
|
News.Show("pd_news_open", L.T("news.open.title"), L.T("news.open.desc"), 2);
|
|
d.OpeningNewsShown = true;
|
|
}
|
|
Session.Save();
|
|
});
|
|
}
|
|
|
|
private static void OnSleepEarly()
|
|
{
|
|
Session.TonightCards.Clear();
|
|
Session.TonightRigs = Session.TonightPoweredRigs = 0;
|
|
Session.TonightKj = 0;
|
|
}
|
|
|
|
private static void OnSleepLate()
|
|
{
|
|
if (!Active) return;
|
|
Log.Guard("夜间结算", Settle);
|
|
}
|
|
|
|
private static void Settle()
|
|
{
|
|
var d = Session.Data;
|
|
int day = StoreStation.GetDayCounter();
|
|
var events = ActiveEvents();
|
|
foreach (var ev in events.Where(e => !d.ActiveEvents.Contains(e))) d.Stable.OnEventStart(ev, day, d.Rng);
|
|
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.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);
|
|
|
|
var report = new NightReport
|
|
{
|
|
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, bonus) in units)
|
|
{
|
|
bool died = unit.Night(bonus, d.Rng);
|
|
Items.Store(item, unit);
|
|
if (died) report.Burnt.Add(item.name);
|
|
}
|
|
|
|
double rewardBefore = d.Network.Reward;
|
|
d.Network.Night(day, d.Market.Price, hash);
|
|
if (d.Network.Reward < rewardBefore) News.Show("pd_news_halving_" + day, L.T("news.halving.title"), L.T("news.halving.desc"), 2);
|
|
double crcFactor = d.Stable.Night(day, d.Rng, 0);
|
|
if (crcFactor < 1) d.Hot.Balances[Assets.CRC] = d.Hot.Get(Assets.CRC) * crcFactor;
|
|
d.Market.Night(events, d.Rng, day, Session.Price);
|
|
report.Price = d.Market.Price;
|
|
d.LastNight = report;
|
|
d.Day = day;
|
|
|
|
var ps = PlayerStore.Instance;
|
|
if (mined > 0) ps.AddNightLog(L.T("nightlog.mined", Fmt.Num(mined)));
|
|
foreach (var name in report.Burnt) ps.AddNightLog(L.T("nightlog.burnt", name), "cc7755");
|
|
int unpowered = report.Rigs - report.PoweredRigs;
|
|
if (unpowered > 0 && units.Count + unpowered > 0) ps.AddNightLog(L.T("nightlog.unpowered", unpowered), "cc7755");
|
|
Session.Save();
|
|
}
|
|
}
|
|
|
|
/// <summary>mod 新闻:不带价格修正的新闻事件,和原版新闻一样出现在报纸上。</summary>
|
|
public static class News
|
|
{
|
|
public static void Show(string id, string title, string text, int days)
|
|
{
|
|
var mgr = StoreStation.Instance?.storeEventManager;
|
|
if (mgr == null || mgr.IsEventActive(id)) return;
|
|
mgr.ActivateEvent(new StoreEvent
|
|
{
|
|
identifier = id, newsName = title, displayName = title, newsDescription = text,
|
|
duration = days, eventType = StoreEvent.EventType.COSMETIC, eventArea = StoreEvent.EventArea.ALL,
|
|
importance = 2, cooldown = 0, negociationDatas = new List<NegociationData>(),
|
|
});
|
|
}
|
|
}
|
|
}
|