Black market: useful goods only, player selling with price-dependent speed and taint
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
5b57f3eedc
commit
502366e7c4
10 files changed
+363
-21
No files matched your search
@@ -37,23 +37,22 @@ namespace Decentralized.Domain
|
||||
public double DeskToday;
|
||||
public int DeskDay = -1;
|
||||
|
||||
/// <summary>违禁品池:游戏物品 id 与违禁等级(1 低、2 中、3 高)。全部来自游戏已有的违禁品。</summary>
|
||||
/// <summary>违禁品池:游戏物品 id 与违禁等级(1 低、2 中、3 高)。都是能转手的货(枪械、钥匙卡、密码解序器芯片、爆炸物);弹药、毒品、药品玩家用不上,不上架。</summary>
|
||||
public static readonly KeyValuePair<string, int>[] Pool =
|
||||
{
|
||||
P("small_pistol_ammo", 1), P("heavy_pistol_ammo", 1), P("handmade_pistol", 1), P("printed_gun", 1), P("stun_baton", 1),
|
||||
P("dream_cap_seed", 1), P("eng_keycard", 1), P("med_keycard", 1), P("ser_keycard", 1), P("sup_keycard", 1),
|
||||
P("crypto_module_ser", 1), P("crypto_module_sup", 1),
|
||||
P("revolver", 2), P("heavy_handmade_pistol", 2), P("small_pistol_ammo_p", 2), P("heavy_pistol_ammo_p", 2),
|
||||
P("flashbang_grenade", 2), P("smoke_grenade", 2), P("dream_dust", 2), P("restricted_chemical", 2),
|
||||
P("sci_keycard", 2), P("sec_keycard", 2), P("crypto_module_eng", 2), P("crypto_module_med", 2), P("unlicensed_phagimycin_pill", 2),
|
||||
P("shotgun", 3), P("smg", 3), P("c4", 3), P("fanta_pill", 3), P("nightmare_dust", 3), P("cmd_keycard", 3), P("crypto_module_sec", 3),
|
||||
P("handmade_pistol", 1), P("printed_gun", 1), P("stun_baton", 1),
|
||||
P("eng_keycard", 1), P("med_keycard", 1), P("ser_keycard", 1), P("sup_keycard", 1), P("crypto_module_ser", 1), P("crypto_module_sup", 1),
|
||||
P("revolver", 2), P("heavy_handmade_pistol", 2), P("flashbang_grenade", 2), P("smoke_grenade", 2),
|
||||
P("sci_keycard", 2), P("sec_keycard", 2), P("crypto_module_eng", 2), P("crypto_module_med", 2),
|
||||
P("shotgun", 3), P("smg", 3), P("c4", 3), P("cmd_keycard", 3), P("crypto_module_sec", 3),
|
||||
};
|
||||
|
||||
/// <summary>高科技物品池(不是违禁品,黑市上要加价)。</summary>
|
||||
/// <summary>高科技物品池(不是违禁品,黑市上要加价):矿机能用上的系统模组、能量电池、能量阵列,和矿架本身。</summary>
|
||||
public static readonly string[] TechPool =
|
||||
{
|
||||
"hand", "aug_chip", "energy_credit_hyp", "energy_credit_breeder", "makeshift_reactor", "mirage_projector", "printer",
|
||||
"system_module_overclock", "system_module_performance", "system_module_quality", "module_extractor_advanced", "powerblock",
|
||||
"system_module_overclock", "system_module_performance", "system_module_quality", "system_module_eco", "system_module_efficiancy",
|
||||
"system_module_fineness", "system_module_streamlining", "energy_credit_ext", "energy_credit_hyp", "energy_credit_breeder",
|
||||
"powerblock", "module_extractor_advanced", "pd_rig",
|
||||
};
|
||||
|
||||
private static KeyValuePair<string, int> P(string id, int level) => new KeyValuePair<string, int>(id, level);
|
||||
@@ -84,7 +83,7 @@ namespace Decentralized.Domain
|
||||
var c = UsedDealers.Card(gpus, Tuning.BmGpuFake, 0, rng);
|
||||
goods.Add(new BmGood { Item = "gpu:" + c.Model, Kind = GoodKind.Gpu, Level = 2, Model = c.Model, FakeOf = c.FakeOf, Health = c.Health, Price = price(CardValue.Of(c.Model, c.Health), GoodKind.Gpu) });
|
||||
}
|
||||
else if (r < Tuning.BmGpuChance + Tuning.BmTechChance && rep >= Tuning.BmMidRep && tech.Count > 0)
|
||||
else if (r < Tuning.BmGpuChance + Tuning.BmTechChance && tech.Count > 0)
|
||||
{
|
||||
int k = rng.Range(0, tech.Count - 1);
|
||||
string id = tech[k];
|
||||
|
||||
@@ -59,6 +59,7 @@ namespace Decentralized.Domain
|
||||
{
|
||||
public string Kind; // ready / scam_refund / scam_loss / rug / intercept / reopen
|
||||
public BmOrder Order;
|
||||
public BmSale Sale;
|
||||
public double Amount;
|
||||
}
|
||||
|
||||
@@ -84,7 +85,7 @@ namespace Decentralized.Domain
|
||||
public bool Closed(int day) => day <= ClosedUntil;
|
||||
|
||||
/// <summary>托管中和已提前放款但尚未交付的资金(信用点),平台跑路的概率随它增加。</summary>
|
||||
public double Held => Orders.Where(o => o.State == OrderState.Pending).Sum(o => (double)o.Price);
|
||||
public double Held => Orders.Where(o => o.State == OrderState.Pending).Sum(o => (double)o.Price) + HeldSales;
|
||||
|
||||
public static int OrderPrice(long baseValue, GoodKind k = GoodKind.Contraband) => (int)Math.Max(1, Math.Round(baseValue * (1 + Extra(k)) * (1 - Tuning.BmOrderDiscount)));
|
||||
public static int EscrowFee(int price) => (int)Math.Ceiling(price * Tuning.BmEscrowFee);
|
||||
@@ -151,18 +152,23 @@ namespace Decentralized.Domain
|
||||
}
|
||||
|
||||
/// <summary>每晚推进订单:平台跑路、到期的订单(卖家跑路、被截获、死投被挖走)、转入可取状态。镇压期间到期顺延一天。</summary>
|
||||
public List<BmEvent> Night(int day, bool crackdown, Wallet w, Rng rng, int secRep = 0)
|
||||
public List<BmEvent> Night(int day, bool crackdown, Wallet w, Rng rng, int secRep = 0, Func<string, double> price = null)
|
||||
{
|
||||
var ev = new List<BmEvent>();
|
||||
if (!Honeypot(day) && rng.Chance(HoneypotChance(secRep))) { HoneypotUntil = day + Tuning.BmHoneypotDays; if (!Forum.Contains("easy")) Forum.Add("easy"); }
|
||||
if (ClosedUntil == day) ev.Add(new BmEvent { Kind = "reopen" });
|
||||
if (!Closed(day) && Orders.Any(o => o.State == OrderState.Pending) && rng.Chance(RugChance))
|
||||
if (!Closed(day) && (Orders.Any(o => o.State == OrderState.Pending) || Sales.Any(x => x.State == SaleState.Listed || x.State == SaleState.Sold)) && rng.Chance(RugChance))
|
||||
{
|
||||
foreach (var o in Orders.Where(o => o.State == OrderState.Pending))
|
||||
{
|
||||
o.State = OrderState.Lost; o.Why = "rug";
|
||||
ev.Add(new BmEvent { Kind = "rug", Order = o, Amount = o.Price });
|
||||
}
|
||||
foreach (var sl in Sales.Where(x => x.State == SaleState.Listed || x.State == SaleState.Sold))
|
||||
{
|
||||
ev.Add(new BmEvent { Kind = "sale_rug", Sale = sl, Amount = sl.State == SaleState.Sold ? sl.Proceeds : sl.ListPrice });
|
||||
sl.State = SaleState.Lost; sl.Why = "rug";
|
||||
}
|
||||
ClosedUntil = day + Tuning.BmRugClosedDays;
|
||||
Offers.Clear(); Catalog.Clear(); Sellers.Clear();
|
||||
return ev;
|
||||
@@ -186,6 +192,7 @@ namespace Decentralized.Domain
|
||||
o.State = OrderState.Ready;
|
||||
ev.Add(new BmEvent { Kind = "ready", Order = o });
|
||||
}
|
||||
if (price != null) SalesNight(day, crackdown, w, price, rng, ev);
|
||||
// 卖家落网:近期成交过的卖家各有小概率被抓,他们留存的订单记录之后会连累买家
|
||||
foreach (var name in Orders.Where(x => x.State == OrderState.Done && day - x.DueDay <= 14).Select(x => x.Seller).Distinct().ToList())
|
||||
{
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Decentralized.Domain
|
||||
{
|
||||
public enum SaleState { Listed, Sold, Paid, Lost, Delisted }
|
||||
|
||||
/// <summary>玩家在黑市上架的一件货。货交给平台(从储藏区拿走),成交后货款托管几天再到钱包,可能带污点。</summary>
|
||||
public sealed class BmSale
|
||||
{
|
||||
public string Item;
|
||||
public string Model, FakeOf;
|
||||
public double Health;
|
||||
/// <summary>标价倍率与标价(信用点)。</summary>
|
||||
public double Mult;
|
||||
public int ListPrice;
|
||||
public int ListedDay, PayDay;
|
||||
public SaleState State = SaleState.Listed;
|
||||
/// <summary>成交后扣掉抽成的货款(信用点)与其中带的污点。</summary>
|
||||
public int Proceeds;
|
||||
public double Taint;
|
||||
/// <summary>终态原因:fake(买家看穿假卡退货)/ rug / delist。</summary>
|
||||
public string Why;
|
||||
}
|
||||
|
||||
public sealed partial class BlackMarket
|
||||
{
|
||||
public List<BmSale> Sales = new List<BmSale>();
|
||||
/// <summary>玩家作为卖家的好评(%):影响成交速度;卖假卡被看穿会下降,每笔成交回升一点。</summary>
|
||||
public int Rating = Tuning.BmRatingStart;
|
||||
|
||||
/// <summary>期望成交天数:倍率 ≤0.9 一天,1.0 两天,1.8 十四天,之间插值(0.9–1.0 线性,1.0 以上指数)。</summary>
|
||||
public static double ExpectedDays(double m)
|
||||
{
|
||||
if (m <= 0.9) return Tuning.BmSellDaysFast;
|
||||
if (m < 1.0) return Tuning.BmSellDaysFast + (m - 0.9) / 0.1 * (Tuning.BmSellDays1 - Tuning.BmSellDaysFast);
|
||||
return Tuning.BmSellDays1 * Math.Pow(Tuning.BmSellDaysMax / Tuning.BmSellDays1, (m - 1.0) / (Tuning.BmSellMax - 1.0));
|
||||
}
|
||||
|
||||
private static double T(double m) => Math.Max(0, Math.Min(1, (m - Tuning.BmSellMin) / (Tuning.BmSellMax - Tuning.BmSellMin)));
|
||||
/// <summary>货款带污点的概率与(带的时候)污点占货款的比例:都随标价倍率上升。</summary>
|
||||
public static double TaintChance(double m) => Tuning.BmSaleTaintChanceMin + T(m) * (Tuning.BmSaleTaintChanceMax - Tuning.BmSaleTaintChanceMin);
|
||||
public static double TaintRatio(double m) => Tuning.BmSaleTaintRatioMin + T(m) * (Tuning.BmSaleTaintRatioMax - Tuning.BmSaleTaintRatioMin);
|
||||
|
||||
/// <summary>每晚成交的概率:1 / 期望天数,乘好评系数(好评 90 为 1,封顶 1.1),最多 1。</summary>
|
||||
public double SaleChance(double m) => Math.Min(1, 1 / ExpectedDays(m) * Math.Min(1.1, Rating / (double)Tuning.BmRatingStart));
|
||||
|
||||
public static int ListPriceOf(long refValue, double m) => (int)Math.Max(1, Math.Round(refValue * m));
|
||||
public static int ListFee(int listPrice) => (int)Math.Ceiling(listPrice * Tuning.BmListFee);
|
||||
|
||||
/// <summary>上架:交付一件货,收上架费(付给 feeAsset 币,污点与成本按比例带走)。倍率超出范围、平台关闭或余额不足返回 null。</summary>
|
||||
public BmSale List(string item, string model, string fakeOf, double health, long refValue, double m, Wallet w, string feeAsset, int day, Func<string, double> price)
|
||||
{
|
||||
if (m < Tuning.BmSellMin - 1e-9 || m > Tuning.BmSellMax + 1e-9 || refValue <= 0 || Closed(day) || feeAsset == Assets.CRC) return null;
|
||||
int listPrice = ListPriceOf(refValue, m);
|
||||
double p = price(feeAsset);
|
||||
if (p <= 0) return null;
|
||||
double qty = ListFee(listPrice) / p;
|
||||
if (w.Avail(feeAsset) + 1e-9 < qty) return null;
|
||||
double total = w.Value(price);
|
||||
double share = total > 0 ? Math.Min(1, ListFee(listPrice) / total) : 0;
|
||||
w.Taint -= w.Taint * share; w.Basis -= w.Basis * share;
|
||||
w.Add(feeAsset, -qty);
|
||||
var s = new BmSale { Item = item, Model = model, FakeOf = fakeOf, Health = health, Mult = m, ListPrice = listPrice, ListedDay = day };
|
||||
Sales.Add(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
public void Delist(BmSale s) { s.State = SaleState.Delisted; s.Why = "delist"; }
|
||||
|
||||
/// <summary>未到账的货款(信用点):跑路时一并归零,也推高跑路概率。</summary>
|
||||
public double HeldSales => Sales.Where(x => x.State == SaleState.Sold).Sum(x => (double)x.Proceeds);
|
||||
|
||||
/// <summary>每晚推进出售:上架的货按概率成交(假卡可能被看穿退货),成交的货款托管到期后进钱包。镇压期间平台下线,不推进。</summary>
|
||||
private void SalesNight(int day, bool crackdown, Wallet w, Func<string, double> price, Rng rng, List<BmEvent> ev)
|
||||
{
|
||||
if (crackdown) return;
|
||||
foreach (var s in Sales.Where(x => x.State == SaleState.Listed && x.ListedDay < day).ToList())
|
||||
{
|
||||
if (!rng.Chance(SaleChance(s.Mult))) continue;
|
||||
if (s.FakeOf != null && rng.Chance(Tuning.BmFakeDetect))
|
||||
{
|
||||
s.State = SaleState.Delisted; s.Why = "fake";
|
||||
Rating = Math.Max(0, Rating - Tuning.BmRatingFakeLoss);
|
||||
ev.Add(new BmEvent { Kind = "sale_fake", Sale = s });
|
||||
continue;
|
||||
}
|
||||
s.State = SaleState.Sold;
|
||||
s.Proceeds = (int)Math.Round(s.ListPrice * (1 - Tuning.BmCommission));
|
||||
s.Taint = rng.Chance(TaintChance(s.Mult)) ? s.Proceeds * TaintRatio(s.Mult) : 0;
|
||||
s.PayDay = day + Tuning.BmSaleHold;
|
||||
Rating = Math.Min(100, Rating + 1);
|
||||
if (Honeypot(day)) Traps.Add(new BmTrap { Day = day + Tuning.BmTrapDelay, Amount = s.Proceeds, Why = "honeypot", Item = s.Item });
|
||||
ev.Add(new BmEvent { Kind = "sale_sold", Sale = s, Amount = s.Proceeds });
|
||||
}
|
||||
foreach (var s in Sales.Where(x => x.State == SaleState.Sold && day >= x.PayDay).ToList())
|
||||
{
|
||||
double p = price(Assets.CRT);
|
||||
if (p <= 0) continue;
|
||||
w.Add(Assets.CRT, s.Proceeds / p);
|
||||
w.Taint += s.Taint;
|
||||
w.Basis += s.Proceeds;
|
||||
s.State = SaleState.Paid;
|
||||
ev.Add(new BmEvent { Kind = "sale_paid", Sale = s, Amount = s.Proceeds });
|
||||
}
|
||||
// 买家落网:近期到账的出售记录会连累卖家(玩家)
|
||||
var recent = Sales.Where(x => x.State == SaleState.Paid && day - x.PayDay <= 14).ToList();
|
||||
if (recent.Count > 0 && rng.Chance(Tuning.BmSellerBust))
|
||||
{
|
||||
foreach (var s in recent) Traps.Add(new BmTrap { Day = day + Tuning.BmTrapDelay, Amount = s.Proceeds, Why = "seller", Item = s.Item });
|
||||
Forum.Add("busted_buyer");
|
||||
}
|
||||
Sales.RemoveAll(x => (x.State == SaleState.Paid || x.State == SaleState.Delisted || x.State == SaleState.Lost) && day - Math.Max(x.ListedDay, x.PayDay) > 14);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -99,7 +99,13 @@ namespace Decentralized.Domain
|
||||
public const double BmHoneypotBase = 0.01, BmHoneypotPerSecRep = 0.0004, BmHoneypotMax = 0.06, BmControlled = 0.35, BmSellerBust = 0.008;
|
||||
public const int BmHoneypotDays = 6, BmTrapDelay = 4;
|
||||
/// <summary>货架上除违禁品外的两类货:高科技物品(需中档声望)和显卡的出现概率、加价(在现货溢价 / 订单价之外再加),显卡里夹假卡的比例。</summary>
|
||||
public const double BmTechChance = 0.15, BmGpuChance = 0.20, BmTechMarkup = 0.5, BmGpuMarkup = 0.2, BmGpuFake = 0.20;
|
||||
public const double BmTechChance = 0.30, BmGpuChance = 0.30, BmTechMarkup = 0.5, BmGpuMarkup = 0.2, BmGpuFake = 0.20;
|
||||
/// <summary>玩家上架出售:标价倍率范围(相对参考价)、上架费、成交抽成、成交后货款托管天数、假卡被买家看穿的概率;
|
||||
/// 倍率 ≤0.9 / 1.0 / 1.8 时的期望成交天数(之间插值);货款带污点的概率与比例随倍率从下限涨到上限;卖家好评的初始值、看穿一次扣的点数。</summary>
|
||||
public const double BmListFee = 0.05, BmCommission = 0.08, BmSellMin = 0.6, BmSellMax = 1.8, BmFakeDetect = 0.5;
|
||||
public const double BmSellDaysFast = 1, BmSellDays1 = 2, BmSellDaysMax = 14;
|
||||
public const double BmSaleTaintChanceMin = 0.2, BmSaleTaintChanceMax = 0.9, BmSaleTaintRatioMin = 0.2, BmSaleTaintRatioMax = 0.8;
|
||||
public const int BmSaleHold = 3, BmRatingStart = 90, BmRatingFakeLoss = 10;
|
||||
/// <summary>黑市人脉升级的价格。</summary>
|
||||
public const int BmUnlockPrice = 1500;
|
||||
/// <summary>单个金融违规事件记入的罪证上限。</summary>
|
||||
|
||||
Reference in new issue
Block a user