Artemis Tutorials

Events – Artemis Mission Scripting 101 – Part Two

This is a three part tutorial written for Artemis 1.702

The Artemis Spaceship Bridge Simulator opens the door to a new kind of story telling. Breaking the barrier between writer and reader, we have a player crew that explores the opportunities presented in an interactive storyline.
In our first tutorial we laid out an interesting playfield for our characters with our protagonist, the SS AJAX, pitting our fearless crew against three Kralian antagonists.
The playfield also has a several passive characters in the form of a space station, pod of space whales and even an anomaly. We also have another antagonist, a space monster, though the monster lacks motivation.

For this tutorial we're going to create three mission scripts, each a simple example of an important building block that can be strung together for more ambitious missions.

All story telling is about characters, events and timing. Characters move through the events in a certain structure, one thing happening after another, sometimes the end is told first, sometime we end in the middle. With Artemis each mission has the chance of being told in any order.

This part of the tutorial will be about setting up events.

The Artemis simulator uses “events” to keep track of everything. Each event is a block of actions that take place in order once the mission starts. Strictly speaking all of the events are read immediately and, unless prevented, all actions would happen immediately also.

In order to set up a compelling adventure we need something for a storyline. It doesn’t need to be lengthy or complicated, but you’ll usually want to be more than “go there, shoot that”. Artemis already has a competent “Invasion” mode if you just want to fly around blowing up aliens.

For the purposes of this tutorial we are going to borrow from a famous scenario that is short, to the point and always ends with a bang.

As a reminder when creating a new mission you need to create a new folder in the /Program Files/Artemis/dat/Missions folder. The new folder name must start with MISS_, contain no spaces and should give a clear, but abbreviated, idea about the mission name. As an example the "Module 3 bases" folder is called "MISS_Module_3_bases". Inside the folder you only need one file, the XML mission that must be similarly named, but end with dot xml, as opposed to dot doc or dot txt.
There are many text editors that you can choose from, I personally prefer BBEdit, and the Artemis community has the fantastic Artemis Mission Editor.

Example:
Folder: MISS_AJAX_tutorial_2
XML File: MISS_AJAX_tutorial_2.xml
Download this tutorial mission as zip file.

We still recommend that you don't get in the habit of editing the mission files while they are in the Mission folder itself, instead work on the files somewhere else and then copy them into the Mission folder for testing. This is just good workflow habit.

Artemis missions are structured as XML. In this case we open and close with an "event" tag.

<!---this will be our first event -->
<event>

</event>


Now we have an empty event waiting to be filled with actions. The “event” tag has no properties, it is only a wrapper.

Artemis Markup Language has a healthy number of actions we can choose from. You can refer to the “mission-file-docs.txt” that comes with your install of Artemis for the comprehensive list or the Artemis wiki. Actions are broken down into commands and conditions. Commands tell the simulator to do things; condition statements define circumstances under which actions will be taken. Unlike many other scripting languages condition statements do not need to be closed or have end tags. While convenient for beginners, inevitably this can cause confusion when you have nested conditions. Just keep in mind that each condition is applied to everything after that until the closing “event” tag.

We first need to set up our playfield and place our characters at the start of our mission. We want a nice opening title, our player ship, what resources it should have at start, a friendly space station and our neutral ship. We want to keep our neutral ship from wandering off, so clear the AI stack and tell it to stay in one place. We also don’t want a mischievous Comm officer accidentally ordering our “crippled” transport to head anywhere.
After that we’ll drop in a nebula for color, a minefield to give our Helm something to think about and an asteroid field for fun.

<mission version="1">
<!--- COMMENT: this is where we specify what appears when the mission first starts -->
<start>
<!--- have a nice big mission title appear on the main screen -->
<big_message title="AJAX tutorial 2" subtitle1="written by Michael Sweeney"/>

<!--- add the player ship named "AJAX" to the exact center -->
<!--- this is just a training cruise, after all... -->
<create type ="player" x="50000" y="0" z="50000" name="SS AJAX"/>
<set_object_property name="SS AJAX" property="countNuke" value="0"/>
<set_object_property name="SS AJAX" property="countHoming" value="2"/>
<set_object_property name="SS AJAX" property="countMine" value="0"/>
<set_object_property name="SS AJAX" property="countECM" value="2"/>

