2026-11-03 16:01:20 +08:00
|
|
|
using System.Collections.Generic;
|
|
|
|
|
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;
|
2026-11-03 16:51:12 +08:00
|
|
|
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}");
|
|
|
|
|
}));
|
2026-11-03 16:39:40 +08:00
|
|
|
ModHelper.AddDebugFunction(ModInfo.Id, ModInfo.Name, "Tainted wallet (test)", () => Log.Guard("带污点的钱包(测试)", () =>
|
|
|
|
|
{
|
|
|
|
|
var w = Session.Data.Hot;
|
|
|
|
|
w.Add(Assets.PSC, 100); w.Taint += 3000; w.Basis += 2000;
|
|
|
|
|
Log.Info($"钱包:PSC {w.Get(Assets.PSC):0.##},污点 {w.Taint:0}");
|
|
|
|
|
}));
|
2026-11-03 16:01:20 +08:00
|
|
|
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);
|
2026-11-03 16:20:58 +08:00
|
|
|
c.clientBuyingTagList.Add("SEED");
|
2026-11-03 16:01:20 +08:00
|
|
|
c.mainDialogue.SetText(c.displayName, "CRT.").SetEndAction(() => { });
|
|
|
|
|
c.AddBasicDialog();
|
|
|
|
|
c.CompleteClientCreation();
|
|
|
|
|
Mark(c, Assets.CRT);
|
2026-11-03 16:25:38 +08:00
|
|
|
Log.Info($"用币付款顾客(测试)已设置,钱包污点 {Session.Data.Hot.Taint:0.##},当前顾客 {PlayerStore.Instance.currentClientInstance?.GetClientBlueprint()?.identifier},队列 {PlayerStore.Instance.storeClientManager.clientStack.Count} 人");
|
2026-11-03 16:20:58 +08:00
|
|
|
PlayerStore.Instance.currentClientInstance = null; // 测试:丢掉在场的顾客(开局的高利贷者不可遣散)
|
|
|
|
|
PlayerStore.Instance.storeClientManager.clientStack.Insert(0, c);
|
|
|
|
|
PlayerStore.Instance.TryCallNextClient();
|
2026-11-03 16:25:38 +08:00
|
|
|
// 把后柜里的种子都标成赃物(热度 50%),买走后钱包的污点应为成交额的一半
|
|
|
|
|
foreach (var it in EmporiumEntry.Instance.backInvinvElement.childItems)
|
|
|
|
|
if (it.IsTag("SEED")) it.ModifyTag("STOLEN_VALUE_INT", t => t.Enable().SetInt(50));
|
2026-11-03 16:01:20 +08:00
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
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;
|
2026-11-03 16:20:58 +08:00
|
|
|
double total = 0; // 这位顾客这一单一共付了多少币
|
2026-11-03 16:01:20 +08:00
|
|
|
c.isNoContributeToEvidence = true;
|
|
|
|
|
c.onItemBought = (item, cost) =>
|
|
|
|
|
{
|
|
|
|
|
before?.Invoke(item, cost);
|
2026-11-03 16:20:58 +08:00
|
|
|
Log.Guard("用币付款成交", () => { total += Pay(c, asset, item, cost); Say(c, asset, total); });
|
2026-11-03 16:01:20 +08:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2026-11-03 16:20:58 +08:00
|
|
|
/// <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)
|
2026-11-03 16:01:20 +08:00
|
|
|
{
|
|
|
|
|
var d = Session.Data;
|
|
|
|
|
double price = Session.Price(asset);
|
2026-11-03 16:20:58 +08:00
|
|
|
if (cost <= 0 || price <= 0) return 0;
|
2026-11-03 16:01:20 +08:00
|
|
|
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}");
|
2026-11-03 16:20:58 +08:00
|
|
|
return qty;
|
2026-11-03 16:01:20 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|