using System;
using System.Collections.Generic;
using UnityEngine;
namespace Decentralized
{
///
/// 借用原版小偷灯招揽换币客户:在原版小偷灯的工厂外包一层,切换顺序末尾加一个目标"换币客户"(解锁换币台后才有)。
/// 原版按灯的目标去公开的顾客表()里造顾客,所以顾客面板、灯的提示、概率都走原版逻辑。
/// 霓虹色:底图换成原版图集里熄灭的暗灯(存档里记的仍是原版的图,卸载后不缺图),上面用原版的图片叠加层
/// (getItemSpriteModifierForItemFunc,运行时委托,不进存档)画黄绿色光晕。原版遇到不认识的目标会点亮成第一种颜色,我们排在它后面改回熄灭的底图。
/// 切换只接管进出我们目标的那一步,其余交给原来的切换函数,别的 mod 往灯上加的目标也照样能切到。
///
public static class OtcLamp
{
/// 灯的目标 = 顾客表里的顾客标识。
public const string Target = "pd_otc";
private const string OverlaySprite = "otc_lamp_on";
/// 原版暗灯所在的图集与熄灭时的图(BlackLampHelper 里是私有常量)。
private const string LampAtlas = "Items/items_sign", LampOff = "black_lamp";
private static readonly Action OnShowcaseChanged = (item, _, __) => Log.Guard("展示柜刷新换币灯", () => Refresh(item));
public static bool IsLamp(GameItem item) => item != null && item.identifier == BlackLampHelper.BLACK_LAMP_ID;
public static bool IsOurs(GameItem item) => IsLamp(item) && BlackLampHelper.GetTarget(item) == Target;
/// 在原版小偷灯的工厂外包一层(物品目录初始化时)。
public static void Wrap(ModItemDirectory dir)
{
try
{
var make = DirectoryMaster.GetFactory(BlackLampHelper.BLACK_LAMP_ID);
if (make == null) { Log.Warn("[OTC] 找不到原版小偷灯"); return; }
dir.Set(BlackLampHelper.BLACK_LAMP_ID, () =>
{
var lamp = make();
var prev = lamp.onActivateSlotItemFunc;
lamp.onActivateSlotItemFunc = (it, inv, slot) => Log.Guard("小偷灯切换", () => Cycle(it, inv, slot, prev));
var prevSprites = lamp.getItemSpriteModifierForItemFunc;
lamp.getItemSpriteModifierForItemFunc = it => Overlay(it, prevSprites);
return lamp;
});
Log.Info("[OTC] 已包装原版小偷灯");
}
catch (Exception ex) { Log.Error("[OTC] 包装小偷灯失败:" + ex); }
}
///
/// 切换:当前是"换币客户"时回到原版第一个目标;否则先走原来的切换,原来的切换绕回第一个目标、而且换币台已解锁时,改成"换币客户"。
///
private static void Cycle(GameItem lamp, GameInventory inv, SlotMarker slot, Action prev)
{
string first = BlackLampHelper.TARGETS[0];
if (IsOurs(lamp))
{
SetTarget(lamp, first);
BlackLampHelper.RefreshLampSprite(lamp);
AudioManager.Instance.Play2("click_vintage");
}
else
{
string before = BlackLampHelper.GetTarget(lamp);
prev?.Invoke(lamp, inv, slot);
if (Unlock.OtcUnlocked && before != first && BlackLampHelper.GetTarget(lamp) == first) SetTarget(lamp, Target);
}
Refresh(lamp);
}
public static void SetTarget(GameItem lamp, string target) => lamp.ModifyTag(BlackLampHelper.LAMP_TARGET_TAG, s => { s.Enable().SetString(target); });
/// 目标是"换币客户"、而且灯在展示柜里时,叠一层霓虹灯图(盖住原版退回的点亮图)。
private static List Overlay(GameItem lamp, Func> prev)
{
var list = prev?.Invoke(lamp) ?? new List();
if (IsOurs(lamp) && InShowcase(lamp))
{
var sprite = Items.ModSprite(OverlaySprite);
if (sprite != null) list.Add(new ItemSpriteModifier(sprite, Vector2.zero, 0, isFlipped: false, 10, haveMask: false, Color.white));
}
return list;
}
private static bool InShowcase(GameItem item)
{
var sc = EmporiumEntry.Instance?.showcaseElement;
return sc != null && sc.childItems.Contains(item);
}
/// 换币灯在展示柜里:底图改成熄灭的暗灯(光晕由叠加层画);然后重画。
private static void Refresh(GameItem item)
{
if (!IsLamp(item)) return;
if (IsOurs(item) && InShowcase(item)) item.SetSpriteQuick(LampAtlas, LampOff);
item.Validate();
}
///
/// 读档、开新游戏后:在展示柜的放入、取出回调后面挂上刷新(原版在这两个回调里重设灯的底图,我们排在它后面重画叠加层),
/// 先解绑再挂,避免读档几次挂几次;再把展示柜里的灯刷新一遍。
///
public static void Attach()
{
var sc = EmporiumEntry.Instance?.showcaseElement;
if (sc == null) return;
sc.onSlotAddItemLateFunc = (Action)Delegate.Remove(sc.onSlotAddItemLateFunc, OnShowcaseChanged);
sc.onSlotAddItemLateFunc = (Action)Delegate.Combine(sc.onSlotAddItemLateFunc, OnShowcaseChanged);
sc.onSlotRemoveItemEndFunc = (Action)Delegate.Remove(sc.onSlotRemoveItemEndFunc, OnShowcaseChanged);
sc.onSlotRemoveItemEndFunc = (Action)Delegate.Combine(sc.onSlotRemoveItemEndFunc, OnShowcaseChanged);
foreach (var item in sc.childItems) Refresh(item);
}
}
}