[Guide] Mission Director Basics - Writing Your First Mission

The place to discuss scripting and game modifications for X³: Terran Conflict and X³: Albion Prelude.

Moderators: Moderators for English X Forum, Scripting / Modding Moderators

dillpickle
Posts: 1159
Joined: Mon, 3. Nov 08, 14:25
x3tc

[Guide] Mission Director Basics - Writing Your First Mission

Post by dillpickle » Fri, 26. Jul 13, 12:03

I was asked to write a guide to explain mission briefings, so here goes....

I figured the best way to explain it was with a short mission I wrote to cover some of the basics of getting started with writing plots with MD.

Resources
The files for this mission are here. The file structure is for X3TC, for Albion Prelude they need to go in the addon folder.

The 'Mission Director conversations.xml' in the 't' folder only contains the three specific conversations for this mission to make them easier to reference, in order for them to work in game you will need to extract the latest 'conversations.xml' from the relevant games CAT/DATS and add these three conversations to 'conversations.xml' in the 't' folder.

There is also x3_terran_conflict_director and ap_director which are bookmarked pdf versions of director.htm (found in the director folder), which contains most of the MD variables, Conditions and Actions that can be used, as well as a lot of other useful stuff for mission coding.

In this topic the cue structure is stripped out to make it easier to read, so you will need to refer to Mission Basics.xml to see the full layout with various sub cues etc...
Also I suggest taking a look at Ketraar's [Video Tutorial] Mission Director Basics for details on cue structure, naming conventions etc... There's no point me explaining this when it's already been covered.

Finally I strongly recommend using Visual Studio Express for Windows - it's free, and will make use of the director schemas so you won't be guessing what conditions or actions you can use, what flags can be set etc...

[ external image ] [ external image ]

Also there is some level of error checking, which makes tracking down a missing '>' in several thousand lines of code, which can cause your whole mission to disappear in the game, a lot easier than scanning the file line by line in notepad...

dillpickle
Posts: 1159
Joined: Mon, 3. Nov 08, 14:25
x3tc

Post by dillpickle » Fri, 26. Jul 13, 12:03

Mission Scenario

When the player is rank 4 with the Argon, and in an Argon core sector they will receive a message asking for help.
Mission guidance will direct them to talk to someone in Argon Prime who will ask the player to investigate reports of a Kha'ak station in Presidents End.
If the player flies to Presidents End via The Wall or Home of Light, then they will meet on route a mercenary who will offer to help for a price - the briefing will update to account for this meeting.
If the player jumps directly to Presidents End, then the mercenary never shows up, and nothing extra appears on the mission briefing.
Once the player is a certain distance from the Kha'ak station, enemy ships are generated, and when a little closer the mission updates to 'Destroy the Station'.
When the station is destroyed, the player is directed back to Argon Prime to collect their reward, and the mission is cleaned up and finished.

Code: Select all

<cue name="DPMB01" delay="5s">
  <condition>
    <check_all>
      <check_value value="{player.notoriety.argon.rank}" min="4"/>
      <match_sector sector="{player.sector}" race="argon" core="1"/>
    </check_all>
  </condition>
  <timing>
    <time exact="5s"/>
  </timing>
  <action>
    <do_all>
      <load_text fileid="8350"/>
      <find_sector name="DPMB01.ArgonPrime" x="1" y="3"/>
      <find_sector name="DPMB01.PresEnd" x="2" y="4"/>
      <find_sector name="DPMB01.TheWall" x="2" y="3"/>
      <find_sector name="DPMB01.HomeOfLight" x="1" y="4"/>
      <find_station name="DPMB01.Mission Station" class="equipment" race="argon">
        <sector sector="DPMB01.ArgonPrime"/>
      </find_station>
      <do_choose>
        <do_when value="{object.exists@DPMB01.Mission Station}" exact="0">
          <find_station name="DPMB01.Mission Station" class="station" race="argon">
            <sector sector="DPMB01.ArgonPrime"/>
          </find_station>
          <do_choose>
            <do_when value="{object.exists@DPMB01.Mission Station}" exact="0">
              <create_station name="DPMB01.Mission Station" race="argon" typename="SS_DOCK_A_TRADE" invincible="1">
                <sector sector="DPMB01.ArgonPrime"/>
              </create_station>
            </do_when>
            <do_otherwise>
              <set_invincible object="DPMB01.Mission Station" invincible="1"/>
            </do_otherwise>
          </do_choose>
        </do_when>
        <do_otherwise>
          <set_invincible object="DPMB01.Mission Station" invincible="1"/>
        </do_otherwise>
      </do_choose>
      <create_station name="DPMB01.KhaakStation" race="khaak" typename="SS_DOCK_K" invincible="1">
        <position x="-60km" y="-20km" z="-60km" max="5km"/>
        <sector sector="DPMB01.PresEnd"/>
        <equipment loadout="default"/>
      </create_station>
      <create_actor name="DPMB01.Mission Actor" character="{8350,1001}" race="argon" face="109" voice="114" object="DPMB01.Mission Station" location="crew"/>
      <ask_question name="DPMB01.Actor Q1" author="{actor.name@DPMB01.Mission Actor}" text="{8350,10001}"/>
    </do_all>
  </action>
</cue>
This is the main mission cue where we define the sectors/objects we're going to use in the mission.

Code: Select all

<condition>
  <check_all>
    <check_value value="{player.notoriety.argon.rank}" min="4"/>
    <match_sector sector="{player.sector}" race="argon" core="1"/>
  </check_all>
</condition>
The condition is the check we make to trigger the cue, in this case it's for Argon

Rank 4, and the player in an Argon core sector.

Code: Select all

<timing>
  <time exact="5s"/>
</timing>
timing is the delay between the condition being met and the

actions running.

Code: Select all

<load_text fileid="8350"/>
As we're using custom text we need to load our text file.

Code: Select all

<find_sector name="DPMB01.ArgonPrime" x="1" y="3"/>
<find_sector name="DPMB01.PresEnd" x="2" y="4"/>
<find_sector name="DPMB01.TheWall" x="2" y="3"/>
<find_sector name="DPMB01.HomeOfLight" x="1" y="4"/>
Defines the sectors we're going to use for the mission.

