Skip to content

Adding A Custom Faction (Above 0.8)

Ansible2 edited this page Jul 17, 2022 · 13 revisions

This will apply to any version above 0.8 (for now). It is not a difficult task, however, it is tedious when doing a mod the size of CUP.

Files To Edit:

  • Headers\descriptionEXT\Faction Headers\Faction Master.hpp
  • Headers\descriptionEXT\Faction Headers\Define Factions.hpp (BELOW 0.9.1)

Create A Table File:

In this hypothetical, the faction I am adding will be called MyFaction.

  1. Create a header (.hpp or .h) file in Headers\descriptionEXT\Faction Headers folder. This is where you will put the information for the faction. I will refer to my file as MyFaction Unit Table.hpp.

  2. In the Faction Master.hpp file, put a #include with the filename that you just created. Mine will be #include "MyFaction Unit Table.hpp"

BEFORE:

...
#include "Zombies And Demons Unit Table.hpp"
#include "CUP Unit Table.hpp"

AFTER:

...
#include "Zombies And Demons Unit Table.hpp"
#include "CUP Unit Table.hpp"
#include "MyFaction Unit Table.hpp"

Ideally, this file you just created is where you should place all the faction classes for the specific addon you want to support.

Create Your First Custom Faction:

  1. Now define a class for your faction (SEE NOTE 1)
class myFaction_faction
{
};
  1. Give the faction a name with an entry for the displayName string property. (SEE NOTE 2)
class myFaction_faction
{
   displayName = "myMod - My Faction";
};
  1. Add infantry definitions to your table by creating an array property infantry[] in the class as can be seen below. I added two units, "I_Soldier_A_F" and "I_Soldier_AAR_F" (SEE NOTE 3)
class myFaction_faction
{
   displayName = "myMod - My Faction";
   infantry[] = {
      "I_Soldier_A_F",
      "I_Soldier_AAR_F"
   };
};

Adding your faction to the selection list: (ONLY APPLIES BELOW 0.9.1)

  1. Navigate to Headers\descriptionEXT\Faction Headers\Define Factions.hpp
  2. In the #define FACTION_COUNT list add a new iteration of the highest number by one:

BEFORE:

...
62,\
63

AFTER:

...
62,\
63,\
64
  1. In the #define FACTION_STRINGS list add the displayName property of your faction anywhere in the list ABOVE DLC & VANILLA FACTIONS (SEE NOTE 4). This NEEDS TO BE THE SAME AS THE CLASS PROPERTY STRING YOU MADE IN THE Create Your First Custom Faction SECTION STEP 2

BEFORE:

...
   "Zombies & Demons - Spider Zombies", \
   "Zombies & Demons - Walkers"

AFTER:

...
   "Zombies & Demons - Spider Zombies", \
   "Zombies & Demons - Walkers", \
   "myMod - My Faction"
  1. Now your faction should be implemented and can be selected in the mission parameter menu.

Adding vehicles your faction (OPTIONAL):

Vehicles are where things need a bit of detail.

Some features require certain stipulations or considerations be made when adding vehicles due to the many supports offered. I have done my best behind the scenes to make sure there are fall through cases if a vehicle class can't be found or the it does not meet the requirements needed to perform an action. However, there are still cracks.

When I use WARNING: it means you should almost certainly follow what it says or it will cause errors or a fall through. CAUTION: means that you should consider the guideline carefully and decide on what you want.

  1. Light cars are, for me at least, vehicles without much armor and/or clearly exposed turret gunners. To add them to the faction class, simply create a lightCars[] property array just like with the infantry and add your classes.
class myFaction_faction
{
   displayName = "myMod - My Faction";
   infantry[] = {
      "I_Soldier_A_F",
      "I_Soldier_AAR_F"
   };
   lightCars[] = {
      "B_T_LSV_01_armed_F"
   };
};
  1. Heavy cars are what you would expect, MRAPs or up armored vehicles that use some sort of protection for their turrets but aren't quite on par with IFVs or APCs. Just like with light cars, we add a property array heavyCars[] to the faction class with the vehicle classnames.
class myFaction_faction
{
   displayName = "myMod - My Faction";
   infantry[] = {
      "I_Soldier_A_F",
      "I_Soldier_AAR_F"
   };
   lightCars[] = {
      "B_T_LSV_01_armed_F"
   };
   heavyCars[] = {
      "I_MRAP_03_gmg_F",
      "I_MRAP_03_hmg_F"
   };
};
  1. Light armor is again nothing special. Vehicles that are not tanks but also not 4-wheeled cars with armor (IFVs & APCs). Here, we use the lightArmor[] property.
