Custom DALLAS Script Example Part I ( V1.0 ) Atan


Sometimes it becomes necessary to use custom function inside a DALLAS level script.
One reason might be controlling a lot of the same objects or if you run out of DALLAS variables, Flags.
Let me show you one example:

image
Inside your level you may have 6 switches and you want to control each one by DALLAS.
You want each switch to toggle by hit.

This picture show the basic steps for one switch:

image

This is easy going up to now, but think about what would happen if your switch count increases.
Because we can't use the same flag for every switch, we must insert 5 more flags now:

image

Easy doing by Copy and Paste and renaming each entry. But this is only true for simple level scripts.
When you get to advanced level scripting you will soon find out that handling becomes harder. Soon you'll lost sight.
In the next step I will show you the basics to making things easier, doing your first steps with custom functions.

All you need is an simple text editor like Notepad, no programming tool is needed and sure, you'll need some basics in C/C++.
But following this example will allow even beginners to see how to do it. So explore it and you'll soon be able to make your own custom functions. Looking into the dallasfunction.cpp will be very helpful too. But be sure not to change this file during your experiments.
Hint: Do NOT use Word or similar programs for your scripts.
Let's say our level is named 'mylevel'
Open your 'mylevel'.cpp with Notepad. This file was generated by DALLAS during the above steps inside your
D3SDK OSIRIS folder. You can't see the file? Choose 'ALL files' inside the Dialog box will do the trick.
If you open the file look for this section:

//===============================================================
//Start of Custom Script Block - DO NOT EDIT ANYTHING BEFORE THIS
//===============================================================
/**{CUSTOM_SCRIPT_BLOCK_START}** DO NOT EDIT!**/

// Enter your custom script code here

/**{CUSTOM_SCRIPT_BLOCK_END}**** DO NOT EDIT! **/
// ============================================================
// End of Custom Script Block - DO NOT EDIT ANYTHING AFTER THIS
// ============================================================


You may use the Search function for this, just search for : Start of

As the sentence in the middle says... exactly there you must enter your customs now.

Close the file again, we will first look at some theory. So lets see what we need, why we need it and how to begin.
Remember what our first function should do:
We want to simplify resetting our custom flags by one call out of DALLAS.
Follow/read the steps below, later you'll find the whole program at the bottom.

Step one:

// Defines how many Flags we need
//
#define MAX_SWITCH_FLAGS	6


MAX_SWITCH_FLAGS is a name of our choice which will be used later.
6 is our count of switches.

Step two:

// our boolean Flag array
//
bool StopSwitch[ MAX_SWITCH_FLAGS ];


This way we constructed 6 boolean variables.
bool means a value between 0 and 1 ( or false and true)
StopSwitch is the name for our array of boolean values
MAX_SWITCH_FLAGS, yes we defined it above and it means 6.

bool StopSwitch[ MAX_SWITCH_FLAGS ] means now the same as:
bool StopSwitch[0]
bool StopSwitch[1]
bool StopSwitch[2]
bool StopSwitch[3]
bool StopSwitch[4]
bool StopSwitch[5]
You see, we own 6 variables now exact as we need for our 6 switches.

Step three:

The way DALLAS will be able to handle our customs is to enumerate them.

/*
$$ENUM StopSwitch
0:"StopSwitch1"
1:"StopSwitch2"
2:"StopSwitch3"
3:"StopSwitch4"
4:"StopSwitch5"
5:"StopSwitch6"
$$END
*/


StopSwitch : is the name of the block, we will need it below for the custom functions
0:"StopSwitch1" : if you select StopSwitch1 inside DALLAS it will give the value 0
5:"StopSwitch6" : will give the value 5


Step four:

Now we will come to the core, our first custom function.

//=========== First function:  Clear all the flags by single DALLAS command =====

/*
$$ACTION
Custom
Clear all StopSwitchFlags
aClearAllStopSwitchFlags
Clear custom StopSwitchFlags
Clears the custom StopSwitchFlags This is used at levelstart

Parameters:
  None
$$END
*/