Code: Select all

<find_station name="DPMB01.Mission Station" class="equipment" race="argon">
  <sector sector="DPMB01.ArgonPrime"/>
</find_station>
Find a station for our mission actor, in this case the Equipment dock in Argon Prime.

We also need some contingencies in case the station doesn't exist:

Code: Select all

<do_choose>
  <do_when value="{object.exists@DPMB01.Mission Station}" exact="0">
    <find_station name="DPMB01.Mission Station" class="station" race="argon">
      <sector sector="DPMB01.ArgonPrime"/>
    </find_station>
    <do_choose>
      <do_when value="{object.exists@DPMB01.Mission Station}" exact="0">
        <create_station name="DPMB01.Mission Station" race="argon" typename="SS_DOCK_A_TRADE" invincible="1">
          <sector sector="DPMB01.ArgonPrime"/>
        </create_station>
      </do_when>
      <do_otherwise>
        <set_invincible object="DPMB01.Mission Station" invincible="1"/>
      </do_otherwise>
    </do_choose>
  </do_when>
  <do_otherwise>
    <set_invincible object="DPMB01.Mission Station" invincible="1"/>
  </do_otherwise>
</do_choose>
If it can't find the equipment dock, then it will look for any Argon station in Argon Prime, if it still can't find a station then it will create a trade dock for the mission to use. The station is set as invincible, so it doesn't disappear or get destroyed during the mission.

Code: Select all

<create_station name="DPMB01.KhaakStation" race="khaak" typename="SS_DOCK_K" invincible="1">
  <position x="-60km" y="-20km" z="-60km" max="5km"/>
  <sector sector="DPMB01.PresEnd"/>
  <equipment loadout="default"/>
</create_station>
Create our Kha'ak station to find and destroy, initially set as invincible so it doesn't get destroyed before we need it to be.

Code: Select all

<create_actor name="DPMB01.Mission Actor" character="{8350,1001}" race="argon" face="109" voice="114" 

object="DPMB01.Mission Station" location="crew"/>
Create our mission actor and add them as crew to our mission station.

Code: Select all

<ask_question name="DPMB01.Actor Q1" author="{actor.name@DPMB01.Mission Actor}" text="{8350,10001}"/>
Finally we ask our question (incoming message) that will return a value we can use to trigger our next cue.
Last edited by dillpickle on Fri, 26. Jul 13, 12:15, edited 2 times in total.

dillpickle
Posts: 1159
Joined: Mon, 3. Nov 08, 14:25
x3tc

Post by dillpickle » Fri, 26. Jul 13, 12:03

We've now set up our sectors, stations and actor so it's time to start the mission.

Code: Select all

<cue name="DPMB01 Start Mission">
  <condition>
    <question_answered question="DPMB01.Actor Q1" answer="Accept"/>
  </condition>
  <action>
    <do_all>
      <set_value name="DPMB01.Mission Step" exact="1"/>
      <create_offer actor="DPMB01.Mission Actor" conversation="DPMB01.Mission Actor Conv01" discipline="XXXXP"/>
      <create_briefing cue="DPMB01 Start Mission" story="{8350,1}" text="{8350,201}" title="{8350,101}" background="sector_argon_eq.tga">
        <mission level="easy"/>
        <objectives>
          <objective step="{value@DPMB01.Mission Step}">
            <talkto actor="DPMB01.Mission Actor"/>
          </objective>
        </objectives>
      </create_briefing>
      <set_objective cue="DPMB01 Start Mission" story="{8350,1}" text="{8350,201}" noabort="1" title="{8350,101}">
        <briefing cue="DPMB01 Start Mission" step="{value@DPMB01.Mission Step}"/>
        <mission level="easy"/>
        <talkto actor="DPMB01.Mission Actor"/>
      </set_objective>
      <set_value name="DPMB01.Mission Step" operation="add"/>
    </do_all>
  </action>
</cue>

Code: Select all

<condition>
  <question_answered question="DPMB01.Actor Q1" answer="Accept"/>
</condition>
The question we asked in the previous cue is the trigger for this one.

Code: Select all

<set_value name="DPMB01.Mission Step" exact="1"/>
I set a value for the mission steps, whilst it is perfectly acceptable to just number them 1, 2, 3 etc... as you go along, the variable gives you more flexibility for example:
  • If you have optional steps in a mission, then you can just add to the mission step number if they get used, in either case the mission briefing will display correctly.
  • When writing a plot you sometimes find you need to add or remove steps to the mission, the variable removes the need to manually change all the step numbers.
  • There is only a limited amount of space on the briefing screen, if the mission turns into a lengthy one with lots of steps, then we can simply not add 1 to the step value for some of the minor steps, just leaving us with the important steps of the mission.

Code: Select all

<create_offer actor="DPMB01.Mission Actor" conversation="DPMB01.Mission Actor Conv01" discipline="XXXXP"/>
Create our offer for the mission.

Disciplines:
  • XXXXP - Plot
  • TXXX - Trade
  • XFXX - Fight
  • XXBX - Build
  • XXXT - Think

Code: Select all

<create_briefing cue="DPMB01 Start Mission" story="{8350,1}" text="{8350,201}" title="{8350,101}" background="sector_argon_eq.tga">
  <mission level="easy"/>
  <objectives>
    <objective step="{value@DPMB01.Mission Step}">
      <talkto actor="DPMB01.Mission Actor"/>
    </objective>
  </objectives>
</create_briefing>
We now create the mission briefing, with the mission cue. Story, Text and Title layout positions can be seen below, backgrounds are found in director/images folder and are in *.tga format, you can also create your own backgrounds with photoshop/gimp etc... and are 683 x512 pixels in size.

[ external image ]

Code: Select all

<mission level="easy"/>
Straight forward, how difficult the mission is. Available options:
  • Trivial
  • Very Easy
  • Easy
  • Average
  • Hard
  • Very Hard
  • Impossible (Not typicallyused)
Other options that can be displayed on the briefing screen:

Code: Select all

