Skip to content

交易

This content is not available in your language yet.

玩家把船开进城市港口范围后,通过港口面板进入“购物车式”交易界面,按“基础价 × 库存系数 × 关系系数(卖出再乘新鲜度系数)“的价格与城市买卖物品;城市库存每个游戏日自动补货,奢侈品价格与库存随距产地距离梯度变化。

交易是金币的主要来源与去向:玩家通过出售生产品、怪物掉落物换取金币,再购入弹药、食物、建材维持航行与建设。累计卖出收入还直接驱动“贸易大亨”胜利路线(见 游戏循环与胜负)。

玩家接触路径:

  1. 把船开进某城市的触发半径(来自 cities.csv 的 radius 列 × 世界缩放,详见下文)。
  2. 屏幕右侧自动弹出港口面板(含“交易 / 修船 / 招募 / 外交”按钮,HarborPanel.cs)。敌对城市的交易按钮被禁用。
  3. 点击“交易”打开全屏交易弹窗(TradingPanel.cs):左列是城市在售商品(购买),右列是玩家全船 Storage 容器里的物品(出售)。
  4. + / / 按钮把买卖条目加入“待执行清单”,底部实时显示金币与买入箱空间预览,点确认一次性结算。

交易对象目前只有两类:城市CityTrader.cs,每个城市生成时自动挂载)和测试商家TradingTestSetup.cs,仅当场景预设配了 TestTrader.json 时生成,开发用)。TraderType.NPCShip 枚举已定义但当前没有任何生成路径——不存在与 NPC 船只的交易

