Skip to content

阵营与外交

This content is not available in your language yet.

三个外交国家 + 一个永久中立的自由港联合 + 默认敌对的海盗/怪物;玩家对每个国家维护一个整数声望(≥50 友好 / ≤-30 敌对 / 其余中立),声望分档决定交易价格、巡逻船与城防炮是否开火、能否申请国籍;国家之间还有一张会被玩家行为和世界新闻改写的关系矩阵。

阵营与外交系统(FactionManager.cs,位于 Assets/Scripts/Service/FactionSystem/)是全游戏敌我判定的唯一裁决源。它管理三类状态:

  1. 玩家对各国的声望:每国一个无上下限的整数,实时换算成三态关系(Friendly / Neutral / Hostile)。
  2. 国家间关系:三态对称矩阵,开局由配置表预置,游戏中被动态触发器和世界新闻改写。
  3. 玩家国籍:玩家船可申请加入某国,国籍影响攻击行为的合法性判定、本国购物折扣和占领城市后的归属。

武器自动索敌、AI 船选目标、船只碰撞伤害、巡逻船虚拟战斗,全部经由统一的关系查询入口(FactionRelation.cs)问询本系统。

玩家接触本系统的入口:

  • 外交面板DiplomacyPanel.cs,Modal 层):显示三国声望数值、国与国关系矩阵,并提供三个外交动作(贸易协定 / 停火协议 / 申请国籍)。从港口的外交按钮打开时动作可执行;从模式栏打开时仅可查看。面板只显示已发现的国家。
  • 港口与交易:关系决定能否停靠休整(敌对城停靠不算休息)、买卖价格加成。
  • 战斗后果:击杀有国籍的船、占领城市、击杀 Boss 都会改变声望,声望跨过阈值时关系翻转,该国巡逻船和城防炮立即改变敌我态度。
  • 顶部 HUD:当前所在海域归属国及关系实时显示(CurrentLocationPresenter.cs)。

在游戏循环中的位置:声望是把“航海—贸易—战斗”串起来的长线资源,也是一条胜利路线——三国声望全部达到 50 即达成外交家(Diplomat)胜利(见 游戏循环与胜负)。

阵营分三类,行为完全不同:

分类 成员 参与声望/外交 参与领地划分 对玩家默认态度
外交阵营 country_001 西班牙、country_002 英格兰、country_003 法兰西 按声望分档
领地阵营(仅领地) country_free 自由港联合 否(声望锁定 0,写入被白名单守卫拒绝) 永久 Neutral
未注册阵营 Pirate(AI 船默认阵营)、Enemy(怪物/Boss)、其他任意未登记字符串 永久 Hostile(对玩家和所有国家对称敌对)
  • 外交阵营清单来自 CSV 配置表 FactionConfig.csv(每行一国);country_free 为代码常量追加(FactionManager.cs,注释说明 CSV 暂无 is_diplomatic 列)。
  • 国家中文名、地图颜色等展示信息在 countries.csv(属城市系统,见 城市与国家)。
  • 对非外交阵营写声望会被守卫直接拒绝并打警告日志,保证声望字典不被污染(FactionManager.cs,回归测试 FactionFactionsSplitTests.cs)。

关系判定规则(优先级从上到下)

Section titled “关系判定规则(优先级从上到下)”

任意两个阵营 A、B 的关系按以下顺序裁决(FactionManager.cs + FactionRelation.cs):

优先级 条件 结果
1 任一方 ID 为空 Neutral
2 A 与 B 是同一字符串 Friendly
3 任一方是字面量 "Player" 走玩家声望分档(见下节);对方若是仅领地阵营 → Neutral;对方若未注册 → Hostile
4 两国关系表中有记录(preset 或运行时改写) 查表返回
5 任一方未注册(既非外交也非领地阵营) Hostile
6 其余 Neutral

注意:只有字面量 "Player" 走玩家路径。玩家持有 country_001 国籍时,查询 country_001country_002 仍是纯国家间关系,不会被玩家声望污染(专门回归测试覆盖)。

  • 声望是每国独立的整数,无上限也无下限(代码不做 clamp)。
  • 分档规则(阈值含等号):
