
本指南将帮助你在选中单位或建筑时,在其前方添加小型自定义PIP图像,以帮助识别它们的能力或仅用于装饰目的。本指南目前仅涵盖重制版的自定义图形,以及在游戏中已有的旧版图形中使用标准PIP。 1. 在DEFINES.H文件中添加初始项目定义,(虽然不是必需的,但有助于整理你的条目)。 (示例) /* ** 此MOD在NW新增内容上生成PIP。 */ #define PIPS // NightFalcon101 #ifdef PIPS // NightFalcon101 #endif // PIPS

2) 如下文DLLInterface.CPP文件中所述,无需添加或修改任何内容,只需进行标记以指出DLL_Draw_Intercept的布局,因为之后我们将从另一个文档中引用此变量。 (示例) /* ** 下方部分为原始代码,无需归入PIPS项目,但需标记以指出其布局及必要性。 */ //#ifdef PIPS // NightFalcon101 void DLL_Draw_Intercept(int shape_number, int x, int y, int width, int height, int flags, const ObjectClass *object, DirType rotation, long scale, const char *shape_file_name, char override_owner) { DLLExportClass::DLL_Draw_Intercept(shape_number, x, y, width, height, flags, object, rotation, scale, shape_file_name, override_owner); } //#endif // PIPS

3)在DLLInterface.CPP的DLLExportClass::DLL_Draw_Intercept列表底部添加内容。 (示例) #ifdef PIPS // NightFalcon101 if ((shape_file_name != NULL) && object && object->Is_Techno() && ( (strcmp(shape_file_name, "MEDICPIP") == 0) || (strcmp(shape_file_name, "NUKEPIP") == 0) // 在此处添加新行项目,在上方行末尾添加"||"。 ) ){ } #endif // PIPS

4) 前往TECHNO.CPP文件,这里会用到DLLInterface.CPP文件中步骤2提到的布局。我们将使用相同的公式,并在前面加上extern变量,以便能从DLLInterface.CPP文件中调用其函数(这意味着该变量正从DLLInterface.CPP的原始文件外部作为交叉引用使用)。 (示例) #ifdef PIPS // NightFalcon101 extern void DLL_Draw_Intercept(int shape_number, int x, int y, int width, int height, int flags, const ObjectClass *object, DirType rotation, long scale, const char *shape_file_name, char override_owner); #endif // PIPS

