Development:Campaigns

From VsWiki
Revision as of 15:35, 3 April 2011 by Pyramid (talk | contribs) (Conditions)
Jump to: navigation, search
arrow_left.png Edit faction relationships arrow_up.png HowTos Edit Missions arrow_right.png

Editing Campaigns

Note: The information contained here is useful only to those willing to learn a minimal amount of python code (the language does not need to be learned, only the formatting restrictions imposed). A GUI based campaign editor is in development, but work has stalled due to lack of time on the developer's part. If anyone wishes to assist, please contact dandandaman.

An example campaign can be found under the following link

To write a campaign, you'll require missions. The mission system is what is used by both the mission bbs, and the campaign. As a start, it is good to plan to use only the mission types available, as writing your own can be a pain, and requires a degree of proficiency with python and vegastrike which you may not have for a little while. If you are developing a campaign and do require something specific that isn't available, just ask, and we'll see what can be done.

Since you are then limited to the missions we have, you'll want a nice reference about what each of the variables for each mission are ... and what they do. We don't actually have one ;-) but we have something that is almost as good: verify_missions.py At the bottom of this file is a list of the mission types, and slightly more descriptive labels for the arguments (their meanings should be relatively easy to glean from that info, but ask if you're unsure :-) ).

That is unfortunately the easy part. The harder part (easy once you understand it) is then writing the campaign. The campaign for Vega Strike is stored in campaigns.py.

Before we proceed I think it's best if you look at this stuff and try to understand a little bit yourself. At the top of campaigns.py is a whole bunch of text, the dialog and strings used by all the various campaign 'nodes.'

A 'node' is a branch of a campaign, it is where fixers get created and the decision to accept or deny a mission occurs, or where the campaign is branched automatically (depending on some conditions that you might want to specify. I.e. you might have a branching storyline depending on whether a flight group still exists or not).

Typically, each node contains a mission ... Cargo missions are a special case, they have a special type of node wrapper, and are probably the easiest to start with. Anyway, get yourself a text editor with syntax highlighting for python, and have a look at the nodes in the function LoadTestCampaign (this is a short test campaign that I made to demonstrate a bug).

There was more documentation somewhere, but it appears to have been vanquished. So, ask the inevitable questions!

Campaign Structure

Campaign Integration

You will need to create a new campaign python file (e.g. campaign_mycamp.py), which then will be integrated into the campaigns.py with the following additions:

import campaign_mycampaign

campaignsloaders = [ ...
  lambda:campaign_mycamp.LoadMyCampaign()
]

The basic structure of your new campaign_mycamp.py file will then be:

import universe
import campaign_lib
from campaign_lib import *

### define node dialogs
...

### define fixer sprites
...

def LoadMyCampaign():

  ### define nodes
  ...

  # savegame_variable (can't contain spaces)
  vs = Campaign("campaign_mycamp")
  # the starting node.
  vs.Init(FirstNode)

  ### define node missions
  ...

  # finalize campaign definition
  return vs


Campaign Missions

Nodes

There are 2 types of nodes:

  • CampaignClickNode() - here you have to talk to a fixer and accept or reject the proposed mission.
  • CampaignNode() - creates an action, like adding reward or adjusting a faction relation, without fixer intervention.

Nodes must be initialized first:

    ThisNode   = CampaignClickNode() # initialize the node
    ActionNode = CampaignNode()

The nodes are then connected with the last four arguments in the MakeMission function:

MakeMission(vs, ... 
    RejectNode, # If you reject the mission twice. "None" means that he continues asking you forever until you accept
    LoseNode, # Node if you lose the mission
    WinNode, # Node if you win the mission
    ThisNode) # The node for this mission 

The complete mission statement and the different types of mission nodes that can be created are described in the following section. Further down, you will find the singular structure of the arguments.

MakeMission Node

MakeMission(savegame_variable, fixer_sprite, start_location, end_location, click_script, 
mission_script, mission_arguments, completion_script, dialog_dictionary, reject_node, lose_node, 
win_node, this_node)

MakeCargoMission Node

MakeCargoMission(savegame_variable, fixer_sprite, start_location, end_location, 
click_script, mission_script, mission_arguments, completion_script, dialog_dictionary, 
reject_node, lose_node, win_node, this_node)

MakeNoFailureCargoMission Node

MakeNoFailureCargoMission(savegame_variable, fixer_sprite, start_location, end_location, 
click_script, mission_script, mission_arguments, completion_script, dialog_dictionary, 
reject_node, lose_node, win_node, this_node)

Init Node

NodeName.Init(savegame_variable, start_location, dialog_dictionary, fixer_sprite, 
subnode_script, completion_script, next_node)

Mission Arguments

  • savegame_variable - usually vs
  • fixer_sprite - sprite file for the fixer in the form (sprite_path, display_name, full_screen_sprite), e.g. ("campaign/captain.sprite","Talk_To_The_Captain","campaign/heads/captain.sprite")
  • start_location - a command for location checking containing a tuple with (sector/system, base), e.g. [InSystemCondition("Crucible/Cephid_17","Serenity")]
  • end_location - same format as start_location
  • click_script - script to be run as you click on the fixer. A common use is to AddCredits() for the previous mission.
  • mission_script - script to be run to start the mission (usually None if you don't have a script, but ambush is also common.)
  • mission_arguments - depend on the mission. E.g. for cargo mission you will give the loaded cargo as arguments: ("Recycled_Plastics",50,False)
  • completion_script - script to be set on completion (-1=Failure, 0=Not Accepted, 1=Succeed, 2=In progress), often just vs.name+"_mission"
  • dialog_dictionary - the lines that the fixer says: a dictionary with {dialog_type, dialog_lines_list}, see structure description further down
  • reject_node - name of the node if you reject the mission twice. "None" means that fixer continues asking you forever until you accept
  • lose_node - next node if you are unsuccessful in the mission
  • win_node - next node if you successfully complete the mission
  • this_node - name of the node for this mission, e.g. FirstNode

Subnodes

  • TrueSubnode
  • GoToSubnode
  • GoToSubnodeIfTrue
  • TrueBackwardsSubnode

Conditions

  • SaveVariableCondition
  • HaveCredits
  • InSystemCondition
  • HasUndocked
  • CargoSpaceCondition
  • AtMostActiveMissionsCondition
  • AtLeastActiveMissionsCondition
  • OrCondition
  • AndCondition
  • InvertCondition

Scripts

Scripts and script arguments can be seen in data/modules/campaign_lib.py. The usual arguments are: (scriptarguments, nextscript), where the next script can be omitted and is nested as the last script argument.

  • AddCredits(numcreds,nextscript)
  • AddCargo(name,num,missionflag,nextscript)
  • RemoveCargo(name,num,missionflag,nextscript)
  • SetSaveVariable(varname,varvalue,nextscript)
  • IncSaveVariable(varname,nextscript)
  • AddTechnology(technology,nextscript)
  • AdjustRelation(us,them,change,nextscript)
  • ClearFactionRecord(fac,newrelation,nextscript)
  • ClearRecord(nextscript)
  • PushRelation(faction,nextscript)
  • PopRelation(faction,nextscript)
  • LaunchWingmen(faction,shiptype,num,nextscript)
  • ChangeSystemOwner(system,faction,nextscript)
  • SaveVariableGreaterScript(var,val,nextscript)
  • DisplayTextIfTrueScript(text,nextscript)
  • RemoveCredits(numcreds,nextscript)
  • SetCredits(numcreds,nextscript)
  • PushCredits(nextscript)
  • PopCredits(nextscript)
  • PushNews(story,nextscript)
  • LoadMission(name,missionname,missionargs,nextscript=None,briefing=,briefing_done=,vars=None,vars_done=None)
  • AddSprite(name,sprite,pos,nextscript)
  • AddPythonSprite(name,sprite,center_position,widthheight,text,python,nextscript)
  • AddRemovingSprite
  • AddConversationStoppingSprite
  • GoToSubnodeIfTrue
  • TrueSubnode
  • TrueBackwardsSubnode
  • GoToSubnode

Remarks:

  • relation is saved as two bidirectional values ranging from -0.5 to 1.0 in a variable "Relation_to_factionname" with two float values appended. One is the players relation to that faction, the second is the faction relation to the player.

Dialogs

The structure for the dialog_dictionary is as follows:

dialog_dictionary = { 
  "intro":     [conversation],
  "reject1":   [conversation],
  "reconsider":[conversation],
  "reject2":   [conversation],
  "accept":    [conversation],
  "accept2":   [conversation],
  "reminder":  [conversation],
  "failure":   [conversation],
}

with:
conversation = (speaker1, line1, ...), (speaker2, line1, ...), ..., soundfile

For Init Nodes you will supply only one [conversation].

Examples

The first major campaign written (Jenek)

See also the forum thread (comments & feedback) when this mission was first put into SVN. FIXME Improve/expand it?

Ending Node with AddCredits and AdjustRelation

    FinalNode.Init(vs, # savegame variable
        [], #start location
        [], #dialog
        None, # fixer sprite
        TrueSubnode(AddCredits(100000,AdjustRelation("privateer","pirates",0.01))), # subnode script
        None, # completion script
        [CampaignEndNode(vs)]) # continue with next mission

See Also


arrow_left.png Edit faction relationships arrow_up.png HowTos Edit Missions arrow_right.png