class myFaction_faction
{
   displayName = "myMod - My Faction";
   infantry[] = {
      "I_Soldier_A_F",
      "I_Soldier_AAR_F"
   };
   lightCars[] = {
      "B_T_LSV_01_armed_F"
   };
   heavyCars[] = {
      "I_MRAP_03_gmg_F",
      "I_MRAP_03_hmg_F"
   };
   lightArmor[] = {
      "I_APC_Wheeled_03_cannon_F",
      "I_APC_tracked_03_cannon_F"
   };
};
  1. Lastly for the land vehicles, we have the heavyArmor[] property. Simply put, these are tanks for me.
class myFaction_faction
{
   displayName = "myMod - My Faction";
   infantry[] = {
      "I_Soldier_A_F",
      "I_Soldier_AAR_F"
   };
   lightCars[] = {
      "B_T_LSV_01_armed_F"
   };
   heavyCars[] = {
      "I_MRAP_03_gmg_F",
      "I_MRAP_03_hmg_F"
   };
   lightArmor[] = {
      "I_APC_Wheeled_03_cannon_F",
      "I_APC_tracked_03_cannon_F"
   };
   heavyArmor[] = {
      "I_MBT_03_cannon_F"
   };
};
  1. Next we have the transportHelicopters[] property. WARNING: Transport helicopters are what are used for the door gunner support. Your FIRST ENTRY in the array will the the one selected for this support. Make sure there is at least one turret on the left-hand side of the aircraft or it will greatly diminish the utility of the support. If no turrets are present on this vehicle, a default fall through vehicle will be used instead. (SEE NOTE 5)
class myFaction_faction
{
   displayName = "myMod - My Faction";
   infantry[] = {
      "I_Soldier_A_F",
      "I_Soldier_AAR_F"
   };
   lightCars[] = {
      "B_T_LSV_01_armed_F"
   };
   heavyCars[] = {
      "I_MRAP_03_gmg_F",
      "I_MRAP_03_hmg_F"
   };
   lightArmor[] = {
      "I_APC_Wheeled_03_cannon_F",
      "I_APC_tracked_03_cannon_F"
   };
   heavyArmor[] = {
      "I_MBT_03_cannon_F"
   };
   transportHelicopters[] = {
      "I_Heli_light_03_unarmed_F"
   };
};
  1. Another entry to add is the cargoAircraft[] property. These can be comprised of either fixed or rotary wing aircraft. CAUTION: contrary to the name, these should still ideally have troop seats as they are used for paratroopers. While they are also used for supply drops, they do not need a dedicated cargo space such as Vehicle In Vehicle. It's mostly an aesthetic choice beyond the seats.
class myFaction_faction
{
   displayName = "myMod - My Faction";
   infantry[] = {
      "I_Soldier_A_F",
      "I_Soldier_AAR_F"
   };
   lightCars[] = {
      "B_T_LSV_01_armed_F"
   };
   heavyCars[] = {
      "I_MRAP_03_gmg_F",
      "I_MRAP_03_hmg_F"
   };
   lightArmor[] = {
      "I_APC_Wheeled_03_cannon_F",
      "I_APC_tracked_03_cannon_F"
   };
   heavyArmor[] = {
      "I_MBT_03_cannon_F"
   };
   transportHelicopters[] = {
      "I_Heli_light_03_unarmed_F"
   };
   cargoAircraft[] = {
      "I_Heli_Transport_02_F"
   };
};
  1. Then there are casAircraft[]. These are what will be selected from whenever a CAS support is called. WARNING: There are three requirements as of 0.8 for CAS aircraft. They need to fixed wing, they need to have a gun/canon, and they need to support pylons.
class myFaction_faction
{
   displayName = "myMod - My Faction";
   infantry[] = {
      "I_Soldier_A_F",
      "I_Soldier_AAR_F"
   };
   lightCars[] = {
      "B_T_LSV_01_armed_F"
   };
   heavyCars[] = {
      "I_MRAP_03_gmg_F",
      "I_MRAP_03_hmg_F"
   };
   lightArmor[] = {
      "I_APC_Wheeled_03_cannon_F",
      "I_APC_tracked_03_cannon_F"
   };
   heavyArmor[] = {
      "I_MBT_03_cannon_F"
   };
   transportHelicopters[] = {
      "I_Heli_light_03_unarmed_F"
   };
   cargoAircraft[] = {
      "I_Heli_Transport_02_F"
   };
   casAircraft[] = {
      "I_Plane_Fighter_03_dynamicLoadout_F"
   };
};
  1. Now we have the attackHelicopters[]. CAUTION: Attack helicopters are used for the attack helicopter gunner support. As with the door gunner support, your first entry is the one (as of 0.8.1) that will be used for the support. However, you should only select helicopters that have a turret with a significant range of motion or 360 turret rotation. This is so that when the helicopter is orbiting the play area, a player can actually aim towards the center. (SEE NOTE 6)