5a) 5a)THIS SECTION IS MASSIVE AND TO A PROFESSIONAL C++ USER IS PROBABLY NOT STREAMLINED. However, to a novice like me I personally like to separate things to specific functions/units, and those with a discerning eye can also see the moving of the PIP applies to only "some" units and not all. Additionally, this is where the custom legacy graphics are implemented mentioned below if the image is in a .SHP file (personally i do not know how to do that, but will update this guide when & if i figure it out). Its also important to note the "ORANGE" text is the folder the .tga image will be going into OR the .SHP file will be going into. (EXAMPLE) #ifdef PIPS // NightFalcon101 /* ** PIP SECTION 1 ** THIS SECTION IS NEEDED FOR REMASTERED GRAPHICS, IF THE DESIRED ART IMAGE IS PROPERLY ADDED TO A .SHP IMAGE AND .MIX FILE THEN PIP SECTION 2 WHICH COVERS THE LEGACY GRAPHICS ISNT NEEDED. */ // Remastered Rendering For Technician & Surgeon if (MedicPip == 0){ int PIP_MEDIC = MedicPip - 0; if (window == WINDOW_VIRTUAL){ if ((What_Am_I() == RTTI_INFANTRY) && ((*(InfantryClass *)this == INFANTRY_TECH) || (*(InfantryClass *)this == INFANTRY_SURG))){ if (Is_Selected_By_Player(House)){ int medpipx = x + lx - 2 - 3; // LEFT AND RIGHT int medpipy = y + ly - 3 - 1; // UP AND DOWN // THIS REMASTERED SECTION ONLY WORKS IF THE ART TILE/KEY/NAMES/VALUE IS IN COMMON_VFX.XML AND .tga PICTURE IS IN THE ART/TEXTURES/SRGB/COMMON/VFX/"FOLDER NAME". DLL_Draw_Intercept(PIP_MEDIC, medpipx, medpipy, 8, 8, SHAPE_WIN_REL | SHAPE_CENTER, this, DIR_N, 0x0100, "MEDICPIP", HOUSE_NONE); } } } else { // Legacy Rendering For Technician & Surgeon if (Is_Selected_By_Player(House) && House->Is_Ally(PlayerPtr)){ // THIS LEGACY SECTION ONLY WORKS IF THE .SHP IMAGE FILE BELOW HAS BEEN ADDED IN A .MIX FILE AND .tga PICTURE IS IN THE ART/TEXTURES/SRGB/COMMON/VFX/"FOLDER NAME". void const *medpipshapefile = MFCD::Retrieve("MEDICPIP.SHP"); int medpipx = x + lx - 4 -1; // LEFT AND RIGHT int medpipy = y + ly -6; // UP AND DOWN CC_Draw_Shape(medpipshapefile, PIP_MEDIC, medpipx, medpipy, window, SHAPE_BOTTOM | SHAPE_WIN_REL, NULL, NULL); } } } // Remastered Rendering For Nuclear Specialist & Nuclear K9 if ((What_Am_I() == RTTI_INFANTRY) && ((*(InfantryClass *)this == INFANTRY_NSPC) || (*(InfantryClass *)this == INFANTRY_NKK9))) { if (NukePip == 0) { int PIP_NUCLEAR = NukePip - 0; if (window == WINDOW_VIRTUAL) { if (Is_Selected_By_Player(House)) { int nukepipx = x + lx - 2 - 3; // LEFT AND RIGHT int nukepipy = y + ly - 3 - 1; // UP AND DOWN // MOVE NUKE PIP IF UNIT HAS AMMO PIPS if (width - (3 * (Class_Of().Max_Pips() + ((Techno_Type_Class()->MaxAmmo > 0) ? Techno_Type_Class()->MaxAmmo : 0))) < 6) { nukepipy -= 4; // UP AND DOWN } // THIS REMASTERED SECTION ONLY WORKS IF THE ART TILE/KEY/NAMES/VALUE IS IN COMMON_VFX.XML AND .tga PICTURE IS IN THE ART/TEXTURES/SRGB/COMMON/VFX/"FOLDER NAME". DLL_Draw_Intercept(PIP_NUCLEAR, nukepipx, nukepipy, 8, 8, SHAPE_WIN_REL | SHAPE_CENTER, this, DIR_N, 0x0100, "NUKEPIP", HOUSE_NONE); } } else { // Legacy Rendering For Nuclear Specialist & Nuclear K9 if (Is_Selected_By_Player(House) && House->Is_Ally(PlayerPtr)) { // THIS LEGACY SECTION ONLY WORKS IF THE .SHP IMAGE FILE BELOW HAS BEEN ADDED IN A .MIX FILE AND .tga PICTURE IS IN THE ART/TEXTURES/SRGB/COMMON/VFX/"FOLDER NAME". void const *nukepipshapefile = MFCD::Retrieve("NUKEPIP.SHP"); int nukepipx = x + lx - 4 - 1; // LEFT AND RIGHT int nukepipy = y + ly - 6; // UP AND DOWN // MOVE NUKE PIP IF UNIT HAS AMMO PIPS if (width - (3 * (Class_Of().Max_Pips() + ((Techno_Type_Class()->MaxAmmo > 0) ? Techno_Type_Class()->MaxAmmo : 0))) < 6) { nukepipy -= 5; // UP AND DOWN } CC_Draw_Shape(nukepipshapefile, PIP_NUCLEAR, nukepipx, nukepipy, window, SHAPE_BOTTOM | SHAPE_WIN_REL, NULL, NULL); } } } } // Remastered Rendering For Nuke Tank & Nuclear Transport if ((What_Am_I() == RTTI_UNIT) && ((*(UnitClass *)this == UNIT_NTNK) || (*(UnitClass *)this == UNIT_NTRA))) { if (NukePip == 0) { int PIP_NUCLEAR = NukePip - 0; if (window == WINDOW_VIRTUAL) { if (Is_Selected_By_Player(House)) { int nukepipx = x + lx - 2 - 3; // LEFT AND RIGHT int nukepipy = y + ly - 3 - 1; // UP AND DOWN // MOVE NUKE PIP IF UNIT HAS AMMO PIPS if (width - (3 * (Class_Of().Max_Pips() + ((Techno_Type_Class()->MaxAmmo > 0) ? Techno_Type_Class()->MaxAmmo : 0))) < 6) { nukepipy -= 4; // UP AND DOWN } // THIS REMASTERED SECTION ONLY WORKS IF THE ART TILE/KEY/NAMES/VALUE IS IN COMMON_VFX.XML AND .tga PICTURE IS IN THE ART/TEXTURES/SRGB/COMMON/VFX/"FOLDER NAME". DLL_Draw_Intercept(PIP_NUCLEAR, nukepipx, nukepipy, 8, 8, SHAPE_WIN_REL | SHAPE_CENTER, this, DIR_N, 0x0100, "NUKEPIP", HOUSE_NONE); } } else { // Legacy Rendering For Nuke Tank & Nuclear Transport if (Is_Selected_By_Player(House) && House->Is_Ally(PlayerPtr)) { // THIS LEGACY SECTION ONLY WORKS IF THE .SHP IMAGE FILE BELOW HAS BEEN ADDED IN A .MIX FILE AND .tga PICTURE IS IN THE ART/TEXTURES/SRGB/COMMON/VFX/"FOLDER NAME". void const *nukepipshapefile = MFCD::Retrieve("NUKEPIP.SHP"); int nukepipx = x + lx - 4 - 1; // LEFT AND RIGHT int nukepipy = y + ly - 6; // UP AND DOWN // MOVE NUKE PIP IF UNIT HAS AMMO PIPS if (width - (3 * (Class_Of().Max_Pips() + ((Techno_Type_Class()->MaxAmmo > 0) ? Techno_Type_Class()->MaxAmmo : 0))) < 6) { nukepipy -= 5; // UP AND DOWN } CC_Draw_Shape(nukepipshapefile, PIP_NUCLEAR, nukepipx, nukepipy, window, SHAPE_BOTTOM | SHAPE_WIN_REL, NULL, NULL); } } } } // Remastered Rendering For Nuclear Destroyer & Nuclear Submarine if ((What_Am_I() == RTTI_VESSEL) && ((*(VesselClass *)this == VESSEL_NKDD) || (*(VesselClass *)this == VESSEL_NSUB))) { if (NukePip == 0) { int PIP_NUCLEAR = NukePip - 0; if (window == WINDOW_VIRTUAL) { if (Is_Selected_By_Player(House)) { int nukepipx = x + lx - 2 - 3; // LEFT AND RIGHT int nukepipy = y + ly - 3 - 1; // UP AND DOWN // MOVE NUKE PIP IF UNIT HAS AMMO PIPS if (width - (3 * (Class_Of().Max_Pips() + ((Techno_Type_Class()->MaxAmmo > 0) ? Techno_Type_Class()->MaxAmmo : 0))) < 6) { nukepipy -= 4; // UP AND DOWN } // THIS REMASTERED SECTION ONLY WORKS IF THE ART TILE/KEY/NAMES/VALUE IS IN COMMON_VFX.XML AND .tga PICTURE IS IN THE ART/TEXTURES/SRGB/COMMON/VFX/"FOLDER NAME". DLL_Draw_Intercept(PIP_NUCLEAR, nukepipx, nukepipy, 8, 8, SHAPE_WIN_REL | SHAPE_CENTER, this, DIR_N, 0x0100, "NUKEPIP", HOUSE_NONE); } } else { // Legacy Rendering For Nuclear Destroyer & Nuclear Submarine if (Is_Selected_By_Player(House) && House->Is_Ally(PlayerPtr)) { // THIS LEGACY SECTION ONLY WORKS IF THE .SHP IMAGE FILE BELOW HAS BEEN ADDED IN A .MIX FILE AND .tga PICTURE IS IN THE ART/TEXTURES/SRGB/COMMON/VFX/"FOLDER NAME". void const *nukepipshapefile = MFCD::Retrieve("NUKEPIP.SHP"); int nukepipx = x + lx - 4 - 1; // LEFT AND RIGHT int nukepipy = y + ly - 6; // UP AND DOWN // MOVE NUKE PIP IF UNIT HAS AMMO PIPS if (width - (3 * (Class_Of().Max_Pips() + ((Techno_Type_Class()->MaxAmmo > 0) ? Techno_Type_Class()->MaxAmmo : 0))) < 6) { nukepipy -= 5; // UP AND DOWN } CC_Draw_Shape(nukepipshapefile, PIP_NUCLEAR, nukepipx, nukepipy, window, SHAPE_BOTTOM | SHAPE_WIN_REL, NULL, NULL); } } } }




