Before we start

From WiCWiki

Jump to: navigation, search

Contents

Intro

Before you throw yourself over the rest of the tutorial it would be a good idea to read the following pages. They will give you useful startup tips and clues on where to find files for the upcoming chapters in the tutorial. We will use a modified version of the map europe1 for most of our examples throughout this tutorial. If you want to have access to the test map and code files you must install the ‘big’ mod kit.


We renamed the map to europeTest after we started to work with this tutorial so in some places and some screen shots the name europe1 is still there, read it as europeTest. If not stated otherwise, europeTest is the map to use. We have also created a folder of all the files used in our test map. This folder can be found here: tutorial files\maps\europeTest\. If you copy the whole map folder to your mod folder root direction all files path will be according to the paths we use in this tutorial. When we use a file path that looks something like this; wic\foo\bar.fnord, with ‘wic’ as root folder, we always refer to the folder where you have the mod kit installed. In this folder you will also find the important tools, the Juicemaker and WICEd and WinSDF.


The JuiceMaker is an important tool when you are working with *.juice files. We will refer to *.juice files like everywhere in this tutorial and we use them a lot. A *.juice file is simply a text file which you can open in a text editor or in the JuiceMaker tool. The important thing whether you are working with them in a text editor or not is to save them in the JuiceMaker tool cause that will auto generate a bunch of files that are necessary for the game to work. (If stated differently somewhere in this tutorial that is a LIE! J To save *.juice files in the Juice Maker tool is crucial) Make sure you always have an up to date *.loc and *.ice file in the same folder as the *.juice file.


We have another very useful ‘tool’ called the Degug_viewer. It is mostly used for debug purposes and for making objective cameras. We think it is a good idea to use this and you can read more about it in the chapter about the debug viewer.


The test map we’ve made covers the most common situations in single player, not all of them. This map is not fun to play, balanced or complete but that was never our intention. This map is made simply for you to have a pretty easy and clear reference map. You can find the test map files here: tutorial files\maps\europeTest and we will list the most used files soon.


We know this tutorial is very, very long and no; you won’t need everything to be able to make a single player map. Some of the chapters are meant to be in the orders they are with references to previous or coming chapters. Some of the chapters were not there from the beginning but got added since we discovered that they would probably be needed.


In some of the chapters in this tutorial we will add changes to files in the end of the chapter in an ’Appendix’ sub chapter. Sometimes it is no major changes for example the mapvars.py file in this chapters ‘Appendix’ chapter, contains only comments. If you make sure your files look like the changed files in the chapters ’Appendix’ sub chapters you should always be able to start the game.


If you take a look in the ‘The first whole event’ chapter you might get a feeling of what is most important for you. That chapter will cover the code for the first whole event from the test map and hopefully you will be able to understand the rest of the test map with this tutorial as a reference.


The API we use are our own i.e. nothing you can find with Google. This is also one of the reasons why the tutorial is so long and boring (Naaah, not boring J) because not much of it will explain itself. Especially if you don’t is an experienced coder or scripter. The language we use is called Python and you can find more about this language at the following website http://www.python.org but to know Python is not crucial.


You can find the whole API here: wic\python\.

When you want to test your mission

When you are working on scripting your single player mission and you want to try it there are two ways;

the ‘-map’ way (which is the easiest), and the ‘custom mission way’. When you start your mission with ‘-map’ the map will start directly without entering the games lobby first. Make sure you have a shortcut to the wic.exe in the same folder as you have the mod kit installed. Right click on the wic shortcut. Add –map europeTest (or whatever your map is called) in the target box, right after the last quotation mark and press the apply button. This might save you a lot of time and is really the fastest way to test your map.

The other way is the ‘custom mission way’. Everytime you have made a change in the script and want to try it you must pack all the files in a *.sdf file. How you do this is described in detail in the chapter called ‘Custom Mission’.


Python files

There area a lot of python files used by World in Conflict as you will notice in the coming pages. There is however a couple that is more important for you when trying to startup a “homemade” single player map.

We usually use 4 of them where 2 are crucial for the game to even start. Server.py and Client.py you really must have. Allunits.py and mapvars.py is not crucial but we use them in our test map so it is a good thing if you have them.

On the following pages we have a very short description on how the files work and crucial things you must add in them. For a detailed description please take a look in the chapter about Python files and Event structure. This is just to get you started.

Server.py

This file is autogenerated by WICEd and is the primary file used to create a singleplayer map. When autogenerated, this file will be filled with scripts adapted for multiplayer.

So the first thing you need to do is to delete everything in the file.

Then add the following scripts.

