Black market: 18 merchant types from the game's items and player professions

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
ZHU MINCHAOandClaude Sonnet 5.5 committed 2026-11-03 21:02:54 +08:00
1 parent 378203d04d
commit 61ec91b34d
11 files changed
+132 -52

No files matched your search

+1 -7
View File
@@ -5,7 +5,7 @@ using System.Linq;
namespace Decentralized.Domain
{
/// <summary>货的种类:违禁品、高科技物品、显卡。</summary>
public enum GoodKind { Contraband, Tech, Gpu }
public enum GoodKind { Contraband, Tech, Gpu, Goods }
/// <summary>黑市货架上的一种货。显卡的 Item 是 "gpu:型号",Model 是标称型号,FakeOf 非空表示背后是别的芯片(买家看不到)。</summary>
public class BmGood
@@ -47,12 +47,6 @@ namespace Decentralized.Domain
P("shotgun", 3), P("smg", 3), P("c4", 3), P("cmd_keycard", 3), P("crypto_module_sec", 3),
};
/// <summary>药品池:只有药物商家卖,也能转手出售。</summary>
public static readonly KeyValuePair<string, int>[] PharmaPool =
{
P("unlicensed_phagimycin_pill", 2), P("dream_dust", 2), P("restricted_chemical", 2), P("fanta_pill", 3), P("nightmare_dust", 3),
};
/// <summary>高科技物品池(不是违禁品,黑市上要加价):矿机能用上的系统模组、能量电池、能量阵列,和矿架本身。</summary>
public static readonly string[] TechPool =
{
+70
View File
@@ -0,0 +1,70 @@
using System.Collections.Generic;
using System.Linq;
namespace Decentralized.Domain
{
/// <summary>商家货架上的一项货:游戏物品 id、货的种类、违禁等级(只对违禁品有意义,随黑市声望放开)。</summary>
public struct BmEntry
{
public string Id;
public GoodKind Kind;
public int Level;
}
/// <summary>
/// 商家类型的货表。除了矿卡,其余都按玩家能走的路线配货:矿工、酿酒师、化学师、药剂师、枪械师、水培农场主、养殖户、水务、仓储、工具、奢侈品,
/// 加上违禁品(军火、证件芯片)。大宗商家什么都卖。
/// </summary>
public static class Merchants
{
private static BmEntry C(string id, int level) => new BmEntry { Id = id, Kind = GoodKind.Contraband, Level = level };
private static BmEntry T(string id) => new BmEntry { Id = id, Kind = GoodKind.Tech, Level = 3 };
private static BmEntry G(string id) => new BmEntry { Id = id, Kind = GoodKind.Goods, Level = 0 };
private static BmEntry[] Gs(params string[] ids) => ids.Select(G).ToArray();
public static readonly Dictionary<MerchantType, BmEntry[]> Table = new Dictionary<MerchantType, BmEntry[]>
{
[MerchantType.Rigs] = new[] { T("pd_rig"), T("energy_credit_ext"), T("energy_credit_hyp"), T("energy_credit_breeder"), T("powerblock"), T("recharger"), T("current_converter") },
[MerchantType.Modules] = new[] { T("system_module_overclock"), T("system_module_performance"), T("system_module_quality"), T("system_module_eco"), T("system_module_efficiancy"),
T("system_module_fineness"), T("system_module_streamlining"), T("module_extractor_advanced"), T("module_bay_expansion_kit") },
[MerchantType.Arms] = new[] { C("handmade_pistol", 1), C("printed_gun", 1), C("stun_baton", 1), C("revolver", 2), C("heavy_handmade_pistol", 2), C("flashbang_grenade", 2), C("smoke_grenade", 2),
C("shotgun", 3), C("smg", 3), C("c4", 3), G("combat_knife"), G("combat_machete"), G("hatchet"), G("crowbar"), G("kitchen_cleaver"), G("skinning_knife"), G("stun_gun"), G("tazer") },
[MerchantType.GunMods] = Gs("silencer2", "laser2", "match_barrel", "trigger_group", "mag_10mm_high", "mag_22_high", "mag_10mm_smg_high", "rds", "compensator", "stock", "grip", "bipod", "barrel",
"printer_chip_gun_part", "printer_chip_silencer", "printer_chip_handmade_pistol_frame", "printer_chip_heavy_handmade_pistol_frame", "printer_module_cnc", "printer_module_metal", "gun_part", "printer_plastic"),
[MerchantType.Docs] = new[] { C("eng_keycard", 1), C("med_keycard", 1), C("ser_keycard", 1), C("sup_keycard", 1), C("crypto_module_ser", 1), C("crypto_module_sup", 1),
C("sci_keycard", 2), C("sec_keycard", 2), C("crypto_module_eng", 2), C("crypto_module_med", 2), C("cmd_keycard", 3), C("crypto_module_sec", 3) },
[MerchantType.Pharma] = new[] { C("unlicensed_phagimycin_pill", 2), C("dream_dust", 2), C("fanta_pill", 3), C("nightmare_dust", 3), C("zyanide_pill", 2),
G("black_injector"), G("pure_white_injector"), G("large_purple_injector"), G("pink_injector"), G("pink_alt_injector"), G("blue_blood_bag"), G("surgery_tool"), G("zerochew"), G("phagimycin_pill") },
[MerchantType.Chem] = new[] { C("restricted_chemical", 2), G("common_chemical"), G("flux_agent"), G("advanced_flux_agent"), G("chem_module"), G("evaporator_module_solvent_recovery"),
G("chem_scanner"), G("med_bottle_blue"), G("med_bottle_orange"), G("med_bottle_red"), G("med_bottle_small_pink"), G("med_bottle_violet"), G("100ml_cylinder"), G("5ml_dropper") },
[MerchantType.Brewer] = new[] { G("wine_yeast"), G("wine_superyeast"), G("wine_yeast_infinite"), C("wine_yeast_red", 1), G("wine_berry"), G("bloomberry_seed"), G("nudka"), G("red_beer"), G("beerCase"), G("wine_bottle") },
[MerchantType.Farm] = new[] { G("nutrifruit_seed"), G("kotton_seed"), G("fillerweed_seed"), G("hydroreed_seed"), G("bloomberry_seed"), C("dream_cap_seed", 1),
G("farm_module_nutrifruit"), G("farm_module_kotton_loom"), G("farm_module_fillerweed_production"), G("farm_module_hydroreed_filter"), G("farm_module_dream_cap"), G("farm_module_smuggler"),
G("plant_analyser"), G("plant_dna_disk"), G("nutrient_tablet"), G("hydroreed_filter") },
[MerchantType.Husbandry] = Gs("tilapia_roe", "sturgeon_roe", "caviar", "ras", "serum_green", "serum_red",
"livestock_feed_dispenser", "auto_butcher", "industrial_fish_feed", "animal_cage"),
[MerchantType.Miner] = Gs("common_ore", "rare_ore", "metal_ingot", "scrap_metal", "common_electronic", "rare_electronic", "hypertech_electronic", "metal_scanner", "wire", "advanced_flux_agent"),
[MerchantType.Water] = Gs("water_filter_adv", "portable_water_purifier", "water_tank", "uv_filter", "water_tablet_container", "water_test_container", "aquascan", "bottled_water_premium", "water_jug", "water_ration"),
[MerchantType.Storage] = Gs("smuggler_bay", "smuggler_bay_mod", "smuggler_bay_mini", "storage_bay_large", "storage_bay_expansion_kit", "hypertech_bay", "machine_bay_ext", "storage_bay_chem",
"storage_bay_gun", "backpack_large_military"),
[MerchantType.Tools] = Gs("turbo_booster", "turbo_booster_adv", "turbo_booster_hypertech", "welder", "xray_scanner", "magnifier", "labeler_blue", "toolbox", "wire_cutter", "mind_reprogrammer"),
[MerchantType.Luxury] = new[] { C("pheromone_perfume", 2), G("neuroactive_perfume"), G("self_refilling_neuroactive_perfume"), G("skincare_cream"), G("packet_red_cigarette"), G("gamblers_coin"), G("kotton_fabric"), G("armor_lining") },
};
private static readonly Dictionary<string, BmEntry> ById = BuildIndex();
private static Dictionary<string, BmEntry> BuildIndex()
{
var d = new Dictionary<string, BmEntry>();
foreach (var e in Table.Values.SelectMany(x => x)) d[e.Id] = e;
foreach (var kv in BlackMarket.Pool) d[kv.Key] = new BmEntry { Id = kv.Key, Kind = GoodKind.Contraband, Level = kv.Value };
foreach (var id in BlackMarket.TechPool) d[id] = new BmEntry { Id = id, Kind = GoodKind.Tech, Level = 3 };
return d;
}
/// <summary>这个物品 id 在黑市上是不是一件货(现货柜台、商家货架里出现过的,都能转手出售)。</summary>
public static bool IsGood(string id) => ById.ContainsKey(id);
public static BmEntry Info(string id) => ById[id];
}
}
+20 -35
View File
@@ -5,8 +5,8 @@ using System.Linq;
namespace Decentralized.Domain
{
public enum PayMode { Escrow, Advance }
/// <summary>商家类型:全新矿卡经销商、二手矿卡贩子、模组高科技、军火、证件芯片、药物,大宗商家随机出现。</summary>
public enum MerchantType { GpuNew, GpuUsed, Mods, Arms, Docs, Pharma, Bulk }
/// <summary>商家类型:矿卡(全新 / 二手)、矿架能源、模组、军火、枪匠配件、证件芯片、药物、化学、酿酒、水培、养殖、矿工、水务、仓储、工具、奢侈品;大宗商家随机出现。</summary>
public enum MerchantType { GpuNew, GpuUsed, Rigs, Modules, Arms, GunMods, Docs, Pharma, Chem, Brewer, Farm, Husbandry, Miner, Water, Storage, Tools, Luxury, Bulk }
public enum OrderState { Pending, Ready, Done, Refunded, Lost }
/// <summary>黑市上的卖家:成交数与好评率公开;是不是骗子是隐藏的。</summary>
@@ -104,33 +104,28 @@ namespace Decentralized.Domain
public double RugChance => Math.Min(Tuning.BmRugMax, Tuning.BmRugBase + Held / 10000.0 * Tuning.BmRugPerTenK);
private static readonly MerchantType[] Regular = { MerchantType.GpuNew, MerchantType.GpuUsed, MerchantType.Mods, MerchantType.Arms, MerchantType.Docs, MerchantType.Pharma };
/// <summary>每周必有的"矿工路线"商家类型(从中抽 2 家),其余按全部类型抽。</summary>
private static readonly MerchantType[] Core = { MerchantType.GpuNew, MerchantType.GpuUsed, MerchantType.Rigs, MerchantType.Modules };
private static readonly MerchantType[] Others = { MerchantType.Arms, MerchantType.GunMods, MerchantType.Docs, MerchantType.Pharma, MerchantType.Chem, MerchantType.Brewer,
MerchantType.Farm, MerchantType.Husbandry, MerchantType.Miner, MerchantType.Water, MerchantType.Storage, MerchantType.Tools, MerchantType.Luxury };
private static double F(Rng rng, double lo, double hi) => lo + rng.NextDouble() * (hi - lo);
/// <summary>商家类型对应的货(含货种、库存),按声望放开违禁等级。</summary>
/// <summary>商家类型对应的货(含货种、库存),违禁品按声望放开等级。</summary>
private List<BmListing> MerchantGoods(int idx, BmSeller s, int day, int rep, Rng rng, Func<string, long> value)
{
var list = new List<BmListing>();
int n = s.Type == MerchantType.Bulk ? 2 : Tuning.BmMerchantListings;
var contra = new List<KeyValuePair<string, int>>();
switch (s.Type)
{
case MerchantType.Arms: contra = Pool.Where(x => ArmsIds.Contains(x.Key)).ToList(); break;
case MerchantType.Docs: contra = Pool.Where(x => !ArmsIds.Contains(x.Key)).ToList(); break;
case MerchantType.Pharma: contra = PharmaPool.ToList(); break;
case MerchantType.Bulk: contra = Pool.Concat(PharmaPool).ToList(); break;
}
contra = contra.Where(x => x.Value <= MaxLevel(rep)).ToList();
var tech = TechPool.ToList();
bool gpuKind = s.Type == MerchantType.GpuNew || s.Type == MerchantType.GpuUsed;
var entries = s.Type == MerchantType.Bulk ? Merchants.Table.Values.SelectMany(x => x).GroupBy(x => x.Id).Select(g => g.First()).ToList()
: gpuKind ? new List<BmEntry>() : Merchants.Table[s.Type].ToList();
entries = entries.Where(e => e.Kind != GoodKind.Contraband || e.Level <= MaxLevel(rep)).ToList();
var gpus = UsedDealers.Pool(day);
for (int i = 0; i < n; i++)
{
int qty = s.Type == MerchantType.Bulk ? rng.Range(Tuning.BmBulkQtyMin, Tuning.BmBulkQtyMax) : s.Type == MerchantType.GpuNew ? rng.Range(Math.Max(1, Tuning.BmQtyMin - 1), Tuning.BmQtyMax - 2) : rng.Range(Tuning.BmQtyMin, Tuning.BmQtyMax);
double jitter = F(rng, 0.97, 1.03);
BmListing l = null;
bool gpuKind = s.Type == MerchantType.GpuNew || s.Type == MerchantType.GpuUsed;
if (s.Type == MerchantType.Bulk) gpuKind = false;
BmListing l;
if (gpuKind)
{
bool fresh = s.Type == MerchantType.GpuNew;
@@ -138,23 +133,14 @@ namespace Decentralized.Domain
if (fresh) c.Health = 100;
l = new BmListing { Item = "gpu:" + c.Model, Kind = GoodKind.Gpu, Level = 2, Model = c.Model, FakeOf = c.FakeOf, Health = c.Health, Price = (int)Math.Max(1, Math.Round(CardValue.Of(c.Model, c.Health) * s.Factor * jitter)) };
}
else if (s.Type == MerchantType.Mods || (s.Type == MerchantType.Bulk && tech.Count > 0 && (contra.Count == 0 || rng.Chance(0.4))))
{
if (tech.Count == 0) continue;
int k = rng.Range(0, tech.Count - 1);
string id = tech[k]; tech.RemoveAt(k);
long v = value(id);
if (v <= 0) continue;
l = new BmListing { Item = id, Kind = GoodKind.Tech, Level = 3, Price = (int)Math.Max(1, Math.Round(v * s.Factor * jitter)) };
}
else
{
if (contra.Count == 0) continue;
int k = rng.Range(0, contra.Count - 1);
var pick = contra[k]; contra.RemoveAt(k);
long v = value(pick.Key);
if (v <= 0) continue;
l = new BmListing { Item = pick.Key, Kind = GoodKind.Contraband, Level = pick.Value, Price = (int)Math.Max(1, Math.Round(v * s.Factor * jitter)) };
if (entries.Count == 0) break;
int k = rng.Range(0, entries.Count - 1);
var e = entries[k]; entries.RemoveAt(k);
long v = value(e.Id);
if (v <= 0 || v > Tuning.BmMaxUnitValue) { i--; continue; }
l = new BmListing { Item = e.Id, Kind = e.Kind, Level = e.Level, Price = (int)Math.Max(1, Math.Round(v * s.Factor * jitter)) };
}
l.Seller = idx; l.Qty = qty;
list.Add(l);
@@ -162,13 +148,12 @@ namespace Decentralized.Domain
return list;
}
private static readonly HashSet<string> ArmsIds = new HashSet<string> { "handmade_pistol", "printed_gun", "stun_baton", "revolver", "heavy_handmade_pistol", "flashbang_grenade", "smoke_grenade", "shotgun", "smg", "c4" };
/// <summary>每周重新生成商家、货架和论坛情报(与现货同一天刷新):从 6 种类型里抽 BmMerchantCount 家,另有概率出现一家大宗商家。</summary>
public void RefreshOrders(int day, int rep, Rng rng, Func<string, long> value)
{
Sellers.Clear(); Catalog.Clear(); Forum.Clear();
var types = Regular.OrderBy(_ => rng.NextDouble()).Take(Tuning.BmMerchantCount).ToList();
var types = Core.OrderBy(_ => rng.NextDouble()).Take(Tuning.BmCoreMerchants).ToList();
types.AddRange(Others.OrderBy(_ => rng.NextDouble()).Take(Tuning.BmMerchantCount - Tuning.BmCoreMerchants));
if (rng.Chance(Tuning.BmBulkChance)) types.Add(MerchantType.Bulk);
foreach (var t in types)
{
+4 -2
View File
@@ -106,10 +106,12 @@ namespace Decentralized.Domain
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, BmMaxListings = 10;
/// <summary>商家货架:每周的商家数(从 6 种类型里抽)、每家的货种数、每种货的库存范围;大宗商家出现概率、库存范围、送货天数;
/// <summary>商家货架:每周的商家数(其中 2 家从矿卡 / 矿架 / 模组 4 类里抽,其余从其他类型里抽)、每家的货种数、每种货的库存范围;大宗商家出现概率、库存范围、送货天数;
/// 各类商家的价格系数范围(订单价 = 基础价 × 系数);批量折扣档(件数、折扣)。</summary>
public const int BmMerchantCount = 5, BmMerchantListings = 4, BmQtyMin = 3, BmQtyMax = 6, BmBulkQtyMin = 10, BmBulkQtyMax = 25, BmBulkDays = 6;
public const int BmMerchantCount = 7, BmCoreMerchants = 2, BmMerchantListings = 3, BmQtyMin = 2, BmQtyMax = 5, BmBulkQtyMin = 10, BmBulkQtyMax = 25, BmBulkDays = 6;
public const double BmBulkChance = 0.25, BmFactorMin = 0.70, BmFactorMax = 0.95, BmFactorNewMin = 0.85, BmFactorNewMax = 1.00, BmFactorUsedMin = 0.65, BmFactorUsedMax = 0.90, BmFactorBulkMin = 0.55, BmFactorBulkMax = 0.75;
/// <summary>商家货架上单件基础价的上限(过贵的货不上,免得一件把周转量撑歪)。</summary>
public const long BmMaxUnitValue = 4000;
public const int BmBulk1Count = 5, BmBulk2Count = 10;
public const double BmBulk1Discount = 0.05, BmBulk2Discount = 0.10;
/// <summary>出售量越大货款越容易带污点:近 7 天成交额达到参考量时,污点概率与比例各加最多 BmVolumeTaintMax。</summary>
+2 -2
View File
@@ -56,7 +56,7 @@ namespace Decentralized
if (it == null || it.identifier == null) return null;
if (Items.IsGpu(it)) return "gpu:" + Items.ToUnit(it).Model;
string id = it.identifier;
return BlackMarket.Pool.Any(x => x.Key == id) || BlackMarket.PharmaPool.Any(x => x.Key == id) || BlackMarket.TechPool.Contains(id) ? id : null;
return Merchants.IsGood(id) ? id : null;
}
public static System.Collections.Generic.List<GameItem> Sellable() =>
@@ -71,7 +71,7 @@ namespace Decentralized
return Value(id);
}
public static GoodKind KindOf(string id) => id.StartsWith("gpu:") ? GoodKind.Gpu : BlackMarket.TechPool.Contains(id) ? GoodKind.Tech : GoodKind.Contraband;
public static GoodKind KindOf(string id) => id.StartsWith("gpu:") ? GoodKind.Gpu : Merchants.Info(id).Kind;
/// <summary>每周刷新:现货与订单目录一起。返回是否刷新了。</summary>
public static bool Restock(SaveData d, int day, bool force = false)
+4
View File
@@ -69,6 +69,10 @@ namespace Decentralized
BlackDelivery.Restock(d, day, true);
vals.Add(d.Black.CatalogValue);
}
var missing = Merchants.Table.SelectMany(kv => kv.Value.Select(e => (kv.Key, e.Id))).Where(x => BlackDelivery.Value(x.Item2) <= 0).Select(x => x.Item1 + ":" + x.Item2).ToList();
var costs = Merchants.Table.SelectMany(kv => kv.Value.Select(e => (kv.Key, e.Id))).Select(x => BlackDelivery.Value(x.Item2)).Where(v => v > 0).OrderBy(v => v).ToList();
Log.Info("黑市抽样:基础价 >2500 的货:" + string.Join(", ", Merchants.Table.SelectMany(kv => kv.Value.Select(e => (kv.Key, e.Id))).Select(x => (id: x.Item2, v: BlackDelivery.Value(x.Item2))).Where(x => x.v > 2500).Select(x => x.id + "=" + x.v)));
Log.Info($"黑市抽样:无法造出或价格为 0 的货 {missing.Count} 个:{string.Join(", ", missing)};基础价中位 {costs[costs.Count / 2]},最高 {costs.Last()}");
Log.Info($"黑市抽样:60 周货架总值 平均 {vals.Average():0},最小 {vals.Min():0},最大 {vals.Max():0}");
}));
ModHelper.AddDebugFunction(ModInfo.Id, ModInfo.Name, "Black market events (test)", () => Log.Guard("黑市事件(测试)", () =>
+13 -1
View File
@@ -310,7 +310,6 @@ black.sale.Delisted.fake,buyer spotted the fake and returned it
black.kind.gpunew,GPU brand new
merchant.GpuNew,New GPUs
merchant.GpuUsed,Used GPUs
merchant.Mods,Mods & tech
merchant.Arms,Arms
merchant.Docs,Keycards & chips
merchant.Pharma,Pharma
@@ -320,3 +319,16 @@ black.sell.all,List all
black.sell.listedall,"Listed {0} items."
black.sell.slots,"Listed {0}/{1}"
black.sell.full,"At most {0} listings at a time."
merchant.Rigs,Rigs & power
merchant.Modules,Modules
merchant.GunMods,Gunsmith parts
merchant.Chem,Chemicals
merchant.Brewer,Brewing
merchant.Farm,Hydroponics
merchant.Husbandry,Husbandry
merchant.Miner,Mining supplies
merchant.Water,Water
merchant.Storage,Storage
merchant.Tools,Tools
merchant.Luxury,Luxury
black.kind.Goods,Goods
1 # Probably Decentralized localization table: English (en)
310 black.kind.gpunew
311 merchant.GpuNew
312 merchant.GpuUsed
merchant.Mods
313 merchant.Arms
314 merchant.Docs
315 merchant.Pharma
319 black.sell.listedall
320 black.sell.slots
321 black.sell.full
322 merchant.Rigs
323 merchant.Modules
324 merchant.GunMods
325 merchant.Chem
326 merchant.Brewer
327 merchant.Farm
328 merchant.Husbandry
329 merchant.Miner
330 merchant.Water
331 merchant.Storage
332 merchant.Tools
333 merchant.Luxury
334 black.kind.Goods
+13 -1
View File
@@ -309,7 +309,6 @@ black.sale.Delisted.fake,买家看穿假卡退货
black.kind.gpunew,显卡 全新
merchant.GpuNew,全新矿卡
merchant.GpuUsed,二手矿卡
merchant.Mods,模组高科技
merchant.Arms,军火
merchant.Docs,证件芯片
merchant.Pharma,药物
@@ -319,3 +318,16 @@ black.sell.all,全部上架
black.sell.listedall,"已上架 {0} 件。"
black.sell.slots,"上架 {0}/{1}"
black.sell.full,"最多同时上架 {0} 件。"
merchant.Rigs,矿架与能源
merchant.Modules,模组
merchant.GunMods,枪匠配件
merchant.Chem,化学品
merchant.Brewer,酿酒
merchant.Farm,水培农场
merchant.Husbandry,养殖
merchant.Miner,矿工
merchant.Water,水务
merchant.Storage,仓储
merchant.Tools,工具
merchant.Luxury,奢侈品
black.kind.Goods,商品
1 # Probably Decentralized 本地化表:简体中文(zh)
309 black.kind.gpunew
310 merchant.GpuNew
311 merchant.GpuUsed
merchant.Mods
312 merchant.Arms
313 merchant.Docs
314 merchant.Pharma
318 black.sell.listedall
319 black.sell.slots
320 black.sell.full
321 merchant.Rigs
322 merchant.Modules
323 merchant.GunMods
324 merchant.Chem
325 merchant.Brewer
326 merchant.Farm
327 merchant.Husbandry
328 merchant.Miner
329 merchant.Water
330 merchant.Storage
331 merchant.Tools
332 merchant.Luxury
333 black.kind.Goods
+1 -1
View File
@@ -370,7 +370,7 @@ namespace Decentralized
{
string id = BlackDelivery.SellId(it);
var kind = BlackDelivery.KindOf(id);
var g = new BmGood { Item = id, Kind = kind, Level = kind == GoodKind.Contraband ? BlackMarket.Pool.Concat(BlackMarket.PharmaPool).First(x => x.Key == id).Value : 3 };
var g = new BmGood { Item = id, Kind = kind, Level = kind == GoodKind.Gpu ? 2 : Merchants.Info(id).Level };
if (kind == GoodKind.Gpu) g.Health = Items.ToUnit(it).Health;
g.Price = BlackMarket.ListPriceOf(BlackDelivery.RefValue(it), _sellMult);
return new { g, it };