A scav-type seller visits now and then with three to five used cards. An honest dealer sells at true value, a middleman adds 8%, a scammer mixes in fakes (relabelled cheap chips) priced at 90% of the labelled model's value. The markup is a client-temporary item feature, so a bought card is only worth its real value. Cards are registered as appraisal items; the correct value is the same function as the sale value. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
100 lines
4.7 KiB
C#
100 lines
4.7 KiB
C#
using System.Collections.Generic;
|
||
using Decentralized.Domain;
|
||
|
||
namespace Decentralized
|
||
{
|
||
/// <summary>
|
||
/// 二手显卡贩子:偶尔上门,把几张卡摆上柜台,玩家按外观自己判断(翻面看背面)。
|
||
/// 老实人按真实价值卖,中间商加价,骗子夹带假卡并按标称型号报价;价格是柜台上的临时加价,买下之后卡只值真实价值。
|
||
/// 另外把显卡登记为鉴定公会的鉴定物品,正确价值与实际售价是同一个数。
|
||
/// </summary>
|
||
public static class UsedDealerClient
|
||
{
|
||
public const string Appraisal = "pd_gpu_appraisal";
|
||
private const double VisitChance = 0.05;
|
||
private static int lastVisitDay = -1;
|
||
|
||
public static void Subscribe()
|
||
{
|
||
ModHook.OnGenerateCustomerNormal += OnGenerate;
|
||
ModHelper.AddAppraisalItem(ModInfo.Id, Appraisal, Items.GpuId("RZX50"), 2, CreateForAppraisal, u => (int)CardValue.True(Items.ToUnit(u)),
|
||
Items.IsGpu, null, () => L.T("appraisal.gpu"));
|
||
ModHelper.AddDebugFunction(ModInfo.Id, ModInfo.Name, "Used dealer visit (test)", () => PlayerStore.Instance.storeClientManager?.AddClient(Create(DealerKind.Scammer)));
|
||
}
|
||
|
||
public static void Unsubscribe()
|
||
{
|
||
ModHook.OnGenerateCustomerNormal -= OnGenerate;
|
||
ModHelper.RemoveAppraisalItems(ModInfo.Id);
|
||
}
|
||
|
||
private static void OnGenerate(StoreClientManager manager)
|
||
{
|
||
if (Session.Data == null || !Unlock.IsUnlocked) return;
|
||
Log.Guard("二手贩子", () =>
|
||
{
|
||
int day = StoreStation.GetDayCounter();
|
||
if (day < 3 || day == lastVisitDay || !Session.Data.Rng.Chance(VisitChance)) return;
|
||
lastVisitDay = day;
|
||
manager.AddClient(Create(UsedDealers.Kind(day, Session.Data.Rng)));
|
||
});
|
||
}
|
||
|
||
/// <summary>鉴定公会送来的卡:一成是假卡;默认估价是按标称型号算的价。</summary>
|
||
private static GameItem CreateForAppraisal()
|
||
{
|
||
var rng = Session.Data?.Rng ?? new Rng(1);
|
||
int day = StoreStation.GetDayCounter();
|
||
var cards = UsedDealers.Cards(DealerKind.Middleman, day, rng);
|
||
var c = cards[0];
|
||
var item = Items.NewCard(c.Model, c.Health, c.FakeOf, rng);
|
||
AppraisalHelper.InitAppraisalItem(item, (int)CardValue.Of(c.Model, c.Health));
|
||
return item;
|
||
}
|
||
|
||
private static StoreClient Create(DealerKind kind)
|
||
{
|
||
int day = StoreStation.GetDayCounter();
|
||
var rng = Session.Data.Rng;
|
||
var cards = UsedDealers.Cards(kind, day, rng);
|
||
var client = new StoreClient
|
||
{
|
||
identifier = "pd_used_dealer",
|
||
displayName = L.T("dealer.name"),
|
||
spriteName = SpriteDict.GetRandomScavSpriteName(),
|
||
clientIntent = StoreClient.ClientIntent.SELL,
|
||
};
|
||
StoreClientFactionSetup.InitScav(client);
|
||
client.mainDialogue.SetText(client.displayName, L.T("dealer.line1." + rng.Range(1, 3))).NextDialogue().SetText(client.displayName, L.T("dealer.line2." + rng.Range(1, 3)))
|
||
.SetEndAction(() => Log.Guard("二手贩子上货", () =>
|
||
{
|
||
NegociationUIManager.Instance.OpenUI();
|
||
var placed = new List<string>();
|
||
foreach (var c in cards)
|
||
{
|
||
var item = Items.NewCard(c.Model, c.Health, c.FakeOf, rng);
|
||
if (c.MarkupPct != 0) item.AddItemFeature(Markup(c.MarkupPct));
|
||
PlayerStore.Instance.AddDirectSellingItemToTable(item);
|
||
placed.Add($"{c.Model}{(c.FakeOf != null ? "←" + c.FakeOf : "")} {c.Health:0}% {c.MarkupPct:+0;-0}%");
|
||
}
|
||
Log.Info($"二手贩子({kind}):{string.Join(",", placed)}");
|
||
}));
|
||
client.AddBasicDialog();
|
||
client.CompleteClientCreation();
|
||
return client;
|
||
}
|
||
|
||
/// <summary>柜台上的临时加价:离开贩子之后自动去掉(游戏按客户临时特征处理)。</summary>
|
||
private static ItemFeature Markup(int pct)
|
||
{
|
||
var f = new ItemFeature(ItemFeature.FeatureType.ClientTemporary) { identifier = "pd_used_markup", category = "markup", valueStage = ItemFeature.ValueStage.Market };
|
||
string text = L.T("dealer.markup");
|
||
f.SetPublicDisplay(text);
|
||
f.SetActualDisplay(text);
|
||
f.isFeatureMatch = true;
|
||
f.SetPreExposedValueMod(pct);
|
||
return f;
|
||
}
|
||
}
|
||
}
|