《命令与征服:重制版》MOD制作图文教程

红色警戒 2020年07月01日 15:46

      《命令与征服:重制版》MOD制作图文教程今天带给大家,本篇文章详细说明了如何去制作命令与征服:重制版的mod,学会之后即可制作更加好玩的游戏mod,还能让红警玩家一起体验你的成果。

      《命令与征服:重制版》是对命令与征服的高清重置,当然一些制作MOD的方法可以继承,不过一些老版的工具代码无法使用了,下边就给大家带来“bbitt”分享的命令与征服重制版MOD制作图文教程,大家可以来看一看。

      命令与征服重制版MOD制作图文教程

      我们先准备一些东西:

      1.有一定储备的知识:具备一定的计算机编程语言知识,MOD的制作不只是随便修改一下代码就OK的。

      2.Microsoft Visual Studio:要下载2017版本,2019版与官方提供的开源存在一定冲突。我在附件里会提供下载安装用的程序。

      3.批量UTF8查找工具:我附件会提供一个,你们若是有更好的请自行准备。

      4.《命令与征服》MOD开发用的开源代码:正版游戏安装目录中会有提供。

      现在开始教程:

      一、下载安装 Microsoft Visual Studio 2017版,选择 使用C++桌面开发 其他用不到,就不要装了。

      右边的安装详细信息里的建议都选上。里面有你对应系统的一些补丁、编程语言包之类的。

      然后右下角点 安装 ,我因为已经装好了所以是“关闭”。

      注意:将你的系统设置为支持UTF8编码,如果不设置的话 Microsoft Visual Studio 会将源码程序中编码编译成其他编码,生成MOD的时候会报错。

      Win10设置方法:

      1、首先在开始菜单单击鼠标右键,点击 运行 ;

      2、输入control回车打开控制面板>时钟和区域>区域>管理>更该系统区域设置>勾选"Beta 版: 使用 Unicode UTF-8 提供全球语言支持" 。

      二、我们找到游戏安装目录中的 SOURCECODE 目录(正版有,盗版有没有不知道),将其拷贝出来(存哪你自己决定,别问我)。这个目录就是官方提供的开源代码程序。

      用 Microsoft Visual Studio 打开你拷贝出去的目录中的 CnCRemastered.sln 文件(文件→打开→项目/解决方案),右边的解决方案资源管理器就会如图中所示加载完毕。

      里面包含两个项目,分别对应的是《红色警戒》和《命令与征服》,请根据自己的目标来修改。我这里就以《命令与征服》中修改一个单位“jeep”车为例。点开 TiberianDawn 项目,

      我们可以看到很多的文件,哪个文件才是我们要找的目标呢?

      接下来我们就需要用到 批量UTF8查找工具 了,我附件有提供,如果你们有其他工具请注意,一定要使用支持UTF8的工具。MOD修改时需要用到游戏中的一些要素,我们就通过查找这些要素来定位要找的文件。

      这里因为打算要修改的是游戏里单位的属性,我们已知的要素包含名字“jeep”和购买价格“COST”两个字符串,我们就搜索这两组字符串来找文件。

      以我提供的修改器为例:

      目录选择拷贝出去的目录中 tiberiandawn 目录,原字符串名改为 JEEP ,不区分大小写,选中 仅查找不替换 ,新字符串名留空,点执行会生成一个文本文档,不要关闭。

      将原字符串名改为 COST(购买价格),点执行又会生成一个文本文档。我们现在对比两份文档,可以看到这两种字符串在同一个文件中出现了:UDATA.CPP

      窗口切换到Microsoft Visual Studio ,找到之前打开的TiberianDawn 项目下 Source Files 目录中的 UDATA.CPP 文件并双击打开。按 Ctrl+F 弹出搜索框 输入 jeep 回车,就

      找到了我们要搜索的字符段。

      我们看下下边的内容:

      //符号左边边是源代码,右边是对该段代码的描述。

      // Jeep (hummer)

      static UnitTypeClass const UnitJeep(

      UNIT_JEEP,

      TXT_JEEP, // NAME: Text name of this unit type. 这个单位类型的名字

      "JEEP", // NAME: Text name of this unit type. 这个单位类型的名字(和上一个有什么区别不知道,没做测试)

      ANIM_FRAG1, // EXPLOSION: Type of explosion when destroyed. 摧毁时的爆炸类型

      2, // Build level. 建造、制造等级

      STRUCTF_NONE, // Building prerequisite. 建造、制造先决条件

      true, // Can this be a goodie surprise from a crate? 这个是否能从“板条箱”中得到(游戏里拾取箱子)

      true, // Is a leader type? 是否是领航类型

      false, // Only has eight facings? 是否只有8个朝向?(应该是车辆朝的方向:上、下、左、右、左上、右上、左下、右下)

      false, // Always use the given name for the vehicle? 始终使用车辆的给定名称?

      false, // Is this a typical transport vehicle? 这是典型的运输工具吗?

      false, // Can it be crushed by a heavy vehicle? 能被重型车压碎吗?

      false, // Can this unit squash infantry? 这个单位能压制步兵吗?

      false, // Does this unit harvest Tiberium? 这个单位能运送泰伯利亚矿石吗?

      false, // Is invisible to radar? 这个单位在雷达上隐形吗?

      true, // Is selectable by player? 这个单位能否被玩家选中?

      true, // Can it be a target for attack or move? 是否是可以被移动或攻击的目标

      false, // Is it insignificant (won't be announced)? 是否无关紧要

      false, // Is it immune to normal combat damage? 对正常战斗伤害免疫吗?

      true, // Is it equipped with a combat turret? 它装备了战斗炮塔吗?

      false, // Fires multiple shots in quick succession? 快速射击是否连续射出多发子弹?

      true, // Can it be repaired in a repair facility? 它能在修理厂修理吗?

      true, // Can the player construct or order this unit? player可以建造或命令这个单元吗?

      true, // Is there a crew inside? 里面有人吗?(有人的话击毁后可以掉出小兵)

      false, // Does it have a rotating radar dish? 它有旋转的雷达天线吗?

      false, // Is there an associated firing animation? 是否存在关联的射击动画?

      false, // Must the turret be in a locked down position while moving? 移动时炮塔是否锁定不动?

      true, // Does it lay tracks while moving? 它在移动时会留下痕迹吗?

      false, // Is this a gigundo-rotund-enormous unit? 是一个 gigundo-圆形-巨大 单元吗?(不懂)

      false, // Is the unit's art as "chunky" cardinal facing only? (不懂)

      false, // Is the unit capable of cloaking? 这个单位能隐形吗?

      false, // Does the unit have a constant animation? 该单元是否具有常量动画?

      -1, // AMMO: Number of shots it has (default). 弹药量 -1是无限

      150, // STRENGTH: Strength (in damage points). 装甲强度(俗称血量)

      2, // SIGHTRANGE: Range of sighting. 视线范围

      1, // COST: Cost to build (Credits). 价格(我这里改成1是因为测试MOD用)

      5, // SCENARIO: Starting availability scenario. 可用性开始场景(不明白用法)

      80,41, // RISK/RWRD: Risk/reward rating values. 风险与回报评级值(不太懂用法)

      HOUSEF_MULTI1|

      HOUSEF_MULTI2|

      HOUSEF_MULTI3|

      HOUSEF_MULTI4|

      HOUSEF_MULTI5|

      HOUSEF_MULTI6|

      HOUSEF_JP|

      HOUSEF_GOOD, // OWNABLE: Ownable by house (bit field).

      WEAPON_M60MG,WEAPON_NONE, 第一武器 ,第二武器

      ARMOR_ALUMINUM, // ARMOR: Armor type 装甲类型 ALUMINUM 是铝

      SPEED_WHEEL, // MOVE: Locomotion type. 移动类型 WHEEL轮式

      MPH_MEDIUM_FAST, // SPEED: Miles per hour. 速度(英里每小时) 格式不太懂,这个应该是个变量可以参考其他单位

      10, // ROT: Rate of turn (degrees per tick). 炮塔转动速度

      0, // Turret center offset along body centerline. 炮塔中心沿着身体中心线偏移(使用方法不明)

      MISSION_HUNT // ORDERS: Default order to give new unit. 订单:给予新单位的默认订单。(用法不明)

      );

      根据自己的目的进行修改代码。(我这里只是修改了价格为1)

      三、当你把所有要修改的修改完成后我们接下来生成MOD文件

      鼠标右键点击 Microsoft Visual Studio 的窗口中右边解决方案资源管理器中 TiberianDawn 项目,弹出菜单后选择 生成

      生成时会在下边的输出窗口有各种提示,如果有错误会提示哪里有错误,请根据提示修正问题。如果正常生成完成就会提示 生成: 成功 xx 个,失败 0 个,最新 0 个,跳过 0 个

      这里重说一下,如果你之前没有将系统修改为支持UTF8编码,就会提示:

      warning C4819: 该文件包含不能在当前代码页(936)中表示的字符。请将该文件保存为 Unicode 格式以防止数据丢失

      生成成功后我们到源代码目录中的 bin 目录下的 Win32 目录中有4个文件,其中我们要用到的只有 TiberianDawn.dll 和 TiberianDawn.pdb 两个文件。

      MOD文件已经准备好了,现在建立一个目录 bbitt - TD Only (名字你自己决定,这里就以我准备的测试用MOD举例)。在bbitt - TD Only 目录下新建一个 DATA 目录。

      将之前准备好的 TiberianDawn.dll 和 TiberianDawn.pdb 两个文件复制进去。

      然后回到 bbitt - TD Only 目录下新建一个文本文档,内容为:

      {

      "name": "bbitt - TD Only", MOD名字 bbitt - TD Only ,我怕识别不了就和目录名字相同

      "description": "Changes Hummer cost = 1", MOD简介 Changes Hummer cost = 1 改变hummer的价额为1

      "author": "bbitt", 作者

      "load_order": 1, 加载顺序

      "version_low": 0, 版本低

      "version_high": 1, 版本高,与版本低之间貌似一个设为1,另一个必须设为0

      "game_type": "TD" 游戏类型:泰伯利亚黎明

      }

      内容填好后将其重命名为 ccmod.json 注意扩展名,可不是 ccmod.json.txt 。

      这样MOD目录就OK了。我们现在需要的就是将其放在游戏专门的MODS目录中。具体位置是在 文档>CnCRemastered>Mods>Tiberian_Dawn 目录中。

      好了我们测试一下,看看我们的MOD是否能加载,是否有效果。进入游戏、选项、模组,OK,我们的MOD已经刷新出来了。选中然后点确定,会重启游戏。

      重启后模组就加载好了,测试一下,完美!

      首先对上边关于单位的代码段中关于可购买的阵营做一个补充 HOUSEF_GOOD, // OWNABLE: Ownable by house (bit field).

      这段代码代表的是可购买的阵营 HOUSEF_GOOD 是GDI HOUSEF_BAD 是NOD ,如果设置成 HOUSEF_GOOD|(回车换行)HOUSEF_BAD, 就是两个阵营都能选。

      四、上边给大家讲到了UDATA.CPP 中对于游戏中单位的修改。通过之前提到的对比方式我们可以在以下几个文件中查到并修改相关的一些数据。

      AADATA.CPP 里面存放的是飞行单位的数据

      BDATA.CPP 里面存放的是建筑物的数据

      BBDATA.CPP 里面可以找到子弹相关数据(修改武器属性可以用到)

      CONST.CPP 里面存放的是常量数据,我们可以在里面找到武器属性、弹头伤害等相关的数据

      DEFINE.H 里面是一些定义 比如武器有哪些、弹头有哪些,因为没深层次研究所以不知道是否在这里增加武器。因为就算光在这里增加武器,没修改其他相关代码也没用。

      飞行单位和建筑物的修改,我就不做过多介绍了,仔细看好 // 符号右边的相关注释,实在不知道怎么改对比一下同类其他单位或建筑物的代码,一般不会有什么大问题。

      我们接下来讲一下CONST.CPP 中武器伤害的修改。

      首先我们先通过之前查找单位相关代码中找到关于 第一武器和第二武器的代码。然后在 CONST.CPP 中查找你相关的武器代码,例如 WEAPON_M60MG (jeep的M60机枪)

      可以看到以下的代码:

      ***************************************************************************

      ** 这些是各种武器及其特点

      **

      ** 子弹类型 伤害,再次发射间隔,范围, 声音,动画 //右边的是武器代码

      */

      WeaponTypeClass const Weapons[WEAPON_COUNT] = {

      {BULLET_SNIPER, 125, 40, 0x0580, VOC_SNIPER, ANIM_NONE}, // WEAPON_RIFLE

      {BULLET_SPREADFIRE, 25, 50, 0x0400, VOC_MINI, ANIM_GUN_N}, // WEAPON_CHAIN_GUN

      {BULLET_BULLET, 1, 7, 0x01C0, VOC_RIFLE, ANIM_NONE}, // WEAPON_PISTOL

      {BULLET_BULLET, 15, 20, 0x0200, VOC_MGUN2, ANIM_NONE}, // WEAPON_M16

      {BULLET_TOW, 30, 60, 0x0400, VOC_BAZOOKA,ANIM_NONE}, // WEAPON_DRAGON

      {BULLET_FLAME, 35, 50, 0x0200, VOC_FLAMER1,ANIM_FLAME_N}, // WEAPON_FLAMETHROWER

      {BULLET_FLAME, 50, 50, 0x0200, VOC_FLAMER1,ANIM_FLAME_N}, // WEAPON_FLAME_TONGUE

      {BULLET_CHEMSPRAY, 80, 70, 0x0200, VOC_FLAMER1,ANIM_CHEM_N}, // WEAPON_CHEMSPRAY

      {BULLET_GRENADE, 50, 60, 0x0340, VOC_TOSS, ANIM_NONE}, // WEAPON_GRENADE

      {BULLET_APDS, 25, 60, 0x0400, VOC_TANK2, ANIM_MUZZLE_FLASH}, // WEAPON_75MM

      {BULLET_APDS, 30, 50, 0x04C0, VOC_TANK3, ANIM_MUZZLE_FLASH}, // WEAPON_105MM

      {BULLET_APDS, 40, 80, 0x04C0, VOC_TANK4, ANIM_MUZZLE_FLASH}, // WEAPON_120MM

      {BULLET_APDS, 40, 60, 0x0600, VOC_TANK4, ANIM_MUZZLE_FLASH}, // WEAPON_TURRET_GUN

      {BULLET_SSM, 75, 80, 0x0500, VOC_ROCKET1,ANIM_NONE}, // WEAPON_MAMMOTH_TUSK

      {BULLET_SSM2, 75, 80, 0x0600, VOC_ROCKET1,ANIM_NONE}, // WEAPON_MLRS

      {BULLET_HE, 150, 65, 0x0600, VOC_TANK1, ANIM_MUZZLE_FLASH}, // WEAPON_155MM

      {BULLET_BULLET, 15, 30, 0x0400, VOC_MGUN11, ANIM_GUN_N}, // WEAPON_M60MG

      {BULLET_SSM, 60, 35, 0x0780, VOC_ROCKET2,ANIM_NONE}, // WEAPON_TOMAHAWK

      {BULLET_SSM, 60, 40, 0x0680, VOC_ROCKET2,ANIM_NONE}, // WEAPON_TOW_TWO

      {BULLET_NAPALM, 100, 20, 0x0480, VOC_NONE, ANIM_NONE}, // WEAPON_NAPALM

      {BULLET_LASER, 200, 90, 0x0780, VOC_LASER, ANIM_NONE}, // WEAPON_OBELISK_LASER

      {BULLET_SAM, 50, 50, 0x0780, VOC_ROCKET2,ANIM_NONE}, // WEAPON_NIKE

      {BULLET_HONEST_JOHN, 100, 200, 0x0A00, VOC_ROCKET1,ANIM_NONE}, // WEAPON_HONEST_JOHN

      {BULLET_HEADBUTT, 100, 30, 0x0180, VOC_DINOATK1,ANIM_NONE}, // WEAPON_STEG

      {BULLET_TREXBITE, 155, 30, 0x0180, VOC_DINOATK1,ANIM_NONE}, // WEAPON_TREX

      #ifdef PETROGLYPH_EXAMPLE_MOD

      {BULLET_NUKE_LOB, 150, 130, 0x0B00, VOC_NUKE_LOB, ANIM_MUZZLE_FLASH}, // WEAPON_NUKE_LOB

      #endif //PETROGLYPH_EXAMPLE_MOD

      从上边代码可以看出M60机枪的默认属性

      使用的子弹类型是BULLET_BULLET(普通子弹),伤害值——15,射击间隔(暂定为15=1秒)2秒,射击距离为0x0400(怎么计算不知道),声音为VOC_MGUN11,射击动画 ANIM_GUN_N

      这段代码结合其他武器代码,我们可以修改伤害值不用说,比如把射击距离改的和155MM舰炮一样0x0600,子弹类型改成 BULLET_HE(高爆)或者 BULLET_NUKE_LOB (核弹)。

      我们接下来看一下子弹的相关数据,以高爆弹 BULLET_HE为例,我们从BBDATA.CPP 里查到代码如下:

      tatic BulletTypeClass const Class120mm(

      BULLET_HE,

      "120mm", // NAME: Text name of this unit type. 单位名称

      true, // Flies over tall walls? 是否飞跃建筑物

      false, // Homes in on target? 房屋是否列为目标

      true, // Projectile arcs to the target? 向目标发射弧线弹道吗

      false, // Is this a dropping bomb-like object? 这是否是一个炸弹

      false, // Is this projectile invisible? 这个投射物不可见吗?

      false, // Will it blow up even if it gets just NEAR to target? 接近目标,会爆炸吗?

      false, // Does it have flickering flame animation? 是否有闪烁的火焰动画

      false, // Can it run out of fuel? 是否会耗光燃料

      true, // Is there no visual difference between projectile facings? 抛射面之间是否没有视觉差异

      true, // Is projectile inherently inaccurate? 抛射本身就不准确吗?

      false, // Translucent colors are used? 使用半透明的颜色

      false, // Good against aircraft? 是否对飞机有好处

      0, // ARMING: Time to arm projectile after launch. 发射后准备发射的时间

      0, // RANGE: Inherent override range factor. 固有覆盖范围因子

      MPH_MEDIUM_FAST, // SPEED: Miles per hour.

      0, // ROT: Rate of turn (degrees per tick). 旋转速度

      WARHEAD_HE, // WARHEAD: If fires weapon, warhead type 子弹的弹头类型

      ANIM_ART_EXP1 // Explosion to use upon impact. 子弹爆炸的动画

      );。

      子弹的弹头相关数据还在 CONST.CPP 中,就在武器代码的下方:

      /***************************************************************************

      ** 这些是各种弹头。

      **

      ** 扩散系数, 是否摧毁墙壁,是否摧毁建筑, 是否摧毁泰矿, {装甲防御表} ///装甲防御表代表不同的装甲在该种弹头的攻击下受到的不同的伤害比例

      ** -vs- {无装甲, 木头, 铝质, 钢铁, 混凝土}

      */

      WarheadTypeClass const Warheads[WARHEAD_COUNT] = {

      { 2,false,false,false,{0x100, 0x80, 0x90, 0x40, 0x40}}, // WARHEAD_SA Small arms -- good against infantry.

      { 6,true,true,true,{0xE0, 0xC0, 0x90, 0x40, 0x100}}, // WARHEAD_HE High explosive -- good against buildings & infantry.

      { 6,true,true,false,{0x40, 0xC0, 0xC0, 0x100, 0x80}}, // WARHEAD_AP Armor piercing -- good against armor.

      { 8,false,true,true,{0xE0, 0x100, 0xB0, 0x40, 0x80}}, // WARHEAD_FIRE Incendiary -- Good against flammables.

      { 4,false,false,false,{0x100, 0x100, 0x100, 0x100, 0x100}},// WARHEAD_LASER Light Amplification of Stimulated Emission by Radiation.

      { 7,true,true,true,{0x100, 0x100, 0xC0, 0xC0, 0xC0}}, // WARHEAD_PB Particle beam (neutron beam).

      { 4,false,false,false,{0x100, 0x20, 0x20, 0x10, 0x10}}, // WARHEAD_FIST Punching in hand-to-hand combat.

      { 4,false,false,false,{0x100, 0x20, 0x20, 0x10, 0x10}}, // WARHEAD_FOOT Kicking in hand-to-hand combat.

      { 4,false,false,false,{0x100, 0x08, 0x08, 0x08, 0x08}}, // WARHEAD_HOLLOW_POINT Sniper bullet type.

      {255,false,false,false,{0x100, 0x01, 0x01, 0x01, 0x01}}, // WARHEAD_SPORE

      { 1, true,true,false,{0x100, 0xC0, 0x80, 0x20, 0x08}}, // WARHEAD_HEADBUTT

      { 1, true,true,false,{0x100, 0xC0, 0x80, 0x20, 0x08}}, // WARHEAD_FEEDME

      };

      对比一下各种弹头对于不同类型伤害,可以看出,WARHEAD_HE 弹头,对于无装甲目标的时候的伤害是最高的 0xE0 。只要不超过这个值你可以根据需要自己设置。

      五,超级武器冷却间隔的设置

      STEAM创意工厂已经有人放出了修改了冷却时间的MOD,这里就给大家讲一下搜索以及修改的原理

      我们首先要知道两个要素:1 超级武器里的核武 NUKE ;2 时间 TIME ,其次要知道 TIME 这个要素肯定有很多地方会用到,相对的 NUKE 则会用到的地方少一些。

      在 Microsoft Visual Studio 打开的源代码中按 CTRL+SHIFT+F 弹出搜索框,查找内容一栏输入 NUKE ,查找范围选择 当前项目 ,然后点 查找全部,会在下方出现 查找结果 。

      我们从查找结果列表中可以看到列出的各个文件中包含 NUKE 这个代码的所有文件和相对应的代码语句。鼠标点击列表中的任意一项就会打开对应的文件以及定位到对应的语句。

      通过查找列表可以看到 SOURCECODE\TIBERIANDAWN\DEFINES.H(320):#define NUKE_GONE_TIME 14*TICKS_PER_MINUTE 这一项中两个要查找的要素都包含。

      点击该项打开文件,我们可以看到以下代码段:

      /**********************************************************************

      ** These defines control the rate of ion cannon and airstrike recharging.

      */

      #define NUKE_GONE_TIME 14*TICKS_PER_MINUTE //核武冷却时间

      #define ION_CANNON_GONE_TIME 10*TICKS_PER_MINUTE //离子加农炮冷却时间

      #define AIR_CANNON_GONE_TIME 8*TICKS_PER_MINUTE //空中打击冷却时间

      #define OBELISK_ANIMATION_RATE 15

      这就是超级武器的冷却时间。但是 TICKS_PER_MINUTE 是什么意思呢?用上边讲到的方法,我们查找 TICKS_PER_MINUTE ,在 ABSTRACT.CPP 文件中可以找到以下代码段:

      /****************************************************************************

      ** Timer constants. These are used when setting the countdown timer.

      ** Note that this is based upon a timer that ticks every 60th of a second.

      */

      #define TICKS_PER_SECOND 15

      #define TICKS_PER_MINUTE (TICKS_PER_SECOND * 60)

      #define TIMER_SECOND 60

      #define TIMER_MINUTE (TIMER_SECOND*60)

      这个是整个源代码中对于一些时间变量的定义。比如你查到的时间变量是 14*TICKS_PER_MINUTE ,这个是多久?通过这个定义就知道了,是14分钟。如果查到的是 14*TIMER_SECOND,就是14秒。

      了解了时间变量 TICKS_PER_MINUTE 的含义,我们回到之前的超级武器冷却时间的代码段,就明白了该怎么设置了吧。3*TICKS_PER_SECOND ? 1*TICKS_PER_MINUTE?一切都随你所愿。如果想

      彻底无冷却就改成 0*TICKS_PER_MINUTE 即可。
      附件链接:https://pan.baidu.com/s/1O9OE6PWy4OM9unHSSizJjQ

      提取码:cx1j