5b) 5b) 此内容承接自5a。 // 对核虎鲸攻击直升机及苏联M4莫洛特进行重制渲染 若 ((What_Am_I() == RTTI_AIRCRAFT) && ((*(AircraftClass *)this == AIRCRAFT_NOAH) || (*(AircraftClass *)this == AIRCRAFT_SM4M))) { 若 (NukePip == 0) { int PIP_NUCLEAR = NukePip - 0; 若 (window == WINDOW_VIRTUAL) { 若 (Is_Selected_By_Player(House)) { int nukepipx = x + lx - 2 - 3; // 左右位置 int nukepipy = y + ly - 3 - 1; // 上下位置 // 若单位有弹药指示点则移动核弹指示点 若 (width - (3 * (Class_Of().Max_Pips() + ((Techno_Type_Class()->MaxAmmo > 0) ? Techno_Type_Class()->MaxAmmo : 0))) < 6) { nukepipy -= 4; // 上下位置 } // 此重制部分仅在艺术素材/键名/名称/数值存在于COMMON_VFX.XML及相关文件时生效tga图片位于ART/TEXTURES/SRGB/COMMON/VFX/"文件夹名称"中。 DLL_Draw_Intercept(PIP_NUCLEAR, nukepipx, nukepipy, 8, 8, SHAPE_WIN_REL | SHAPE_CENTER, this, DIR_N, 0x0100, "NUKEPIP", HOUSE_NONE); } } else { // 用于核弹虎鲸攻击直升机和苏联M4莫洛特的传统渲染 if (Is_Selected_By_Player(House) && House->Is_Ally(PlayerPtr)) { // 此传统部分仅在以下.SHP图像文件已添加到.MIX文件中且.tga图片位于ART/TEXTURES/SRGB/COMMON/VFX/"文件夹名称"时才有效。 void const *nukepipshapefile = MFCD::Retrieve("NUKEPIP.SHP"); int nukepipx = x + lx - 4 - 1; // 左右 int nukepipy = y + ly - 5; // 上下 // 如果单位有弹药指示点,则移动核弹指示点 if (width - (3 * (Class_Of().Max_Pips() + ((Techno_Type_Class()->MaxAmmo > 0) ?无法识别内容,已删除。TILE/KEY/NAMES/VALUE位于COMMON_VFX.XML中,.tga图片位于ART/TEXTURES/SRGB/COMMON/VFX/"文件夹名称"。 DLL_Draw_Intercept(PIP_NUCLEAR, nukepipx, nukepipy, 8, 8, SHAPE_WIN_REL | SHAPE_CENTER, this, DIR_N, 0x0100, "NUKEPIP", HOUSE_NONE); } } else { // 核电站、导弹发射井、研究设施和医院的传统渲染 if (Is_Selected_By_Player(House) && House->Is_Ally(PlayerPtr)) { // 此传统部分仅在以下.SHP图像文件已添加到.MIX文件中且.tga图片位于ART/TEXTURES/SRGB/COMMON/VFX/"文件夹名称"时才有效。 void const *nukepipshapefile = MFCD::Retrieve("NUKEPIP.无法识别或无法翻译,已删除。


