Jump to content

[IV | .NET] Writing .net scripts in C#


Recommended Posts

Making a .netscripthook mod using C#

 

Aims: To give you the basics in the C# programming language, so you can write your own scripts for the .netscript hook.

 

Requirements:

•A C# Devlopment Enviroment (Visual Studio 2005/2008, C# Express Editions 2005/2008). The express editions are free from micrsoft. http://www.microsoft.com/Express/. If you're at a University and the University has registered with MS. Then you can get Studio 2008 Professional for free from MS via the dreamspark system.

- Lastest version of .netscripthook (0.86 at time of writing) -> http://www.gtaforums.com/index.php?showtopic=392325

 

 

Intro

So you want to create your own script for GTA IV, this tutorial will introduce you to the basics of programming in C# andcreating a script for the scripthook. Before you can even begin to write scripts . You need to know the programming basics, and how a scripthook script is set up. We'll shall begin with the basics.

 

 

Programming with C#

 

Programming with C# is relatively easy, its syntax is similar to Java, but once you know the basics, loops, if statments, switches etc you can apply these quite easy to other programming languages. Lets start with Data types.

 

Data types

If you're going to be writing scripts, you're going to need to declare varibles to hold information or data, depending on what you're working with. I'm only going to show you the datatypes that you'll probably be using.

 

 

- int, signed 32bit whole number(ranges from -2,147,483,648 to 2,147,483,647)

- float, signed 32bit floating point number(ranges from ±1.5 × 10−45 to ±3.4 × 1038)

- bool, true/false (0 or 1)

- String, text.

 

 

The above are the datatypes you'll probably use when writing scripts. When to use these should be self explanatory. If you've got a whole number, and you know its always going to remain whole then use an int. If you've got a decimal number (3.14) then use a float datatype. If you use the wrong type then the complier with complain when compling the script.

 

To declare and use these datatypes, is fairly straight foward.

 

 

int i;float f;bool b;string s;

 

 