关系 = Friendly 若 声望 >= friendly_threshold (50)
= Hostile 若 声望 <= hostile_threshold (-30)
= Neutral 其余 (-29 ~ 49)
  • 阈值逐国配置;未在表中的国家用代码常量默认值 (50, -30)(FactionManager.cs GetThresholds)。

FactionConfig.csv(CSV 配置表,全量 3 行):

country_id 初始声望 友好阈值 敌对阈值 开局关系
country_001(西班牙) 0 50 -30 Neutral
country_002(英格兰) -50 50 -30 Hostile(开局即敌国)
country_003(法兰西) 0 50 -30 Neutral

边界示例(来自测试 FactionManagerTests.cs):声望 49 仍是 Neutral,50 才是 Friendly;-29 仍是 Neutral,-30 即 Hostile。

声望每次变动都广播变更消息(旧值/新值/旧关系/新关系),驱动外交面板刷新、胜利判定和动态关系触发。

FactionRelationPreset.csv(CSV 配置表,全量 3 行,关系对称存储):

西班牙 country_001 英格兰 country_002 法兰西 country_003
西班牙 country_001 Hostile Friendly
英格兰 country_002 Hostile Neutral
法兰西 country_003 Friendly Neutral

国家间关系会在运行时被两条途径改写(只存在于当局内存中):动态关系触发器、世界新闻(均见下文)。

声望事件 = 事件类型 → (目标国声望变化, 目标国敌国声望变化, 是否重置)。实际生效的数值是 FactionManager.cs 中的代码常量ReputationEventConfig.csv 虽然存在且内容一致,但运行时并不加载它,见“已知限制”)。

