nib's Mapper Resource Center
     

Script Mover: Part 2

by BOlty BOy


Part 2 is an overview of scripting. If you are happy with scripting then you may wish to pass over it and head straight to Part 3.


Assumptions:

This tutorial assumes you have a good working knowledge of gtkRadiant as well as a firm understanding on creating maps. This tutorial does not explain how to create brushes, create entities or set key values. If you need help with those, check out the getting started tutorial. Also, you can download all the files in the tutorial here. The zip includes a copy of the map file without any entities so you follow along the tutorial without having to first create the map.

 

Part 2:
Scripting 101

What is script?

Well you will have seen already that a number of entites have a 'scriptname' key. This refers to a section of code in the script file. Every piece of code in the script file has to be referenced by an entity through the use of the scriptname key.

So when I say 'piece of code' what do I mean? A piece of code is represented like this...

AnyName
{
   //THE CODE GOES IN HERE
}

The text beginning with '//' means it's not real code and will have no effect on the game - you can use these purely to add comments to your code.

The code always goes in the curly braces '{' = begin code '}' = end code. So if I wanted an entity to reference the above code I would give it the key: scriptname - AnyName.

Most the time a piece of code like this will be broken up in to smaller chunks of code. Like this:

AnyName
{
	trigger BOB
	{
	//CODE GOES HERE
	}

	trigger CLAIRE
	{
	//MORE CODE GOES HERE
	}
}

The word 'trigger' is almost always used at the start of a new chunk of code like this. It's just saying - this is a point where a new section of code will be triggered.

Now if we wanted to reference the chunk of code 'BOB' from our entity we would give the entity the following keys: scriptname - AnyName, target - BOB.

Making this relevant to our map imagine we had made some code to make the lever go up and down:

lever1
{
	trigger UP
	{
	//CODE TO MAKE LEVER GO UP
	}

	trigger DOWN
	{
	//CODE TO MAKE LEVER GO DOWN
	}
}

I want to make the lever go down so I give an entity the keys - 'scriptname - Lever1' and 'target - DOWN'. So when i trigger that entity it will tell that chunk of code to activate, in this case the lever will go down.
As well as activating a chunk of code from an entity you can activate code within code! It's almost the same as what you've just seen. Imagine I have an entity that has activated the UP chunk of code above. When this code has finished carrying out it's instructions we want the Down chunk of code to be activated. So in a real world case this could make the lever go back down after it's moved up. You would do this like this:

lever1
{
	trigger UP
	{
	//CODE TO MAKE LEVER GO UP
	trigger lever1 down
	}

	trigger DOWN
	{
	//CODE TO MAKE LEVER GO DOWN
	}
}

The word "trigger" is used again. It's like saying - go and look for the following trigger. Then "lever1" points to the main section of code and "down" points to the "trigger down" chunk of code within it.

That's the basics of scripting - now I'll go over the different code words that we will be using.

Spawn - This is actually similar to UP and DOWN in the examples above. The spawn section of code will run automatically when a new game round starts. Would look like this:

lever1
{
	spawn
	{
	//code would go here that gives the entity some initial settings at start of round.	
	}

	trigger UP
	{
	//CODE TO MAKE LEVER GO UP
	}

	trigger DOWN
	{
	//CODE TO MAKE LEVER GO DOWN
	}
}

Although you always need a spawn in your code you do not need to give it any code. It can remain blank within the { }. Note that the word 'spawn' is not preceeded by a 'trigger'. This is because the only time spawn is triggered is automatically at the start of the round.

Wait - this is a peice of code that will pause the code for a set period of time. Saying "wait 4000" will pause the code at whatever instruction it got to for 4 seconds (wait time is measured in milliseconds and 1000 milliseconds = 1 second). Another example, we want the lever to go up and then pause for 4 seconds before coming down...