<!--- add space station "OUTPOST ALPHA" to the center right -->
<create type ="station" raceKeys="friendly" hullKeys="base" x="25000" y="0" z="50000" name="OUTPOST ALPHA"/>

<!--- add a friendly spaceship to the center left -->
<create type ="neutral" raceKeys="friendly" hullKeys="cargo" x="75000" y="0" z="50000" name="TR80" angle="0"/>
<set_object_property name="TR80" property="willAcceptCommsOrders" value="0" />
<clear_ai name="TR80"/>
<add_ai name="TR80" type="DIR_THROTTLE" value1="0" value2="0" />

<!--- add a nebula to the top left -->
<create type ="nebulas" count="10" startX="75000" startY="0" startZ="25000" radius ="5000" startAngle="0" endAngle="360" randomRange="2000" randomSeed="1"/>

<!--- add a mine field that separates the bad guys from our player -->
<create type ="mines" count="20" startX="65000" startY="0" startZ="25000" endX="65000" endY="0" endZ="75000"/>

<!--- add an asteroid field that separates the our player from the station -->
<create type ="asteroids" count="20" startX="35000" startY="0" startZ="25000" endX="35000" endY="0" endZ="75000"/>

</start>
<!-- ******************************************************************************************** -->
<!-- events go here -->

</mission>


With our playfield defined we can start thinking about our events.

We’ll start small, setting up a simple event that will be triggered when the player ship moves outside a sphere we’ll place around them. Since we can’t actually predict what the player crew will do, we can at least hope they’ll start moving in some direction away from where they started. In order to pique the interest of our player crew, we’ll have the Comm officer receive an urgent message for help. We can’t be certain they’ll have an attentive Comm station, so we’ll also create a pop up on the main viewer.

<!--- our first event, get the player crews attention -->
<event>
<if_variable name="distressSignal" comparator="!=" value="1"/>
<if_outside_sphere name="SS AJAX" centerX="50000" centerY="0" centerZ="50000" radius ="2000"/>
<incoming_comms_text from="TR80">
Imperative!^
This is the Transport 80 ARGUS! 19 light years out of Altair Six!^
We have struck a gravitic mine and have lost all power!^
Our hull is penetrated and we have sustained many casualties!^
Our life support system is failing!
</incoming_comms_text>
<warning_popup_message message="ALERT! Distress signal from TR80!" consoles="M"/>
<set_variable name="distressSignal" value="1"/>
</event>


Obviously, we hope the implied urgency of the distress signal will motivate the player crew to move in the direction of TR80. Pay close attention to the two conditions that we have set for our command to present the comm message and warning pop up.
First we check if a variable has a specific value, is “distressSignal” set to 1? If it isn’t the next condition is checked, is the object “SS AJAX” outside a specific sphere? If both of these conditions are met then our Comm station gets the distress signal and the main screen gets the pop up warning. We also set the variable “distressSignal” to 1, so the two messages will only be presented once. Otherwise the messages would be shown over and over as long as the object “SS AJAX” was outside the box!

When the mission started the neutral cargo ship was placed on the left center of the minefield. We gave it a direction of 0 and throttle of 0, so it wouldn’t be moving.

We hope the player crew will move in the direction of the distressed transport, so we’ll add another box just in front of the mine field that divides the playfield. This box will trigger another distress call, naming the player ship specifically, but also popping up a warning that they are approaching the Kralien frontier.

<!--- our second event, increase the drama! -->
<event>
<if_variable name="warningZone1" comparator="!=" value="1"/>
<if_inside_box name="SS AJAX" leastX="65000" leastZ="0" mostX="65100" mostZ="100000"/>
<incoming_comms_text from="TR80">
Terran Cruiser?!^
Can you assist us?
</incoming_comms_text>
<warning_popup_message message="WARNING! Kralien Neutral Zone Ahead!" consoles="M"/>
<set_variable name="warningZone1" value="1"/>
</event>


A second box that surrounds the mine field itself will issue yet another pop up that makes clear the player ship has moved into Kralien space. We use a third box to increase the tension!

