# 07 经济、生产与建筑：从一格矿到一辆坦克

红警的经济系统不是一个不断加减的“金钱变量”。地图保存矿石，矿车保存货物，House 保存可消费资产和存储容量，工厂对象保存生产中的商品及尚未支付余额，建筑负责让商品进入地图。把这些状态分开，才能解释断矿、爆仓、缺电、暂停建造、出口堵塞和占领建筑为何产生不同后果。

本文以提交 `0dc09bb1d6188d1ec79ab4765b22a48b75ffee32` 为依据。这里的 `Tiberium` 是沿用前作的内部命名，在本作对应矿石经济；不能因变量名相同，就把前作的逐包卸矿或数值规则直接套过来。

## 1. 钱有两种：Credits 与受容量约束的矿石资金

`HouseClass::Available_Money` 返回 `Tiberium + Credits`。`Harvested` 将矿车收入加入 Tiberium，并按 Capacity 截断；`Refund_Money` 则直接增加 Credits。`Spend_Money` 优先用 Tiberium，不足部分再从 Credits 扣除。[HOUSE.CPP:1802–1922](https://github.com/electronicarts/CnC_Red_Alert/blob/0dc09bb1d6188d1ec79ab4765b22a48b75ffee32/CODE/HOUSE.CPP#L1802-L1922)

| 状态 | 可以怎样变化 | 玩家可观察的意义 |
|---|---|---|
| 矿车 `Gold/Gems/Tiberium` | 采矿增加，卸货清空 | 车里有货不等于钱到账 |
| House `Tiberium` | 卸货增加、消费减少、容量不足截断 | 筒仓及炼矿厂关系到这部分财富 |
| House `Credits` | 退钱增加、矿石资金不足时扣除 | 退款不受当前矿石容量直接限制 |
| House `Capacity` | 建筑启用/移除/易主改变 | 容量与资金是两种独立状态 |

`Adjust_Capacity` 对容量减少提供两种处理：若减少后矿石资金超过容量，`inanger=true` 会取走超额部分；否则把超额转入 Credits。但必须再查调用者：当前 `BuildingClass::Limbo` 明确传 true，出售最终也调用 Limbo，因此不能从参数名推断“主动出售必定保住超额矿石资金”。[HOUSE.CPP:1942–1962](https://github.com/electronicarts/CnC_Red_Alert/blob/0dc09bb1d6188d1ec79ab4765b22a48b75ffee32/CODE/HOUSE.CPP#L1942-L1962)、[BUILDING.CPP:2255–2274](https://github.com/electronicarts/CnC_Red_Alert/blob/0dc09bb1d6188d1ec79ab4765b22a48b75ffee32/CODE/BUILDING.CPP#L2255-L2274)

例如当前 Credits=200、Tiberium=900、Capacity=1000，一车交来 500：可储矿石资金只从 900 到 1000，超出部分在此入口被截掉；总可用钱为 1200。之后花 300，只把 Tiberium 减到 700。这里的数值是演示状态变化，非某关初始资金设定。

## 2. 矿车不是每帧“找最近矿”的单一函数

`Mission_Harvest` 是 `LOOKING → HARVESTING → FINDHOME → HEADINGHOME` 等状态构成的任务。没有己方活动炼矿厂时会转守卫；装满先回家；旧采矿点可保存在 `ArchiveTarget`，交货后继续使用。找不到矿也有闲置及通知 House 矿源短缺的处理。[UNIT.CPP:2749–2922](https://github.com/electronicarts/CnC_Red_Alert/blob/0dc09bb1d6188d1ec79ab4765b22a48b75ffee32/CODE/UNIT.CPP#L2749-L2922)

`Goto_Tiberium` 从当前格向外按方形环扫描，而非给整个地图所有矿格计算全局最短路。候选检查包括地图边界、同一移动区域、没有其他 Techno 占位、地形为矿石；人类战役玩家还受已探明条件限制。找到候选只是设置导航目的地，实际走过去仍由移动系统处理。[UNIT.CPP:2161–2248](https://github.com/electronicarts/CnC_Red_Alert/blob/0dc09bb1d6188d1ec79ab4765b22a48b75ffee32/CODE/UNIT.CPP#L2161-L2248)

这解释了为什么“看起来最近”和“源码首先找到”不总相同。扫描顺序、通行区域、占位和当前保存的采矿点都参与决策。它是成本可控的局部策略，不是实时物流优化器。

`Harvesting` 每轮减少当前格的一份矿层，再增加货物计数。普通矿石增加 Gold；宝石先增加 Gems，并在容量允许时额外增加最多三份 Gems 与总装载计数，所以宝石会更快填满矿车。总价值由 `Credit_Load` 计算为 `Gold × Rule.GoldValue + Gems × Rule.GemValue`。[UNIT.CPP:2267–2329](https://github.com/electronicarts/CnC_Red_Alert/blob/0dc09bb1d6188d1ec79ab4765b22a48b75ffee32/CODE/UNIT.CPP#L2267-L2329)、[UNIT.CPP:4790–4793](https://github.com/electronicarts/CnC_Red_Alert/blob/0dc09bb1d6188d1ec79ab4765b22a48b75ffee32/CODE/UNIT.CPP#L4790-L4793)

规则构造默认值为容量 28、GoldValue=35、GemValue=110，随后又允许 INI 覆盖。只在没有覆盖的假设下，满车普通矿是 980，满车宝石是 3080；这应叫“构造默认值演算”，不应作为所有地图和发行版固定收入。[RULES.CPP:237–239](https://github.com/electronicarts/CnC_Red_Alert/blob/0dc09bb1d6188d1ec79ab4765b22a48b75ffee32/CODE/RULES.CPP#L237-L239)、[RULES.CPP:466–478](https://github.com/electronicarts/CnC_Red_Alert/blob/0dc09bb1d6188d1ec79ab4765b22a48b75ffee32/CODE/RULES.CPP#L466-L478)

## 3. 进厂与卸货通过对象间握手完成

回程先 `Find_Docking_Bay`，再向炼矿厂发送 `RADIO_HELLO`。这里的 Radio 是游戏对象之间的同步消息接口，不是联网数据包。炼矿厂用 `RADIO_DOCKING` 指定南侧接近点，必要时要求倒车；收到 `RADIO_IM_IN` 后让矿车执行 `MISSION_UNLOAD`。[BUILDING.CPP:215–325](https://github.com/electronicarts/CnC_Red_Alert/blob/0dc09bb1d6188d1ec79ab4765b22a48b75ffee32/CODE/BUILDING.CPP#L215-L325)

矿车的卸货流程先转到西向、播放卸载动作，动画达到指定阶段后一次调用 `House->Harvested(Credit_Load())`，清空 Gold、Gems、Tiberium，结束联络，再回采矿任务。这就是当前主体路径的到账点。[UNIT.CPP:2348–2390](https://github.com/electronicarts/CnC_Red_Alert/blob/0dc09bb1d6188d1ec79ab4765b22a48b75ffee32/CODE/UNIT.CPP#L2348-L2390)

仓库还保留 `BuildingClass::Mission_Harvest` 逐包索取货物的代码，但 `UnitClass::Offload_Tiberium_Bail` 的价值返回部分在 `TOFIX` 内，常规路径返回零。若只搜索函数名、看到“Offload”就写成逐包现金流，会得到错误的当前机制。这也是阅读老项目必须追真实调用者的原因。[BUILDING.CPP:3735–3795](https://github.com/electronicarts/CnC_Red_Alert/blob/0dc09bb1d6188d1ec79ab4765b22a48b75ffee32/CODE/BUILDING.CPP#L3735-L3795)、[UNIT.CPP:4299–4312](https://github.com/electronicarts/CnC_Red_Alert/blob/0dc09bb1d6188d1ec79ab4765b22a48b75ffee32/CODE/UNIT.CPP#L4299-L4312)

## 4. 生产对象与生产建筑不是同一个东西

玩家点击生产后，`HouseClass::Begin_Production` 按 RTTI 类别获取工厂对象，必要时新建 `FactoryClass`。House 分别保存步兵、车辆、建筑、飞机、舰船的工厂索引，因此玩家这条路径是按类别维护当前生产槽，而不是每一座兵营天然拥有独立的玩家订单队列。[HOUSE.CPP:2394–2434](https://github.com/electronicarts/CnC_Red_Alert/blob/0dc09bb1d6188d1ec79ab4765b22a48b75ffee32/CODE/HOUSE.CPP#L2394-L2434)、[HOUSE.CPP:6945–6988](https://github.com/electronicarts/CnC_Red_Alert/blob/0dc09bb1d6188d1ec79ab4765b22a48b75ffee32/CODE/HOUSE.CPP#L6945-L6988)

`FactoryClass::Set` 会立即创建实际的产品对象，但它尚未摆上地图；保存总价到 `Balance`，并记录 PurchasePrice。这样，生产中的坦克已经有身份和所属 House，工厂只是掌管它的完成度、计费和交付。[FACTORY.CPP:290–329](https://github.com/electronicarts/CnC_Red_Alert/blob/0dc09bb1d6188d1ec79ab4765b22a48b75ffee32/CODE/FACTORY.CPP#L290-L329)

生产划分为 54 个进度阶段。每次推进按“剩余余额÷剩余阶段”计算本次费用；若钱不足，把刚推进的阶段退回去；否则花钱并减余额。完成时停表并结清剩余余额。因此资金短缺通常体现为进度卡住，继续到账又能推进，不需要一开始付清全价。[FACTORY.H:92](https://github.com/electronicarts/CnC_Red_Alert/blob/0dc09bb1d6188d1ec79ab4765b22a48b75ffee32/CODE/FACTORY.H#L92)、[FACTORY.CPP:201–239](https://github.com/electronicarts/CnC_Red_Alert/blob/0dc09bb1d6188d1ec79ab4765b22a48b75ffee32/CODE/FACTORY.CPP#L201-L239)、[FACTORY.CPP:615–626](https://github.com/electronicarts/CnC_Red_Alert/blob/0dc09bb1d6188d1ec79ab4765b22a48b75ffee32/CODE/FACTORY.CPP#L615-L626)

举例：商品价格 540、没有价格修正，54 阶段平均每步 10。完成 20 步时已付 200、Balance=340；暂停只是停进度，取消则按完整成本减余额退回已支付部分，并删除未交付对象。取消不是给一辆未出厂坦克按二手比例折价。[FACTORY.CPP:382–391](https://github.com/electronicarts/CnC_Red_Alert/blob/0dc09bb1d6188d1ec79ab4765b22a48b75ffee32/CODE/FACTORY.CPP#L382-L391)、[FACTORY.CPP:469–500](https://github.com/electronicarts/CnC_Red_Alert/blob/0dc09bb1d6188d1ec79ab4765b22a48b75ffee32/CODE/FACTORY.CPP#L469-L500)

## 5. 建造速度包含多层系数

基础 `TechnoTypeClass::Time_To_Build` 按成本、全局 BuildSpeedBias 和分钟 tick 数计算。对象层再引入 House 建造速度、多人单位惩罚、电力及工厂数量。其中启用 CSII 代码且 `NewUnitsEnabled` 为真时，工厂数量除数最多计 2；其他路径可以按实际数量除。不能无条件说“多造工厂无限加速”，也不能把“双工厂封顶”套到所有运行模式。[TECHNO.CPP:6075–6078](https://github.com/electronicarts/CnC_Red_Alert/blob/0dc09bb1d6188d1ec79ab4765b22a48b75ffee32/CODE/TECHNO.CPP#L6075-L6078)、[TECHNO.CPP:653–698](https://github.com/electronicarts/CnC_Red_Alert/blob/0dc09bb1d6188d1ec79ab4765b22a48b75ffee32/CODE/TECHNO.CPP#L653-L698)

值得单列的是两层电力折算：对象建造时间先把供电比例限制并分段处理，低于一半按一半、四分之三至满电之间按四分之三，然后取倒数；`FactoryClass::Start` 又将此时间除以限制在 1/16～1 的供电比例，再除以 54，最后把每阶段间隔限制到 1～255。这是当前代码真实的两次处理。[FACTORY.CPP:411–447](https://github.com/electronicarts/CnC_Red_Alert/blob/0dc09bb1d6188d1ec79ab4765b22a48b75ffee32/CODE/FACTORY.CPP#L411-L447)

在其他条件相同、忽略截断和上下限时，半电会在前层乘 2，后层再乘 2，总计约四倍的启动计算时间。这个推导针对启动时计算出的 rate；不要据此宣称已在进行的每笔订单都会每帧按最新电力连续重算。当前 `FactoryClass::AI` 推进主体没有重算上述 rate。

另一个易混点是 AI：建筑 `Factory_AI` 还维护建筑自己的工厂并向 House 询问建议商品。这条电脑生产路径与玩家 House 分类槽并不完全相同，分析作弊、排队或多厂效率时要先确定研究哪条路径。[BUILDING.CPP:5281–5325](https://github.com/electronicarts/CnC_Red_Alert/blob/0dc09bb1d6188d1ec79ab4765b22a48b75ffee32/CODE/BUILDING.CPP#L5281-L5325)

## 6. 建造资格与成品交付是两道关

`HouseClass::Can_Build` 先排除 TechLevel=-1，按运行模式过滤资料片新增类型，再检查所属阵营、前置建筑位图和科技等级。高级电厂可满足普通电厂前置；非战役模式中两种科技中心位图有互通处理；非人类战役 House 还有提前放行分支。这是任务设计与遭遇战规则共存的结果。[HOUSE.CPP:784–876](https://github.com/electronicarts/CnC_Red_Alert/blob/0dc09bb1d6188d1ec79ab4765b22a48b75ffee32/CODE/HOUSE.CPP#L784-L876)

生产完成并不保证成功生成在地面。`HouseClass::Place_Object` 查找能够生产该商品的建筑：单位经 `Exit_Object` 出厂，建筑通过指定格子 `Unlimbo` 落位。放置失败时，完成产品仍可能等待；成功后才把产品从工厂移交并清理生产记录。出口被堵与造不出来因此属于不同问题。[HOUSE.CPP:2918–3045](https://github.com/electronicarts/CnC_Red_Alert/blob/0dc09bb1d6188d1ec79ab4765b22a48b75ffee32/CODE/HOUSE.CPP#L2918-L3045)

电脑建筑工厂的出口返回值进一步区分取消、暂时阻塞及成功：阻塞会设置三秒 PlacementDelay 再试。这是一种简单的重试协议，而不是让生产线程一直等出口清空。[BUILDING.CPP:5200–5275](https://github.com/electronicarts/CnC_Red_Alert/blob/0dc09bb1d6188d1ec79ab4765b22a48b75ffee32/CODE/BUILDING.CPP#L5200-L5275)

## 7. 建筑在开业、受损、出售和被占领时改变 House

`Grand_Opening` 增加耗电与容量、标记统计需要重算，并处理炼矿厂附带矿车、部分规则下直升机场附带飞机等特殊效果。炼矿厂送车有 ScenarioInit、captured、Debug_Map、玩家及 PurchasePrice 条件，不能说“任何方式得到炼矿厂都送一辆车”。生成失败时还有退款补偿。[BUILDING.CPP:2383–2456](https://github.com/electronicarts/CnC_Red_Alert/blob/0dc09bb1d6188d1ec79ab4765b22a48b75ffee32/CODE/BUILDING.CPP#L2383-L2456)

发电量按最大生命值比例折算。建筑 AI 发现 Strength 与 LastStrength 不同，就计算新旧发电差并更新 House。这使攻击电厂可以先产生断电效果，不必等它被摧毁。[BUILDING.CPP:929–934](https://github.com/electronicarts/CnC_Red_Alert/blob/0dc09bb1d6188d1ec79ab4765b22a48b75ffee32/CODE/BUILDING.CPP#L929-L934)、[BUILDING.CPP:4607–4615](https://github.com/electronicarts/CnC_Red_Alert/blob/0dc09bb1d6188d1ec79ab4765b22a48b75ffee32/CODE/BUILDING.CPP#L4607-L4615)

缺电除了影响建造，也会使标记为需电的防御建筑停止开火；House 还周期性向高于黄色生命阈值、存在耗电的己方建筑施加小额损伤。飞机补弹间隔则使用另一套最低一半供电比例，不能直接沿用建造的倍数。[BUILDING.CPP:2853–2862](https://github.com/electronicarts/CnC_Red_Alert/blob/0dc09bb1d6188d1ec79ab4765b22a48b75ffee32/CODE/BUILDING.CPP#L2853-L2862)、[HOUSE.CPP:1066–1086](https://github.com/electronicarts/CnC_Red_Alert/blob/0dc09bb1d6188d1ec79ab4765b22a48b75ffee32/CODE/HOUSE.CPP#L1066-L1086)、[BUILDING.CPP:3989–4030](https://github.com/electronicarts/CnC_Red_Alert/blob/0dc09bb1d6188d1ec79ab4765b22a48b75ffee32/CODE/BUILDING.CPP#L3989-L4030)

维修建筑按全局帧取模的维修节奏支付一笔费用、增加固定生命步长，达到上限封顶；钱不够关闭维修状态。维修费又从 Raw_Cost、最大生命、RepairStep、RepairPercent 推导，移动单位有另一组 URepair 参数。[BUILDING.CPP:5462–5481](https://github.com/electronicarts/CnC_Red_Alert/blob/0dc09bb1d6188d1ec79ab4765b22a48b75ffee32/CODE/BUILDING.CPP#L5462-L5481)、[TECHNO.CPP:6139–6169](https://github.com/electronicarts/CnC_Red_Alert/blob/0dc09bb1d6188d1ec79ab4765b22a48b75ffee32/CODE/TECHNO.CPP#L6139-L6169)

出售是逆向施工任务：先结束维修并通知占用者离开，再处理幸存人员、播放拆除状态，最终退款和删除。人类退款采用 Raw_Cost × 阵营成本倍率 × RefundPercent；当前有效函数体没有按剩余生命值比例折算。炼矿厂 Raw_Cost 会扣除附带矿车成本，避免把整套购买价都当成空建筑残值。[BUILDING.CPP:3385–3586](https://github.com/electronicarts/CnC_Red_Alert/blob/0dc09bb1d6188d1ec79ab4765b22a48b75ffee32/CODE/BUILDING.CPP#L3385-L3586)、[TECHNO.CPP:5743–5761](https://github.com/electronicarts/CnC_Red_Alert/blob/0dc09bb1d6188d1ec79ab4765b22a48b75ffee32/CODE/TECHNO.CPP#L5743-L5761)、[BDATA.CPP:3672–3682](https://github.com/electronicarts/CnC_Red_Alert/blob/0dc09bb1d6188d1ec79ab4765b22a48b75ffee32/CODE/BDATA.CPP#L3672-L3682)

占领更不是简单改颜色：`BuildingClass::Captured` 从旧 House 移除发电、耗电和容量，处理附属单位及停靠者，清理建筑工厂，调整活动计数、地基归属、视野和雷达，再以 captured 模式重新开业。工程师的一次点击之所以能改变生产网络，是因为易主函数维护了这些跨系统约束。[BUILDING.CPP:2936–3098](https://github.com/electronicarts/CnC_Red_Alert/blob/0dc09bb1d6188d1ec79ab4765b22a48b75ffee32/CODE/BUILDING.CPP#L2936-L3098)

## 源码阅读路线与未验证部分

从 `Unit::Mission_Harvest/Harvesting/Mission_Unload → House::Harvested/Spend_Money → Factory::Set/Start/AI → House::Place_Object → Building::Grand_Opening` 追一车矿换成一件产品，再读 `Can_Build`、维修、出售与易主。单位如何进厂和载人，可继续读 [08 单位与特殊机制](08-units-and-special-mechanics.md)。

本章没有把静态公式包装为已运行的速度测试。缺少最终加载规则时，各兵种价格、真实满车收入、科技树、发电量及造速只能按具体数据集确认。生产中的 rate 是否被外围事件触发重启、极端容量变化及占领瞬间的经济顺序，适合进一步配合断点和录像验证。