void aClearAllStopSwitchFlags(void)
{
	int j = 0;
	
	for ( j = 0; j < MAX_SWITCH_FLAGS; j++ ) {
		StopSwitch[j] = false;
	}	
}

//========= End of first function ========================================


I will try to explain this baby in detail:

This part inside /* */ is needed to tell DALLAS what kind of function is so you can find it inside DALLAS
and gives some information about the function.

/* 						this is needed to border (begin) the description
$$ACTION 					It's an ACTION function which means that there is no return value.
Custom						And it is a Custom which will be found at that area inside DALLAS later.
Clear all StopSwitchFlags				Description shown inside the script
aClearAllStopSwitchFlags				our own Function name, (a)  like action (name of your choise)
Clear custom StopSwitchFlags 			Description
Clears the custom StopSwitchFlags This is used at levelstart	Description

Parameters					Parameters needed, here none
  None
$$END						End of the ACTION					
*/						this is needed to border (end) the discription


The descriptions will be shown inside DALLAS dialog inside the bottom text area if you select the function.

image

This part is the function itself.
DALLAS knows about it by the aClearAllStopSwitchFlags Entry inside the description block above.

void aClearAllStopSwitchFlags( void )
{
	int j = 0;
	
	for ( j = 0; j < MAX_SWITCH_FLAGS; j++) {
		StopSwitch[j] = false;
	}	
}


void aClearAllStopSwitchFlags(void)

void :					our function returns nothing
aClearAllStopSwitchFlags : 			we named our function like this. Prefix a is for ACTION
(void) :					This function needs no parameter (input)

{ 					Function body start
int j = 0; 					integer variable 'j' is set to 0
for (j=0; j < MAX_SWITCH_FLAGS; j++) 	as long as j <  MAX_SWITCH_FLAGS run the loop ( 0 to 5 )
{ :					loop start
StopSwitch[j] = false; 			and fill our array with 0
} 					loop end
} 					Function body end


Remember, if j = 0
StopSwitch[j] is the same as StopSwitch[0] and so on.
BTW:
j = 5 means that you put 5 into the integer variable j.
If you want action if j equals 5 you need to write: if( j == 5){your action}

Now mark and copy the following part: (or use the 'Grab' button)

//Defines how many Flags
//
#define MAX_SWITCH_FLAGS	6

// our boolean Flag array
//
bool StopSwitch[ MAX_SWITCH_FLAGS ];

// Enumerated names Names to be used inside DALLAS
// and custom functions below
//

/*
$$ENUM StopSwitch
0:"StopSwitch1"
1:"StopSwitch2"
2:"StopSwitch3"
3:"StopSwitch4"
4:"StopSwitch5"
5:"StopSwitch6"
$$END
*/

/*
$$ACTION
Custom
Clear all StopSwitchFlags
aClearAllStopSwitchFlags
Clear custom StopSwitchFlags[10]
Clears the custom StopSwitchFlags[10] This is used at levelstart

Parameters:
  None
$$END
*/
void aClearAllStopSwitchFlags(void)
{
	int j = 0;
	
	for (j=0; j < MAX_SWITCH_FLAGS; j++){
		StopSwitch[j] = false;
	}	
}


