Missions 101

This is a moderated forum that collects tutorials, guides, and references for creating Transcendence extensions and scripts.
Post Reply
User avatar
Xephyr
Militia Captain
Militia Captain
Posts: 857
Joined: Fri Dec 14, 2007 1:52 am
Location: Orion Arm, Milky Way
Contact:

Missions are one of the hardest things to mod in. They're hard to think up, hard to code, hard to test, etc. so we don't see a whole lot of them. Here I'll try to demystify some of it.

Firstly, if you want a detailed explanation of <MissionType> elements, check out the page on the wiki. It's not quite up to date, but it has a lot of it there. Also look at the comments in RPGMissions.xml, for both regular missions and the delivery mission screen.

To assign a mission to a player through a dockscreen, you should use rpgMissionAssignment in an action element.

Code: Select all

						<Action name="Mission Board" key="B" default="1">
								(rpgMissionAssignment {
									missionCriteria: (cat "n +exampleMission;")
									noMissionTextID: 'descNoMissions
									maxPerStation: 1
									})
						</Action>
This will select a mission with the "exampleMission" attribute. You can also specify a mission by unid, I think, through the usual criteria format. Note that maxPerStation isn't a required field. You can examine this closer in RPGCode.xml.

Now, this is one of the simplest missions I've made. The player is tasked with destroying an enemy ship. I've commentated the code the best I could, and you should be able to stick this in an XML and have it work. This is more or less the "template" I use when I create new missions.

Code: Select all

	<MissionType UNID="&msHunterKiller;"
			name=				"Hunter Killer"
			attributes=			"exampleMission"

			level=				"1"
				 
			expireTime=			"5400"
			failureAfterOutOfSystem="5400"
			>
			
		<Events>

			<OnCreate>
			;	This is called when the mission is created.
			;	Typically, this is used to destroy the mission if a previous mission wasn't completed.
			
			;	example of this
			
<!-- 				(not (msnFind "r +unid:&msTaikonAutons;"))
					(msnDestroy gSource) -->
						
			;	restricting to a particular node