<mission level="easy"/>
<reward money="" other=""/>
<timer duration=""/>
The reward for completing the mission either Money - '10,000 credits', or Other, usually a textid - 'Blueprints for a Heavy Centaur Prototype', or could be both - '10,000 Credits + Blueprints for a Heavy Centaur Prototype'.
Timer - how long is available to complete the mission, not commonly used in plot missions.

Code: Select all

<objectives>
  <objective step="{value@DPMB01.Mission Step}">
    <talkto actor="DPMB01.Mission Actor"/>
  </objective>
</objectives>
The objectives for the mission, starting with the step number, then the objective for the player to carry out, in this case we're directing the player to talk to our mission actor.

There are a number of predefined objectives:
  • deliver - Deliver ware
  • destroy - Destroy object
  • dockat - Dock at object
  • flyto - Fly to location or object
  • follow - Follow object
  • kill - Kill actor
  • talkto - Talk to actor
  • protect - Protect object
  • find - Find object
  • buy - Buy ware
  • sell - Sell ware
  • build - Build object
Depending on which is used there will be other options that need specifying - an actor to kill or talk to, a station to dock at or protect, a ship to follow or destroy etc...
For these objectives mission guidance will be set to the actor/object specified.

There is also the <custom/> objective, which can be used for any objective that doesn't fit into the predefined list - 'Board Yaki Orca', where you don't want mission guidance active - 'Find Pirates Secret Base', or where an object is destroyed whilst the mission briefing is still active - examples of some of these will be shown later.

You can also list multiple steps for the mission:

Code: Select all

<objectives>
  <objective step="{value@DPMB01.Mission Step}">
    <talkto actor="DPMB01.Mission Actor"/>
  </objective>
  <objective step="{value@DPMB01.Mission Step}+1">
    <flyto>
      <sector sector="DPMB01.PresEnd"/>
    </flyto>
  </objective>
  <objective step="{value@DPMB01.Mission Step}+2">
    <destroy object="DPMB01.KhaakStation"/>
  </objective>
</objectives>
This can be useful in cases such as delivering multiple wares, so the player can plan ahead without waiting for one part to finish before finding out what's needed next.

Next we have the objective:

Code: Select all

<set_objective cue="DPMB01 Start Mission" story="{8350,1}" text="{8350,201}" noabort="1" title="{8350,101}">
  <briefing cue="DPMB01 Start Mission" step="{value@DPMB01.Mission Step}"/>
  <mission level="easy"/>
  <talkto actor="DPMB01.Mission Actor"/>
</set_objective>
Mostly the same as the briefing, layout for titles etc... below. We do however have the 'noabort' which in this case is set to '1' as we don't want the player to accidentally remove it from they're active missions.

[ external image ]

Finally for this cue:

Code: Select all

<set_value name="DPMB01.Mission Step" operation="add"/>
We add 1 to the step value so the briefing screen shows correctly.

So now we have an active mission with our first briefing screen complete:

[ external image ]
Last edited by dillpickle on Sun, 28. Jul 13, 14:14, edited 3 times in total.

dillpickle
Posts: 1159
Joined: Mon, 3. Nov 08, 14:25
x3tc

Post by dillpickle » Fri, 26. Jul 13, 12:04

On to the next part of the mission:

Code: Select all

<cue name="DPMB01 Conv01 Done">
  <condition>
    <conversation_completed actor="DPMB01.Mission Actor" conversation="DPMB01.Mission Actor Conv01" answer="accept"/>
  </condition>
  <action>
    <do_all>
      <remove_offer actor="DPMB01.Mission Actor" conversation="DPMB01.Mission Actor Conv01" discipline="XXXXP"/>
      <create_briefing cue="DPMB01 Start Mission" title="{8350,101}" text="{8350,202}" background="station_khaak.tga">
        <mission level="easy"/>
        <objectives>
          <objective step="{value@DPMB01.Mission Step}">
            <flyto>
              <sector sector="DPMB01.PresEnd"/>
            </flyto>
          </objective>
        </objectives>
      </create_briefing>
      <set_objective cue="DPMB01 Start Mission" title="{8350,101}" text="{8350,202}">
        <briefing cue="DPMB01 Start Mission" step="{value@DPMB01.Mission Step}"/>
        <mission level="easy"/>
        <flyto>
          <sector sector="DPMB01.PresEnd"/>
        </flyto>
      </set_objective>
      <set_value name="DPMB01.Mission Step" operation="add"/>
    </do_all>
  </action>
</cue>

Code: Select all

<condition>
  <conversation_completed actor="DPMB01.Mission Actor" conversation="DPMB01.Mission Actor Conv01" answer="accept"/>
</condition>
We trigger this cue with the completion of the conversation set in <create_offer/>
Note:<conversation_completed/> always has to be a sub cue to the cue with the corresponding <create_offer/>, otherwise it won't work.

Code: Select all

<remove_offer actor="DPMB01.Mission Actor" conversation="DPMB01.Mission Actor Conv01" 

discipline="XXXXP"/>
Remove the offer and conversation from the mission actor.

The rest of the cue is basically the same as the previous one, dealing with updating the mission briefings and guidance.
Strictly speaking we don't need 'story', 'title', 'text' etc... as they are the same already defined for this briefing cue, we are however using a different background.

[ external image ]
Last edited by dillpickle on Fri, 26. Jul 13, 12:21, edited 2 times in total.

dillpickle
Posts: 1159
Joined: Mon, 3. Nov 08, 14:25
x3tc

Post by dillpickle » Fri, 26. Jul 13, 12:04

OK, so we are now on our way to President's End, and we have two options depending on how we decide to get there.
The first is if we fly via The Wall or Home of Light, where we're going to have a mercenary show up and offer to help.

Code: Select all

