Price entry for listings with tiers as helpers; exclude storage containers from selling
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
ce02773738
commit
776f66fd2c
5 files changed
+83
-24
No files matched your search
@@ -30,6 +30,8 @@
|
||||
- 订单改成商家货架(用户意见):黑市页"订单"改名"商家",每周从 6 种类型里抽 5 家(全新矿卡经销商、二手矿卡贩子、模组高科技、军火、证件芯片、药物),另有 25% 的周出现一家大宗商家(库存 10–25 件、价格系数 0.55–0.75、送货 6 天)。每家有自己的价格系数(订单价 = 基础价 × 系数,一般 0.70–0.95,全新卡 0.85–1.00,二手卡 0.65–0.90),每家 4 种货、库存 3–6 件。一次订 5 件以上 95 折、10 件以上 9 折。界面:件数按钮 ×1 / ×5 / ×10,商家按钮,所选商家的货架。药物(药片、梦尘、管制化学品)只在药物商家和大宗商家出现,也能转手出售。每周货架总值在游戏里抽样 60 周平均 13.2k(目标 1.4 万)。
|
||||
- 商家类型扩到 18 种 + 大宗(用户意见,对照游戏的物品目录和玩家职业):全新矿卡经销商、二手矿卡贩子、矿架与能源、模组、军火(枪、手雷、炸药、刀具、电击枪)、枪匠配件(枪械配件、3D 打印芯片与模组、枪械零件)、证件芯片、药物(药片、注射器、血袋、手术工具)、化学品(化学用品、助熔剂、化学设备模组、量筒试剂瓶)、酿酒(酵母、荧光莓、啤酒、酒瓶)、水培农场(种子、水培模组、植物分析仪)、养殖(鱼卵、鱼子酱、循环水养殖系统、血清、屠宰机)、矿工(矿石、金属锭、电子元件、拾荒扫描仪)、水务(滤水、净水、储水、检测)、仓储(走私暗格、储藏区扩建、军用背包)、工具(涡轮增压器、等离子切割机、X 射线扫描仪、心智重编程器)、奢侈品(香水、精华液、香烟)。每周 7 家:2 家从矿卡 / 矿架 / 模组 4 类里抽(保证矿工路线总有货),其余 5 家从其余类型里抽;每家 3 种货,库存 2–5 件,单件基础价超过 4000 的不上。游戏里抽样 60 周货架总值平均 13.2k(目标 1.4 万)。药物改成并入药物商家,现货柜台的货不变。所有货都能转手出售。
|
||||
- 尖端店铺与个人卖家(用户意见):贵货(单件基础价 ≥ 2000:超科技涡轮增压器、超科技储藏区、心智重编程器、顶级显卡等)不再被一刀切掉,改由"尖端店铺"卖:每周只有 15% 的概率出现,2 种货、库存 1–2 件、价格系数 0.85–1.00、送货 5 天;顶级全新显卡也在这里。个人卖家:每周固定 2 位,什么都卖(可能是药、模组、显卡、仍有 10% 混进贵货),每件价格系数各自随机 0.50–1.20(捡漏或被宰),库存 1–2 件,是骗子的概率 25%,都是新号所以只接受托管。常规商家仍只卖基础价 ≤ 4000 的货。
|
||||
- 定价改成直接输价格(用户意见):点货架上的"上架"或"我的订单"里的"改价",出现"设定标价"页,显示参考价(真实价)和输入框;×0.6–×1.8 档位只是帮忙把价格填进输入框,也可以手输整数,输入后显示"标价 83(×1.38)";价格要在参考价的 0.6–1.8 倍之间(显示可输范围),确定后走付款确认(上架费 5% / 改价费 2% 按新标价算)。成交速度和货款污点都按 标价 ÷ 参考价 的实际比例连续计算(不再只有档位)。"我的订单"里每件上架的货显示"参考 60 标价 83(×1.38)",下面是"改价"和"撤下"。出售页顶上的档位按钮保留,作为默认倍率(预填价格、"全部上架"用)。游戏内验证:档位填价(×1.5 → 90)、手输 83(×1.38,上架费 5)、范围外(200)被拒并提示 36–108。
|
||||
- 自己的储藏区和背包不再出现在可上架的货里,有内容的容器也不行(之前储藏区(扩建)会被列出来,上架会把里面的东西一起带走)。
|
||||
- 上架后可以改价(用户意见):"我的订单与情报"页每件上架的货下面一排倍率按钮(0.6–1.8,当前的带方括号)和"撤下",点倍率先走付款确认(改价费 2%,`BmRepriceFee`,手输平台地址),标价按参考价重算,成交概率按新倍率走,上架日不变。游戏内验证:0.6 倍的 RTX 70 改成 ×1.2,改价费 12,标价 600。蜜罐基础概率维持 1%(模拟里进取策略罪证 ≥ 300 约 48 天,用户认为可接受)。
|
||||
- 追查调整(经济模拟后):同一晚到期的追查按来源合成一次事件,记入货款的 40%(`BmTrapShare`),同一次蜜罐 / 落网累计最多 400(`BmTrapWindowCap`);没收到货的订单(骗子退款、被截获、跑路、拒签、被查封)取消对应追查。原来每单各记一次、每晚上限 400,一个蜜罐窗口能连续记几千,模拟里一局 120 天几乎一直在罪证线以上。
|
||||
- 手输收款地址(用户意见):Web3 里的付款与转账——黑市现货、商家下单、上架费、混币器存入、Ponero 兑换——点下去先出"确认付款"页,显示摘要和收款地址(商家是名字里的 0x… ,平台、混币器、Ponero 兑换处各有自己的随机地址,存档保存),要手输地址才放款,不分大小写,输错提示"地址不符,没有付款",可取消。DEX 兑换和银行存取不加(没有收款方);交易所的转账等阶段 5 多钱包时再接同一个确认页。游戏内验证:现货买超频模组,输错一位被拒、输对成交;Ponero 兑换处进入确认页。
|
||||
|
||||
@@ -65,8 +65,11 @@ namespace Decentralized
|
||||
return Merchants.IsGood(id) ? id : null;
|
||||
}
|
||||
|
||||
/// <summary>自己的储藏区、背包不能上架:卖掉会带走里面的东西,也会丢掉容量。</summary>
|
||||
private static readonly System.Collections.Generic.HashSet<string> StorageIds = new System.Collections.Generic.HashSet<string>(Merchants.Table[MerchantType.Storage].Select(e => e.Id));
|
||||
|
||||
public static System.Collections.Generic.List<GameItem> Sellable() =>
|
||||
GraphUtils.FindAllChildrenType<GameItem>(EmporiumEntry.Instance.invElement, i => GeneralHelper.IsItemOwned(i) && SellId(i) != null, i => i.identifier != Items.Rig);
|
||||
GraphUtils.FindAllChildrenType<GameItem>(EmporiumEntry.Instance.invElement, i => GeneralHelper.IsItemOwned(i) && SellId(i) != null && !StorageIds.Contains(i.identifier) && i.FindAllChildItems().Count == 0, i => i.identifier != Items.Rig);
|
||||
|
||||
/// <summary>参考价:显卡按标称型号与成色,其余按游戏基础价。</summary>
|
||||
public static long RefValue(GameItem it)
|
||||
|
||||
@@ -300,7 +300,7 @@ black.sell.listed,"Listed: {0} at {1}."
|
||||
black.sell.delist,Take down
|
||||
black.sell.rating,"Rating {0}%"
|
||||
black.mine.sales,My listings
|
||||
black.mine.sale,"{0} x{1}: {2}"
|
||||
black.mine.sale,"{0} ref {1} price {2} (x{3}): {4}"
|
||||
black.sale.Listed,listed
|
||||
black.sale.Sold,"sold, payout day {0}"
|
||||
black.sale.Paid,paid
|
||||
@@ -343,6 +343,13 @@ black.pay.cancel,Cancel
|
||||
black.pay.bad,Address does not match; nothing paid.
|
||||
pay.mix,"Mixer {0} {1}"
|
||||
pay.swap,"Ponero desk {0} {1}"
|
||||
pay.listfee, (listing fee)
|
||||
pay.listfee," (listing fee x{0})"
|
||||
pay.repricefee," (repricing fee x{0})"
|
||||
black.sell.repriced,"Repriced: {0}, now {1}."
|
||||
black.edit.ref,"Reference price {0}"
|
||||
black.edit.input,Enter a price
|
||||
black.edit.price,"Price {0} (x{1})"
|
||||
black.edit.ok,OK
|
||||
black.edit.cancel,Cancel
|
||||
black.edit.range,"The price must be 0.6 to 1.8 times the reference ({0} to {1})."
|
||||
black.sell.reprice,Reprice
|
||||
|
@@ -299,7 +299,7 @@ black.sell.listed,"已上架:{0},标价 {1}。"
|
||||
black.sell.delist,撤下
|
||||
black.sell.rating,"好评 {0}%"
|
||||
black.mine.sales,我的上架
|
||||
black.mine.sale,"{0} ×{1}:{2}"
|
||||
black.mine.sale,"{0} 参考 {1} 标价 {2}(×{3}):{4}"
|
||||
black.sale.Listed,上架中
|
||||
black.sale.Sold,"已成交,第 {0} 天放款"
|
||||
black.sale.Paid,已到账
|
||||
@@ -342,6 +342,13 @@ black.pay.cancel,取消
|
||||
black.pay.bad,地址不符,没有付款。
|
||||
pay.mix,"混币器 {0} {1}"
|
||||
pay.swap,"Ponero 兑换处 {0} {1}"
|
||||
pay.listfee,(上架费)
|
||||
pay.listfee,"(上架费 ×{0})"
|
||||
pay.repricefee,"(改价费 ×{0})"
|
||||
black.sell.repriced,"已改价:{0},标价 {1}。"
|
||||
black.edit.ref,"参考价 {0}"
|
||||
black.edit.input,输入标价
|
||||
black.edit.price,"标价 {0}(×{1})"
|
||||
black.edit.ok,确定
|
||||
black.edit.cancel,取消
|
||||
black.edit.range,"标价要在参考价的 0.6 到 1.8 倍之间({0} 到 {1})。"
|
||||
black.sell.reprice,改价
|
||||
|
@@ -18,6 +18,9 @@ namespace Decentralized
|
||||
private static Page _page = Page.Home;
|
||||
private sealed class PendingPay { public string Address, Summary; public int Total; public Action Execute; }
|
||||
private static PendingPay _pay;
|
||||
private sealed class EditPrice { public GameItem Item; public BmSale Sale; public string Id; public long Ref; }
|
||||
private static EditPrice _edit;
|
||||
private static string _editPrice = "";
|
||||
private static string _addr = "";
|
||||
private static string _amount = "";
|
||||
private static string _message;
|
||||
@@ -33,7 +36,7 @@ namespace Decentralized
|
||||
{
|
||||
var page = p;
|
||||
string name = L.T("tab." + p.ToString().ToLowerInvariant());
|
||||
b.AddButton(page == _page ? $"[{name}]" : name, () => { _page = page; _message = null; _pay = null; Open(); });
|
||||
b.AddButton(page == _page ? $"[{name}]" : name, () => { _page = page; _message = null; _pay = null; _edit = null; Open(); });
|
||||
}
|
||||
b.End();
|
||||
b.AddSeparator();
|
||||
@@ -51,7 +54,7 @@ namespace Decentralized
|
||||
b.Show();
|
||||
}
|
||||
|
||||
private static void Go(Page p) { _page = p; _message = null; _pay = null; Open(); }
|
||||
private static void Go(Page p) { _page = p; _message = null; _pay = null; _edit = null; Open(); }
|
||||
|
||||
private static void Entry(CustomUIBuilder b, string icon, string name, string line1, string line2, Page target)
|
||||
{
|
||||
@@ -248,7 +251,7 @@ namespace Decentralized
|
||||
if ((t == Web3Tab.Mixer && !Unlock.MixerUnlocked) || (t == Web3Tab.Black && !Unlock.BlackUnlocked)) continue;
|
||||
var tab = t;
|
||||
string name = L.T("web3.sub." + t.ToString().ToLowerInvariant());
|
||||
b.AddButton(tab == _web3Tab ? $"[{name}]" : name, () => { _web3Tab = tab; _message = null; _pay = null; Open(); });
|
||||
b.AddButton(tab == _web3Tab ? $"[{name}]" : name, () => { _web3Tab = tab; _message = null; _pay = null; _edit = null; Open(); });
|
||||
}
|
||||
b.End();
|
||||
if (_web3Tab == Web3Tab.Mining) { ReportPage(b); return; }
|
||||
@@ -310,10 +313,11 @@ namespace Decentralized
|
||||
if (t == BlackTab.Desk && !desk) continue;
|
||||
var tab = t;
|
||||
string name = L.T("black.sub." + t.ToString().ToLowerInvariant());
|
||||
b.AddButton(tab == _blackTab ? $"[{name}]" : name, () => { _blackTab = tab; _message = null; _pay = null; Open(); });
|
||||
b.AddButton(tab == _blackTab ? $"[{name}]" : name, () => { _blackTab = tab; _message = null; _pay = null; _edit = null; Open(); });
|
||||
}
|
||||
b.End();
|
||||
if (d.Black.Closed(day)) { b.AddLabel(L.T("black.rugged", d.Black.ClosedUntil - day + 1)); return; }
|
||||
if (_edit != null) { EditPage(b); return; }
|
||||
if (_blackTab == BlackTab.Desk && desk) { DeskPage(b, rep, day); return; }
|
||||
if (_blackTab == BlackTab.Mine) { MinePage(b, day); return; }
|
||||
if (_blackTab == BlackTab.Sell) { SellPage(b, day); return; }
|
||||
@@ -366,7 +370,7 @@ namespace Decentralized
|
||||
}
|
||||
b.End();
|
||||
b.AddLabel(L.T("mixer.balance", _payAsset, Fmt.Num(d.Hot.Avail(_payAsset))) + " " + L.T("black.sell.rating", d.Black.Rating) + " " + L.T("black.sell.slots", d.Black.ActiveListings, Tuning.BmMaxListings));
|
||||
b.AddButton(L.T("black.sell.all"), () => BeginPay(d.Address("platform"), L.T("black.sell.all") + L.T("pay.listfee"), BlackDelivery.Sellable().Sum(it => BlackMarket.ListFee(BlackMarket.ListPriceOf(BlackDelivery.RefValue(it), _sellMult))), ListAll));
|
||||
b.AddButton(L.T("black.sell.all"), () => BeginPay(d.Address("platform"), L.T("black.sell.all") + L.T("pay.listfee", _sellMult.ToString("0.0", CultureInfo.InvariantCulture)), BlackDelivery.Sellable().Sum(it => BlackMarket.ListFee(BlackMarket.ListPriceOf(BlackDelivery.RefValue(it), _sellMult))), ListAll));
|
||||
b.AddSeparator();
|
||||
var items = BlackDelivery.Sellable();
|
||||
if (items.Count == 0) { b.AddLabel(L.T("black.sell.none")); return; }
|
||||
@@ -384,7 +388,7 @@ namespace Decentralized
|
||||
GoodHead(c, g, "");
|
||||
c.AddLabel(L.T("black.price", g.Price));
|
||||
c.AddFlexibleSpace();
|
||||
c.AddButton(L.T("black.sell.list"), () => BeginPay(d.Address("platform"), ItemName(g.Item) + L.T("pay.listfee"), BlackMarket.ListFee(g.Price), () => ListItem(it)));
|
||||
c.AddButton(L.T("black.sell.list"), () => BeginEdit(new EditPrice { Item = it, Id = g.Item, Ref = BlackDelivery.RefValue(it) }, g.Price));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -409,13 +413,13 @@ namespace Decentralized
|
||||
Open();
|
||||
}
|
||||
|
||||
private static void ListItem(GameItem it)
|
||||
private static void ListItem(GameItem it, double mult)
|
||||
{
|
||||
var d = Session.Data;
|
||||
string id = BlackDelivery.SellId(it);
|
||||
if (id == null) { Open(); return; }
|
||||
var u = Items.IsGpu(it) ? Items.ToUnit(it) : null;
|
||||
var s = d.Black.List(id, u?.Model, u?.FakeOf, u?.Health ?? 0, BlackDelivery.RefValue(it), _sellMult, d.Hot, _payAsset, StoreStation.GetDayCounter(), Session.Price);
|
||||
var s = d.Black.List(id, u?.Model, u?.FakeOf, u?.Health ?? 0, BlackDelivery.RefValue(it), mult, d.Hot, _payAsset, StoreStation.GetDayCounter(), Session.Price);
|
||||
if (s == null) { _message = d.Black.ActiveListings >= Tuning.BmMaxListings ? L.T("black.sell.full", Tuning.BmMaxListings) : L.T("msg.balance"); Open(); return; }
|
||||
it.Destroy();
|
||||
_message = L.T("black.sell.listed", ItemName(id), s.ListPrice);
|
||||
@@ -551,6 +555,51 @@ namespace Decentralized
|
||||
Open();
|
||||
}
|
||||
|
||||
private static void BeginEdit(EditPrice e, int initial)
|
||||
{
|
||||
_edit = e;
|
||||
_editPrice = initial.ToString(CultureInfo.InvariantCulture);
|
||||
_message = null;
|
||||
Open();
|
||||
}
|
||||
|
||||
private static int MinPrice(long refValue) => (int)Math.Ceiling(Tuning.BmSellMin * refValue - 1e-9);
|
||||
private static int MaxPrice(long refValue) => (int)Math.Floor(Tuning.BmSellMax * refValue + 1e-9);
|
||||
|
||||
/// <summary>设定标价:显示参考价,档位按钮只是帮忙填价格,价格也可以手输;按 标价 / 参考价 的比例算成交和污点。</summary>
|
||||
private static void EditPage(CustomUIBuilder b)
|
||||
{
|
||||
var e = _edit;
|
||||
b.AddHeader(ItemName(e.Id));
|
||||
b.AddLabel(L.T("black.edit.ref", e.Ref));
|
||||
b.BeginPanel(RightW, -1f, TextAnchor.MiddleCenter, 0f, 0f);
|
||||
b.AddInput(L.T("black.edit.input"), _editPrice, s => _editPrice = s, "price", s => _editPrice = s);
|
||||
b.End();
|
||||
b.BeginRow();
|
||||
foreach (var m in SellMults)
|
||||
{
|
||||
double mult = m;
|
||||
b.AddButton("×" + m.ToString("0.0", CultureInfo.InvariantCulture), () => { _editPrice = BlackMarket.ListPriceOf(e.Ref, mult).ToString(CultureInfo.InvariantCulture); Open(); });
|
||||
}
|
||||
b.End();
|
||||
if (int.TryParse((_editPrice ?? "").Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out int p) && p > 0)
|
||||
b.AddLabel(L.T("black.edit.price", p, (p / (double)e.Ref).ToString("0.00", CultureInfo.InvariantCulture)));
|
||||
b.BeginRow();
|
||||
b.AddButton(L.T("black.edit.ok"), () =>
|
||||
{
|
||||
if (!int.TryParse((_editPrice ?? "").Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out int price) || price < MinPrice(e.Ref) || price > MaxPrice(e.Ref))
|
||||
{ _message = L.T("black.edit.range", MinPrice(e.Ref), MaxPrice(e.Ref)); Open(); return; }
|
||||
double mult = price / (double)e.Ref;
|
||||
var d = Session.Data;
|
||||
int fee = e.Sale != null ? BlackMarket.RepriceFee(price) : BlackMarket.ListFee(price);
|
||||
_edit = null;
|
||||
BeginPay(d.Address("platform"), ItemName(e.Id) + L.T(e.Sale != null ? "pay.repricefee" : "pay.listfee", mult.ToString("0.00", CultureInfo.InvariantCulture)), fee,
|
||||
() => { if (e.Sale != null) RepriceSale(e.Sale, mult); else ListItem(e.Item, mult); });
|
||||
});
|
||||
b.AddButton(L.T("black.edit.cancel"), () => { _edit = null; _message = null; Open(); });
|
||||
b.End();
|
||||
}
|
||||
|
||||
private static void RepriceSale(BmSale s, double mult)
|
||||
{
|
||||
var d = Session.Data;
|
||||
@@ -581,20 +630,11 @@ namespace Decentralized
|
||||
{
|
||||
var sale = sl;
|
||||
string st = sale.State == SaleState.Sold ? L.T("black.sale.Sold", sale.PayDay) : L.T("black.sale." + sale.State + (sale.State == SaleState.Delisted && sale.Why != null ? "." + sale.Why : ""));
|
||||
l.AddLabel(L.T("black.mine.sale", ItemName(sale.Item), sale.Mult.ToString("0.0", CultureInfo.InvariantCulture), st));
|
||||
l.AddLabel(L.T("black.mine.sale", ItemName(sale.Item), sale.Ref, sale.ListPrice, sale.Mult.ToString("0.00", CultureInfo.InvariantCulture), st));
|
||||
if (sale.State == SaleState.Listed)
|
||||
{
|
||||
l.BeginRow();
|
||||
foreach (var m in SellMults)
|
||||
{
|
||||
double mult = m;
|
||||
string n = m.ToString("0.0", CultureInfo.InvariantCulture);
|
||||
l.AddButton(Math.Abs(mult - sale.Mult) < 1e-9 ? $"[{n}]" : n, () =>
|
||||
{
|
||||
if (Math.Abs(mult - sale.Mult) < 1e-9) return;
|
||||
BeginPay(d.Address("platform"), ItemName(sale.Item) + L.T("pay.repricefee", n), BlackMarket.RepriceFee(BlackMarket.ListPriceOf(sale.Ref, mult)), () => RepriceSale(sale, mult));
|
||||
});
|
||||
}
|
||||
l.AddButton(L.T("black.sell.reprice"), () => BeginEdit(new EditPrice { Sale = sale, Id = sale.Item, Ref = sale.Ref }, sale.ListPrice));
|
||||
l.AddButton(L.T("black.sell.delist"), () => Delist(sale));
|
||||
l.End();
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user