145 lines
7.2 KiB
C#
145 lines
7.2 KiB
C#
using System;
|
|||
|
|
using System.Collections.Generic;
|
||
|
|
using System.Linq;
|
||
|
|
using Decentralized.Domain;
|
||
|
|
using UnityEngine;
|
||
|
|
|
||
|
|
namespace Decentralized
|
||
|
|
{
|
||
|
|
/// <summary>
|
||
|
|
/// RatDigg 矿机(M1 / M2 / M3):独立的机器,窗口里有电池槽、模块槽(和矿架同一套效果)和修理槽,没有显卡槽。
|
||
|
|
/// 夜间和矿架一样先从电池扣电、有电才挖;损耗与暴毙沿用 <see cref="Unit"/>(暴毙系数 0.5,每天损耗 0.8)。
|
||
|
|
/// 暴毙后成了"损坏的矿机":往修理槽里按顺序放电子元件修好(见 <see cref="AsicRepair"/>),健康扣 20 点。
|
||
|
|
/// </summary>
|
||
|
|
public static class AsicItems
|
||
|
|
{
|
||
|
|
public const string Prefix = "pd_asic_";
|
||
|
|
public const string StepTag = "PD_REPAIR_STEP", ProgTag = "PD_REPAIR_PROG";
|
||
|
|
|
||
|
|
public static string Id(string model) => Prefix + model.ToLowerInvariant();
|
||
|
|
public static bool Is(GameItem it) => it != null && it.identifier != null && it.identifier.StartsWith(Prefix);
|
||
|
|
|
||
|
|
public static void Register(ModItemDirectory dir)
|
||
|
|
{
|
||
|
|
foreach (var spec in Hardware.Specs.Values.Where(s => s.Asic))
|
||
|
|
{
|
||
|
|
var s = spec;
|
||
|
|
dir.Add(Id(s.Model), () => Create(s));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private static int Step(GameItem m) => m.IsTag(StepTag) ? m.GetTagReadonly(StepTag).GetInt() : 0;
|
||
|
|
private static int Prog(GameItem m) => m.IsTag(ProgTag) ? m.GetTagReadonly(ProgTag).GetInt() : 0;
|
||
|
|
|
||
|
|
private static GameItem Create(HardwareSpec spec)
|
||
|
|
{
|
||
|
|
var battery = new GameSlotInventory();
|
||
|
|
var repair = new GameSlotInventory();
|
||
|
|
var modules = new GameGridInventory(MachineHelper.DEFAULT_MODULE_BAY_CONFIG, 7);
|
||
|
|
var window = MachineHelper.CreateMachineryWindow(true,
|
||
|
|
MachineHelper.PowerPanel(battery),
|
||
|
|
MachineHelper.Panel(L.T("rig.label.modules"), modules, "module"),
|
||
|
|
MachineHelper.Panel(L.T("asic.label.repair"), repair, "upgrade"));
|
||
|
|
var m = ItemDirectory.CreateEmptyItem(Id(spec.Model)).SetContentWindow(window);
|
||
|
|
m.SetSpriteAndShapeFromMod(ModInfo.Id, "asic_" + spec.Model.ToLowerInvariant());
|
||
|
|
m.name = L.T("item.asic.name", spec.Model);
|
||
|
|
m.unitValue = spec.Price;
|
||
|
|
MachineHelper.SetupBatterySlot(battery, m);
|
||
|
|
m.EnableTag("CONTAINER_TAG");
|
||
|
|
m.EnableTag("STANDARD_MACHINE_TAG");
|
||
|
|
MachineryHelper.InitMachinery(m, (int)Math.Ceiling(spec.Kj));
|
||
|
|
MachineHelper.SetupModuleBay(modules, m, () => Update(m, modules));
|
||
|
|
repair.mayInventoryAddItemFunc = (it, _) =>
|
||
|
|
{
|
||
|
|
var u = Items.ToUnit(m);
|
||
|
|
var need = AsicRepair.Need(u.Model, Step(m));
|
||
|
|
return GeneralHelper.IsItemOwned(it) && u.Dead && need != null && it.identifier == need.Value.Item;
|
||
|
|
};
|
||
|
|
repair.onSlotAddItemEndFunc = (it, _, _) => Log.Guard("矿机修理", () => TakeRepair(m, repair, modules, it));
|
||
|
|
m.onLoaded = _ => Update(m, modules);
|
||
|
|
m.onCycleEndEarlySlotItemFunc = (_, _, _) => Log.Guard("矿机扣电", () => NightDraw(m, battery, modules));
|
||
|
|
ModHelper.SetSource(m, ModInfo.Id, ModInfo.Name);
|
||
|
|
Update(m, modules);
|
||
|
|
return m;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>名字、说明、价值与耗电(耗电按模块效果重算)。</summary>
|
||
|
|
private static void Update(GameItem m, GameInventory modules)
|
||
|
|
{
|
||
|
|
var u = Items.ToUnit(m);
|
||
|
|
var b = Items.Bonus(m, modules);
|
||
|
|
int baseKj = (int)Math.Ceiling(u.Label.Kj);
|
||
|
|
m.ModifyTag("MACHINERY_DRAWN_POWER_BASE", s => s.Enable().SetInt(baseKj));
|
||
|
|
m.ModifyTag(MachineryHelper.MACHINERY_DRAWN_POWER, s => s.Enable().SetInt(u.Dead ? 0 : (int)Math.Ceiling(u.Kj(b))));
|
||
|
|
Describe(m, u);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>按标签刷新名字、说明、价值(夜间损耗之后也走这里)。</summary>
|
||
|
|
public static void Refresh(GameItem m) => Describe(m, Items.ToUnit(m));
|
||
|
|
|
||
|
|
private static void Describe(GameItem m, Unit u)
|
||
|
|
{
|
||
|
|
var spec = u.Label;
|
||
|
|
m.name = L.T(u.Dead ? "item.asic.dead.name" : "item.asic.name", spec.Model);
|
||
|
|
if (u.Dead)
|
||
|
|
{
|
||
|
|
var need = AsicRepair.Need(u.Model, Step(m));
|
||
|
|
m.shortDescription = need == null ? L.T("item.asic.dead.fixed") : L.T("item.asic.dead.desc", L.T("mat." + need.Value.Item), need.Value.Count - Prog(m));
|
||
|
|
m.unitValue = Math.Max(1, (long)Math.Round(spec.Price * Tuning.AsicDeadValue));
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
string cond = GeneralHelper.IsItemOwned(m)
|
||
|
|
? Mathf.RoundToInt((float)u.Health) + "%"
|
||
|
|
: L.T(u.Health >= 85 ? "item.gpu.grade.1" : u.Health >= 60 ? "item.gpu.grade.2" : u.Health >= 35 ? "item.gpu.grade.3" : "item.gpu.grade.4");
|
||
|
|
m.shortDescription = L.T("item.asic.desc", Fmt.Num(spec.DisplayHash), Fmt.Num(spec.Kj), cond);
|
||
|
|
m.unitValue = CardValue.Of(spec.Model, u.Health);
|
||
|
|
}
|
||
|
|
|
||
|
|
private static void NightDraw(GameItem m, GameSlotInventory battery, GameInventory modules)
|
||
|
|
{
|
||
|
|
var u = Items.ToUnit(m);
|
||
|
|
Session.TonightRigs++;
|
||
|
|
if (u.Dead) return;
|
||
|
|
var b = Items.Bonus(m, modules);
|
||
|
|
int kj = (int)Math.Ceiling(u.Kj(b));
|
||
|
|
if (battery.childItems.Count == 0 || !PowerHelper.DrawPowerSource(battery.childItem, kj)) return;
|
||
|
|
Session.TonightPoweredRigs++;
|
||
|
|
Session.TonightKj += kj;
|
||
|
|
Session.TonightCards.Add(new KeyValuePair<GameItem, ModuleBonus>(m, b));
|
||
|
|
Update(m, modules);
|
||
|
|
}
|
||
|
|
|
||
|
|
private static void TakeRepair(GameItem m, GameSlotInventory slot, GameInventory modules, GameItem item)
|
||
|
|
{
|
||
|
|
var u = Items.ToUnit(m);
|
||
|
|
if (!u.Dead) return;
|
||
|
|
int step = Step(m), prog = Prog(m);
|
||
|
|
int took = AsicRepair.Insert(u.Model, ref step, ref prog, item.identifier, item.unitCount);
|
||
|
|
if (took <= 0) return;
|
||
|
|
m.ModifyTag(StepTag, s => s.Enable().SetInt(step));
|
||
|
|
m.ModifyTag(ProgTag, s => s.Enable().SetInt(prog));
|
||
|
|
if (took >= item.unitCount) { slot.Expel(item); item.Destroy(); }
|
||
|
|
else item.GetSplitItem(took).Destroy();
|
||
|
|
if (AsicRepair.Done(u.Model, step))
|
||
|
|
{
|
||
|
|
u.Dead = false;
|
||
|
|
u.Health = Math.Max(10, u.Health - Tuning.AsicRepairHealthCut);
|
||
|
|
m.ModifyTag(Items.DeadTag, s => s.Disable());
|
||
|
|
m.ModifyTag(StepTag, s => s.Enable().SetInt(0));
|
||
|
|
m.ModifyTag(ProgTag, s => s.Enable().SetInt(0));
|
||
|
|
Items.Store(m, u);
|
||
|
|
EmporiumAudioPlayer.Instance?.ratchet?.Play();
|
||
|
|
Log.Info($"矿机 {u.Model} 修好了,健康 {u.Health:0}");
|
||
|
|
}
|
||
|
|
Update(m, modules);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>造一台矿机:按健康度写标签。</summary>
|
||
|
|
public static GameItem New(string model, double health)
|
||
|
|
{
|
||
|
|
var item = ModHelper.SpawnItem(Id(model));
|
||
|
|
Items.Store(item, new Unit { Model = model, Health = health });
|
||
|
|
return item;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|