<cue name="DPMB01 Mercenary SetUp" delay="2s">
  <condition>
    <check_any>
      <check_value value="{player.sector}" exact="{sector@DPMB01.TheWall}"/>
      <check_value value="{player.sector}" exact="{sector@DPMB01.HomeOfLight}"/>
    </check_any>
  </condition>
  <timing>
    <time exact="10s"/>
  </timing>
  <action>
    <do_all>
      <create_ship name="DPMB01.MercShip" race="argon" typename="SS_SH_A_M3_PROTO" capturable="0" highlight="1" warp="1">
        <position object="{player.ship}" min="10km" max="15km"/>
        <sector sector="{player.sector}"/>
        <equipment loadout="maximum"/>
        <command command="idle"/>
        <pilot jobtextid="60006"/>
      </create_ship>
      <create_actor name="DPMB01.Merc" race="argon" object="DPMB01.MercShip" location="pilot" voiceflags="1"/>
      <create_offer actor="DPMB01.Merc" conversation="DPMB01.Merc Conv01" discipline="XXXXP"/>
      <create_briefing cue="DPMB01 Start Mission" title="{8350,101}">
        <mission level="easy"/>
        <objectives>
          <objective step="{value@DPMB01.Mission Step}">
            <talkto actor="DPMB01.Merc"/>
          </objective>
        </objectives>
      </create_briefing>
      <set_objective cue="DPMB01 Start Mission" title="{8350,101}">
        <briefing cue="DPMB01 Start Mission" step="{value@DPMB01.Mission Step}"/>
        <mission level="easy"/>
        <talkto actor="DPMB01.Merc"/>
      </set_objective>
      <set_value name="DPMB01.Mission Step" operation="add"/>
    </do_all>
  </action>
</cue>

Code: Select all

<condition>
  <check_any>
    <check_value value="{player.sector}" exact="{sector@DPMB01.TheWall}"/>
    <check_value value="{player.sector}" exact="{sector@DPMB01.HomeOfLight}"/>
  </check_any>
</condition>
Check to see if the player is either of the required sectors.

Code: Select all

<create_ship name="DPMB01.MercShip" race="argon" typename="SS_SH_A_M3_PROTO" capturable="0" highlight="1" warp="1">
  <position object="{player.ship}" min="10km" max="15km"/>
  <sector sector="{player.sector}"/>
  <equipment loadout="maximum"/>
  <command command="idle"/>
  <pilot jobtextid="60006"/>
</create_ship>
We create a ship for our mercenary to fly, I've flagged it as non capturable (won't bail), and highlighted so it appears at the top of the sector map.
jobtextid's come from pageid 1000 (301000, 351000, 381000), in this case 'Mercenary'.

Code: Select all

<create_actor name="DPMB01.Merc" race="argon" object="DPMB01.MercShip" location="pilot"/>
Create our mercenary - in this case I'm just using a random Argon pilot, and put them on the mercenary ship as pilot.

Code: Select all

