Files
probably-decentralized/src/Decentralized/Night.cs
T

140 lines
5.9 KiB
C#
Raw Normal View History

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>(),
});
}
}
}