lever1
{
	spawn
	{
	//code would go here that gives the entity some initial settings at start of round.	
	}

	trigger UP
	{
	//CODE TO MAKE LEVER GO UP
	wait 4000
	trigger lever1 down
	}

	trigger DOWN
	{
	//CODE TO MAKE LEVER GO DOWN
	}
}

Quite obvious what's happening here.

gotomarker - ok, now we're getting somewhere. This tells an entity to move to a pat_corner. You would use it like this...

lever1
{
	spawn
	{
	//code would go here that gives the entity some initial settings at start of round.	
	}

	trigger UP
	{
	gotomarker bridge_lever1_uppos 16  //CODE TO MAKE LEVER GO UP
	wait 4000
	trigger lever1 down
	}

	trigger DOWN
	{
	gotomarker bridge_lever1_downpos 16  //CODE TO MAKE LEVER GO DOWN
	}
}

Oh my! This section of code would actually function correctly in your world!!! The code above relates to the script_mover entity - lever1. So whatever movement instructions occur within this code will take effect on the lever1 entity. In this case the lever1 entity will move to the path_corner with the targetname bridge_lever1_uppos. It will wait there for 4 seconds and then move to the path_corner with a targetname bridge_lever1_downpos.

The only addition is the value at the end of the gotomarker command. This number is the speed at which the lever is to move. There are other commands that go with the gotomarker command - these are all listed in the scrtipting documentation that comes with WolfRad.

faceangles - another movement command. This time we can give a value that will tell an entity to rotate to a specific angle. for example:
faceangles 50 0 0 8000 - This tells the entity to rotate to 50 degrees about the x-axis and take 8 seconds to carry out the command. If you later wanted the entity to return to it's old position you would write:
faceangles 0 0 0 8000 - We are telling it to rotate back to 0 degrees. You do not write -50 to get it to go back 50 degrees.

Well, we've very nearly covered all the commands needed. There are many more that may be of use which are covered in the documentation.

Finally we come to 'accum'. You could probably get away without using accum for much of your mapping but if you can get your head round it you'll see it's benefits. Basically accum is a way to store values. So you might want to say:
If the bridge is open set the value of accum to 1. If bridge is closed set value of accum to 0. Then later you may wish to check the brige state so you would check if accum was equal to 1 or 0.

Here's a working example that will be used in our map...

bridge_trigger1
{
 spawn
 {
   accum 1 set 1
 }

 trigger lever1up
 {
   accum 1 abort_if_not_equal 1
   trigger lever1 down
   trigger lever2 down
   accum 1 set 0
   wait 9000
 }

}

When the game starts accum is set to 1 in the 'spawn' section of code. To be precise, 'accum 1' means we want to access an accum storage area that has an ID of '1'. This means you can create multiple accums by giving different id numbers. eg accum 2, accum 17. Then "set 1" sets the value of the accum to 1.

Furthermore, the values stored in accums are specifc to the section of code they reside in (i.e. they have local scope). As you will see, in the section of code named "bridge_trigger2" you can also have an "accum 1" but it is not the same "accum 1" that resides in "bridge_trigger1" - they are entirely different and unrelated.

In the next chunk of code 'trigger lever1up' there is the line "accum 1 abort_if_not_equal 1". It's pretty stright forward - if accum with ID '1' has a value that is not equal to 1 then abort. Abort means stop and exit the code that is currently running - ie the rest of the commands within this section of code will be ignored.

This section of code is saying:
When the game starts set accum 1 with a value 1.
At some point in the game the trigger lever1up will be activated. When this happens check that accum 1 is equal to 1 and if it isn't exit the code. If it is then trigger or activate the code for lever1 starting at the label down and activate the code for lever2 starting at the label down. finally set the value of accum 1 to 0 and pause for 9 sconds.

That's it. You now know all you need to. Or as is more likely you will have to re read everything and see if you can figure out what the hell I'm talking about.

There is one more section. This shows the full script to make the bridge and levers work using all the commands we've encountered.

Conclusion:

Enough with the basic info, move on to Part 3, the final script...