<!--- our third event, increase the drama! -->
<event>
<if_variable name="warningZone2" comparator="!=" value="1"/>
<if_inside_box name="SS AJAX" leastX="65000" leastZ="0" mostX="65100" mostZ="100000"/>
<incoming_comms_text from="TR80">
Our hull is penetrated!^
Life support failing...
</incoming_comms_text>
<warning_popup_message message="ALERT! Entering Kralien Neutral Zone!" consoles="M"/>
<set_variable name="warningZone2" value="1"/>
</event>

<!--- our fourth event, increase the drama! -->
<event>
<if_variable name="warningZone3" comparator="!=" value="1"/>
<if_inside_box name="SS AJAX" leastX="65100" leastZ="0" mostX="65200" mostZ="100000"/>
<warning_popup_message message="REPORT: You are now in violation of Kralien Treaty." consoles="M"/>
<set_variable name="warningZone3" value="1"/>
</event>


When the player ship gets within a certain distance of TR80 another event will trigger that makes the cargo ship apparently disappear. Three Kralien enemy vessels will appear nearby and begin attacking the player ship!

<!--- our fifth event, what happens when we get in range of TR80? ;) -->
<event>
<if_variable name="distressSignal2" comparator="!=" value="1"/>
<if_distance name1="SS AJAX" name2="TR80" comparator="<" value="940"/>
<incoming_comms_text from="TR80">
Terran Cruiser?!^
Are you there?
</incoming_comms_text>
<warning_popup_message message="ALERT! TR80 SIGNAL LOST!" consoles="M"/>
<warning_popup_message message="ALERT! TR80 SIGNAL LOST!" consoles="C"/>

<!--- remove neutral ship -->
<destroy name="TR80"/>

<warning_popup_message message="ALERT! ENEMY SHIPS DETECTED!" consoles="M"/>
<!--- mixing up our franchise references a little? -->
<warning_popup_message message="IT'S A TRAP!" consoles="M"/>

<!--- replace neutral ship with enemy ship -->
<create type ="enemy" raceKeys="Kralien enemy" name="KR01" hullKeys="large" x="75000" y="0" z="50000" angle="0" fleetnumber="1"/>
<clear_ai name="KR01"/>

<!--- add two enemy ships near AJAX -->
<create type ="enemy" raceKeys="Kralien enemy" name="KR02" hullKeys="medium" x="75000" y="0" z="50000" angle="90" fleetnumber="1"/>
<set_relative_position name1="SS AJAX" name2="KR02" distance="940" angle="165"/>
<clear_ai name="KR02"/>

<create type ="enemy" raceKeys="Kralien enemy" name="KR03" hullKeys="medium" x="75000" y="0" z="50100" angle="90" fleetnumber="1"/>
<set_relative_position name1="SS AJAX" name2="KR03" distance="940" angle="0"/>
<clear_ai name="KR03"/>

<!-- exagerate damage to player ship for drama -->
<set_object_property name="SS AJAX" property="shieldStateFront" value="26"/>
<set_object_property name="SS AJAX" property="shieldStateBack" value="19"/>
<set_object_property name="SS AJAX" property="totalCoolant" value="5"/>
<set_object_property name="SS AJAX" property="energy" value="272"/>
<warning_popup_message message="ALERT: DIRECT HIT!" consoles="M"/>
<warning_popup_message message="ALERT: SHIELDS FAILING!" consoles="M"/>

<!--- kill off damage control teams so ship cannot repair -->
<set_damcon_members team_index="0" value="0"/>
<set_damcon_members team_index="1" value="0"/>
<set_damcon_members team_index="2" value="0"/>
<set_damcon_members team_index="3" value="0"/>

<warning_popup_message message="ALERT: DAMCOM TEAMS KILLED!" consoles="M"/>

<!-- set difficulty level to legendary ;) -->
<set_difficulty_level value="10"/>

<set_variable name="distressSignal2" value="1"/>
</event>