from serverimports import *
import mapvars, allunits
def OnGameStarted():
    if IsSinglePlayer():
        DebugMessage( "OnGameStarted:: Singel" )                   
        theGame.PauseGameMode( )
        ClientCommand( 'HideAllDropZones' )
        EnableDropzone( True )
        ShowAllDropships( True )
        theGame.FadeIn( 1.0 )
        if IsLoadedGame():
            RestoreAfterLoad()
        else:
            theGame.ShowGUIChunk( 'reinforcements' )                   
            theGame.ShowGUIChunk( 'support' )
            theGame.ShowGUIChunk( 'minimap' )

While we are here in the server.py file, we can add a function needed for the upcoming tutorial events.

Add def Intro(): after whole of the OnGameStarted() function. To make this new function to run, we have to call it from the OnGameStarted() function. This will be done by inserting Intro() under the else: statement in the end of the OnGameStarted() function.

To hinder the game from crashing now that we call a empty function, we will insert pass or return in the Intro() function. This insertion should be removed later when you start scripting the mission.

The server.py should now look like this.

from serverimports import *
import mapvars, allunits
def OnGameStarted():

    if IsSinglePlayer():
        DebugMessage( "OnGameStarted:: Singel" )                   
        theGame.PauseGameMode( )
        ClientCommand( 'HideAllDropZones' )
        EnableDropzone( True )
        ShowAllDropships( True )
        theGame.FadeIn( 1.0 )
        if IsLoadedGame():
            RestoreAfterLoad()
        else:
            theGame.ShowGUIChunk( 'reinforcements' )                   
            theGame.ShowGUIChunk( 'support' )
            theGame.ShowGUIChunk( 'minimap' )
            Intro()

def Intro():
    pass

Client.py

This file is also autogenerated by WICEd. The auto generated script in this file is multiplayer related and should be deleted and replaced by the following line

from clientimports import *

The client.py file was, during the creation of the singleplayer campaign, mostly used to create objective cameras. You can read about how you create objective cameras in the chapter about objective cameras.

Server_autogen.py

This file is another one autogenerated by WICEd, but should not be altered, at all. Removal and/or alteration of this file will probably cause the game to crash.

Allunits.py

This file is not vital to create a map, but it can be a very useful tool if used correctly. In the creation of the singleplayer campaign we used this python file to create and control all units, groups and AI we had on the map. This file is also used in the test map and in the tutorial.

This python file is not created from the start, so you have to create it yourself.

Create an empty python file (it’s a text file with an .py extension) and name it allunits.

Add the following lines in the top of the file.

from serverimports import *
from wicgame.ai import * 
import mapvars

Mapvars.py

Just as allunits.py the mapvars.py file is not vital for map creation. In the singleplayer campaign we used this file to save and define important variables. This file is also used in the test map and in the tutorial. This python file is not created from the start, so you have to create it yourself.

Juice files.

The juice files are like the python files, numerous and omnipresent. But for the ordinary mortal modder there are only two files to take into consideration in the initial steps.

mapname.juice

(ex. europeTest.juice)

This file is mainly used for multiplayer maps, but it contains a couple of things which will affect singleplayer maps too.

The most important of these is probably the team settings.

Example from europeTest.juice

myAllowedTeam1 USSR
myAllowedTeam2 NATO
myAllowedTeam1SinglePlayer NATO
myAllowedTeam2SinglePlayer USSR

The first two of the above variables sets the multiplayer teams. But it also is used by the AI in singleplayer. This explained more in the chapter about the AI.

The second two variables are the ones used by singleplayer maps. Team 1 is the team the player will belong to.

mapname_singleplayerdata.juice

(ex. europeTest_singleplayerdata.juice)

For single player map making this is the most important juice file. Here you will add objectives, message boxes, areas and much more. Many things in this file will be explained later.

Debug

When you have all your python and juice files in order and have started scripting you will eventually run into crashes and bugs. This is inevitable, trust us. And when you do run into problems, it would be nice if the code at least tried to tell you what or where the problem is.

To enable this report or debug function as we will call it from now on, you have to run WIC with following start parameters, –debug and –dev.

Image:Before_we_start_001.jpg

One way to do this is to start wic with the Run line. Enter the path to wic.exe then add –debug and –dev after it. Now press the ok button and wic will start with both –debug and –dev activated.

The easiest method is, possibly, to make a shortcut to the wic.exe and change in the shortcut properties. Right click on the wic shortcut. Add –debug and –dev in the target box, right after the last quotationmark and press the apply button. Now wic will start with both –debug and –dev when you use the shortcut.

Image:Before_we_start_002.jpg

-dev

This start parameter will enable a popup window that will appear every time there is a python crash. This window will display an error message and often on which line the problem is.

Image:Before_we_start_003.jpg

Pressing ok will resume the map, but no more python scripts will be executed.

-debug

This start parameter will create a text file called wic_computername_debug.txt.

The file will contain the error and often on which line the problem is i.e. the same information as given with –dev. There is however a lot more information in the debug text file.

