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

152 lines
9.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Collections.Generic;
using System.Linq;
using Decentralized.Domain;
namespace Decentralized
{
/// <summary>
/// 用币付款的顾客:每天排队的买家里,按派系(上层 CRC、黑市 CRT、革命派 CRA、下层 PSC)有一小部分改用币结算。
/// 成交时在店里扣回刚入账的信用点,换成币进热钱包;赃物的款项不记销赃,改成币带污点(货值 × 赃物热度%)。
/// </summary>
public static class CoinCustomers
{
private static readonly HashSet<StoreClient> Marked = new HashSet<StoreClient>();
private static int markDay = -1;
public static void Subscribe()
{
ModHook.OnGenerateCustomerLate += OnGenerate;
ModHelper.AddDebugFunction(ModInfo.Id, ModInfo.Name, "Run night (test)", () => Log.Guard("过夜(测试)", () =>
{
// 走游戏自己的夜间流程(EndNight 会触发本 mod 的夜间结算),再进下一天并开门前的日程
// 游戏过夜会清空前柜台,先把自己的东西收进物品栏
foreach (var it in EmporiumEntry.Instance.frontInvinvElement.childItems.ToList())
if (GeneralHelper.IsItemOwned(it)) GraphUtils.TryAcceptAll(EmporiumEntry.Instance.invElement, it);
PlayerStore.Instance.EndNight();
StoreStation.Instance.storeEventManager.OnDayEnd(); // 让事件按天数过期
StoreStation.Instance.StartDay();
Log.Info($"过夜完成,现在是第 {StoreStation.GetDayCounter()} 天");
}));
ModHelper.AddDebugFunction(ModInfo.Id, ModInfo.Name, "Morning report (test)", () => Log.Guard("晨间日志(测试)", () => StartOfDayUIManager.Instance.ShowMorningReport()));
ModHelper.AddDebugFunction(ModInfo.Id, ModInfo.Name, "Newspaper (test)", () => Log.Guard("报纸(测试)", () => NewsUIManager.Instance.ToggleUI()));
ModHelper.AddDebugFunction(ModInfo.Id, ModInfo.Name, "Start crackdown (test)", () => Log.Guard("镇压(测试)", () =>
{
StoreStation.Instance.storeEventManager.ActivateEvent(OperationListSec.Crackdown());
Log.Info("镇压事件已激活");
}));
ModHelper.AddDebugFunction(ModInfo.Id, ModInfo.Name, "Frozen CRT (test)", () => Log.Guard("冻结 CRT(测试)", () =>
{
var w = Session.Data.Hot;
w.Add(Assets.CRT, 1000);
double f = w.Freeze(Assets.CRT, Tuning.CrtFreezeShare, StoreStation.GetDayCounter() + Tuning.CrtUnfreezeAfter);
Log.Info($"CRT {w.Get(Assets.CRT):0},冻结 {f:0},可动用 {w.Avail(Assets.CRT):0}");
}));
ModHelper.AddDebugFunction(ModInfo.Id, ModInfo.Name, "Tainted wallet (test)", () => Log.Guard("带污点的钱包(测试)", () =>
{
var w = Session.Data.Hot;
w.Add(Assets.PSC, 100); w.Add(Assets.CRT, 1000); w.Taint += 3000; w.Basis += 2000;
Log.Info($"钱包:PSC {w.Get(Assets.PSC):0.##},污点 {w.Taint:0}");
}));
ModHelper.AddDebugFunction(ModInfo.Id, ModInfo.Name, "Terminal (test)", () => Log.Guard("终端(测试)", TerminalWindow.Open));
ModHelper.AddDebugFunction(ModInfo.Id, ModInfo.Name, "Black market +50 rep, restock (test)", () => Log.Guard("黑市(测试)", () =>
{
StoreReputation.ModReputation("FACTION_BLACK_MARKET", 50);
if (!Unlock.IsUnlocked) ModHelper.GetNetworkUpgrade(Unlock.Id)?.Unlock();
if (!Unlock.BlackUnlocked) ModHelper.GetNetworkUpgrade(Unlock.BlackId)?.Unlock();
var d = Session.Data;
d.Hot.Add(Assets.PSC, 20); d.Hot.Add(Assets.CRT, 3000); d.Hot.Taint += 2000; d.Hot.Basis += 1000;
BlackDelivery.Restock(d, StoreStation.GetDayCounter(), true);
Log.Info($"黑市:声望 {StoreReputation.GetBMReputation()},上架 {d.Black.Offers.Count} 种:{string.Join(", ", d.Black.Offers.Select(o => o.Item + "×" + o.Qty + "@" + o.Price))},解锁 {Unlock.BlackUnlocked}");
}));
ModHelper.AddDebugFunction(ModInfo.Id, ModInfo.Name, "Courier (test)", () => Log.Guard("黑市快递(测试)", () =>
{
foreach (var o in Session.Data.Black.Orders.Where(x => x.State == OrderState.Pending)) { o.State = OrderState.Ready; }
PlayerStore.Instance.currentClientInstance = null;
PlayerStore.Instance.storeClientManager.clientStack.Insert(0, BlackDelivery.CreateCourier());
PlayerStore.Instance.TryCallNextClient();
}));
ModHelper.AddDebugFunction(ModInfo.Id, ModInfo.Name, "Courier trap (test)", () => Log.Guard("受控交付(测试)", () =>
{
foreach (var o in Session.Data.Black.Orders.Where(x => x.State == OrderState.Pending)) { o.State = OrderState.Ready; o.Controlled = true; }
PlayerStore.Instance.currentClientInstance = null;
PlayerStore.Instance.storeClientManager.clientStack.Insert(0, BlackDelivery.CreateCourier());
PlayerStore.Instance.TryCallNextClient();
}));
ModHelper.AddDebugFunction(ModInfo.Id, ModInfo.Name, "Coin buyer (test)", () => Log.Guard("用币付款顾客(测试)", () =>
{
var c = new StoreClient
{
identifier = "pd_coin_test", displayName = "Coin buyer", spriteName = SpriteDict.GetRandomScavSpriteName(),
clientFaction = "FACTION_BLACK_MARKET", useClientBudget = true, clientIntent = StoreClient.ClientIntent.BUY,
canClientExposeFeature = ClientCanExposeFunc.BasicClientExposeCapacity,
};
c.SetBudget(5000);
c.clientBuyingTagList.Add("SEED");
c.mainDialogue.SetText(c.displayName, "CRT.").SetEndAction(() => { });
c.AddBasicDialog();
c.CompleteClientCreation();
Mark(c, Assets.CRT);
Log.Info($"用币付款顾客(测试)已设置,钱包污点 {Session.Data.Hot.Taint:0.##},当前顾客 {PlayerStore.Instance.currentClientInstance?.GetClientBlueprint()?.identifier},队列 {PlayerStore.Instance.storeClientManager.clientStack.Count} 人");
PlayerStore.Instance.currentClientInstance = null; // 测试:丢掉在场的顾客(开局的高利贷者不可遣散)
PlayerStore.Instance.storeClientManager.clientStack.Insert(0, c);
PlayerStore.Instance.TryCallNextClient();
// 把后柜里的种子都标成赃物(热度 50%),买走后钱包的污点应为成交额的一半
foreach (var it in EmporiumEntry.Instance.backInvinvElement.childItems)
if (it.IsTag("SEED")) it.ModifyTag("STOLEN_VALUE_INT", t => t.Enable().SetInt(50));
}));
}
public static void Unsubscribe() => ModHook.OnGenerateCustomerLate -= OnGenerate;
private static void OnGenerate(StoreClientManager manager)
{
if (Session.Data == null || !Unlock.IsUnlocked) return;
Log.Guard("用币付款", () =>
{
int day = StoreStation.GetDayCounter();
if (day != markDay) { Marked.Clear(); markDay = day; }
foreach (var c in manager.clientStack)
{
if (c == null || c.isSecurity || Marked.Contains(c) || c.clientIntent != StoreClient.ClientIntent.BUY || c.isNoContributeToEvidence) continue;
Marked.Add(c);
string asset = CoinPayment.AssetFor(c.clientFaction);
if (asset == null || !Session.Data.Rng.Chance(CoinPayment.Chance(asset))) continue;
Mark(c, asset);
}
});
}
private static void Mark(StoreClient c, string asset)
{
var before = c.onItemBought;
double total = 0; // 这位顾客这一单一共付了多少币
c.isNoContributeToEvidence = true;
c.onItemBought = (item, cost) =>
{
before?.Invoke(item, cost);
Log.Guard("用币付款成交", () => { total += Pay(c, asset, item, cost); Say(c, asset, total); });
};
}
/// <summary>成交后顾客说的话:告诉玩家这单是币到账,不是信用点。</summary>
private static void Say(StoreClient client, string asset, double total)
{
client.acceptDealDialogue = new Dialogue().SetText(client.displayName, L.T("coinpay.line", Fmt.Num(total), asset));
client.acceptDealDialogue.priority = 4;
client.acceptDealDialoguePlayed = false;
}
private static double Pay(StoreClient client, string asset, GameItem item, int cost)
{
var d = Session.Data;
double price = Session.Price(asset);
if (cost <= 0 || price <= 0) return 0;
int heat = item.IsTag("STOLEN_VALUE_INT") ? item.GetTagReadonly("STOLEN_VALUE_INT").GetInt() : 0;
ModHelper.AddCredit(-cost, false);
double qty = CoinPayment.Receive(d.Hot, asset, cost, price, heat);
d.CoinSalesToday += cost;
Log.Info($"用币付款:{item.name} {cost} 信用点 → {qty:0.####} {asset},污点 +{cost * heat / 100.0:0}");
return qty;
}
}
}