We use several new tags here to effect the player ship in ways that should cause great concern. Obviously we want our trap to be alarming, so we “destroy” the neutral transport and replace it with an enemy ship, making it appear as if it was all a trick. We can be fairly certain this enemy ship will be close to the player ship because it is inside the sphere that triggers the action, but we can’t be certain how the player would actually approach the transport. It is very easy for an inexperienced Helm to over shoot, so we want to be certain our other bad guys appear alarmingly close to our player ship.
We can accomplish this by using the “set_relative_position” tag for our two new bad guys. This allows us to place them within a certain range of our player.

Since we’d like to make sure the players are alarmed and freaked out, we’re going to exaggerate the damage they’d get when the enemy ships appear and start shooting at them.
Using the “set_object_property” tag we reduce front/back shields and take energy levels low.
We’re also going to make any damage taken permanent by setting all Damage Control teams to zero.
Any reasonable cadet would determine that a tactical retreat would be the best move. As is often true in real life, we will set it so that only makes things worse.
If the player ship moves out of range of the enemy vessels damage will be taken to their energy levels, warp drive, shields and maneuvering. We started the player ship with no nukes and limited armaments, so a positive outcome is unlikely.

<!--- our sixth event, what happens when we try to escape? -->
<event>
<if_variable name="distressSignal2" comparator="=" value="1"/>
<if_variable name="noEscape" comparator="!=" value="1"/>
<if_outside_sphere name="SS AJAX" centerX="75000" centerY="0" centerZ="50000" radius ="945"/>
<set_variable name="noEscape" value="1"/>

<!-- leave just enough power to limp away -->
<set_object_property name="SS AJAX" property="energy" value="47"/>

<warning_popup_message message="ALERT: DIRECT HIT!" consoles="M"/>
<warning_popup_message message="ALERT: WARP DAMAGED!" consoles="M"/>
<warning_popup_message message="ALERT: IMPULSE DAMAGED!" consoles="M"/>
<warning_popup_message message="ALERT: SHIELDS DAMAGED!" consoles="M"/>

<!--- set damage to player ship for unwinnable odds -->
<set_player_grid_damage systemType="systemDamageTactical" countFrom="left" index="0" value="1"/>
<set_player_grid_damage systemType="systemDamageTactical" countFrom="left" index="1" value="1"/>
<set_player_grid_damage systemType="systemDamageTactical" countFrom="left" index="2" value="1"/>
<set_player_grid_damage systemType="systemDamageTactical" countFrom="left" index="3" value="1"/>
<set_player_grid_damage systemType="systemDamageImpulse" countFrom="left" index="0" value="1"/>
<set_player_grid_damage systemType="systemDamageImpulse" countFrom="left" index="1" value="1"/>
<set_player_grid_damage systemType="systemDamageImpulse" countFrom="left" index="2" value="1"/>
<set_player_grid_damage systemType="systemDamageImpulse" countFrom="left" index="3" value="1"/>
<set_player_grid_damage systemType="systemWarp" countFrom="left" index="0" value="1"/>
<set_player_grid_damage systemType="systemWarp" countFrom="left" index="1" value="1"/>
<set_player_grid_damage systemType="systemWarp" countFrom="left" index="2" value="1"/>
<set_player_grid_damage systemType="systemWarp" countFrom="left" index="3" value="1"/>
<set_player_grid_damage systemType="systemTurning" countFrom="left" index="0" value="1"/>
<set_object_property name="SS AJAX" property="shieldStateFront" value="13"/>
<set_object_property name="SS AJAX" property="shieldStateBack" value="8"/>
<set_object_property name="SS AJAX" property="totalCoolant" value="5"/>

</event>


We use the “set_player_grid_damage” to force those parts of the ship to be damaged. You can never trust a bad guy to get the lucky shot you need for good drama.

Even with all of this damage, if a crafty Helm were to move out of firing range of our three enemy ships the shields would start recharging. Once the shields are up enough, the ship will regenerate enough power to put up a fight and they could still defeat the bad guys.
We can’t let that happen, now can we?

<!--- our seventh event, keep shields failing or they will recharge on thir own -->
<event>
<if_variable name="distressSignal2" comparator="=" value="1"/>
<if_outside_sphere name="SS AJAX" centerX="75000" centerY="0" centerZ="50000" radius ="150"/>

<if_object_property name1="SS AJAX" name2="shieldStateFront" comparator=">=" value="33"/>
<set_object_property name="SS AJAX" property="shieldStateFront" value="0"/>