If you have both –dev and –debug the error will be displayed twice in the debug file.

The created debug file can be found in My Documents\world in conflict\Debug\wic_computername_debug.txt.

We recommend using both of these parameters when starting your wic.exe. The –dev will give you a quick view of the problem and –debug writes a text file with debug-information, including a callback on the crash. –debug is also good to have if you accidentally press ok on the error window before reading it.


If you choose to not to use –dev and –debug you will not get any indication when stuff goes wrong. The game will continue, but no python scripts will be executed after the error.

When we refer to crashes later on in the tutorial chapters, we will assume you have both –dev and –debug activated.

Debugmessage

If you have used the –debug parameter to start wic, you can use the DebugMessage() function. This function will write the string it gets to the debug text file. This is useful when you want to check if a function is running or get a value from a variable.

DebugMessage( aString )

ex.

This will add the string VillageStart:: to the debug txt file every time the function VillageStart() is executed.

def VillageStart( ):
    DebugMessage( ‘VillageStart::’ )     


ex.

This will add the string VillageStart:: to the debug txt file, but also add the variable value of aUpdate to the string.


def VillageStart():
    DebugMessage( ‘VillageStart:: %s' % aUpdate )

Comments

Commenting is a useful tool we recommend you to use when scripting your mission.

More often than not will you forget certain aspects of the scripts and a few words in a comment can save you a lot of time.


In Python there are two ways to create comments. You can comment either a single line or a whole block of text.

The single line comment starts with a #. It only comments text directly after it on the same line.

The block comment starts with three quotation marks [“””] and ends with three quotation marks [“””]. This will comment everything in between. This method spans over lines as well.

ex.

#This is a single line comment

ex.

"""This is a block comment."""

It will comment everything

that lies within the two triple quotation marks.”””

About the event structure.

In this test map and the tutorial we placed all the code in different events to make everything easy to grasp and to work with. We used this system throughout the whole single player campaign as well. The two best things with it is that you can use the system we call ‘Kick start’ which will start a single event without the rest of the code you can also pretty easy change the orders of the events without to much work because most of the events stand alone.

Here is a stripped version of the first primary objective event and the first secondary objective event with all the actual ‘game code’ removed just to show you the structure of the events. As a standard an event about a primary objective contains the function EventNameSetup(), EventNameCam(), EventNameStart(), and EventNameEnd(). The camera function is not necessary and should be removed if you don’t use an objective camera. If it is a secondary objective we usually just use the two functions EventNameSetup() and EventNameStart(). Usually there is nothing that we trigger on when the secondary objective is finished therefore we don’t need to post an EventNameEnd() function.

After the secondary objective event example, last in this sub chapter, there is another Village event structure without the objective camera.


Some of the code might look a bit strange at the moment but it will be explained in different chapters in the tutorial but this is a good basic structure for the events.


def Intro( ):
    [More code here]
    # Setup all Events.
    VillageSetup( True )
    RescueArtySetup( )

#---------------------------  Village ---------------------------       
def VillageSetup( aKickStart = False ):      
    # Setup the start reaction for the event.
    RE_OnCustomEvent( 'IntroEnd', Action( VillageCam ) )
    RE_OnCustomEvent( 'VillageCamEnd', Action( VillageStart ) )
    if aKickStart:
        PostEvent( 'IntroEnd' )

def VillageCam( ):
    # Start the objective camera for the village objective. We want the command point to be visible
    # in the camera so we set it to active and then shows a message box.
    queVillageCam = ActionQueue( 'queVillageCam' )   
    queVillageCam.AddFunction( StartClientCamera, 'ObjCamVillage', False )
    queVillageCam.Execute( )  
    
    # Setup reactions for what to do if/when the player click esc or the cam is done.
    RE_OnCustomEvent( 'END_OF_CUTSCENE', Action( PostEvent, 'VillageCamEnd' ) )
    RE_OnCustomEvent( 'SKIP_CUTSCENE', Action( PostEvent, 'END_OF_CUTSCENE' ) )     

def VillageStart( ):
    [More code will be here]
    queVillageComplete.AddFunction( VillageEnd )

def VillageEnd():
    # Post that the village event is done and that we want to start the next one.
    PostEvent( 'VillageEnd' )


#-------------------------  RescueArty  -------------------------     

def RescueArtySetup( aKickStart = False ):
    RE_OnCustomEvent( 'RescueArtyStart', Action( RescueArtyStart ) )
    if aKickStart:
        PostEvent( 'RescueArtyStart' )                          

def RescueArtyStart( ):
    [More code will be here]

#---------------------------  Village without objective camera -------------------------

If you don’t want to use the camera in the primary objective the Village Event will look like this.

def VillageSetup( aKickStart = False ):      
    # Setup the start reaction for the event.
    RE_OnCustomEvent( 'IntroEnd', Action( VillageStart ) )
    
    if aKickStart:
        PostEvent( 'IntroEnd' )         

def VillageStart( ):
    [More code will be here]
    queVillageComplete.AddFunction( VillageEnd )

def VillageEnd():
    # Post that the village event is done and that we want to start the next one.
    PostEvent( 'VillageEnd' )

Appendix.

This is how your code files can look at the moment. It is a good basic start.

Changed files in this chapter:

Server.py

Client.py

Allunits.py

Mapvars.py

europeTest.juice


Changes in the server.py file.


from serverimports import *
import mapvars, allunits

def OnGameStarted():
    if IsSinglePlayer():
        DebugMessage( "OnGameStarted:: Singel" )                   
        
        # Disable multiplayer game modes
        theGame.PauseGameMode( )
        
        # Hides all DropZone markers
        ClientCommand( 'HideAllDropZones' )
        
        # Show the players DropZone marker
        EnableDropzone( True )
        
        # Show Enemy Teams Dropships
        ShowAllDropships( True )
        
        # Fade in to the game.
        theGame.FadeIn( 1.0 )
        
        # Check if its a loaded game.
        if IsLoadedGame():
            # Restores the GUI and starts the reaction manager after a game has been loaded. 
            RestoreAfterLoad()

        else:
            # Setup the GUI.
            # We only want the mini map to be visible at the beginning, so we turn it on and let the
            # reinforcement and ta menu to be hidden.
            #theGame.ShowGUIChunk( 'reinforcements' )                         
            #theGame.ShowGUIChunk( 'support' )                           
            theGame.ShowGUIChunk( 'minimap' )
            
            # Start the mission.
            Intro( )
    return 1


def Intro( ):
    DebugMessage( "Intro::" )
    
    # Setup all Events.
    VillageSetup( True )
    RescueArtySetup( )

##---------------------------------------------------------------
#---------------------------  Village ---------------------------     

def VillageSetup( aKickStart = False ):            
    DebugMessage( "VillageSetup::" )

    # Setup the start reaction for the event.
    RE_OnCustomEvent( 'IntroEnd', Action( VillageStart ) )
    RE_OnCustomEvent( 'VillageCamEnd', Action( VillageStart ) )
  
    if aKickStart:
        DebugMessage( "VillageSetup::KickStart" )
        PostEvent( 'IntroEnd' )

def VillageCam( ):
    DebugMessage( "VillageCam::" )
  
    # Setup reactions for what to do if/when the player click esc or the cam is done.
    RE_OnCustomEvent( 'END_OF_CUTSCENE', Action( PostEvent, 'VillageCamEnd' ) )
    RE_OnCustomEvent( 'SKIP_CUTSCENE', Action( PostEvent, 'END_OF_CUTSCENE' ) )            


def VillageStart( ):
    DebugMessage( "VillageStart::" )


def VillageEnd():
    DebugMessage( 'VillageEnd::' )
  
    # Post that the village event is done and we want to start the next one.
    PostEvent( 'VillageEnd' )

##---------------------------------------------------------------
#-------------------------  RescueArty  -------------------------  

def RescueArtySetup( aKickStart = False ):
    DebugMessage( 'RescueArtySetup::' )
    
    RE_OnCustomEvent( 'RescueArtyStart', Action( RescueArtyStart ) )
    
    if aKickStart:
        PostEvent( 'RescueArtyStart' )                               

def RescueArtyStart( ):
    DebugMessage( 'RescueArtyStart::' )

Changes in the client.py file.

from clientimports import *

##---------------------------------------------------------------
#---------------------------  Village ---------------------------     



##---------------------------------------------------------------
#-------------------------  RescueArty  -------------------------  


Changes in the allunits.py file.


from serverimports import *
from wicgame.ai import * 
import mapvars

##---------------------------------------------------------------
#---------------------------  Player ----------------------------
 
##---------------------------------------------------------------
#---------------------------  Village ---------------------------     
 
##---------------------------------------------------------------
#-------------------------  RescueArty  -------------------------  

Changes in the mapvars.py file.

##---------------------------------------------------------------
#---------------------------  Player ----------------------------

##---------------------------------------------------------------
#---------------------------  Village ---------------------------     

##---------------------------------------------------------------
#-------------------------  RescueArty  -------------------------  


Changes in the europeTest.juice file.

If you open europeTest.juice in the ‘JuiceMaker’ tool you will find myMissionStats under myWicedMap->myMissionStats.


myMissionStats
{
    [more variables here]
    myAllowedTeam1 USSR
    myAllowedTeam2 NATO
    myAllowedTeam1SinglePlayer NATO
    myAllowedTeam2SinglePlayer USSR
    [more variables here]
Chapter 2: Custom Mission
Personal tools
User Created Content