事件类型 目标国 目标国的敌国 重置 触发条件(FactionEventHandler.cs
FirstVisit +10 0 在某城市首次完成一笔交易(按城市去重)
TradeSmall +3 0 单次交易卖出收入 1 ~ 100 金
TradeMedium +5 0 单次交易卖出收入 101 ~ 500 金
TradeLarge +8 0 单次交易卖出收入 > 500 金
BossKill +15 0 玩家击杀 Boss,加给 Boss 死亡位置所属海域的国家
MonsterKill +3 0 无触发源(普通怪击杀被显式排除在声望结算外)
AttackShip -30 +5 玩家击杀有国籍的船(仅击杀结算,造成伤害不扣)
AttackCity -50 +10 玩家占领城市(城防炮全灭),扣旧归属国
DeliverStrategic +10 -5 无触发源(预留的战略物资交付事件)
TradeAgreement +20 0 外交面板签订贸易协定,花费 5000 金,要求与该国非 Hostile
Ceasefire 重置为 -20 0 外交面板签订停火协议,花费 10000 金,要求与该国 Hostile

补充规则:

  • “敌国”加成:事件的敌方声望变化加给“与目标国当前关系为 Hostile”的每个外交国。例如击杀英格兰船:英格兰 -30,与英格兰敌对的西班牙 +5,中立的法兰西不变(测试 FactionEventHandlerTests.cs 验证)。
  • 重置语义:Ceasefire 不是加减而是直接把声望设为 -20。-20 高于敌对阈值 -30,停火后关系立即回到 Neutral——但只比阈值高 10 点,再误杀一艘该国船(-30)就重新跌回 Hostile。
  • 交易档位只看卖出收入(TotalSellIncome),买入花费不计入档位,也不产生声望。
  • 击杀无国籍的船(海盗):所有三个外交国各 +1(剿匪是普世善行)。
  • 击杀同国籍的船:除 AttackShip 的 -30 外,攻击者本国额外 -10(即本国合计 -40),并触发国籍撤销(见合法性规则)。
  • 普通怪物伤害/击杀完全不进声望结算(Boss 例外,走独立的 BossKill 通道)。
  • 伤害目标类型为 Crew(船员)或 City(城市)的击杀在船只伤害通道中无声望后果;城市的声望惩罚统一由占领事件结算。

LegalityRules.cs 是一个纯判定函数:输入攻击者国籍与受害者国籍,输出攻击定性(测试 LegalityRulesTests.cs)。

判定顺序 条件 定性 含义
1 目标无国籍 Neutral 打海盗/无主目标,无外交责任
2 攻击者无国籍 Legal 无国籍浪人没有归属义务,怎么打都“合法”(受害国仍按 AttackShip 扣分)
3 双方同国籍 Illegal 攻击本国实体,叛国
4 双方不同国籍 Legal 国与国之间的攻击

定性的后果(FactionEventHandler.cs):

定性 击杀时 仅伤害未击杀时
Neutral(目标无国籍) 所有外交国各 +1
Legal 受害国 AttackShip -30,受害国的敌国各 +5
Illegal 同 Legal,外加攻击者本国 -10 无声望变化,但国籍照样被撤销

国籍自动撤销:只要玩家对“与自己同国籍”的实体造成任何伤害(不需要击杀),国籍立即被撤销。撤销发生在声望结算之前,但该次攻击的国籍标记取的是开火武器初始化时的快照,所以本次击杀仍按 Illegal 结算。

目击判定:不存在。 当前实现没有视野/目击者系统——只要伤害事件带攻击者归因(弹丸都携带主人阵营与国籍,Bullet.csBaseWeapon.cs),无论附近有没有该国船只“看见”,声望都会全局即时结算。等同于全知结算,没有“杀人灭口”的玩法空间。

国籍信息的流转路径:玩家船的国籍存在船只数据上 → 武器初始化时读取并下发给射击策略(BaseWeapon.cs)→ 弹丸命中时连同阵营一起传入伤害结算(DamageableComponent.cs,仅当实际伤害 > 0 且归因非空才广播)→ 声望结算。受害者一侧的国籍由其战斗组件持有(Defender.cs,建筑从所属船的数据同步)。

操作 条件 效果 入口
申请国籍 与目标国关系 Friendly(声望 ≥ 50),且人在该国港口(外交面板的港口模式) 玩家船获得该国国籍 DiplomacyPanel.csCityDiplomacyTrigger.cs
放弃国籍 随时(面板按钮) 国籍清空,变回无国籍浪人 同上
自动撤销 对本国实体造成任何伤害 国籍立即清空 FactionEventHandler.cs

持有国籍的收益与代价:

  • 本国城市购物 9 折(价格修正 0.9,详见下方价格表,CityTrader.cs)。
  • 占领城市归属本国:玩家打下城市时,城市新归属 = 玩家国籍国;无国籍玩家打下城市则城市不变更归属(CityDefense.cs)。
  • 叛国成本:误伤本国船即丢国籍;击杀本国船本国声望 -40(-30 - 10)。
  • 开局国籍由场景预设决定(preset JSON 字段):外循环测试预设给玩家 country_001 国籍,并把该国声望直接置为 50(Friendly 起点),避免“西班牙公民对西班牙中立”的违和感(StarterFleetInitializer.csAssets/StreamingAssets/Presets/外循环测试.json)。

DynamicRelationTrigger.cs 监听声望变化与 Boss 击杀,按三个条件在运行时改写国家间关系。整局共享翻转预算:最多 3 次(代码常量 MaxFlipsPerGame = 3),超过后所有条件不再触发。每次满足条件只翻转一对国家。

条件 触发时机 规则 结果
外交斡旋 玩家任意一次声望变动且变动后与该国关系非 Hostile(不要求关系档位翻转) 扫描所有国家对:两国当前互相 Hostile,且玩家与两国都至少 Neutral 该对关系改善为 Neutral
Boss 击败 玩家击杀 Boss 且 Boss 死在某国海域 该国与其他国家中找到第一个 Hostile 关系 改善为 Neutral
敌意拉拢 玩家在某国声望跌到 ≤ -80(代码常量) 该国把第一个与其“非 Friendly”的他国拉为盟友 该对关系变为 Friendly(两国联手对付玩家)

说明:外交斡旋与敌意拉拢互斥——声望 ≤ -80 时关系必为 Hostile(阈值 -30),斡旋分支先行早退,因此一条声望消息至多翻转一次。翻转计数不存档(场景会话级)。

发现系统的事件调度器(EventScheduler.cs每 7 游戏日投放 1 条新闻,4 类等概率(各 25%,NewsTemplates.cs):

新闻类型 概率 对外交的影响
WarDeclared(英格兰对法兰西宣战) 25% 英格兰↔法兰西 关系直接设为 Hostile(国家对写死)
PeaceMade(英法停战) 25% 英格兰↔法兰西 关系直接设为 Neutral
CurrencyShift 25% 无关系影响(全境某物品价格 ±5%,见 交易
MonsterSurge 25% 无关系影响(仅新闻展示)

新闻直接调用关系写入接口,不消耗动态关系触发器的 3 次翻转预算;战争/和平新闻还会顺带把涉事两国标记为已发现。新闻在玩家靠港时以港口简报形式呈现(见 探索与情报)。

宽限期机制(已实现,未接线)

Section titled “宽限期机制(已实现,未接线)”

FactionRelation.cs 提供按阵营的宽限期:设置后该阵营在 N 秒内被所有敌对判定视为非敌对(设计意图是“刚离港的船短时间不被攻击”)。当前全工程没有任何调用方设置宽限期,机制处于休眠状态。

BossConfig.csv(CSV 配置表,全量 1 行):

含义 单位 Leviathan 当前值
boss_id Boss 标识 Leviathan
max_hp 最大血量 1000
attack 攻击力 点/次 30
detection_radius 检测半径(玩家进入即进入战斗,离开即脱战) 世界单位 40
move_speed 移动速度 世界单位/秒 1.5
roam_interval 游荡间隔(到达路径点后等待时长) 300
respawn_time 死亡后重生延迟 600

重要:这张 CSV 当前不被运行时读取。 BossMonster.cs 的实际数值是 Unity Inspector 序列化字段(默认值与 CSV 行一致,代码注释明确写“硬编码默认值,对应 BossConfig.csv”)。改 CSV 无效,要改挂在 Boss 预制体上的字段。Inspector 中还有两个 CSV 没有的参数:攻击冷却 3 秒(冷却结束后向玩家位置发起一次冲撞)、转向时长 0.8 秒。

Boss 行为摘要(与外交相关的部分):

  • Boss 阵营为 Enemy(未注册阵营,对所有人敌对),目标类型为 Monster——打 Boss 不触发 AttackShip 扣分。
  • Boss 死亡时广播击败消息,携带“死亡位置所属海域的国家”(按领地划分查询)与击杀者阵营(取最后攻击者,缺省视为玩家)。
  • 玩家击杀的后果三联动:海域归属国 +15 声望(BossKill);计入屠龙者(DragonSlayer)胜利(1 只达成);可能触发“Boss 击败”动态关系改善。
  • 死亡后隐藏模型,600 秒后在随机路径点满血重生。

同目录下的 CityDefenseConfig.csv(城防塔数量/血量,5 档城市类型)与 VictoryConfig.csv(胜利阈值)分别属于城防与胜利系统,详见 城市与国家游戏循环与胜负

参数 单位 来源
友好阈值(三国一致) 50(含) 声望点 CSV FactionConfig.csv
敌对阈值(三国一致) -30(含) 声望点 CSV FactionConfig.csv
未配置国家的兜底阈值 (50, -30) 声望点 代码常量 FactionManager.cs
声望上下限 无(不 clamp) 代码现状 FactionManager.cs
初始声望 西/法 0,英 -50 声望点 CSV FactionConfig.csv

交易价格修正(按玩家与城市所属国关系)

Section titled “交易价格修正(按玩家与城市所属国关系)”
买入价 = 基础价 × 修正系数
卖出价 = 基础价 ÷ 修正系数 (NPC 收购价反向修正)
关系 修正系数 实际效果 来源
Hostile 1.5(理论上到不了——敌对城被港口界面拦截交易) 买贵 50% 代码常量 CityTrader.cs
Neutral 1.2 买贵 20%,卖出被压价约 17% 代码常量 CityTrader.cs
Friendly 1.0 原价 代码常量 CityTrader.cs
Friendly 且持该国国籍 0.9 买 9 折,卖出溢价约 11% 代码常量 CityTrader.cs
行动 金币成本 前置条件 声望效果 来源
贸易协定 5000 与该国非 Hostile,人在该国港口 该国 +20 代码常量 CityDiplomacyTrigger.cs
停火协议 10000 与该国 Hostile,人在该国港口 该国声望重置为 -20(→ Neutral) 代码常量 CityDiplomacyTrigger.cs
申请国籍 0 与该国 Friendly,人在该国港口 无直接声望变化 代码 FactionManager.cs
行为 受害国 受害国的敌国 玩家本国 备注
击杀他国船 -30 各 +5 0 Legal
击杀本国船 -30 各 +5 额外 -10(本国即受害国,合计 -40) Illegal,且任意伤害即撤销国籍
击杀无国籍海盗船 三国各 +1
击杀普通怪物 0 0 0 显式排除
击杀 Boss 海域归属国 +15 另计屠龙胜利
占领城市 旧归属国 -50 各 +10 城防炮全灭即占领
参数 来源
整局翻转上限(动态触发器) 3 次 代码常量 DynamicRelationTrigger.cs
敌意拉拢触发声望 ≤ -80 代码常量 DynamicRelationTrigger.cs
新闻投放间隔 7 游戏日 代码常量 EventScheduler.cs
每条新闻为战争/和平的概率 各 25% 代码常量 NewsTemplates.cs
战争/和平新闻涉及的国家对 固定 英格兰↔法兰西 代码常量 NewsTemplates.cs
参数 来源
外交家胜利:三国声望最小值 ≥ 50 代码常量 VictoryManager.csVictoryConfig.csv 同值但未被读取)
征服者胜利:占领城市数 ≥ 2 代码常量 VictoryManager.cs
屠龙者胜利:Boss 击杀数 ≥ 1 代码常量 VictoryManager.cs
  • 交易:交易完成消息驱动 FirstVisit/Trade 系列声望;关系决定价格修正系数;敌对城无法开始交易。
  • 城市与国家:城防炮全灭触发占领与 AttackCity 声望惩罚;占领改写城市归属与领地划分;国家名/颜色来自城市系统配置。
  • 武器与弹药:武器初始化时缓存所属船的阵营与国籍并写入每发弹丸;武器自动索敌只锁定敌对阵营目标(阵营过滤器 CombatUtils.cs)。
  • 伤害与护甲:伤害结算组件在造成实际伤害后广播带归因的伤害消息,是 LegalityRules 与 AttackShip 声望的唯一数据源。
  • 怪物:怪物阵营 Enemy 对所有人敌对;普通怪不进声望;Boss 走独立的击败消息(声望 + 胜利 + 动态关系三联动)。
  • 船只:船间碰撞只在双方敌对时才结算碰撞伤害(ShipCollisionHandler.cs);玩家国籍存于玩家船数据。
  • 遭遇与刷怪:巡逻船以所属城市的国家作为阵营生成(PatrolShipSpawner.cs),两国巡逻船相遇是否开战、巡逻船是否攻击玩家,全部实时查询本系统;玩家声望跌破 -30 的瞬间,该国所有巡逻船与城防炮变为敌对。
  • 探索与情报:外交面板只显示已发现的国家;进入未发现国家的城市范围自动发现该国;每 7 日的世界新闻可改写英法关系并在港口简报中呈现。
  • 游戏循环与胜负:外交家/征服者/屠龙者三条胜利路线的进度全部由本系统的消息驱动。
  • 存档:阵营数据(声望/关系/国籍相关状态)当前不在存档范围内(见已知限制)。
  • 开发者工具DevToolsManager.cs 提供直接设置声望、触发任意外交事件、申请/撤销国籍、打印全部声望的调试接口。
想调什么 改哪里 生效方式
某国初始声望 / 友好阈值 / 敌对阈值 Assets/StreamingAssets/FactionSystem/FactionConfig.csv 对应行 重启游戏即生效(运行时加载)
增删外交国家 FactionConfig.csv 加/删行 + FactionRelationPreset.csv 补关系对 + countries.csv 补展示信息;注意 VictoryManager.cs 的三国列表与 NewsTemplates.cs 的新闻国家对是硬编码,需同步改代码 CSV + 代码
国家间初始关系 Assets/StreamingAssets/FactionSystem/FactionRelationPreset.csv(关系值只认 Hostile/Neutral/Friendly,拼错会被跳过并打警告) 重启游戏即生效
声望事件数值(交易加成、击杀惩罚等) FactionManager.cs LoadDefaultConfig 中的硬编码表ReputationEventConfig.csv 当前不被读取,改它无效 需要程序改代码
交易档位分界(100/500 金) FactionEventHandler.cs 中的比较常量 需要程序改代码
外交行动金币成本(5000/10000) CityDiplomacyTrigger.cs 顶部常量;外交面板按钮文案中的金额是另一份硬编码(DiplomacyPanel.cs),需同步改 需要程序改代码
价格修正系数(1.2/0.9/1.5) CityTrader.cs GetRelationPriceModifier 需要程序改代码
动态关系翻转上限 / 拉拢阈值(3 次 / -80) DynamicRelationTrigger.cs 常量 需要程序改代码
新闻间隔 / 新闻池 EventScheduler.cs(7 日)/ NewsTemplates.cs(4 类模板与国家对) 需要程序改代码
Boss 数值(血量/攻击/检测/速度/游荡/重生) Boss 预制体上 BossMonster 组件的 Inspector 序列化字段;BossConfig.csv 当前只是文档不生效 在 prefab 里改
玩家开局国籍 场景预设 JSON 的 playerNationality 字段(如 Assets/StreamingAssets/Presets/外循环测试.json),空值 = 无国籍浪人 改 preset 即生效
运行时快速验证 开发者工具的声望调试接口(SetReputation / TriggerDiplomacy 等) Play Mode 即时
  1. ReputationEventConfig.csv 是死配置:CSV 与生成的加载器(ReputationEventConfig.cs)都存在,但 FactionManager.cs 注释明确“声望事件配置:仍硬编码”,运行时从不读取该 CSV。CSV 内容与硬编码一致,唯一差异是硬编码多一条 MonsterKill(+3) 而 CSV 没有。策划改 CSV 不会有任何效果。
  2. BossConfig.csv 同样是死配置BossMonster.cs 用 Inspector 序列化字段(默认值与 CSV 一致),CSV 不被读取。VictoryConfig.csv 亦然(VictoryManager.cs 用代码常量)。
  3. MonsterKill 与 DeliverStrategic 事件无触发源:配置存在但全工程没有任何代码发布这两种事件类型,属预留。
  4. 没有目击/视野判定:所有带归因的伤害全局即时结算声望,无“无人看见就不扣分”的机制。
  5. 声望与国家关系不存档:存档系统(Assets/Scripts/Service/SaveSystem/)不包含任何阵营数据——声望、国家间关系、已访问城市、动态翻转计数全部是会话内存状态,重开即回 CSV 初始值。新闻列表本身有持久化(EventScheduler.cs 的 ES3 存取),但读档时不会重放新闻对关系矩阵的修改,存档前发生的“宣战/停战”在读档后丢失。
  6. 武器国籍是初始化快照:武器在所属建筑初始化时缓存玩家国籍(BaseWeapon.cs),之后玩家申请/放弃国籍不会更新已部署武器,其弹丸继续携带旧国籍标记,合法性判定可能与玩家当前国籍不符。
  7. 宽限期机制无调用方FactionRelation.cs 的宽限期(离港保护)已实现但没有任何系统设置它。
  8. FirstVisit 的真实语义是“首次完成交易”:靠港不给声望,必须在该城市执行一笔交易(交易触发器固定把首访标记设 true,由管理器的已访问城市集合去重,CityTradingTrigger.cs + FactionEventHandler.cs)。
  9. 声望无上下限:长期刷交易可以把声望刷到任意高;敌意拉拢的 -80 阈值之下也可以继续无限下跌。
  10. 击杀船员无外交后果:伤害目标类型为 Crew 的击杀不在声望结算分支内。
  11. Boss 击杀者归因是简化实现:取“最后一个攻击 Boss 阵营的人”,缺省为玩家(BossMonster.cs 注释自述“简化:默认 Player”);多方混战时可能误归因。
  12. 新闻翻转不受动态关系预算限制且国家对写死:战争/和平新闻只发生在英格兰↔法兰西之间,且绕过 MaxFlipsPerGame=3 的预算;同一对关系可能被新闻反复横跳。
  13. CityDiplomacyTrigger.cs 的类注释已过时:注释写“无 UI,通过代码/DevTools 调用”,实际上 DiplomacyPanel.cs(Modal)已接通全部三个外交动作。
  14. 国籍展示名与配置 ID 脱节Defender.cs 注释举例国籍为 “Spain”/“England”,实际全链路使用 country_001 等 ID;展示名统一查 countries.csv