Open your 'mylevel'.cpp with Notepad again and paste the copied part inside the custom block.
You don't know where it was? Read carefully from beginning again in this case.
If pasted, use Save As to save your file, be sure to save it as cpp and into the D3-SDK OSIRIS folder!
Now open your level inside D3Edit select WorldView open DALLAS and save.
If there is no error message all went fine up to now. If not, you must look into the 'mylevel'.cpp again and search for the problem. Did you really paste INSIDE the custom block? Is your file ending really cpp?
If you can't figure it out, delete the part inside the custom block, be careful that you delete your custom stuff only and try to compile again.
If it works now look at your custom section carefully for a fault. (shouldn't be one if you copy and paste the sample)

Ok, but let us assume that all went well, you could compile the script.
That's the point where we will look for our custom function inside DALLAS now.

image

Inside this Custom menu point we'll find our custom function.
Now we can reduce the LevelInit script ( Then.. ) to one line only.
Remember you could have cleared 100 flags with this single line now

image

But the best is that we spare our rare DALLAS Flags this way.
Next step is to change our StopSwitch1 handling so it uses our custom variable.
Think over what is needed for this.

  1. We must be able to SET a flag
  2. We must be able to clear a flag
  3. We must be able to ask for the flag state ( 0 or 1 / false or true )

Point 1 and 2 can be done by one single function, Point 3 will become our third function.
For my samples I choose a simple coding so beginners will be able to follow, at least I hope so.
Code Gurus, don't say that this could be done different, much better... I know that, and these samples are not designed for you :)
Now let's start with our second function where we will see how to Set and Clear our custom flags.

/*
$$ACTION
Custom
Set user flag [e:StopSwitch]  to [b:True/False]
aUserStopSwitchFlagSet
Set user flag
  Set a flag to true or false

Parameters:
  UserFlag: The variable to set
  True/False: What to set the flag to
$$END
*/


Our description block is a little different from the first one, it's an Action, and Custom, we know that already.
First point of interest is this line which is shown inside DALLAS later:
Set user flag [e:StopSwitch] to [b:True/False]

This is what I found about DALLAS types
Dallas types:

ID Name How passed



o object object handle
d door handle of door object
r room integer room number
t trigger integer trigger number
i int integer
b bool unsigned byte/bool
f float single-precision float (4 bytes)
p percentage single-precision float in range 0.0 - 1.0
v vector pointer to triplet of floats
s string pointer to null-terminated string
e enum integer (DALLAS defined enumeration)
g flag integer (a combination of flags, DALLAS defined)
a name a specific (non-localizable) name, as of a matcen. Does not appear in the message file.
n sound sound name
h path integer path number
m matcen integer matcen number
l level goal integer level goal number
z streaming audio pointer to null-terminated name of audio file

[e:StopSwitch] means that here will be shown an enumerated inside the DALLAS function line
[b:True/False] means that here will be shown a boolean True or False

Remember, StopSwitch is the name of our enumerated block at the beginning of our custom part

/*
$$ENUM StopSwitch
0:"StopSwitch1"
1:"StopSwitch2"
2:"StopSwitch3"
3:"StopSwitch4"
4:"StopSwitch5"
5:"StopSwitch6"
$$END
*/


True/False will give us the possibility to choose true or false. (1 or 0)
true = Set
false= Clear

The whole line Set user flag [e:StopSwitch] to [b:True/False] says nothing else other then:
That one of the user flags named inside StopSwitch to true or false.

Here is how it looks like inside DALLAS if you right click onto it later:

image
If you right click onto True/False you will be able to choose (oh wonder) True or False.

aUserStopSwitchFlagSet is the name of our second function

Parameters:
UserFlag: The variable to set
True/False: What to set the flag to

This tells us that we must feed our function with two things,
the variable ( 0 -> 5 from our StopSwitch Enum field),
the wanted state of our flag, set to True or clear to False.

image

But I did a step too far with these pictures above because we haven't talked about or inserted the real part of the function..

void aUserStopSwitchFlagSet( int flagnum, bool state)
{
	if ((flagnum >= 0) && (flagnum < MAX_SWITCH_FLAGS)) { // test if our value is between 0 and 5

		if (state){	// this means the same as  if state = = true (1)
			
			// ok, it's 1 so we shall set our flag to true ( Set)

			switch (flagnum){	// switch to which flag that should be changed (0 to 5) 
					// lets say i.e.  it's 3
				case 0:{
					StopSwitch[0] = 1;
					break;
				}
				case 1:{
					StopSwitch[1] = 1;
					break;
				}
				case 2:{
					StopSwitch[2] = 1;
					break;
				}
				case 3:{ // because flagnum is 3 in our example we will go into this case 
					StopSwitch[3] = 1; //  we set this flag
					break; // and break out of the whol chain and end the function
				}
				case 4:{
					StopSwitch[4] = 1;
					break;
				}
				case 5:{
					StopSwitch[5] = 1;
					break;
				}
				default :	 break;
			}
		}//end if (state)
		
		else{	// if the flag should set to false (0), cleared
			switch (flagnum){
			case 0:{
			StopSwitch[0] = 0;
			break;
			}
			case 1:{
			StopSwitch[1] = 0;
			break;
			}
			case 2:{
			StopSwitch[2] = 0;
			break;
			}
			case 3:{
			StopSwitch[3] = 0;
			break;
			}
			case 4:{
			StopSwitch[4] = 0;
			break;
			}
			case 5:{
			StopSwitch[5] = 0;
			break;
			}
			default : break;
			}
		}
	}
}


New things:
if (condition = true) then do this
if not (else) then do that
switch(variable) -> test the given cases, if one case is found do action which belongs to
break -> Ok, we found a matching case and don't want to look for others. That's why we break out of the switch chain now

All we need to finish our custom flag journey is a function to receive a custom flag state.
You know, state means something like: Is our custom flag xyz = true or possibly = false?
We start with the description block again:

/*
$$QUERY
Custom
b:User Flag [e:StopSwitch]
qUserFlagStopSwitch
User flag
  Returns the state of the specified user flag

Parameters:
  UserFlagStopSwitch: The flag whose state to return
$$END
*/


QUERY will tell DALLAS that this function will return something
qUserFlagStopSwitch q identifies a query function (name is of our choice)

Now the function:

bool qUserFlagStopSwitch( int flagnum )	// function returns boolean / function needs a variable (flagnum) to know which flag is meant	
{				// by our enum  StopSwitch we own the correct   flagnum in DALLAS.
	if ((flagnum >= 0) && (flagnum < MAX_SWITCH_FLAGS)){

			switch (flagnum){
			case 0:{
			if (StopSwitch[0] == 1)// attention == is == !!
			return( 1 );
			else
			return( 0 );
			break;
			}
			case 1:{
			if (StopSwitch[1] == 1)
			return( 1 );
			else
			return( 0 );
			break;
			}
			case 2:{
			if (StopSwitch[2] == 1)
			return( 1 );
			else
			return( 0 );
			break;
			}
			case 3:{
			if (StopSwitch[3] == 1)
			return( 1 );
			else
			return( 0 );
			break;
			}
			case 4:{
			if (StopSwitch[4] == 1)
			return( 1 );
			else
			return( 0 );
			break;
			}
			case 5:{
			if (StopSwitch[5] == 1)
			return( 1 );
			else
			return( 0 );
			break;
			}
			default : break;
			}
		}
	else{
		return 0;
		}
}


And finally, the whole code once again:

//===============================================================
//Start of Custom Script Block - DO NOT EDIT ANYTHING BEFORE THIS
//===============================================================
/**{CUSTOM_SCRIPT_BLOCK_START}** DO NOT EDIT!**/

// Enter your custom script code here

//Defines how many Flags
//
#define MAX_SWITCH_FLAGS	6

// our boolean Flag array
//
bool StopSwitch[ MAX_SWITCH_FLAGS ];

// Enumerated names Names to be used inside DALLAS
// and custom functions below
//

/*
$$ENUM StopSwitch
0:"StopSwitch1"
1:"StopSwitch2"
2:"StopSwitch3"
3:"StopSwitch4"
4:"StopSwitch5"
5:"StopSwitch6"
$$END
*/

//============= Our custom functions ===========================

//=========== First function:  Clear all the flags by single DALLAS command =====
/*
$$ACTION
Custom
Clear all StopSwitchFlags
aClearAllStopSwitchFlags
Clear custom StopSwitchFlags[10]
Clears the custom StopSwitchFlags[10] This is used at levelstart

Parameters:
  None
$$END
*/
void aClearAllStopSwitchFlags(void)
{
	int j = 0;
	
	for (j=0; j < MAX_SWITCH_FLAGS; j++){
		StopSwitch[j] = false;
	}	
}

//=========== Second function:  Set or Clear a single flag  ================
/*
$$ACTION
Custom
Set user flag [e:StopSwitch]  to [b:True/False]
aUserStopSwitchFlagSet
Set user flag
  Set a flag to true or false

Parameters:
  UserFlag: The variable to set
  True/False: What to set the flag to
$$END
*/
void aUserStopSwitchFlagSet(int flagnum, bool state)
{

	if ((flagnum >= 0) && (flagnum < MAX_SWITCH_FLAGS)) {

		if (state){
			switch (flagnum){
			case 0:{
			StopSwitch[0] = 1;
			break;
			}
			case 1:{
			StopSwitch[1] = 1;
			break;
			}
			case 2:{
			StopSwitch[2] = 1;
			break;
			}
			case 3:{
			StopSwitch[3] = 1;
			break;
			}
			case 4:{
			StopSwitch[4] = 1;
			break;
			}
			case 5:{
			StopSwitch[5] = 1;
			break;
			}
			default : break;
			}
		}
		else{
			switch (flagnum){
			case 0:{
			StopSwitch[0] = 0;
			break;
			}
			case 1:{
			StopSwitch[1] = 0;
			break;
			}
			case 2:{
			StopSwitch[2] = 0;
			break;
			}
			case 3:{
			StopSwitch[3] = 0;
			break;
			}
			case 4:{
			StopSwitch[4] = 0;
			break;
			}
			case 5:{
			StopSwitch[5] = 0;
			break;
			}
			default : break;
			}
		}
	}
}

//=========== Third function:  Get a single flag status ================
/*
$$QUERY
Custom
b:User Flag [e:StopSwitch]
qUserFlagStopSwitch
User flag
  Returns the state of the specified user flag

Parameters:
  UserFlagStopSwitch: The flag whose state to return
$$END
*/
bool qUserFlagStopSwitch(int flagnum)
{
	if ((flagnum >= 0) && (flagnum < MAX_SWITCH_FLAGS)){

			switch (flagnum){
			case 0:{
			if (StopSwitch[0] == 1)
			return( 1 );
			else
			return( 0 );
			break;
			}
			case 1:{
			if (StopSwitch[1] == 1)
			return( 1 );
			else
			return( 0 );
			break;
			}
			case 2:{
			if (StopSwitch[2] == 1)
			return( 1 );
			else
			return( 0 );
			break;
			}
			case 3:{
			if (StopSwitch[3] == 1)
			return( 1 );
			else
			return( 0 );
			break;
			}
			case 4:{
			if (StopSwitch[4] == 1)
			return( 1 );
			else
			return( 0 );
			break;
			}
			case 5:{
			if (StopSwitch[5] == 1)
			return( 1 );
			else
			return( 0 );
			break;
			}
			default : break;
			}
		}
	else{
		return 0;
		}
}

/**{CUSTOM_SCRIPT_BLOCK_END}**** DO NOT EDIT! **/
// ============================================================
// End of Custom Script Block - DO NOT EDIT ANYTHING AFTER THIS
// ============================================================



Once again, it could have be done different but I hope that this way even beginners are able to understand the code.
One little problem is still inside this code, if you shoot i.e. with a vauss against our switch,
it will toggle by EACH hit which may not be wanted.
And you need a custom switch to follow that (toggle) example, feel free to extract the switch and the gam entry out of
my D3 Singleplayer level Firing Range.
I assume that you are able to handle customs inside D3Edit and your levels.
If not, don't even think to try out this tutorial, learn the basics first!


Categories:
Descent3LevelEditing

UpDateNeeded (Minor edits left to do)

There are no comments on this page. [Add comment]

Valid XHTML 1.0 Transitional :: Valid CSS :: Powered by WikkaWiki