Campaign Description.ext
Caveat
Two types of description.ext file exist in the flashpoint world
- Mission Descriptions.
- Campaign Descriptions.
They have nothing in common with each other
If you are looking for the nitty gritty of description.ext in missions, you are in the wrong place.
Intro
Compared to the effort of creating any single mission, the effort to house them in a campaign is trivial. This document is intensely detailed. Most of it you dont need to successfully write excellent campaigns. Here's what you need to know:
MyGreatCampaign/ folder contains everything to do with your campaign. MyGreatCampaign/ lives inside the ~/Campaigns directory of ofp. (or one of it's mods) There are no other gotcha's, no other 'places' where you have to modify ofp to play MyGreatCampaign. . The sequence of missions is defined in the description.ext file in this folder. . A MissionS/ folder, within MyGreatCampaign/ folder contains all the mission folders. . All of of your individual missions go into this MissionS/ folder. There are no files in this MissionS/ folder, only individual mission folders. Each 'mission' is in it's own, arbitrarily named directory, within this MissionS/ directory . The content of any mission folder is an exact copy of what they were, played as single missions. No changes No alterations No additions
MyGreatCampaign/ directory contains only a few ( but identical in intent) files that single mission folders have:
Overview (html and jpeg) description.ext
As a convenience, other files might exist in this folder. Their purpose is to provide a global radio, global sounds, global language definitions. They are no different in content or purpose than those in any mission folder and are not covered here. If you put them in, it's because you want to refer to a common set of radio messages for many missions. A common way of saying "get down", in six languages.
A campaign folder does not contain a mission.sqm. There is no 'mission'., there are Missions/
The Glue
Description.ext in the MyGreatCampaign/ directory is the glue that sequences which mission to play next. It does contain other niceties such as rewards and faces, but sequencing is it's essential purpose.
Like mission.sqm, like config.cpp, description.ext is a TokenClass file.
The organisation of a description.ext is as follows;
campaign { chapter1 {missions...}; chapter2 {missions...}; chapterlast {missions...}; };
Only one campaign class exists. The name of this class is fixed as 'campaign'
At least one chapter exists. Most campaigns only have one chapter.
Many missions might exist (in each chapter)
All missions from all chapters are in the unitary Missions/ directory.
The order of chapters and missions are unimportant!
There is NO default behaviour where chapter 1 will "fall thru" to the next chapter. Each and every chapter and each and every mission must be specifically targeted.
The names given to the chapters and missions are arbitrary, but generally reflect the name of the associated mission folders
Campaign Class Fundamentals
Campaign class basics
The campaign class is a container. It contains chapters, which contain missions.
The chapter and mission classes within the campaign class rely on inheritance. The intent of inheritance is to provide fall thru behavior. Ie, what to do when nothing's specifically been said to do. It is specifically geared to end a chapter or a complete mission, or allow a cut scene to do it's thing (not do anything player wise). Thus, at close to top of file, you will see something like this:
class NoEndings { lost = ; end1 = ; end2 = ; end3 = ; end4 = ; end5 = ; end6 = ; };
Chapters, the overall campaign itself, some missions, have nothing further to do (other than exit completely, or exit the chapter). Chapters, missions, the campaign itself will inherit this class (when programmed to do so). This saves you specifically declaring all possible outcomes for each mission, when only a few are needed.
Typically, in single player campaigns, you aint gonna die forever. You will live to fight the mission again. Thus
class MissionDefault : NoEndings { lives = -1; };
The name :MissionDefault and all names for all classes are arbitrary, ':MissionDefault' is an accepted de-facto standard name for missions to inherit. Left to itself, simply inheriting the mission default means you will exit the game at end of mission/chapter. Indeed the last chapter (if any) last mission, does exactly this. But, almost all classes that inherit :MissionDefault will modify some or most of those mission defaults. The intent is to stop tedious typing for every mission.
class Mission123 : MissionDefault { // some body text };
What happens here is that this mission (and almost all missions do this) inherit defaults for anything not specifically over-ridden in the body text. For a clearer understanding, not only will the mission obtain lives = -1, but also grab ending defaults.
class Campaign {
the campaign class is a containing class. It 'contains' all of the chapters making up the campaign!.
this class (which must be called 'Campaign') declares the title of this campaign and which chapter to Start.
name = "My Great Campaign"; firstBattle = Chapter1; class chapter1 {.....}; class chapter2 {.....}; and so on... };
class ChapterN {
Chapters are a containing class. Their intent is to compartmentalize the various missions you have into some semblance of sanity. One such example would be to put all Everon missions in one chapter, all Nogova missions in another.
At least one chapter must exist in a campaign. It need be the only one, and it can contain all missions, should you wish it that way. The name of any chapter class is arbitrary one such example would be NogovaChapter
name = "Chapter I - Battles For Spaghetti Island"; cutscene = MyGreatCutscene.Noe; // a cutscene is optinal class mission1{....}; class mission2{...}; and so on... };
Note that a cutscene is no different to any other 'mission'. It is a mission folder like any other, except there is no Mission class associated with it because it aint, a mission!
class MissionX {
Most mission folders (in the missions directory) have a corresponding mission classes. The name of each mission class should closely correspond to the name of each mission folder to preserve your sanity. Those missions folders not declared as mission classes are cutscenes.
Mission folders that are not declared anywhere in description.ext have no ill effect, they are simply ignored.
The campaign class=
Declare a MissionDefault class as above
Next decide to use either a single chapter, or, multiple chapters in your campaign. Multiple chapters have the 'benefit' of easier-to-handle cutscenes, a potentially nicer fade in and out between chapters, but dont matter muchly. Very few, if any, user inspired campaigns have multiple chapters.
Single Chapter Campaign
A single chapter campaign looks as follows
class Campaign { name = "My Great Campaign"; firstBattle = Chapter1; // might be the only chapter class Chapter1 : NoEndings { name = "Chapter1 Fighting for Everon"; cutscene = AGreatCutscene.Eden; // if any firstMission = FirstMission; class FirstMission: MissionDefault { // ending commands }; class MissionN: MissionDefault { // ending commands }; class LastMission: MissionDefault { // NO ending commands }; }; // end of this chapter }; // end of this campaign
when chapter1 ends, the game ends via : NoEndings
There are no over-rides provided for endings in chapter one, hence when the chapter ends, the campaign ends.
Throughout, unless endings 1 to 6 and loose are declared for each and every chapter and mission, when the time comes for ofp to go look for them, it will crash. This is, the primary use of inheritance.
MultiChapter Campaign
A multi chapter campaign looks as follows
class Campaign { name = "My Great Campaign"; firstBattle = Chapter1; class Chapter1 : NoEndings { end1 = NextChapter; end2 = NextChapter; end3 = NextChapter; end4 = NextChapter; end5 = NextChapter; end5 = NextChapter; loose= NextChapter; ... missions etc }; class NextChapter : NoEndings { end1 = LastChapter ; ...... missions etc }; class LastChapter : NoEndings { // no endings provided missions etc }; };
The difference is that each chapter (except the last) defines another chapter to go to. Like missions, over-riding all endings (1..6) make no difference if they aren't used. The inheritance therefore of : NoEndings is superfluous but hopefully makes the above clearer in content.
The order of Chapters (the top to bottom definition of them) is not important. Chapter one can jump to 3 to 2 to 7 to 5.
Nor is the name of the chapter class important, other than
endX= MustGotoASpcificallyNamedChapterClassName;
It is, as simple as that.
Mission Class
class Mission1 : MissionDefault { noAward=true; end1 = Mission2; // which mission to play on a successful ending end2 = Mission2; // which mission to play on a slightly less successful outcome end3 = Mission2; // etc end4 = Mission2; end5 = Mission2; end6 = Mission2; // lost = Mission1; // which mission to replay if you die. this one. template = Mission1.Noe; // The folder in the Missions/ directory containing the mission };
"Mission1" and "Mission2" are arbitrary names.. There is, but need not be, a close association between the name used for the class and the name of the folder containing the mission itself. Using identical names is a good idea (tm).
The template= is the mission folder to play. It always has an island extension associated with it. In this case, Nogova. There is nothing in this, nor any other script that declares what island the mission is 'on', other than the filename extension itself. It should be instantly apparent that mission folders cannot have whitespace in their names.
Endings 1 to 6, are the result of 'triggers'. They are the result of conditions established by the mission author being activated. It is rare to use more than 2, but, up to six different ending slots are available for use by the author. By convention end1 is the total success ending, but need not be. If there is no end6 condition it matters nothing that it is declared above to 'do something'.
Conversely If it's not declared, and is used, it matters a great deal. Often resulting in a crash.
Moving to "Mission2" is standard behaviour for all of the possible endings. The flow of campaign design is that mission1 -> mission2 -> mission3 and so on. It need not be. End4 might be a trigger that if you capture the scud launcher. you get to use it in a separate 'adventure'. It is after all, your campaign. Just bare in mind that there is NO automatic fall thru, you must declare everything required.
Conventionally lost= (which means dead) restarts the same mission. It need not be. It's your campaign,
Where you dont declare an ending.
The MissionDefault class takes over for that ending. The name "MissionDefault" is arbitrary, but, by convention this is what that class is named. The MissionDefault class is written to end (not exit, end) the chapter class within which this mission is contained. It is then the chapter which must decide what to do and etc.
MissionDefault contains other parameters which are not normally over-ridden by the mission itself. Notably lives=-1. Therefore even though you declare all endings in all missions, you still 'inherit' MissionDefault for each mission.
It should be apparent that as the author, you could write a number of missions, perhaps all in the same chapter, all of which have default endings different to the standard. For example end4 always results in the same cutscene, regardless of mission. You would change the : MissionDefault inheritance to MyEnd4Default and not bother declaring end4 in the body text of the mission class (for any missions you want this behaviour to happen in).
When it comes to making several of the ending triggers all behave a similar way, it is easier to use an inheritance than tediously write endings for each one that's default. To be a little more specific, MyEnd4Default would also, undoubtedly, inherit MissionDefault in its own right to include standard mission parameters (lives = -1) and endings it does not handle.
If all of the above is currently a little too deep for you, using the above class as a template will work for most of what you want to do.
THE LAST MISSION
class MissionLast : MissionDefault { lost = MissionLast; template = MissionLast.Noe; };
The name "MissionLast" is arbitrary, the name is whichever mission you decide to be the last one.
The difference between this, and any other mission is that no endings are declared, therefore default behaviour happens.
Either to be specific, or where MissionDefault does not end the chapter (because you wrote it some other way) you can declare the endings as follows
end1 = ; end2 = ; end3 = ; end4 = ; end5 = ; end6 = ;
The chapter class will take over and use it's endings instead.