<create_offer actor="DPMB01.Merc" conversation="DPMB01.Merc Conv01" discipline="XXXXP"/>
Create the offer conversation for the mercenary.
Note Regarding mission offers from pilots on ships:
Ships generally fall into two categories, small ships and big ships. Small ships only have a pilot - M5, M4, M3, TS, TP, so the actor can only be the pilot.
Big Ships - TL, M6, M7, M2, M1 have a pilot and crew, for these ships the mission actor needs to be set as crew for the conversation to work.
The two oddities are the M8 and TM, whilst technically small ships in the fact that they only have a pilot, they are classified as big ships (for the TM possibly as it can be boarded and/or dock ships, and in the case of the M8 possibly to prevent the player from launching 50 bombers from a single carrier (but I'm only guessing)). The problem is, as big ships, for the conversation to work the mission actor has to be on the crew, but as they don't have a crew, only a pilot, they can't be used for ship based mission offers.

So we talk to our mercenary and have the option of either accepting or declining their offer of help, first we'll look at dealing with accepting their help:

Code: Select all

<cue name="DPMB01 MercAccept">
  <condition>
    <conversation_completed actor="DPMB01.Merc" conversation="DPMB01.Merc Conv01" answer="accept"/>
  </condition>
  <action>
    <do_all>
      <remove_offer actor="DPMB01.Merc" conversation="DPMB01.Merc Conv01" discipline="XXXXP"/>
      <create_briefing cue="DPMB01 Start Mission" title="{8350,101}" text="{8350,202}" background="station_khaak.tga">
        <mission level="easy"/>
        <objectives>
          <objective step="{value@DPMB01.Mission Step}">
            <flyto>
              <sector sector="DPMB01.PresEnd"/>
            </flyto>
          </objective>
        </objectives>
      </create_briefing>
      <set_objective cue="DPMB01 Start Mission" title="{8350,101}" text="{8350,202}">
        <briefing cue="DPMB01 Start Mission" step="{value@DPMB01.Mission Step}"/>
        <mission level="easy"/>
        <flyto>
          <sector sector="DPMB01.PresEnd"/>
        </flyto>
      </set_objective>
      <set_value name="DPMB01.Mission Step" operation="add"/>
      <do_choose>
        <do_when value="{player.money}" min="{value@L2M024.SR2ReplaceTotal}">
          <reward_player>
            <money exact="-50000"/>
          </reward_player>
          <set_command object="DPMB01.MercShip" command="protect" commandobject="{player.ship}"/>
        </do_when>
        <do_otherwise>
          <play_text priority="99">
            <line pageid="13" textid="1254"/>
          </play_text>
          <clear_actor_location actor="DPMB01.Merc"/>
          <destroy_object object="DPMB01.MercShip" warp="1"/>
        </do_otherwise>
      </do_choose>
    </do_all>
  </action>
</cue>
First we remove the mission offer and update the mission briefing/objectives to 'Fly to President's End'.

Next we need to pay the mercenary.

Code: Select all

<do_choose>
  <do_when value="{player.money}" min="50000">
    <reward_player>
      <money exact="-50000"/>
    </reward_player>
    <set_command object="DPMB01.MercShip" command="protect" commandobject="{player.ship}"/>
    <set_value name="DPMB01.MercHired" exact="1"/>
  </do_when>
  <do_otherwise>
    <play_text priority="99">
      <line pageid="13" textid="1254"/>
    </play_text>
    <clear_actor_location actor="DPMB01.Merc"/>
    <destroy_object object="DPMB01.MercShip" warp="1"/>
  </do_otherwise>
</do_choose>
We check to make sure the player has enough money, if they do then the money is removed from the player's account and the mercenary is told to protect the player.
A value is set so we can reference it to check if the mercenary has been hired later in the mission.

Code: Select all

<set_value name="DPMB01.MercHired" exact="1"/>
If the player doesn't have the money, then the line "Insufficient Credits" plays and the ship is removed from the game.

Code: Select all

<clear_actor_location actor="DPMB01.Merc"/>
We use this so the actor can still be tracked by the mission, but isn't destroyed with their ship. If we didn't do this, then when the ship gets destroyed the mission briefing would display 'Talk to <invalid>'.

And if we refuse their offer:

Code: Select all

<cue name="DPMB01 MercRefuse">
  <condition>
    <conversation_completed actor="DPMB01.Merc" conversation="DPMB01.Merc Conv01" answer="refuse"/>
  </condition>
  <action>
    <do_all>
      <remove_offer actor="DPMB01.Merc" conversation="DPMB01.Merc Conv01" discipline="XXXXP"/>
      <create_briefing cue="DPMB01 Start Mission" title="{8350,101}" text="{8350,202}" background="station_khaak.tga">
        <mission level="easy"/>
        <objectives>
          <objective step="{value@DPMB01.Mission Step}">
            <flyto>
              <sector sector="DPMB01.PresEnd"/>
            </flyto>
          </objective>
        </objectives>
      </create_briefing>
      <set_objective cue="DPMB01 Start Mission" title="{8350,101}" text="{8350,202}">
        <briefing cue="DPMB01 Start Mission" step="{value@DPMB01.Mission Step}"/>
        <mission level="easy"/>
        <flyto>
          <sector sector="DPMB01.PresEnd"/>
        </flyto>
      </set_objective>
      <set_value name="DPMB01.Mission Step" operation="add"/>
      <clear_actor_location actor="DPMB01.Merc"/>
      <destroy_object object="DPMB01.MercShip" warp="1"/>
    </do_all>
  </action>
</cue>
Mostly the same as if accepted, except she ship and actor are simply removed.
Last edited by dillpickle on Fri, 26. Jul 13, 12:23, edited 3 times in total.

dillpickle
Posts: 1159
Joined: Mon, 3. Nov 08, 14:25
x3tc

Post by dillpickle » Fri, 26. Jul 13, 12:04

Entering President's End,

Code: Select all

<cue name="DPMB01 Enter PresEnd">
  <condition>
    <check_value value="{player.sector}" exact="{sector@DPMB01.PresEnd}"/>
  </condition>
  <action>
    <do_all>
      <cancel_cue cue="DPMB01 Mercenary SetUp"/>
      <do_if value="{value@DPMB01.MercHired}" exact="1" negate="1">
        <remove_offer actor="DPMB01.Merc" conversation="DPMB01.Merc Conv01" discipline="XXXXP"/>
        <clear_actor_location actor="DPMB01.Merc"/>
        <destroy_object object="DPMB01.MercShip" warp="1"/>
      </do_if>
      <create_briefing cue="DPMB01 Start Mission" title="{8350,101}">
        <mission level="average"/>
        <objectives>
          <objective step="{value@DPMB01.Mission Step}">
            <custom action="{35,2006}" text="{lookup.type.name@SS_DOCK_K}"/>
          </objective>
        </objectives>
      </create_briefing>
      <set_objective cue="DPMB01 Start Mission" title="{8350,101}">
        <briefing cue="DPMB01 Start Mission" step="{value@DPMB01.Mission Step}"/>
        <mission level="average"/>
        <custom action="{35,2006}" text="{lookup.type.name@SS_DOCK_K}" guidance="{sector@DPMB01.PresEnd}"/>
      </set_objective>
      <set_value name="DPMB01.Mission Step" operation="add"/>
    </do_all>
  </action>
</cue>
We check the player is in President's End:

Code: Select all

<condition>
  <check_value value="{player.sector}" exact="{sector@DPMB01.PresEnd}"/>
</condition>

Code: Select all

<cancel_cue cue="DPMB01 Mercenary SetUp"/>
Cancel the mercenary branch of the mission, it has now either run, or if not we don't want it triggering if the player jumped directly to President's End then doubles back into The Wall or Home of Light.

Code: Select all

<do_if value="{value@DPMB01.MercHired}" exact="1" negate="1">
  <remove_offer actor="DPMB01.Merc" conversation="DPMB01.Merc Conv01" discipline="XXXXP"/>
  <clear_actor_location actor="DPMB01.Merc"/>
  <destroy_object object="DPMB01.MercShip" warp="1"/>
</do_if>
Now we check to see if the mercenary was hired, using the value we set in the DPMB01 MercAccept cue, and if not hired then the offer, actor and ship are removed. This is done as there is a possibility that the player could fly via The Wall or Home of Light and then into President's End without talking to the mercenary, once in President's End the mission would update to 'Find Kha'ak Station', but the mercenary would still exist with their offer that wouldn't work as the mercenary's cue had been cancelled, so we tidy them away.

Code: Select all

<set_objective cue="DPMB01 Start Mission" title="{8350,101}">
  <briefing cue="DPMB01 Start Mission" step="{value@DPMB01.Mission Step}"/>
  <mission level="average"/>
  <custom action="{35,2006}" text="{lookup.type.name@SS_DOCK_K}" guidance="{sector@DPMB01.PresEnd}"/>
</set_objective>
This time we are using a custom objective instead of <find object="DPMB01.KhaakStation"/>

for two reasons:
First if we used <find object="DPMB01.KhaakStation"/> then the mission guidance would highlight the station and we want the player to actively look for it.
Secondly we are going to be destroying te station later in the mission, do using the actual object for the briefings would cause <invalid>s later on the briefing screen.
I've set the guidance to President's End so the mission will highlight the correct sector.
We could if we wanted remove mission guidance altogether at this stage, for this we'd use:

Code: Select all

<remove_objective cue="DPMB01 Start Mission"/>
Immediately before we <set_objective/>, if doing this then all Story, Title, Chapter etc... need to be set again in the <set_objective/>.

We now have a couple of different briefing screens depending on how we got there.
The first if we flew via The Wall or Home of Light and spoke to the mercenary, the second if we jumped directly to President's End:

[ external image ] [ external image ]
Last edited by dillpickle on Fri, 26. Jul 13, 12:25, edited 2 times in total.

dillpickle
Posts: 1159
Joined: Mon, 3. Nov 08, 14:25
x3tc

Post by dillpickle » Fri, 26. Jul 13, 12:05

The next step is to create some enemies near the Kha'ak station, for this we're going to be using the OBS (Opponent Balancing System) library, which will generate suitable enemies depending on the players combat rank.
Libraries can seem a little daunting at first, but once you get your head around them they are a great asset in mission building - why spend hours working out and coding something that already exists...

Code: Select all

<cue name="DPMB01 Create Enemies">
  <condition>
    <object_position object="DPMB01.KhaakStation" max="40km">
      <position object="{player.ship}"/>
      <sector sector="DPMB01.PresEnd"/>
    </object_position>
  </condition>
  <cues>
    <cue name="DPMB01 CS OBS Cancel">
      <condition>
        <cue_is_complete cue="DPMB01 Create Enemies"/>
      </condition>
      <cues>
        <cue ref="OBS">
          <params>
            <param name="OBS Cue" value="DPMB01"/>
            <param name="OBS Cancel Cue" value="DPMB01 CS OBS Cancel"/>
            <param name="OBSMissionRank" value="{player.fightrank.rank}" comment="A 0-30 scale preferably based on the players fight rank"/>
            <param name="OBSDifficultyRank" value="{lookup.level@average}" comment="A 1-8 scale of difficulty"/>
            <param name="OBS Fleet Group Name" value="Khaak Group"/>
            <param name="OBS Support Fleet Group Name" value="Khaak Group" comment="The group name where all support ships are saved too"/>
            <param name="OBSFleetRace" value="{lookup.race@khaak}"/>
            <param name="OBSFleetPilotsRace" value="{lookup.race@khaak}"/>
            <param name="OBSPosition" value="5km"/>
            <param name="OBSFleetPositionObject" value="{object@DPMB01.KhaakStation}"/>
            <param name="OBSFleetCapturable" value="1" comment="0/1 Sets if the created ships are capturable"/>
            <param name="OBSFleetRelation" value="-1"/>
            <param name="OBSFleetRaceLogic" value="0"/>
            <param name="OBSFleetCovered" value="0"/>
            <param name="OBSFleetHighlight" value="0"/>
            <param name="OBS Dock Support" value="1" comment="0/1 Sets if the created support ships are docked with their homebase"/>
            <param name="OBS Support Overflow" value="1" comment="0/1 Sets if additional support ships are created outside when the homebase is full"/>
          </params>
        </cue>
        <cue name="DPMB01 Khaak Group Commands">
          <condition>
            <cue_cancelled cue="DPMB01 CS OBS Cancel"/>
          </condition>
          <action>
            <set_group_command group="DPMB01.Khaak Group" command="killenemies"/>
          </action>
        </cue>
      </cues>
    </cue>
  </cues>
</cue>

Code: Select all

<condition>
  <object_position object="DPMB01.KhaakStation" max="40km">
    <position object="{player.ship}"/>
    <sector sector="DPMB01.PresEnd"/>
  </object_position>
</condition>
We're going to create the enemies when the player is 40km from the Kha'ak station.

We then run the OBS library, feeding it the various parameters we need, the race of the ememy, where we want them etc...

Code: Select all

<cue ref="OBS">
  <params>
    <param name="OBS Cue" value="DPMB01"/>
    <param name="OBS Cancel Cue" value="DPMB01 CS OBS Cancel"/>
    <param name="OBSMissionRank" value="{player.fightrank.rank}" comment="A 0-30 scale preferably based on the players fight rank"/>
    <param name="OBSDifficultyRank" value="{lookup.level@average}" comment="A 1-8 scale of difficulty"/>
    <param name="OBS Fleet Group Name" value="Khaak Group"/>
    <param name="OBS Support Fleet Group Name" value="Khaak Group" comment="The group name where all support ships are saved too"/>
    <param name="OBSFleetRace" value="{lookup.race@khaak}"/>
    <param name="OBSFleetPilotsRace" value="{lookup.race@khaak}"/>
    <param name="OBSPosition" value="5km"/>
    <param name="OBSFleetPositionObject" value="{object@DPMB01.KhaakStation}"/>
    <param name="OBSFleetCapturable" value="1" comment="0/1 Sets if the created ships are capturable"/>
    <param name="OBSFleetRelation" value="-1"/>
    <param name="OBSFleetRaceLogic" value="0"/>
    <param name="OBSFleetCovered" value="0"/>
    <param name="OBSFleetHighlight" value="0"/>
    <param name="OBS Dock Support" value="1" comment="0/1 Sets if the created support ships are docked with their homebase"/>
    <param name="OBS Support Overflow" value="1" comment="0/1 Sets if additional support ships are created outside when the homebase is full"/>
  </params>
</cue>
Which, for the most part are self explanatory.

Once the OBS has run, we can tell the enemies we created what to do:

Code: Select all

<cue name="DPMB01 Khaak Group Commands">
  <condition>
    <cue_cancelled cue="DPMB01 CS OBS Cancel"/>
  </condition>
  <action>
    <set_group_command group="DPMB01.Khaak Group" command="killenemies"/>
  </action>
</cue>
Once we get closer to the station well change the objective, and update the guidance to highlight the station:

Code: Select all

<cue name="DPMB01 In Range">
  <condition>
    <object_position object="DPMB01.KhaakStation" max="20km">
      <position object="{player.ship}"/>
      <sector sector="DPMB01.PresEnd"/>
    </object_position>
  </condition>
  <action>
    <do_all>
      <set_invincible object="DPMB01.KhaakStation" invincible="0"/>
      <create_briefing cue="DPMB01 Start Mission" title="{8350,101}">
        <mission level="hard"/>
        <objectives>
          <objective step="{value@DPMB01.Mission Step}">
            <custom action="{35,2004}" text="{lookup.type.name@SS_DOCK_K}" guidance="DPMB01.KhaakStation"/>
          </objective>
        </objectives>
      </create_briefing>
      <set_objective cue="DPMB01 Start Mission" title="{8350,101}">
        <briefing cue="DPMB01 Start Mission" step="{value@DPMB01.Mission Step}"/>
        <mission level="hard"/>
        <custom action="{35,2004}" text="[o]{lookup.type.name@SS_DOCK_K}[/o]" guidance="DPMB01.KhaakStation"/>
      </set_objective>
      <set_value name="DPMB01.Mission Step" operation="add"/>
    </do_all>
  </action>
</cue>

Code: Select all

<set_invincible object="DPMB01.KhaakStation" invincible="0"/>
Remember to set the Kha'ak stations invincibility so we can destroy it.

Code: Select all

<custom action="{35,2004}" text="[o]{lookup.type.name@SS_DOCK_K}[/o]" guidance="DPMB01.KhaakStation"/>
I've used colour tags for the objective text purely for cosmetic reasons, any of the default objective options automatically colour the objective text in orange - 'Fly To: President'sEnd', with a custom objective the text is white (as can be seen in the 'Find: Kha'ak Station' images).

After this stage our briefing looks thus:

[ external image ]
Last edited by dillpickle on Fri, 26. Jul 13, 12:28, edited 2 times in total.

dillpickle
Posts: 1159
Joined: Mon, 3. Nov 08, 14:25
x3tc

Post by dillpickle » Fri, 26. Jul 13, 12:05

Once the station has been destroyed we'll send the player back to the actor who offered the mission to report in and get their reward.

Code: Select all

<cue name="DPMB01 Station Destroyed">
  <condition>
    <object_exists object="DPMB01.KhaakStation" negate="1"/>
  </condition>
  <action>
    <do_all>
      <create_offer actor="DPMB01.Mission Actor" conversation="DPMB01.Mission Actor Conv02" discipline="XXXXP"/>
      <create_briefing cue="DPMB01 Start Mission" title="{8350,101}">
        <mission level="easy"/>
        <objectives>
          <objective step="{value@DPMB01.Mission Step}">
            <talkto actor="DPMB01.Mission Actor"/>
          </objective>
        </objectives>
      </create_briefing>
      <set_objective cue="DPMB01 Start Mission" title="{8350,101}">
        <briefing cue="DPMB01 Start Mission" step="{value@DPMB01.Mission Step}"/>
        <mission level="easy"/>
        <talkto actor="DPMB01.Mission Actor"/>
      </set_objective>
      <create_ship name="DPMB01.Reward" race="argon" dockobject="DPMB01.Mission Station" typename="SS_SH_A_M6M_PROTO">
        <equipment loadout="maximum"/>
      </create_ship>
    </do_all>
  </action>
</cue>

Code: Select all

<condition>
  <object_exists object="DPMB01.KhaakStation" negate="1"/>
</condition>
Check that the Kha'ak station no longer exists.

We create our offer conversation and update or mission briefing, we also create our reward:

Code: Select all

<create_ship name="DPMB01.Reward" race="argon" dockobject="DPMB01.Mission Station" typename="SS_SH_A_M6M_PROTO">
  <equipment loadout="maximum"/>
</create_ship>
Our final briefing screen, the first if the mission ran smoothly, the second illustrates the error we get if we used:

Code: Select all

<destroy object="DPMB01.KhaakStation"/>
Instead of:

Code: Select all

<custom action="{35,2004}" text="{lookup.type.name@SS_DOCK_K}" guidance="DPMB01.KhaakStation"/>
for the briefing.

[ external image ] [ external image ]

Now it's time to wrap the mission up and clean it up:

Code: Select all

<cue name="DPMB01 Mission End">
  <condition>
    <conversation_completed actor="DPMB01.Mission Actor" conversation="DPMB01.Mission Actor Conv02" answer="accept"/>
  </condition>
  <action>
    <do_all>
      <remove_offer actor="DPMB01.Mission Actor" conversation="DPMB01.Mission Actor Conv02" discipline="XXXXP"/>
      <set_owner object="DPMB01.Reward" race="player"/>
      <remove_object object="DPMB01.Reward"/>
      <remove_briefing cue="DPMB01 Start Mission"/>
      <remove_objective cue="DPMB01 Start Mission" status="complete"/>
      <destroy_actor actor="DPMB01.Mission Actor"/>
      <destroy_actor actor="DPMB01.Merc"/>
      <destroy_object object="DPMB01.MercShip" warp="1"/>
      <destroy_group group="DPMB01.Khaak Group" warp="1"/>
      <set_invincible object="DPMB01.Mission Station" invincible="0"/>
      <set_value name="My Plot Progress" exact="1"/>
      <cancel_cue cue="DPMB01"/>
    </do_all>
  </action>
</cue>

Code: Select all

<condition>
  <conversation_completed actor="DPMB01.Mission Actor" conversation="DPMB01.Mission Actor Conv02" answer="accept"/>
</condition>
Our conversation being completed is the trigger for this cue.

Code: Select all

<remove_offer actor="DPMB01.Mission Actor" conversation="DPMB01.Mission Actor Conv02" discipline="XXXXP"/>
Remove the offer conversation.

Code: Select all

<set_owner object="DPMB01.Reward" race="player"/>
<remove_object object="DPMB01.Reward"/>
We turn ownership of the reward ship over to the player, <remove_object object="DPMB01.Reward"/> this just removes the reward ship from being tracked by the MD.

Code: Select all

<remove_briefing cue="DPMB01 Start Mission"/>
<remove_objective cue="DPMB01 Start Mission" status="complete"/>
Remove the briefing and objective, marking it as completed.

Code: Select all

<destroy_actor actor="DPMB01.Mission Actor"/>
<destroy_actor actor="DPMB01.Merc"/>
We can now destroy our actors.

Code: Select all

<destroy_object object="DPMB01.MercShip" warp="1"/>
Ge rid of the mercenary ship.

Code: Select all

<destroy_group group="DPMB01.Khaak Group" warp="1"/>
Destroy any left over Kha'ak ships from our mission.

Code: Select all

<set_invincible object="DPMB01.Mission Station" invincible="0"/>
Reset he invincibility of our mission offer station.

Code: Select all

<set_value name="My Plot Progress" exact="1"/>
A value is set to tell us the plot is complete, we can use this if we want to continue this plot, or start

another that is dependant on this one being completed first.

Code: Select all

<cancel_cue cue="DPMB01"/>
Finally the cue is cancelled.
Last edited by dillpickle on Sun, 28. Jul 13, 19:27, edited 4 times in total.

dillpickle
Posts: 1159
Joined: Mon, 3. Nov 08, 14:25
x3tc

Post by dillpickle » Fri, 26. Jul 13, 12:05

Reserved 1
Last edited by dillpickle on Fri, 26. Jul 13, 12:12, edited 1 time in total.

dillpickle
Posts: 1159
Joined: Mon, 3. Nov 08, 14:25
x3tc

Post by dillpickle » Fri, 26. Jul 13, 12:05

Reserved 2
Last edited by dillpickle on Fri, 26. Jul 13, 12:12, edited 1 time in total.

dillpickle
Posts: 1159
Joined: Mon, 3. Nov 08, 14:25
x3tc

Post by dillpickle » Fri, 26. Jul 13, 12:06

Reserved 3

User avatar
X2-Illuminatus
Moderator (Deutsch)
Moderator (Deutsch)
Posts: 24950
Joined: Sun, 2. Apr 06, 16:38
x4

Post by X2-Illuminatus » Fri, 26. Jul 13, 12:23

Great! Thank you very much. :) I linked your tutorial in the Tutorials and Resources thread, so it doesn't get lost.
Nun verfügbar! X3: Farnham's Legacy - Ein neues Kapitel für einen alten Favoriten

Die komplette X-Roman-Reihe jetzt als Kindle E-Books! (Farnhams Legende, Nopileos, X3: Yoshiko, X3: Hüter der Tore, X3: Wächter der Erde)

Neuauflage der fünf X-Romane als Taschenbuch

The official X-novels Farnham's Legend, Nopileos, X3: Yoshiko as Kindle e-books!

User avatar
jack775544
Posts: 1277
Joined: Tue, 13. Dec 11, 08:27
x4

Post by jack775544 » Fri, 26. Jul 13, 12:46

Sooo much code.
Thanks for this dillpickle, I'll make sure to have a deeper look when I decide to experiment with MD again.
1940s - Various "computers" are "programmed" using direct wiring and switches. Engineers do this in order to avoid the tabs vs spaces debate.

biohazard15
Posts: 193
Joined: Tue, 1. May 07, 20:40
x3tc

Post by biohazard15 » Fri, 26. Jul 13, 14:50

Thank you for great guide!

User avatar
Juggernaut93
Posts: 2897
Joined: Sun, 17. Jul 11, 21:03
x4

Post by Juggernaut93 » Sun, 28. Jul 13, 12:48

Oh, thank you very much! :D

EDIT:
dillpickle wrote: Disciplines:
  • XXXXP - Plot
  • TXXX - Trade
  • XFXX - Fight
  • XXBX - Build
  • XXXT - Trade
The last one should be "Think" :)

dillpickle
Posts: 1159
Joined: Mon, 3. Nov 08, 14:25
x3tc

Post by dillpickle » Sun, 28. Jul 13, 15:31

Juggernaut93 wrote: The last one should be "Think" :)
Thanks, fixed.... at least someone made it pat the first post... :wink:

User avatar
Juggernaut93
Posts: 2897
Joined: Sun, 17. Jul 11, 21:03
x4

Post by Juggernaut93 » Sun, 28. Jul 13, 18:45

Am I missing something or the mercenary ship will continue to protect the player ship even after the mission is finished? :gruebel:

dillpickle
Posts: 1159
Joined: Mon, 3. Nov 08, 14:25
x3tc

Post by dillpickle » Sun, 28. Jul 13, 19:29

Juggernaut93 wrote:Am I missing something or the mercenary ship will continue to protect the player ship even after the mission is finished? :gruebel:
No, you weren't missing something- I'd removed the actor, but not his ship, have now fixed it...

akruppa
Posts: 31
Joined: Fri, 25. Oct 13, 13:57
x3ap

Re: [Guide] Mission Director Basics - Writing Your First Mission

Post by akruppa » Sat, 18. Jan 14, 02:41

dillpickle wrote:The 'Mission Director conversations.xml' in the 't' folder only contains the three specific conversations for this mission to make them easier to reference, in order for them to work in game you will need to extract the latest 'conversations.xml' from the relevant games CAT/DATS and add these three conversations to 'conversations.xml' in the 't' folder.
I'm experimenting with MD under X3AP and found that conversations are not taken into account if they are in their own .xml file in addon/t/. So users officially have to extract conversations.xml from the .cat/.dat, and manually edit in the new conversations from community-written missions? It seems to me that this very much runs counter to the purpose of the MD, allowing the community to write and share missions more easily...