<!-- 					(gr (sysGetNode) "SK")
					(msnDestroy gSource) -->
					
			;	You can do lots of creative things here, like calculating the ships max speed or the unid of the ship
			</OnCreate>
			
			<OnAccepted>
			;	This is called when the mission is accepted. Other fields like OnAcceptedUndock can be used as well, though there aren't many cases where the difference matters
			
			(block (theShip)
			
			(block nil
			
			;	We create a Corsair a few hundred light seconds out from the central star.
			
			(setq theShip (sysCreateShip &scCorsair; (sysVectorRandom Nil (random 600 700)"t") &svPirates;))
			
			;	order the ship to wait for the player, attack, then gate out
			;	this is for somewhat realistic behavior, if the ship just abruptly stopped after destroying the player it would be jarring
			;	remember that shpOrder works in order, the next line is called after the previous has been completed
			
			(shpOrder theShip 'waitForTarget gPlayerShip)
			(shpOrder theShip 'attack gPlayerShip)
			(shpOrder theShip 'gate)
			
			;	Remember the enemy ship as the target
					
			(msnSetData gSource 'targetID (objGetID theShip))

			;	we need to register the enemy ship for events so we can tell when its been destroyed
			
			(objRegisterForEvents gSource theShip)
			))
			</OnAccepted>

			<OnPlayerArrived>
				;	This is called when the player gets close enough to the enemy vessel
				;	this is probably redundant because we already ordered the ship to attack when the player arrives already
				;	but it works and i am lazy so i never took it out
				
				(shpOrder TheShip 'attack gPlayership)
			</OnPlayerArrived>
			
			<OnSetPlayerTarget>
				;	This is called as soon as the player is booted from the mission giver dockscreen
				;	naturally, this is where you should set the player's target
				
				(rpgSetTarget gSource aReason (objGetObjByID (msnGetData gSource 'targetID)))
			</OnSetPlayerTarget>
			
			<OnObjDestroyed>
				;	Destroying the enemy vessel results in a successful mission
				;	msnSuccess is what resolves the mission and can be placed under any other events
				
				(switch
					(eq (objGetID aObjDestroyed) (msnGetData gSource 'targetID))
						(msnSuccess gSource)
					)
			</OnObjDestroyed>
			
			<OnObjEnteredGate>
				;	If the enemy vessel enters the gate, then the mission is a failure
				;	you could also have the mission fail if the player is killed
				;	which is helpful if you anticipate the player will have insurance
				;	in this case they would get a second chance to take out the ship before it gates
				
				(switch
					(eq (objGetID aObj) (msnGetData gSource 'targetID))
						(msnFailure gSource)
					)
			</OnObjEnteredGate>
			
			<OnCompleted>
				;	When we complete the mission, we cancel the playerships orders because we pointed it at a target. this clears the marker.
				;	This is where you should set globaldata like epitath entries, ie. 'Rescued Project Lamplighter scientists'
				
					(block Nil
						(shpCancelOrders gPlayerShip)								
						)
			</OnCompleted>
			
		<OnReward>
			;	Pay the player.
			;	rpgMissionRewardPayment allows a flat value in credits, or other currencies
			;	If you want payment to scale along system level or other values, you need to write your own global
			;	You can also give the player non-currency rewards here like items or other stuff
			
			(rpgMissionRewardPayment 500)
		</OnReward>
			
		</Events>
		
		<Language>
		
		<!-- This is the name of the mission, which appears on the mission screen. -->
		
			<Text id="Name">
				"Hunter Killer"
			</Text>
			
		<!-- This is the summary of the mission, which appears on the mission screen. -->	
		
			<Text id="Summary">
					(cat
						"Mission summary. Located "
						"in " (sysGetName) "."
						)
			</Text>

		<!-- This text is what appears via the rpgMissionAssignment action, because no text is defined otherwise.-->
			
			<Text id="Intro">
				(list
					{
						desc: (cat
							"You enter the mission board and are approached by a recruiter.\n\n"
							"\"We've got a mission for you, if you're interested.\""
							)
							
						nextLabel: "\"[W]hat's happening?\""
						}
					)
			</Text>
			
			<!-- This describes the mission and gives options for accepting or declining. -->
					
			<Text id="Briefing">
				(list
					{
						desc: (cat							
							"\"We've located a pirate ship that's been preying on traffic lanes in the system. Your job is to go out there and poke some holes in its hull. We'll pay you 500 credits if you succeed.\""
							)
							
						acceptLabel: "\"[I]'m in.\""
						declineLabel: "\"[S]orry, not interested.\""
						}
					)
			</Text>
			
			<!-- This appears when the mission is accepted. -->
					
			<Text id="AcceptReply">
				"\"Great; I'll program their last known location into your ship's computer for you.\""
			</Text>
			
			<!-- This appears if its declined. -->
			
			<Text id="DeclineReply">
				"\"What the hell are you doing here, then?\""
			</Text>
			
			<!-- This shows if the player enters the dockscreen pane while the mission is in progress. -->
			
			<Text id="InProgress">
				"\"What are you doing here? Has the ship been destroyed?\""
			</Text>
			
			<!-- This shows if the player failed the mission and returns. -->
			
			<Text id="FailureDebrief">
				"\"How did you manage to screw that one up? Get the hell out of here!\""
			</Text>
			
			<!-- This shows if the player succeeded in the mission and returns.-->
			
			<Text id="SuccessDebrief">
				"\"Great job, Captain. We've deposited 500 credits into your account.\""
			</Text>
			
			<!-- This shows on the player's messages when the mission is successful. ie where 'autopilot engaged' shows up.-->
			
			<Text id="SuccessMsg">
				"\"Mission complete!\""
			</Text>
			
			<!-- Mostly for error handling, this is in case the player has already been debriefed but somehow gets back into dockscreen. I think this is for handling multiple objects giving missions but I don't really know.-->
			
			<Text id="AlreadyDebriefed">
				"\"Mission already completed\""
			</Text>
			
			<!-- If, for whatever reason, the mission isn't available but the player finds their way into the dockscreen.-->
			
			<Text id="Unavailable">
				"\"Mission unavailable\""
			</Text>
		</Language>
	</MissionType>
If you have any specific questions feel free to ask.
Last edited by Xephyr on Tue Jul 26, 2016 2:01 pm, edited 2 times in total.
Project Renegade (Beta) : "The Poor Man's Corporate Command!"
Real programmers count from 0. And sometimes I do, too.
JohnBWatson
Fleet Officer
Fleet Officer
Posts: 1452
Joined: Tue Aug 19, 2014 10:17 pm

Very nice. I'm glad to see an explanation of the new mission system posted; I'd been waiting for it to gain some traction and popularity among modders before updating my own tutorial mod to implement it.
User avatar
digdug
Fleet Admiral
Fleet Admiral
Posts: 2620
Joined: Mon Oct 29, 2007 9:23 pm
Location: Decoding hieroglyphics on Tan-Ru-Dorem

Nice ! This was Highly needed.
I still think that collecting all these templates in a single place would be a great thing to do.
Post Reply