规则 数值 来源
触发判定 玩家船与港口参考点的直线距离 ≤ 城市触发半径,每帧检测 代码 CityTradingTrigger.cs
触发参考点 优先用 HarborRegistry 注册的港口位置,无港口时回退城市自身位置 代码 CityTradingTrigger.cs
城市触发半径 cities.csv 的 radius(45~60)× 世界 cityRadiusScale CSV cities.csv + JSON DataSets/world/*.json
cityRadiusScale real 世界 = 1.0(半径 45~60 米);compact 世界 = 0.2(9~12 米) JSON DataSets/world/real.json / compact.json
敌对城市 进入范围仍弹港口面板,但交易/修船/招募按钮禁用;也不记录“停靠港口”(不破除 Stress、不更新复活点) 代码 HarborPanel.csCityTradingTrigger.cs

敌对判定来自玩家与城市所属国家的声望关系(FactionRelation.GetRelation,默认阈值:声望 ≥ 50 为 Friendly,≤ −30 为 Hostile,其余 Neutral;自由港所属 country_free 不参与外交,永久 Neutral)。详见 阵营与外交

进入城市范围还有两个交易相关副作用(见 探索与情报):

  • 自动“发现”该城市及其所属国家(DiscoveryAccess.DiscoverCity)。
  • 发布一次港口简报:自上次简报以来的世界新闻 + 最多 3 条流言。流言之一是邻近(直线 3000 米内)已发现产地城市的奢侈品价格,带 ±30% 随机误差RumorGenerator.csRandom.Range(0.7, 1.3))。

整个交易在一个会话(TradingSession.cs)中进行,确认前不产生任何实际转移:

  1. 开始:UI 调用 CityTradingTrigger.StartTrading(),要求玩家仍在范围内。会话记录交易城市与国家 ID。交易开始后港口面板让位给交易弹窗。
  2. 加入购买(玩家从城市买):请求数量超过“城市当前库存 − 已加入购物车数量”时自动截断到最大可买量(仍算成功);库存已被购物车占满时返回“库存已售罄”。加入时锁定单价(之后城市库存变化不影响已加入条目的价格)。
  3. 加入出售(玩家卖给城市):同样按“玩家持有量 − 已加入数量”自动截断。出售按 (物品, 新鲜度) 分行展示,但同一物品的鲜/陈两行共享同一个待卖计数。
  4. 预览验证CalculatePreview):
    • 金币验证:交易后金币 = 当前金币 + 总卖出收入 − 总购买支出,< 0 则“金币不足”。即同一次结算里卖货收入可以直接抵扣买货支出
    • 空间验证:购买需要的买入箱格子数 = 每种物品 ⌈数量 ÷ 最大堆叠⌉ 之和(最大堆叠取自物品配置,缺省 50),超过买入箱剩余格子则“买入箱空间不足”。
  5. 执行:先执行全部出售(先拿钱),再执行全部购买(再花钱)。执行成功后会话保持打开,可继续交易;执行后清空购物车。
  6. 结束:关闭弹窗调用 TradingManager.EndTrading(),不结算未确认的购物车。

所有价格都从一张全局静态价格表ItemPriceConfig.cs)查起,该表按以下顺序被写入:

  1. 代码默认表:20 种物品的硬编码价格(见下方“公式与数值”),未配置物品一律回退 10 金
  2. 城市初始化覆盖:每个城市生成时,把自己在 CityInventory.csv 中的 buy_price(> 0 时)写入全局表(CityTrader.LoadInventoryFromCityManager)。
  3. 奢侈品产地价覆盖:随后把 GoodsOrigin 距离梯度算出的本城奢侈品价 × 全局价格修正器写入全局表(CityTrader.LoadLuxuryGradientInventory)。

注意这是一张全局表:多个城市对同一物品写不同价格时,最后初始化的城市覆盖前面所有城市(详见“已知限制”)。

买入单价 = round( round( 基础价 × 库存价格系数 ) × 关系系数 )
  • 库存价格系数(TraderItemConfig.PriceModifier):城市商品恒为 1.0(CityTrader.cs 写死);只有测试商家的 TestTrader.json 里可配非 1 值。
  • 关系系数见下表。
收购单价 = round( 基础价' × (1 / 关系系数) ) (关系系数为 1.0 时不变)
实际成交单价 = max(1, round( 收购单价 × 新鲜度系数 ))
  • 基础价’:城市有该商品条目时 = round(基础价 × 库存价格系数);城市不卖该物品时直接取全局基础价(城市默认收购一切物品NPCTrader._buyAllItems = true)。
  • 关系系数取倒数:关系差时城市压价收购,关系好且同国籍时城市加价收购。
  • 新鲜度系数:Fresh / 无保鲜概念 = 1.0;Stale(陈旧)= 0.5FreshnessState.cs 常量 StaleValueMultiplier),折后最低 1 金。腐烂物不存在折扣问题——过期物品已被转换成 RottenFood / StaleWater(基础价均为 1 金)。见 物品与库存

默认没有买卖价差:同一物品在同一城市,买入价和收购价都从同一基础价推出(CityInventory.csvsell_price 列代码从不读取)。价差完全由两个修正产生:

  • 关系:Neutral 城市买入贵 20%、收购低约 16.7%(×1/1.2)。自由港永久 Neutral,所以在自由港交易永远吃这组双向价差。
  • 新鲜度:陈旧货卖出打 5 折。

全局价格修正器(GlobalPriceModifier)

Section titled “全局价格修正器(GlobalPriceModifier)”
  • 世界事件调度器(EventScheduler.cs)每 7 个游戏日投放 1 条新闻,4 类各 25% 概率:宣战 / 停战 / 通货变动 / 怪物潮(NewsTemplates.cs)。
  • 通货变动新闻从 {IronPlate, Wood, Coal, Bullet} 均匀抽 1 种物品,价格乘数 0.95 或 1.05(各 50%),对该物品的全局修正系数累乘GlobalPriceModifier.Apply)。
  • 修正系数随存档保存/读取(WorldStateInfo.cs,见 存档)。
  • 当前唯一应用点:城市初始化时计算奢侈品上架价(CityTrader.LoadLuxuryGradientInventoryprice × modifier.Get(itemId))。注意这两个集合不相交——见“已知限制”。

6 种奢侈品各有唯一产地城市(GoodsOrigin.csvGoodsOriginRegistry.cs 懒加载)。每个城市初始化时按“距产地的直线距离”计算本城的上架价与库存:

距离km = √( (Δx × positionScale)² + (Δz × positionScale)² ) ÷ 1000 (Δ 取 cities.csv 坐标差)
上架价 = round( BasePrice × (1 + PriceRisePerKm × 距离km) ) × 全局价格修正器,最低 1 金
上架库存 = round( max( BaseStock × (1 − StockDropPerKm × 距离km), BaseStock × MinStockRatio ) ),最低 0

规则:

  • 产地城市距离为 0:原价、满库存。
  • 自由港(city_005)一律不上架任何奢侈品GoodsOriginRegistry.cs 硬编码跳过,返回“不上架”)。
  • 库存梯度有保底:跌到 BaseStock × MinStockRatio 后不再下降。
  • 奢侈品条目追加在 CityInventory.csv 条目之后;同物品 ID 时 GoodsOrigin 覆盖 CityInventory(当前两表物品不重叠,规则备而未用)。
  • 库存派生:MaxStock = 上架库存 × 2DailyRefresh = max(1, 上架库存 ÷ 5)(整除)。

示例(“正常游玩”预设,real 世界 positionScale = 1.0):

物品 在产地 在异地 计算过程
LuxuryWine(产地马德里 city_001) 5 金 / 库存 400 塞维利亚 city_002:11 金 / 库存 248 距离 ≈ 1.90 km;价 = round(5×(1+0.6×1.90));库存 = round(400×(1−0.2×1.90))
LuxurySilk(产地马赛 city_007) 80 金 / 库存 150 马德里 city_001:622 金 / 库存 8 距离 ≈ 5.64 km;价 = round(80×(1+1.2×5.64));库存触底 = round(150×0.05)=8

compact 世界(positionScale = 0.1)所有距离缩小 10 倍,梯度相应变缓。

城市商品来自 CityInventory.csv(每行一个 城市×物品 条目),运行时派生为商家库存(CityTrader.csTraderInventory.cs):

运行时字段 派生公式 说明
InitialStock(初始库存) = CSV stock 开局即有
MaxStock(库存上限) = CSV stock × 2 补货与收购都不会超过它
DailyRefresh(每日补货量) = CSV stock ÷ 5(整除) 例:stock 80 → 每日 +16
PriceModifier = 1.0(写死) 城市无单品价格系数

补货规则(TraderInventory.cs):

  • 监听游戏日变化事件(DateTimeManager.OnDayChanged),每个游戏日刷新一次(同一天去重)。
  • 新库存 = min(当前库存 + DailyRefresh, MaxStock)
  • 1 游戏日 = 1440 游戏分钟;默认速度下 1 现实秒 = 1 游戏小时,即 1 游戏日 = 24 现实秒(随游戏速度档位缩放,见 时间与调度)。
  • 库存为 0 的商品不出现在在售列表,补货后重新上架。

玩家卖给城市的物品去向(NPCTrader.Buy):城市有该商品条目时入库(仍受 MaxStock 封顶,溢出部分消失);城市没有该条目时物品直接消失。两种情况金币都照付——城市金币无限(NPCTrader.Gold = long.MaxValue)。

限制 规则 来源
必须有买入箱 购买的物品只进“买入箱”建筑(PurchaseBox);一个都没有时无法购买 代码 PlayerTrader.cs
买入箱容量 每个买入箱 100 格 Storage 容器;1×1 建筑,需玩家自己建造(见 修建 CSV BuildingContainerConfig.csvBuildingConfig.csv
空间验证单位 按格子数验证:⌈数量 ÷ 物品最大堆叠⌉,最大堆叠见 物品数据表,未配置回退 50 代码 TradingSession.cs
出售货源 全船 Storage 类容器(含仓库、买入箱),不含地面物品、生产建筑的输入/输出格 代码 PlayerTrader.cs
出售扣货顺序 按容器/槽位遍历顺序扣减,不保证陈货先出 代码 PlayerTrader.cs 注释
金币 存在玩家船数据上(ShipData.gold),见 船只 代码 TradingManager.cs

每次成功执行且会话带国家 ID 时发布交易完成事件(TradeCompletedMessage),两个系统消费:

声望FactionEventHandler.cs,数值硬编码在 FactionManager.cs):

事件 条件 对交易国声望
FirstVisit 本局首次在该城市完成交易(按城市去重;只靠岸不交易不算) +10
TradeSmall 单次结算卖出收入 1~100 金 +3
TradeMedium 单次结算卖出收入 101~500 金 +5
TradeLarge 单次结算卖出收入 > 500 金 +8

只有卖出计声望,纯购买不加;声望只给交易城市所属国家。

胜利VictoryManager.cs):累计卖出收入 ≥ 50000 金(代码常量 TradeTycoonThreshold)达成“贸易大亨”胜利。

CityInventory.csv 有两个变体,由场景预设 JSON 的 trading 轴选择(ScenarioLoader.cs):

变体 定位 与 standard 的差异
DataSets/trading/standard/ 正常游玩数值 基准
DataSets/trading/rich/ 测试用富裕环境 同样的城市×物品组合,库存约 ×4~×10(多数 ×5),价格约 ÷2;额外带 TestTrader.json(在 (10, 0, 10) 生成一个蓝色圆柱测试商家,9 种商品)

预设归属:正常游玩.json 未配 trading 轴 → 走默认路径 standard战斗测试.json 显式 standard;其余测试预设(交易测试、日常测试、集成测试、外循环测试等共 11 个)全部用 rich。standard 变体目录下没有 TestTrader.json,所以正常游玩不会出现测试商家。

公式 内容 来源
玩家买入单价 round( round(基础价 × 库存系数) × 关系系数 ) 代码 TraderInventory.cs + CityTrader.cs
城市收购单价 round( 基础价' × (1/关系系数) ) 代码 CityTrader.cs
实际卖出成交价 max(1, round(收购单价 × 新鲜度系数)) 代码 TradingSession.cs
奢侈品上架价 max(1, round( round(BasePrice × (1 + PriceRisePerKm × 距离km)) × 全局修正 )) 代码 GoodsOriginRegistry.cs + CityTrader.cs
奢侈品上架库存 round( max(BaseStock × (1 − StockDropPerKm × 距离km), BaseStock × MinStockRatio) ) 代码 GoodsOriginRegistry.cs
交易后金币 当前金币 + Σ卖出 − Σ购买(≥ 0 才放行) 代码 TradingSession.cs
购买所需格子 Σ ⌈数量 ÷ 最大堆叠⌉(按物品种类分别向上取整) 代码 TradingSession.cs
每日补货 min(当前库存 + DailyRefresh, MaxStock),每游戏日一次 代码 TraderInventory.cs

关系系数表(CityTrader.cs 代码常量)

Section titled “关系系数表(CityTrader.cs 代码常量)”
玩家与城市所属国关系 买入系数(玩家付) 收购系数(玩家收)
Friendly 且同国籍 ×0.9 ×1/0.9 ≈ ×1.111
Friendly ×1.0 ×1.0
Neutral(含自由港,永久中立) ×1.2 ×1/1.2 ≈ ×0.833
Hostile ×1.5(理论值,UI 已拦截交易,正常到不了) ×1/1.5 ≈ ×0.667

代码默认基础价表(ItemPriceConfig.cs 代码常量,单位:金/个)

Section titled “代码默认基础价表(ItemPriceConfig.cs 代码常量,单位:金/个)”
物品 物品 物品
SaltPork 10 Coal 2 MonsterCorpse 30
DrinkableWater 3 Bullet 1 MonsterMeat 8
Grog 8 CannonShell 3 CookedMeal 20
Water 2 AA_Gun_Bullet 1 MonsterBrew 40
Steam 3 Wood 3 RottenFood 1
BeastOil 12 Stone 4 StaleWater 1
BlackPowder 6 IronPlate 8 (未配置物品) 10

这张表是兜底:城市初始化后,凡出现在 CityInventory.csv / GoodsOrigin.csv 的物品会被运行时覆盖(见“已知限制”第 1 条)。Fuel 不在默认表里,价格完全由 CSV 提供。

CityInventory.csv 全量(standard / rich 对照)

Section titled “CityInventory.csv 全量(standard / rich 对照)”

列含义:city_id 城市、item_id 物品、stock 初始库存(同时派生上限 ×2、日补 ÷5)、buy_price 写入全局基础价、sell_price 代码未读取。两变体各 41 行数据。

城市 物品 standard 库存/价 rich 库存/价
city_001 马德里 SaltPork 80 / 8 320 / 4
city_001 马德里 Coal 200 / 2 800 / 1
city_001 马德里 MonsterBrew 30 / 40 120 / 20
city_001 马德里 DrinkableWater 400 / 3 2000 / 2
city_001 马德里 Bullet 300 / 2 2000 / 1
city_001 马德里 CannonShell 100 / 4 1000 / 2
city_001 马德里 Wood 150 / 4 1000 / 2
city_001 马德里 IronPlate 100 / 8 500 / 4
city_001 马德里 Stone 100 / 5 500 / 3
city_002 塞维利亚 SaltPork 80 / 8 320 / 4
city_002 塞维利亚 Coal 200 / 2 800 / 1
city_002 塞维利亚 MonsterBrew 30 / 40 120 / 20
city_002 塞维利亚 DrinkableWater 600 / 2 3000 / 1
city_002 塞维利亚 Bullet 100 / 2 1000 / 1
city_002 塞维利亚 Wood 200 / 3 1000 / 2
city_002 塞维利亚 IronPlate 250 / 6 1500 / 3
city_003 普利茅斯 Bullet 800 / 1 5000 / 1
city_003 普利茅斯 CannonShell 500 / 3 3000 / 2
city_003 普利茅斯 AA_Gun_Bullet 300 / 1 2000 / 1
city_003 普利茅斯 Fuel 300 / 6 2000 / 3
city_003 普利茅斯 DrinkableWater 200 / 4 1000 / 2
city_003 普利茅斯 IronPlate 100 / 9 500 / 5
city_003 普利茅斯 Wood 100 / 5 500 / 3
city_004 朴次茅斯 Wood 400 / 2 2000 / 1
city_004 朴次茅斯 Stone 300 / 3 1500 / 2
city_004 朴次茅斯 IronPlate 200 / 7 1000 / 4
city_004 朴次茅斯 Coal 300 / 2 1500 / 1
city_004 朴次茅斯 Fuel 200 / 5 1000 / 3
city_004 朴次茅斯 DrinkableWater 200 / 3 1000 / 2
city_005 自由港 DrinkableWater 300 / 5 1500 / 3
city_005 自由港 Bullet 200 / 3 1000 / 2
city_005 自由港 CannonShell 100 / 5 500 / 3
city_005 自由港 Wood 100 / 5 500 / 3
city_005 自由港 Stone 80 / 6 400 / 4
city_005 自由港 IronPlate 60 / 11 300 / 6
city_005 自由港 Fuel 100 / 9 500 / 5
city_005 自由港 SaltPork 80 / 13 400 / 7
city_006 勒阿弗尔 Wood 120 / 5 600 / 3
city_006 勒阿弗尔 IronPlate 80 / 10 400 / 5
city_007 马赛 Wood 120 / 5 600 / 3
city_007 马赛 IronPlate 80 / 10 400 / 5

数据设计意图(仅供调参参考,实际生效情况见“已知限制”第 1 条):city_003 是弹药特化港(Bullet 1 金)、city_004 是建材特化港(Wood 2 金)、自由港全线高价(中立价差 + 高标价双重溢价)、city_006/007 是远海高危区的简化补给点。

物品 产地 产地价(金) 产地库存 价格涨幅/km 库存降幅/km 库存保底比例
LuxuryWine city_001 马德里 5 400 0.6 0.20 0.10
LuxuryTobacco city_002 塞维利亚 30 250 1.0 0.30 0.05
LuxuryCloth city_003 普利茅斯 12 300 0.7 0.20 0.10
LuxuryArtillery city_004 朴次茅斯 30 100 1.0 0.30 0.05
LuxuryCoffee city_006 勒阿弗尔 30 300 0.8 0.25 0.05
LuxurySilk city_007 马赛 80 150 1.2 0.30 0.05

自由港 city_005 没有产地行,也不上架任何奢侈品(代码硬编码)。城市坐标(距离计算输入,cities.csv):city_001 (200,150)、city_002 (−1500,1000)、city_003 (2000,500)、city_004 (2500,2000)、city_005 (500,2500)、city_006 (−1000,5000)、city_007 (2000,5500)。

TestTrader.json(仅 rich 变体,开发用)

Section titled “TestTrader.json(仅 rich 变体,开发用)”

名称“测试商店”,位置 (10, 0, 10),类型 City,收购一切。9 种商品:SaltPork(上限 100/初始 50/日补 10)、CookedMeal(80/40/8)、DrinkableWater(200/100/20)、BeastOil(100/30/5,价格系数 1.2,全游戏唯一非 1 库存价格系数示例)、Bullet(500/200/50)、CannonShell(200/100/20)、AA_Gun_Bullet(300/150/30)、IronPlate(100/50/10)、Coal(200/100/20)。

数值 单位 来源
新鲜度折扣(Stale) 0.5,折后最低 1 金 倍率 代码 FreshnessState.cs
世界新闻间隔 7 游戏日 代码 EventScheduler.cs
通货变动概率 每条新闻 25%(4 类均分) 百分比 代码 NewsTemplates.cs
通货变动幅度 ×0.95 或 ×1.05(各 50%),累乘 倍率 代码 NewsTemplates.cs
通货变动物品池 IronPlate / Wood / Coal / Bullet(各 25%) 代码 NewsTemplates.cs
流言价格误差 ×0.7 ~ ×1.3 均匀随机 倍率 代码 RumorGenerator.cs
流言邻城距离上限 3000 代码 RumorGenerator.cs
单次简报流言上限 3 代码 RumorGenerator.cs
买入箱容量 100 CSV BuildingContainerConfig.csv
堆叠数兜底 50 个/格 代码 TradingSession.csPlayerTrader.cs
贸易大亨胜利 累计卖出收入 ≥ 50000 代码 VictoryManager.cs
声望:首次交易 / 小额 / 中额 / 大额 +10 / +3 / +5 / +8 代码 FactionManager.cs
交易额分档 小 ≤ 100 < 中 ≤ 500 < 大 金(单次卖出收入) 代码 FactionEventHandler.cs
UI 列表刷新 0.5 代码 TradingPanel.cs
  • 物品与库存:出售货源是全船 Storage 容器;购买入买入箱;新鲜度(Fresh/Stale)决定卖出折扣;过期转换物 RottenFood/StaleWater 只值 1 金。
  • 生产与制作:生产链产物(CookedMeal、MonsterBrew 等)是主要卖出收入来源。
  • 战利品与掉落:MonsterCorpse(30 金)等怪物掉落是前期重要变现物。
  • 修建:买入箱(PurchaseBox)是 1×1 设施建筑,需先建好才能购买。
  • 城市与国家:交易对象、触发半径、城市类型与坐标都来自城市系统;城市被占领会改变所属国家进而改变关系系数。
  • 阵营与外交:关系状态决定 0.9~1.2 的价格系数与敌对禁入;交易反过来是涨声望最稳定的手段(+3~+10/次)。
  • 探索与情报:靠港自动发现城市;港口简报推送通货变动新闻与奢侈品价格流言;产地价差是探索远港的经济动机。
  • 时间与调度:城市补货与世界新闻都挂在游戏日变化事件上;默认 1 游戏日 = 24 现实秒。
  • 游戏循环与胜负:累计卖出 50000 金达成贸易大亨胜利。
  • 存档:全局价格修正器与新闻列表随世界状态存档;城市当前库存不存档(重新初始化为 CSV 初始值)。
  • 界面总览:港口面板(MainRight 层)与交易弹窗(Modal 层)。
  • 开发者工具:场景预设选择 standard/rich 数据集与测试商家。
想调什么 改哪里 注意
某城市卖什么、卖多少、标价 Assets/StreamingAssets/DataSets/trading/standard/CityInventory.csv(正常游玩)或 rich/(多数测试预设) buy_pricesell_price 列无效;库存上限/日补由 stock 自动派生(×2、÷5),不能独立调
物品兜底价格 ItemPriceConfig.cs 代码默认表 需要程序改;只对不在任何 CSV 里的物品长期生效
奢侈品产地、价格/库存梯度 Assets/StreamingAssets/GoodsOrigin.csv 列:BasePrice、BaseStock、PriceRisePerKm、StockDropPerKm、MinStockRatio;产地城市改 OriginCityId
关系价差幅度 CityTrader.csGetRelationPriceModifier() 代码常量 0.9 / 1.0 / 1.2 / 1.5,需程序改
陈旧货折扣 FreshnessState.cs 常量 StaleValueMultiplier(0.5) 注意此值同时影响食物饱食恢复量,不只交易
补货节奏 TraderInventory.cs(每日一次)或 CSV stock(决定日补量) 想改“每 N 天补货”需程序改
通货变动频率/幅度/物品池 EventScheduler.cs(7 天)、NewsTemplates.cs(±5%、物品池) 代码常量;当前对实际价格无效(见已知限制第 2 条)
声望奖励数值 FactionManager.cs_reputationEvents 硬编码表 代码常量;分档阈值在 FactionEventHandler.cs
贸易胜利门槛 VictoryManager.cs 常量 TradeTycoonThreshold(50000) 代码常量
交易触发距离 cities.csvradius 列 + DataSets/world/*.jsoncityRadiusScale 半径同时是城市 Gizmo/领地视觉半径
买入箱容量 BuildingContainerConfig.csv PurchaseBox 行 StorageCapacity(100) CSV 可改
测试商家 DataSets/trading/rich/TestTrader.json 仅当预设 trading 轴指向含该文件的变体时生成
切换 standard/rich Assets/StreamingAssets/Presets/*.json"trading" 字段 不配 = standard
  1. 全局价格表互相覆盖,“每城一价”实际不成立ItemPriceConfig 是全局静态表,每个城市初始化时把自己的 CSV 标价和奢侈品距离价写进同一张表,而商家报价在交易时实时查这张表。结果是:同一物品在所有城市同价,以最后初始化的城市写入值为准(如 SaltPork 在 CSV 里 city_001 标 8、自由港标 13,实际全图统一为后初始化者的值)。奢侈品的价格梯度同样被覆盖失效,只有库存梯度真实生效;流言播报的产地价用的是独立计算值,可能与商店实价不符。CSV 中的城市差异化标价目前主要剩“该城卖不卖、卖多少库存”的作用。
  2. 通货变动新闻无实际价格效果GlobalPriceModifier 唯一的读取点是城市初始化时的奢侈品上架价,而通货变动新闻的物品池是 IronPlate/Wood/Coal/Bullet——两个集合不相交,所以该系数当前永远是 1.0 参与计算。且 GlobalPriceModifier.cs 注释声称“dock 入场重算 inventory 时应用”,实际代码只在城市 Start 时应用一次,会话中途的通货变动要等读档/重开场景才可能生效(前提是物品池修正)。
  3. sell_price 列是死配置:代码无任何读取(全工程无 .SellPrice 引用),买卖同价由代码结构决定。
  4. PlayerTrader.Buy 把“剩余格子数”当“物品个数”用:单个买入箱单次结算最多入库“空格数”个物品(100 格空箱最多收 100 个),与预览的按格验证(100 格可装 100×50 个)不一致;超出部分自动按单价退款,不报错。大宗采购建议分多次确认或多建买入箱。
  5. 预览的格子估算偏保守TradingSession.cs 内 TODO):按“每种物品都需要全新格子”计算,未考虑买入箱已有同类未满格可合并,可能在实际放得下时提前拦截。
  6. 城市收购无限且无差别_buyAllItems 默认 true,_specificBuyItemIds 白名单机制存在但无任何配置使用;城市金币无限,卖出没有数量上限或价格递减,刷钱的唯一约束是货源和声望分档。
  7. 城市库存不存档:读档后城市库存回到 CSV 初始值;只有全局价格修正器、新闻、发现状态随世界状态存档。
  8. NPC 船交易未实现TraderType.NPCShip 与设计文档(Docs/design/TradingSystem_Design.md)中“与其他船只交易”的设想均未落地,当前交易对象只有城市与开发用测试商家。
  9. 设计文档差异:设计文档中提到的价格随机性、供需动态、品质影响价格均未实现;现状是固定基础价 + 关系/新鲜度/产地三类修正。TradingManager.cs 的序列化字段 _gameDayInSeconds(300 秒)与 _defaultTriggerDistance(50 米)是早期设计遗留,当前无任何消费代码——补货实际走 DateTimeManager 的游戏日(24 现实秒/天),触发距离实际走城市半径。
  10. Assets/StreamingAssets/CitySystem/CityInventory.csv 是未被引用的旧副本(内容与 standard 变体完全相同):运行时加载路径是 DataSets/trading/standard/,改 CitySystem 目录下那份不会生效。
  11. 出售列表的鲜/陈分行共享同一待卖计数,且扣货按槽位顺序、不保证陈货先卖;玩家想“只卖陈货”时可能混卖鲜货(PlayerTrader.cs 注释明示的取舍)。