This will declare the datatypes with their default values. (note that the ; is a end of line terminator, everyline (except for loops and if statments needs to have a ; at the end of it. You can declare and set the varible value at the same time.

 

 

int i = 25;float f = 235.5f;bool b =  false;string s = "Some text here";

 

 

When setting a float value, you need to have a f at the end of the number. This is to designate it as

a float and not a double. Any text for a string varible needs to be enclosed between ""

 

Arrays

Any datatype can be made into an array. An array is basically a collection of that datatype.

 

 

int[] i = new int[]{0, 1, 6, 9, 2};

 

 

That creates an array ints, that can be expanded to include more.

 

 

int[5] i;

 

 

That creates an fixed array of size 5.

 

An item in an array can be accessed by its index number, arrays always start from index 0. So

 

 

i[0] returns 0 first element in the arrayi[3] returns 9 forth element in the array

 

 

These type of arrays do not have any way of counting how many items are in the array, its up to you to keep track of how many are in it.

 

Lists

 

Lists are basically an array, but gives you more control. To use lists within the scripthook, you'll need to add a refence to Systems.Collections.Generic.

 

 

List<int> lInts;lInts = new List<int>();

 

 

That will create a new empty list of ints. To add something to the list, you can use the add method.

 

 

lInts.add(1);lInts.add(5);

 

 

That will add 1 and 5 to the list. You can access a list item, the same as an array.

 

 

lInts[0] is 1;lInts[1] is 5;

 

 

You can remove items from an list by using either remove(item) or removeAt(index). remove will remove an specific item from the list. Whereas removeAt will remove an item at a specifc index.

 

 

lInts.remove(1) //will remove 1 from the listlInts.removeAt(1) //will remove 5 from the list

 

 

Operations on Data types

 

You can carry out various operations on data types (ie add, subtract, devide etc).

 

Addition:

floats, ints and strings can all be added together, providing they are of the same datatype.

 

 

int i = 2; //declare & set i to 2int j = 4; //declare & set j to 4i = i + j; //Add i and J together.float f = 2.0f; //declare & set f to 2.0ffloat j = 2.2f; //declare & set j to 2.2ff = f + j; //add f and j together

 

 

You can combine a operator and the eqauls together. So the addition statements above, become.

 

 

i += j;f += j;

 

 

You can do the above for any operator, add(+) subtract(-), devide(/) and multiply(*).

 

 

int i = 2; //declare & set i to 2int j = 4; //declare & set j to 4i = i * j; //multiply i and J together.float f = 2.0f; //declare & set f to 2.0ffloat j = 2.2f; //declare & set j to 2.2ff = f * j; //devide f and j togetherint i = 2; //declare & set i to 2int j = 4; //declare & set j to 4i = i / j; //devide i and J together.float f = 2.0f; //declare & set f to 2.0ffloat j = 2.2f; //declare & set j to 2.2ff = f / j; //devide f and j togetherint i = 2; //declare & set i to 2int j = 4; //declare & set j to 4i = i - j; //subtract j from ifloat f = 2.0f; //declare & set f to 2.0ffloat j = 2.2f; //declare & set j to 2.2ff = f - j; //subtract j from f

 

 

The String datatype, can only be Added together. This joins the two Strings together(concatenate).

 

 

String s1 = "This is a test string s1";String s2 = "& This is a test string s2";s1 = s1 + s2; //becomes "This is a test string s1& This is a test string s2"

 

 

You can reverse any datatype except for String. By using ! in front of it.

 

 

int i = 2;i = !i; //this will set i to -2;bool b = false;b = !b; //this will set b to true;

 

 

Now you know about some basic datatypes you'll be using, we can now move on to the conditonal statements.

 

Conditional Statements

Conditional statements are statements that can be excuted providing the conditions are met. There are 3 main types of conditional statements.

 

• if statements

• loops

• switch statements

 

Lets start with If statements.

 

IF

If statments can be used to only execute some code, when the condition is met. For example a light. If switch is on, then turn light on, if switch off, turn light off. An if statement is used by the word if and then the condition in brackets. Followed by the code to run enclosed in braces. You can then pecifiy an else condition or just an else, if the condition isn't met.

 

 

bool switch = false;bool lightOn = false;if(switch == true){lightOn = true;} else {lightOn = false;}

 

 

The above statement reads. if the switch is on(set to true), then switch the light on. Otherwise switch the light off. The else statement will execute if the condition isn't met. Can also check if a number is above or below a certain value etc.

 

 

int i = 40;if(i < 35) //i less than 35if(i > 35) //i greater than 35if(i == 35) // i equal to 35if(i <= 35) //i less than or eqal to 35if(i >= 35) //i greater than or equal to 35

 

 

You can combine multiple ifs and if elses.

 

 

int i = 40;if(i < 35){do this;} else if(i > 35){do this} else {do this}

 

 

Lets move on to loops.

 

loops

There are a couple of different types of loops. for, while, do while and for each. Loops will execute a block of code whilst the condition is matched.

 

WHILE.

Loops around until the condition is false. Evaluates the condition at the begining of the loop.

 

 

int i = 20;int a = 0;while(i < 20){a += i;i++;}

 

 

The above will execute while i is less then 20.

 

DO WHILE.

Same as a while loop, except the condition is evaluted at the end of the do cause. So the loop is always run once.

 

 

int i = 20;int a = 0;do{a += i;i++;} while(i < 20)

 

 

FOR.

For loops, can be set to run a number of times, and until a certain point.

 

 

int a = 0;for(int i = 0; i < 20; i++){a += i;}

 

 

FOR EACH.

Used to iterate through an array or collection of objects.

 

 

int a = 0;int[] i = new int[]{1, 2, 3, 4, 5, 6}foreach(int b in i){a += b;}

 

Thats loops, used to excute a block of code while the condition is met. Lets move on to switch statements.

 

switch

Switch statements are basically a block of if statements. Each case within a switch can be considered an if statement.

 

 

switch(i){case 0://execute if i is 0do somethingbreak;case 1://execute if i is 1break;case 25://execute if i is 25case < 56://execute if i less than 56break;default://execute if none of the above is metbreak;}

 

Now thats pretty much the basics you'll need to know for C#. If you haven't programmed before, or even if you have the basics. I'd strongly advise people read a C# tutorial. http://www.softsteel.co.uk/tutorials/cSharp/ But for now, the above is all you'll need for this tutorial.

 

Now we're going to move on to the .netscripthook, and how a script is structured. I'm only going to go through some of the baiscs / features that the scripthook has. If you want more examples then you can look at the example scripts that come with the scripthook.

 

Setting up the IDE for .net scripthook.

 

Before you can start programming a .net scripthook. You'll need to set up a project for the script you're making, and you'll need add refernces to the hook. So you can access its features.

 

I'll use both Microsoft Visual Studio 2008 and Microsoft Visual C# Express 2005 as examples. Visual Studio 2008 will be similar to a 2008 Express Edition, and Express 2005 will be similar to Visual Studio 2005. (I cannot use C# Express 2008 since I need Express 2005 for University.)

 

Right lets setup a project and set up the project for the scripthook. Fire up your development enviroment. You'll see that both express editions 2005 and visual studio 2008 look very similar.

 

http://www.shadowsrealm.co.uk/dev/gtaftuts/dotnet/1.jpg

 

We need to create a project. So under the recent projects box. Click the Create project link.

 

http://www.shadowsrealm.co.uk/dev/gtaftuts/dotnet/2.jpg

 

Note: Since some actions will differ between the two IDEs, I'll refer to Visual Studio 2008 as VS2008, and C# Express 2005 as C#E2005.

 

We need to set the project for the correct type, so it produces a dll file.

 

http://www.shadowsrealm.co.uk/dev/gtaftuts/dotnet/3.jpg

 

VS2008 - In the projects type box, we need to select a C# project, so expand other languages and choose Visual C#. In the templates window choose Class Library, and give the project a name and click OK.

 

C#E2005 - Ensure visual C# is selected in the project types, and choose Class Library in the templates

window, and give it a name and click OK.

 

Now you should be faced with a blank script with some using statements and a constructor.

 

http://www.shadowsrealm.co.uk/dev/gtaftuts/dotnet/4.jpg

 

We need to add using statements and references for the .netscripthook. In the solution explorer, right click References and choose add reference. On the references window. choose Browse, and browse to where you put the .netscripthook. In the folder scripts\For developers\bin\ should be the file ScriptHookDotNet.dll. Choose this file to add the reference. The references folder should of expanded

to show that the scripthook reference has been added. We also need to add the System.Drawing and System.Windows.Forms refrences. These will be under the .net tab.

 

http://www.shadowsrealm.co.uk/dev/gtaftuts/dotnet/5.jpg

 

We now need to add the using statements to the top of the script, so that when we want to use anything from the scripthook. We don't have to put GTA in front of it. We also need the add a using statement for System.Windows.Forms Put: At the bottom of the last using item. put

 

 

using System.Windows.Forms;using GTA;

 

 

So you should have:

 

 

VS2008 -

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Windows.Forms;

using GTA;

 

C#E2005 -

using System;

using System.Collections.Generic;

using System.Text;

using System.Windows.Forms;

using GTA;

 

 

http://www.shadowsrealm.co.uk/dev/gtaftuts/dotnet/6.jpg

 

Before we can start to program a script, we need to set the scriptfile up correctly, so that it inherits the methods from the scripthook. Where the class constructor is.

 

 

Public class Class1.

 

 

Change Class1 to a much better name, and after the name put : Script . So you should now have.

 

 

public class tutScriptVS : Script   {   }

 

 

Before we dive in and start writing scripts for the scripthook. We need to know a few basics about the structure of a .netscripthook. As with any script it needs a constructor. This is where you can set varibles, arrays etc and bind events.The constructor is basically the classes name with no return type. So the constructor for my script is:

 

 

public tutScriptVS(){}

 

 

All the constructors code is enclosed within the braces { }.The constructor is only ran once at the script start up. (as soon as you've loaded the game). So if you want something to run all the time, it needs putting into the scripthooks tick object. To do this you need to bind a method to the tick event. Since we have our script inheriting from the Script object. We can access any properies or methods by using this.

 

 

This.Interval = 5000;this.Tick += new EventHandler(tickEvent);

 

 

The above sets the scripts tick handler, to the tickEvent method. (that we have to create) And sets the Interval to 5000miliseconds. So every 5 seconds, the tick event is run. So any code within the tickEvent method is ran.

 

When creating a method, it needs a access type (public or private) and a return type. For the tickEvent its void. Meaning it doesn't return anything. And in the parameters for the tickEvent, you need a object sender, and EventArgs e.

 

 

public void tickEvent(object sender, EventArgs e){}

 

 

Thats all well, but it's pretty much useless for user interaction. The scripthook comes with a key press handler, so we can have the user interact with our script. Its the same as creating a tick handler, except we use GTA.KeyEventHandler, and set it to the KeyDown method.

 

 

this.KeyDown += new GTA.KeyEventHandler(kdHandler);public void kdHandler(object sender, GTA.KeyEventsArgs e){}

 

 

You can then check for a key press by using an if statement. the KeyEventsArg e, obtains what keys have been pressed. So to check for a press on the with the E key on its own you can use e.Key. Or e.keyWithModifiers to check for a key press using either ctrl, alt or shift. Or specifiy the individual modifier key. System.Windows.Forms.Keys is a list of all the keys in the system. Since we added the using statement for System.Windows.Forms, you can access it by just using Keys.

 

 

//check for single E key pressif(Keys.E == e.Key)//check for e with any modifierif(Keys.E == e.KeyWithModifiers)//check for key press with alt, shift or controlif(Keys.E == e.Control)f(Keys.E == e.Alt)f(Keys.E == e.Shift)

 

 

Well now we can have a script that runs every x seconds and can detect key presses. What about drawing to the screen? Well we can only draw Text and Rectangles to the screen using the PerFrameDrawing method.

 

If you wish to draw a quick text message to the screen, you can use the Game.DisplayText("text here") method. This will show a quick message in the top left corner of the screen.

 

As with the Tick and KeyDown events, the perFrameDrawing needs to be registered to a method.

 

 

this.PerFrameDrawing += new GraphicsEventHandler(gfxDraw)public void gfxDraw(object sender, GraphicsEventArgs e){}

 

 

The methods used for drawing to the screen, are in e.graphics. Lets draw some simple text to the screen. using the e.graphics.DrawText(). We'll see it has 4 possible ways of being called.

 

 

//simply draws a string to the screen at the position givene.graphics.DrawText(float x, float y, string text)//same as above, but the size/colour can be controled by the font objecte.graphics.DrawText(float x, float y, string text, font f)//same as the first one, but can specifiy the colore.graphics.DrawText(float x, float y, string text, color c)//all of the abovee.graphics.DrawText(float x, float y, string text, colorc, font f)

 

 

The X and Y values are float values, and for the screen range from 0 to 1. So X = 0.5f, and Y = 0.5f would draw something in the center of the screen.

 

 

e.graphics.DrawText(0.5f, 0.5f,"Test Text");

 

 

We can change the colour of the text by using the 3rd one, and adding a color value to the end of the call.

 

 

e.graphics.DrawText(0.5f, 0.5f, "Test Text", Color.LammyOrange);

 

 

If we really wanted to customise the text, we could use the second one, and create a font object to use within it.

 

 

Font f = new Font();f.Color = Color.White;f.Height = 0.25f;e.graphics.DrawText(0.5f, 0.5f, "Test Text", f)

 

 

You can also use the graphics method to draw a rectangle to the screen. There are only two options for e.graphics.DrawRectangle().

 

 

DrawRectangle(RectangleF rect, System.Drawing.Color Color);DrawRectangle(float CenterX, float CenterY, float Width, float Height, System.Drawing.Color Color);

 

 

You'll see that the first one takes a RectangleF as positioning and size. The second one takes the values directly into it. There are differences with the way these two work.The first using the RectangleF will start at the coordinates for the rectangle and draw left and down. Where as the second one, will draw from the center. up, down, left and right.

 

 

X ---->

Y

|

|

V

 

 

      ^

      |

<--XY-->

      |

      V

 

 

So:

 

 

//will draw a rectangle in the centre of the screen, 0.2 high and 0.2 wide, in red.e.graphics.DrawRectangle(0.5f, 0.5f, 0.2f, 0.2f, Color.Red)//Same as above, but rather then drawing from the center, it starts at 0.5f and draws down and left.System.Drawing.RectangleF rf = new System.Drawing.RectangleF(0.5f, 0.5f, 0.2f, 0.2f);e.graphics.DrawRectangle(rf, Color.CherryRed);

 

 

Right, so we have a Tick, KeyDown and Drawing. We're ready to start writing scripts. Lets write a script, that will every 20 seconds, set the players health/amour to max, and if in a vehicle, repair/wash the car. And on a key press, spawn a helicopter.

 

So in our prepared script, we need a constructor that will setup the Tick, and keyDown events.

 

 

public testScriptVS(){//set intervalInterval = 20000;//bind tick eventthis.Tick += new EventHandler(testTick);//bind keydown event.this.KeyDown += new GTA.KeyEventHandler(testKeyDown);}

 

 

Right thats our constructor done, it sets the interval and binds the methods. Now we need the tick and key down methods.

 

 

//tick method, ran every 20 secspublic void testTick(object sender, EventArgs e){}//key down handlerpublic void testKeyDown(object sender, GTA.KeyEventArgs e){}

 

 

Now your script should be looking something like this.

 

 

using System;using System.Collections.Generic;using System.Linq;using System.Text;using GTA;namespace tutorialScriptVS{   public class tutScriptVS : Script   {       public tutScriptVS()       {           //set interval           Interval = 20000;           //bind tick event           this.Tick += new EventHandler(testTick);           //bind keydown event.           this.KeyDown += new GTA.KeyEventHandler(testKeyDown);       }           //tick method, ran every 20 secs           public void testTick(object sender, EventArgs e)           {           }           //key down handler           public void testKeyDown(object sender, GTA.KeyEventArgs e)           {           }          }}

 

 

Next up is to set the players health and amour to their max, which is 1000. We can access the player using Player.Character.

 

 

//set health and amourPlayer.Character.Health = 1000;Player.Character.Armor = 1000;

 

 

Put that inside of the tick method, so now every 20 seconds. The players health and armor is being set to 1000 But we still need to repair/wash the players vehicle. The vehicle can be accessed by using Player.Character.CurrentVehicle. But if we try and access this and the player isn't in a vehicle then the script will crash. We can use the method Player.Character.isInVehicle to test if the player is in a vehicle.

 

 

if (Player.Character.isInVehicle()){//repair vehiclePlayer.Character.CurrentVehicle.Repair();//wash vehiclePlayer.Character.CurrentVehicle.Wash();}

 

 

So now we have the players health / amour being set to max, and the players car being repaired and washed. Lets allow the player to spawn a helicopter on key press. In the key down method. We can spawn a vehicle by using the World.CreateVehicle method.

 

 

[code[
World.CreateVehicle(Model Model, Vector3 Position);
[/code]

The model can be created by using its name. ie "ANNIHILATOR". We can use the Around funciton of the position to get a random position within the players position.

if(Keys.Q == e.Key){//get position to put vehicleVector3 vehPos = Player.Character.Position.Around(10.0f);//create vehicleWorld.CreateVehicle(new Model("ANNIHILATOR"), vehPos);}

 

 

Whoo, your script should be looking something like this.

 

 

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Windows.Forms;using GTA;namespace tutorialScriptVS{   public class tutScriptVS : Script   {       public tutScriptVS()       {           //set interval           Interval = 20000;           //bind tick event           this.Tick += new EventHandler(testTick);           //bind keydown event.           this.KeyDown += new GTA.KeyEventHandler(testKeyDown);       }           //tick method, ran every 20 secs           public void testTick(object sender, EventArgs e)           {               //set health and amour               Player.Character.Health = 1000;               Player.Character.Armor= 1000;               if (Player.Character.isInVehicle())               {                   //repair                   Player.Character.CurrentVehicle.Repair();                   //wash                   Player.Character.CurrentVehicle.Wash();               }           }           //key down handler           public void testKeyDown(object sender, GTA.KeyEventArgs e)           {               if (Keys.Q == e.Key)               {                   //get position to put vehicle                   Vector3 vehPos = Player.Character.Position.Around(10.0f);                   //create vehicle                   World.CreateVehicle(new Model("ANNIHILATOR"), vehPos);               }           }          }}

 

 

Right, lets set a few project properties, so that when the mod compiles. Its already set the correct file name. In the solution explorer, right click your project and choose properties.

 

http://www.shadowsrealm.co.uk/dev/gtaftuts/dotnet/7.jpg

 

If we change the Assembly name to have .net on the end of it. The resulting file will end with .net.dll Which is the correct naming for a .net c# script. Clicking on Assembly Information, we can change the title, description and set the version number of the script.

 

http://www.shadowsrealm.co.uk/dev/gtaftuts/dotnet/8.jpg

 

Right now we've set them. I think we're ready to compile and test our script.

 

 

VS2008 - press F7 to build, in the output window it should say:

========== Build: 1 succeeded or up-to-date, 0 failed, 0 skipped ==========

 

 

If it has an error, and the error box isn't showing. Go to View -> Other Windows -> Error List

 

 

C#E2005 - Press F6 to build, in the output box this should be shown.

========== Build: 1 succeeded or up-to-date, 0 failed, 0 skipped ==========

 

 

Deal with any errors, and when it compiles sucessfully. Copy the .net.dll file from the build folder. Default is the project folder debug\bin. To your gta folder /scripts. Now when you run the game, your health and amour should be set every 20 seconds, and when you're in a vehicle it should be repaired / washed every 20 seconds. And pressing Q should spawn an an helicopter.

 

Congratulations you've just sucessfully made your first script for the .net scripthook. You can stop reading here and go play around with it some more. Or you can continue, and I'll explain some more features that can be put into scripts such as catching called mobile numbers, console commands etc.

 

Right lets move on, you've got a pretty simple script that heals the player every 20 secs, and allows the player to spawn a helicopter. It's all well and good having a set Interval, but if we want to change it we have to recompile the script everytime. How about we have a ini file that has the time for us? That we can then access and set the time from that.

 

Luckily the scripthook, has a way of reading from a ini file. And already has a script settings propery. Lets start with making the ini file. The ini file must have the filename as the script. So if you're scripts called tutorialScripVS.net.dll then the ini must have the name tutorialScriptVS.net.ini

 

 

[sETTINGS]INTERVAL = 10000LOADFUEL = Control, W

 

 

Thats all that you need, the Key INTERVAL is in the SETTINGS catergory. Keeping to this format keeps the ini file easy to read when it gets cluttered. Now to access this in the scripthook. We use the Settings property. Just replace the line: Interval = 20000; with

 

 

Interval = Settings.GetValueInteger("INTERVAL", "SETTINGS", 10000);

 

 

Where the 10000 is the default value if it cannot load from the ini file. So now we've got a script that reads from an ini file. So we no longer have to recompile if we wish to change the time. All we have to do is change the time in the ini file, save it. Then use the console to reload the scripts.

 

We can also use the ini file to set the Key to look for. Using:

 

 

Settings.GetValueKey("KEYPRESS", "SETTINGS", Keys.Q);

 

 

Will allow us to load in a key type to check against. We need to create a Key varible above the constructor, to hold our keyPress key.

 

 

Keys keyP;

 

 

Then in the constructor we can set keyP to the settings value.

 

 

KeyP = Settings.GetValueKey("KEYPRESS", "SETTINGS", Keys.Q);

 

 

So now we can control the keyPress and the Interval time from the ini file. But we cannot save to the ini file. That is coming in a later version of the scripthook. Lets move on to catching mobile numbers. The phone feature in IV is pretty cool, but using the scripthook we can catch the numbers dailed. So we could dail "HEL 555 0100", and spawn a FIB car.

 

To do this, we have to bind the number to a method that is called when the number is dailed. We can use the BindPhoneNumber function. We need to do this in the constructor, as we only need to bind the number once.

 

 

BindPhoneNumber("FIB 555 0100", new PhoneDialDelegate(callHandle));

 

 

Now we can create a method, add some spawn code to it.

 

 

public void callHandle(){//get position on street near playerVector3 vehPos = World.GetNextPositionOnStreet(Player.Character.Position.Around(10.0f));//create vehicleWorld.CreateVehicle(new Model("FIB"), vehPos);}

 

 

You'll notice I've used a method called GetNextPositionOnStreet. This method will get a position, so the vehicle is positioned on the street correctly. Now when you dial FIB 555 0100 on the phone, you'll get a FIB car. But you won't know its been spawned until you see it. Lets add a simple message that says "Vehicle Spawned" In the callHandle method add the line:

 

 

Game.DisplayText("Vehicle Spawned");

 

 

Your code at this point should look something like this:

 

 

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Windows.Forms;using GTA;namespace tutorialScriptVS{   public class tutScriptVS : Script   {       public tutScriptVS()       {           //set interval           Interval = Settings.GetValueInteger("INTERVAL", "SETTINGS", 10000);           //bind tick event           this.Tick += new EventHandler(testTick);           //bind keydown event.           this.KeyDown += new GTA.KeyEventHandler(testKeyDown);           //bind phone           BindPhoneNumber("FIB 555 0100", new PhoneDialDelegate(callHandle));       }           //tick method, ran every 20 secs           public void testTick(object sender, EventArgs e)           {               //set health and amour               Player.Character.Health = 1000;               Player.Character.Armor= 1000;               if (Player.Character.isInVehicle())               {                   //repair                   Player.Character.CurrentVehicle.Repair();                   //wash                   Player.Character.CurrentVehicle.Wash();                                  }           }           //key down handler           public void testKeyDown(object sender, GTA.KeyEventArgs e)           {               if (Keys.Q == e.Key)               {                   //get position to put vehicle                   Vector3 vehPos = Player.Character.Position.Around(10.0f);                                      //create vehicle                   World.CreateVehicle(new Model("ANNIHILATOR"), vehPos);               }           }           public void callHandle()           {               //get position on street near player               Vector3 vehPos = World.GetNextPositionOnStreet(Player.Character.Position.Around(10.0f));               //create vehicle               World.CreateVehicle(new Model("FIB"), vehPos);           }          }}

 

 

Its looking good so far, we're reading from an ini file to set an interval and the key press. And we can now phone a number to get a FIB car. We can also do the same and spawn a police by using the console. We can bind a command for the console. Using the BindConsoleCommand method. Again in the constructor we need to put:

 

 

BindConsoleMethod("spawn polcar", new ConsoleCommandDelegate(consoleHandle));

 

 

And we can then add in the method and spawn code.

 

 

public void consoleHandle()           {               //get position on street near player               Vector3 vehPos = World.GetNextPositionOnStreet(Player.Character.Position.Around(10.0f));               //create vehicle               World.CreateVehicle(new Model("POLICE"), vehPos);           }

 

 

And the finished code.

 

 

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Windows.Forms;using GTA;namespace tutorialScriptVS{   public class tutScriptVS : Script   {       public tutScriptVS()       {           //set interval           Interval = Settings.GetValueInteger("INTERVAL", "SETTINGS", 10000);           //bind tick event           this.Tick += new EventHandler(testTick);           //bind keydown event.           this.KeyDown += new GTA.KeyEventHandler(testKeyDown);           //bind phone           BindPhoneNumber("FIB 555 0100", new PhoneDialDelegate(callHandle));       }           //tick method, ran every 20 secs           public void testTick(object sender, EventArgs e)           {               //set health and amour               Player.Character.Health = 1000;               Player.Character.Armor= 1000;               if (Player.Character.isInVehicle())               {                   //repair                   Player.Character.CurrentVehicle.Repair();                   //wash                   Player.Character.CurrentVehicle.Wash();                                  }           }           //key down handler           public void testKeyDown(object sender, GTA.KeyEventArgs e)           {               if (Keys.Q == e.Key)               {                   //get position to put vehicle                   Vector3 vehPos = Player.Character.Position.Around(10.0f);                                      //create vehicle                   World.CreateVehicle(new Model("ANNIHILATOR"), vehPos);               }           }           public void callHandle()           {               //get position on street near player               Vector3 vehPos = World.GetNextPositionOnStreet(Player.Character.Position.Around(10.0f));               //create vehicle               World.CreateVehicle(new Model("FIB"), vehPos);           }           public void consoleHandle()           {               //get position on street near player               Vector3 vehPos = World.GetNextPositionOnStreet(Player.Character.Position.Around(10.0f));               //create vehicle               World.CreateVehicle(new Model("POLICE"), vehPos);           }          }}

 

 

And thats all for time being, I'll try and keep it update to date, and hopefully add some more guides to it. I hope this helps anyone who wishes to start writing .net scripts for IV. If there are any errors within this, please let me know.

 

My advice for anyone writing scripts, it just to play around with the properties and methods avaible to you. Also use the Class view option, its very useful for discovering what a reference can do.

Link to comment
https://gtaforums.com/topic/401577-iv-net-writing-net-scripts-in-c/
Share on other sites

CaptainDingo

I appreciate all the time you took to do this, but unfortunately this is worthless for people like me who don't know C# already. confused.gif

 

It's probably hard for someone who already knows it all, but from my perspective, this is nearly impossible. I can read it five times over and still not understand it, at all. I mean, I understand variables, strings, variable and string operations, but I don't understand the structure encased around them one bit.

 

It's a shame because I have a logical mind for programming, but nobody has come along yet who is really capable of teaching me how to actually program successfully. Like what's a method? What's "public class tutScriptVS : Script" do? What is "(object sender, GTA.KeyEventsArgs e)" all this stuff for? What does any of it mean? It looks like gibberish to me. Arg is the sound I make when I take a huge crap, and that's all I know. notify.gif

 

It's all the little things like this that coders take for granted when they're trying to teach and gloss over or ignore them, but that seriously make me feel confused and unable to learn any of this.

 

I appreciate all the time you took to do this, but unfortunately this is worthless for people like me who don't know C# already. confused.gif

 

It's probably hard for someone who already knows it all, but from my perspective, this is nearly impossible. I can read it five times over and still not understand it, at all. I mean, I understand variables, strings, variable and string operations, but I don't understand the structure encased around them one bit.

 

It's a shame because I have a logical mind for programming, but nobody has come along yet who is really capable of teaching me how to actually program successfully. Like what's a method? What's "public class tutScriptVS : Script" do? What is "(object sender, GTA.KeyEventsArgs e)" all this stuff for? What does any of it mean? It looks like gibberish to me. Arg is the sound I make when I take a huge crap, and that's all I know. notify.gif

 

It's all the little things like this that coders take for granted when they're trying to teach and gloss over or ignore them, but that seriously make me feel confused and unable to learn any of this.

In that case I'll add a few extra bits in, in the coming days but for now

 

what's a method?

- A method is basically a block of code, that can be reused.

 

What's "public class tutScriptVS : Script" do?

- Basically it defines a class, something that can be reused again and again. That code above, it defining a class that is public(accessible to all) and with a name of tutScriptVS, and inherits all the properties and methods from the Script class.

 

What is "(object sender, GTA.KeyEventsArgs e)

- Its a method call, where you're passing in a datatype of object called sender, and a KeyEventsArg called e. I'm assuming the sender object, is the window or method that called this method. And the KeyEventsArg is basically a class, and within that class will be methods/properties relating to Key Events in GTA.

 

Any other questions and I'll try my best to answer them.

CaptainDingo

Thanks.

 

Also, how did you find out things like Player.Character.Health, Player.Character.Current.Vehicle, and um... just other in-game stuff like that? Is there some list of these game references we can use so we can know what they all are for altering?

 

So like, how can I make it so something happens when the player dies?

 

Edit: Nevermind, figured most of it out.

 

However, it seems I can't find out how something happens if Niko is busted rather than dead. There's a player.character.isdead but there's no player.character.busted/arrested or equivalent.

Edited by CaptainDingo
Thanks.

 

Also, how did you find out things like Player.Character.Health, Player.Character.Current.Vehicle, and um... just other in-game stuff like that? Is there some list of these game references we can use so we can know what they all are for altering?

 

So like, how can I make it so something happens when the player dies?

 

Edit: Nevermind, figured most of it out.

 

However, it seems I can't find out how something happens if Niko is busted rather than dead. There's a player.character.isdead but there's no player.character.busted/arrested or equivalent.

You just have to play around with the scripthook. Using the class reference view of Visual studio, you can see what properties and methods the scripthook has.

 

Some things aren't put into the scripthook yet, so at the moment there is no way of dertermining if they are arrested.

 

You can however use a native call, if you can find the native needed and work out its parameters. http://www.gtamodding.com/index.php?title=...ative_functions Has a list of native functions. And there is one called IS_PLAYER_BEING_ARRESTED

 

Now I don't know the parameters for this, but all I assume is it will use one bool value to send the result to. To use a native you can use the GTA.Native.Function.Call("NATIVE_FUNCTION_HERE", params) method.

 

 

bool arr = false;GTA.Native.Function.Call("IS_PLAYER_BEING_ARRESTED", arr);

 

 

Now I've no idea if the above works, you've just got to play around with the parameters or search, although nothing came up for that one.

the hubster

Seeing as this tutorial looks like it is for those new to Visual Studio, I think it is worth mentioning the object browser. You wont be able to get very far in writing scripts if you do not use the object browser to find all the classes/properties/functions you need relating to GTA. Apart from that, nice tutorial, I'm sure allot of people will find it very useful. (Image)

 

 

Hm. You noted that we can't save to a .ini file, but in your Petrol Mod, you do save the last car's fuel value after leaving the game. How'd you do that?

 

He uses the windows function WritePrivateProfileString

Edited by the hubster

 

However, it seems I can't find out how something happens if Niko is busted rather than dead. There's a player.character.isdead but there's no player.character.busted/arrested or equivalent.

Another way you could check if the player got busted, is by using the GetIntegerStatistic method, very easy and I know for a fact it works (in SP that is, I doubt it works in MP).

 

 

    Private timesBusted As Integer = Game.GetIntegerStatistic(IntegerStatistic.TIMES_BUSTED)   Private Sub ssp_Tick(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Tick       If Game.GetIntegerStatistic(IntegerStatistic.TIMES_BUSTED) > timesBusted Then           timesBusted = Game.GetIntegerStatistic(IntegerStatistic.TIMES_BUSTED)           ' do the busted code here       End If   End Sub

 

 

Of course, this example is in VB but can easily be converted to C# from developerfusion.com. As with all other automatic conversion tools, it's far from perfect but it works for the most part. Just remove Handles Me.Tick, otherwise it will throw an error.

http://www.developerfusion.com/tools/convert/vb-to-csharp/

http://www.developerfusion.com/tools/convert/csharp-to-vb/

I can't relly get it to work. i get errors in:

 

 

            [color=red]this.Tick[/color] += new EventHandler(testTick);[color=red]this.KeyDown [/color]+= new KeyEventHandler(keyDown);

 

 

my complete code is:

 

 

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Windows.Forms;using GTA;namespace Test_script{   public class Test : Script   {       public Test()       {           this.Interval = 100;           this.Tick += new EventHandler(testTick);           this.KeyDown += new KeyEventHandler(keyDown);       }       public void testTick (object sender, EventArgs e)       {           if (Player.Character.isDead)           {               Game.DisplayText("Wasted");           }       }       public void keyDown (object sender, KeyEventArgs e)       {           if (Player.Character.isInVehicle())           {               Game.DisplayText("Drive");           }           else           {               Game.DisplayText("RUN");           }       }   }}

 

 

i can't compile due to this. confused.gif

  • 1 year later...

Is there someone who could please give me a short, clean example of a script which just gets the speed of the car you sit in and displays it (no special things, just like upper left corner digits, no eye candy).

I cant find any scripts to peep into for learning purposes, so if someone is kind enough.. thanks a lot. Basically I just need a full frame and getting a keypress + working out a handler to get the speed and compute it, so I can see how it should be done and work with it. That tons of .dll/.asi Speedos arent any help for this.

If you use the above tutorial, which shows you how to use key presses and display stuff on the screen, that's the starting framework, then all you need to do is grab the current vehicle, and grab the speed from it.

 

 

//check if we are actually in a vehicleif(Player.Character.isInVehicle()){float speed = Player.Character.CurrentVehicle.Velocity;}

 

 

or something along those lines.

  • 2 months later...

I was going to ask how this was done, but I decided to do a bit of research and thought I'd post my findings. Please correct me if I'm wrong, because I haven't had a chance to test this.

 

This is how you would set information to a .ini file. I'm using the ini file format from the original tutorial for continuity:

 

Settings.SetValue("INTERVAL", "SETTINGS", [VALUE]);

 

 

where [VALUE] is the value you are trying to set. So let's say you have an integer with a set amount, and you want to write this amount into your ini file.

 

 

int i = 10000;Settings.SetValue("INTERVAL", "SETTINGS", i);

 

 

 

EDIT: Sorry to dig up a few month old post, but I thought if I can help some green scripters learn how to make the next greatest mod, it would be worth it, and it would also be nice to continue this tutorial so we can all learn how to create better scripts.

Edited by Gokaic
  • 8 months later...
  • 9 months later...

Hey friend! Do you know how to spawn attacking peds and, also, bodyguards? I was trying to do it through the Ped.Tasks (building a sequence) but it is not working. I'm also trying to detect when some mobs are dead, but, it seems to be not working properly. Something like this:

 

Ped ped;

ped = World.CreatePed(Player.Character.Position.Around(5.0f));

 

// code code code

 

if(ped.isDead)

// code code code

  • 3 weeks later...
  • 1 month later...

why does this not work when i try BindPhoneNumber? I place this.BindPhoneNumber in script constructor and create my method below the constructor

 

 

using System;using System.Windows.Forms;using GTA;namespace GTA{   public class GTA : Script   {       public GTA()       {           this.BindPhoneNumber("1234567890", new PhoneDialDelegate(WrongNumber));       }       private void WrongNumber()       {           Game.DisplayText("Wrong Number Bitch");       }   }}

 

 

i dial 1234567890 on phone but no method is called and i just get a busy signal, no text is displayed...thanks!!!

 

i also tried multiple strings for phone number like "777 400" or "1111" or "1111111111" and nothing confused.gif

Edited by jitsuin
  • 3 months later...

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • 0 User Currently Viewing
    0 members, 0 Anonymous, 0 Guests

×
×
  • Create New...

Important Information

By using GTAForums.com, you agree to our Terms of Use and Privacy Policy.