6)由于目前我不知道如何将自定义图像上传到.SHP文件中,我决定如果切换到传统图形,就使用预先存在的PIP_COMMANDO和CC_Draw_Shape变量为该单位添加某种标识。你还会注意到,由于尺寸和弹药的原因,SURGEON、TECHNICIAN和AIRCRAFT的PIP位置有所不同。 (示例) #ifdef PIPS // NightFalcon101 /* ** PIP部分2 ** 如果PIP部分1的所需图像已正确添加到.SHP图像和.MIX文件中,则不需要此部分。 ** 如你所见,我选择使用此.MIX中预先存在的突击队员PIP作为一种简单/偷懒的解决方法。 */ if ((What_Am_I() == RTTI_INFANTRY) && ((*(InfantryClass *)this == INFANTRY_SURG) || (*(InfantryClass *)this == INFANTRY_TECH))) { CC_Draw_Shape(Class_Of().无法识别或无法翻译,已删除。无法识别或无法翻译,已删除。

7) 这是在编译PIP项目并将redalert.dll放入DATA文件夹之前的最后一步。 (示例) #ifdef PIPS // NightFalcon101 mutable unsigned int 医疗兵PIP值; mutable unsigned int 核弹PIP值; #endif // PIPS

8)将以下文本添加到COMMON_VFX.XML文件中,并将其放置在DATA/XML/TILESETS文件夹内。你可以将它们添加到其他条目的末尾,或者按名称的字母顺序排列。 (示例) <Tile> <Key> <Name>MEDICPIP</Name> <Shape>0</Shape> </Key> <Value> <Frames> <Frame>medicpip medicpip-0000.tga</Frame> </Frames> </Value> </Tile> <Tile> <Key> <Name>NUKEPIP</Name> <Shape>0</Shape> </Key> <Value> <Frames> <Frame>nukepip nukepip-0000.tga</Frame> </Frames> </Value> </Tile>

9)最后,我们将自定义的.tga图片添加到以下路径:DATA ART TEXTURES SRGB COMMON VFX。在这种情况下,每张图片都需要有自己的文件夹。这里要确保文件夹名称与DLL_Draw_Intercept布局中引号内图片的【ORANGE】代码相匹配。我使用GIMP程序创建.tga图片,在“文件”菜单下选择“导出为”,确保名称与COMMON_VFX.XML文件中的条目匹配,最后确保将其保存为.tga文件(出于某种原因,这些文件不能直接“保存”,必须“导出”)。 (示例) DLL_Draw_Intercept(x, x, x, x, x, x, x, x, "文件夹名称", x);

现在你的单位/建筑将显示你选择的自定义PIP。



2026-02-15 07:00:16 发布在
《命令与征服™:重制版》
说点好听的...
收藏
0
0