<if_object_property name1="SS AJAX" name2="shieldStateBack" comparator=">=" value="27"/>
<set_object_property name="SS AJAX" property="shieldStateBack" value="0"/>

</event>


This will ensure that the shields stay down; the player ship is battered to bits and blown to pieces.

In order to cover our bets about player crew behavior, we’ll add another large event sphere around the space station that will repeat the distress signal!

<!--- our eighth event, just in case the player visits the space station and ignores the distress signal -->
<event>
<if_variable name="distressSignal2" comparator="!=" value="1"/>
<if_variable name="admonishDistress" comparator="!=" value="1"/>
<if_inside_sphere name="SS AJAX" centerX="25000" centerY="0" centerZ="50000" radius ="10500"/>

<incoming_comms_text from="OUTPOST ALPHA">
AJAX?^
We received a distress signal?^
Proceed to help vessel in distress!
</incoming_comms_text>
<warning_popup_message message="ORDERS: Proceed to help TR80!" consoles="M"/>

<set_variable name="admonishDistress" value="1"/>
</event>


We’re also going to need a kill switch once the player ship runs out of power since a zombie ship isn’t fun to play.

<!--- our nineth event, if player runs out of energy, end the game -->
<event>
<if_variable name="distressSignal2" comparator="=" value="1"/>
<if_variable name="gameOver" comparator="!=" value="1"/>
<if_object_property name1="SS AJAX" name2="energy" comparator="<=" value="3"/>
<big_message title="Prayer, Mr. Saavik..." subtitle1="Klingons don't take prisoners."/>
<end_mission/>
<set_variable name="gameOver" value="1"/>
</event>


After all that our player should have a better understanding of life as well as death.

However, as any good Captain knows, there are always… possibilities.
I’ll leave the next two events as an exercise for your imagination.

<!--- our tenth event, I don't believe in the no-win scenario. ;) -->
<event>
<if_variable name="distressSignal2" comparator="=" value="1"/>
<if_variable name="anomalyDrop" comparator="!=" value="1"/>
<if_inside_sphere name="SS AJAX" centerX="75000" centerY="0" centerZ="50000" radius ="100"/>

<!--- add an anomaly near the player -->
<create type="anomaly" x="75000" y="0" z="75000" angle="0" name="ANOMALY"/>
<set_relative_position name1="SS AJAX" name2="ANOMALY" distance="100" angle="165"/>
<set_object_property name="SS AJAX" property="shieldStateFront" value="33"/>
<set_object_property name="SS AJAX" property="shieldStateBack" value="33"/>
<warning_popup_message message="ANOMALY DETECTED!" consoles="M"/>
<set_variable name="anomalyDrop" value="1"/>
</event>

<!-- our eleventh event, must get that simulator checked? ;) -->
<event>
<if_variable name="distressSignal2" comparator="=" value="1"/>
<if_fleet_count fleetnumber="1" comparator="<=" value="0"/>
<big_message title="Unpossible! ..." subtitle1="Enjoy your smirk."/>
<end_mission/>
</event>


There we have a fun scenario that should give an unsuspecting crew a run for their money, and let a captain with a flair for reprogramming surprise everyone.

Writing a mission is more than just stringing events together and making the situation worse for the players! While I was writing the mission scenario above I had to rethink everything after they got in range of TR80 5 or 6 times and tweak all the settings over and over! You don’t want it to be to easy or to hard, but Goldilocks drama means play testing your missions over and over.

This took three days from start to finish to write into a reasonable homage.
Download the tutorial mission folder.

Safe journey!

Comments or suggestions? Please respond to the ARTEMIS FORUM THREAD.

Posted: Monday, April 29, 2013

Past Articles - Artemis Tutorials:
Timing – Artemis Mission Scripting 101 – Part Three - Thursday, May 30, 2013
Events – Artemis Mission Scripting 101 – Part Two - Monday, April 29, 2013
Characters - Artemis Mission Scripting 101 - Part One - Monday, April 22, 2013
What is Artemis? - Friday, April 19, 2013

Categories: Artemis Tutorials | Artemis Missions | 3D Printer |