Campaigns consist of a single campaign file, which contains some data about the campaign itself and a list of missions that are in that campaign, along with a considerable amount of information about how they connect, and one or more sets of mission files. Campaign files go in data\leveldata\campaign, and have the extension .campaign. I'll start by disecting one, rr_oem.campaign, the raider's retreat bonus mission.

I'll also say that my knowledge is both rusty and incomplete. When I don't have information I'll try to say so, and fill it in later or let anyone else who knows better edit it in.

The .campaign file Edit

-- localized display name for the UI
displayName = "$4062"

-- 2 = Extra
contentType = 2
contentName = "rr_oem"
contentOrdered = 0
contentChooseText = "$4062"
contentThumbName = "$4064"
contentThumbDesc = "$4063"
contentSort = 0.5        -- Default is 1.0, so 0.5 will appear _before_ others.
contentRules = "SinglePlayer"        -- A DEFAULT that actually reads from SinglePlayerOptions.lua

ExtFilter = "campaign_rroem,campaign_gbx,campaign_gbx_rroem"

Mission = { }   -- create a mission structure

This is the first part, with the mission data to follow.

displayName, contentChooseText, contentThumbName and contentThumbDesc are all related bits of text. The ins and outs of where you see each one elude me at the moment.

contentName defines the directory name where you'll find your campaign files, and the filename of your campaign's thumbnail, which will be visible if there are multiple campaigns.

contentOrdered controls how the flow of the campaign works. If it's set to zero, missions are mostly treated as stand alone. If you set it to 1, you have to complete them in order and finishing one automatically starts the next one loading.

contentType determines something about how the engine handles it. 0 is used for the HW1 and HW2 campaigns, 1 for the tutorial, and 2 for the raider's retreat campaign. As far I know, if you want your campaign to appear you're going to want to use 2.

contentSort is explained in the comment in the example.

contentRules I honestly don't know much about. To date I just clone this line in my campaigns and if there's good reasons to get more fancy I don't know them.

For ExtFilter, see the page on tags and filtering.

And finally the mission line creates the mission table that we'll stick all our missions data in.

-- Mission 1 
Mission[1] = {
    postload        = function () end,

    directory       = "Mission05OEM",
    level           = "Mission05OEM.level",
    postlevel       = function () postLevelComplete() end,

    displayName     = "$4062",
    description     = "$4063",
        usepersist = "player:Campaign//HOMEWORLDCLASSIC//persist5.lua",
        usedefaultpersist = 1,

postload contains a function, which gets executed when you finish loading the level. Exactly what you can and can't do here I'm not sure, but stock missions usually use it for starting NIS, or not at all.

directory defines where you can find the level files. This will be a subdirectory of data/leveldata/campaign/contentName/. level names the level file that you find in that directory.

postlevel contains a function that gets executed when the level is done. Again, I'm not sure exactly what you can and can't do here.

displayName and description are fairly self explanatory I hope.

usepersist and usedefaultpersist are lines found in the RR mission and not in typical missions, that let it grab the persist file from mission 5 of the campaign. I assume usedefaultpersist just allows it to load the player's assumed fleet from then if no such persist fleet exists.

And that's a campaign file in a nutshell. On to the anatomy of a mission, which is a bit less cut and dried

A mission Edit

Missions are not one file, they are several. They data/leveldata/campaign/campaignname/levelname/. You'll find at least the following files

  • datfiles.lua
  • missionname.level
  • missionname.lua

Some campaign files have more than this, and I have begun to suspect that it will simply execute all lua files it finds in your mission directory, but I have not tested this belief.

datfiles.lua tells you to where to find the dictionaries containing the localization strings for those levels. This is not particularly important if you are not worrying about localizing your mod, and localizing your mod seems like enough of a topic to warrant it's own guide, so I'm going to skip it for now.

The .dds file is the thumbnail to display for your mission in the mission select screen. If I recall my struggles with it correct this must be a .dds file, a tga will not work.

The .level file is physical arrangement of your level, like a .level file for a multiplayer map. Any information on setting up a multiplayer .level file applies here.

Missionname.lua is where the actual logic of your mission will go. This is at it's heart just gamerule scripting, a topic perhaps also deserving of it's own full article.

I'll either write that article or expand this one soon, but this should hopefully fill in some blanks for people already.