class myFaction_faction
{
   displayName = "myMod - My Faction";
   infantry[] = {
      "I_Soldier_A_F",
      "I_Soldier_AAR_F"
   };
   lightCars[] = {
      "B_T_LSV_01_armed_F"
   };
   heavyCars[] = {
      "I_MRAP_03_gmg_F",
      "I_MRAP_03_hmg_F"
   };
   lightArmor[] = {
      "I_APC_Wheeled_03_cannon_F",
      "I_APC_tracked_03_cannon_F"
   };
   heavyArmor[] = {
      "I_MBT_03_cannon_F"
   };
   transportHelicopters[] = {
      "I_Heli_light_03_unarmed_F"
   };
   cargoAircraft[] = {
      "I_Heli_Transport_02_F"
   };
   casAircraft[] = {
      "I_Plane_Fighter_03_dynamicLoadout_F"
   };
   attackHelicopters[] = {
      "O_Heli_Attack_02_dynamicLoadout_black_F"
   };
};
  1. Lastly we have a very obscure property that you probably won't use, heavyGunships[]. Gunships are the AC-130 type aircraft. You probably don't have a replacement for the Black Fish in this case, and will just not need to add the property to the class at all.
class myFaction_faction
{
   displayName = "myMod - My Faction";
   infantry[] = {
      "I_Soldier_A_F",
      "I_Soldier_AAR_F"
   };
   lightCars[] = {
      "B_T_LSV_01_armed_F"
   };
   heavyCars[] = {
      "I_MRAP_03_gmg_F",
      "I_MRAP_03_hmg_F"
   };
   lightArmor[] = {
      "I_APC_Wheeled_03_cannon_F",
      "I_APC_tracked_03_cannon_F"
   };
   heavyArmor[] = {
      "I_MBT_03_cannon_F"
   };
   transportHelicopters[] = {
      "I_Heli_light_03_unarmed_F"
   };
   cargoAircraft[] = {
      "I_Heli_Transport_02_F"
   };
   casAircraft[] = {
      "I_Plane_Fighter_03_dynamicLoadout_F"
   };
   attackHelicopters[] = {
      "O_Heli_Attack_02_dynamicLoadout_black_F"
   };
   heavyGunships[] = {
      "B_T_VTOL_01_armed_F"
   };
};

Inheritance:

If you know how to use it already, then I'm sure you can see the potential to save time already, if not, read on.

Inheritance is a simple thing in making classes that allows you to use/copy properties from one class into another so you only need to write something once instead of say 10 times when a bunch of other classes have the same value for the same property.

For example, take a look at what could have been the travesty of CUP factions for the British Armed Forces:

https://github.com/Ansible2/Arma-3-Survival/blob/c0b8631978cbed9c4f49694f1b5a6e23351ee142/Headers/descriptionEXT/Faction%20Headers/CUP%20Unit%20Table.hpp#L136

You'll see that under the BAF Multicam faction CUP_BAF_MTP_faction I defined a bunch of vehicles. However, I did something different with the Desert camo BAF class.

https://github.com/Ansible2/Arma-3-Survival/blob/c0b8631978cbed9c4f49694f1b5a6e23351ee142/Headers/descriptionEXT/Faction%20Headers/CUP%20Unit%20Table.hpp#L232

Using inheritance (class classToInherit : classToInheritFrom) I was able to share the desert painted vehicles between both the Multicam infantry and the Desert camo infantry for the BAF. Their infantry are not shared as I made an entry specifically in the CUP_BAF_DES_faction for the infantry[] array that then overwrites anything inherited for that property.

Notes:

  1. You'll notice I added _faction to the end of the class name, this is just my naming scheme to help distinguish between actual factions and base classes which I add _base to the end of. You can do the same or don't; it's up to you.
  2. This displayName string entry for the faction class is what will show up in mission parameter menu.
  3. Infantry are the only required entry in order for a faction class to be viable. The simplest way to get classnames is to load in the editor, find the units you want, drop them down, select them, and right-click -> Log -> Log Classes To Clipboard. 3den Enhanced has a wonderful option to do this (in the same Log menu) and includes the "" already.
  4. You'll notice the use of \ after every line in a list except for the last one. Keep this up in order for multiline #defines to work. You can read about them here.
  5. While only the first entry in transportHelicopters[] matters at the moment, you may want to go ahead and add in multiple entries still for the array. In the future, these vehicles will be used for more then just the door gunner support.
  6. If you want to be safe with attack helicopters, use ones that support pylons as I may end up changing them to this in the future.