Shush
Posts: 244
Joined: Sat, 6. Dec 03, 16:21
x4

Re: [Guide] Mission Director Basics - Writing Your First Mission

Post by Shush » Sat, 18. Jan 14, 03:29

akruppa wrote:I'm experimenting with MD under X3AP and found that conversations are not taken into account if they are in their own .xml file in addon/t/. So users officially have to extract conversations.xml from the .cat/.dat, and manually edit in the new conversations from community-written missions? It seems to me that this very much runs counter to the purpose of the MD, allowing the community to write and share missions more easily...
For the majority of scenarios users don't have to do any editing of the conversations.xml file, you can do it for them. i.e. extract it out of the last .cat/.dat to contain a conversations.xml and insert your specific conversations between the last </conversation> and last </conversations>. Then give that conversations.xml file to your user base and they can put it in the appropriate place. Obviously there are a couple of caveats:
  • - You need to extract the correct conversations.xml file for TC or AP and from the appropriate .cat/.dat files.
    - You need to rebuild this conversations file whenever a new patch/addon whatever appears for X3, (unlikely to be happening frequently if at all).
    - Your users need to do the inserting of your conversations themselves if they are trying to get your stuff working with a mod that has it's own conversations.xml file.
I do all of this in my LIFE mod and it works fine.

Post Reply

Return to “X³: Terran Conflict / Albion Prelude - Scripts and Modding”