All pastes #407748 Raw Edit

tutorial 1

public text v1 · immutable
#407748 ·published 2007-03-24 09:06 UTC
rendered paste body
New scripting tutorials

Introduction/Part 1

Introduction:

In this series of tutorials we are going to take you through the process of creating a game mode, from the very basics of populating the world (placing people/vehicles/pickups etc) to more advanced features like streaming checkpoints and user saving and even beyond, to show you a number of features and methods you can optionally include.

Every issue will take you through a small part of your mode, building on the code created last time to eventually create something like the famous LVDM~MG (the mode running on Littlewhiteys server) but with cleaner, faster and more flexible code (to teach good coding practices) (note: this is not a slur against the creator of that mode as it has been built up on top of other modes, using practices which have since been deprecated (better versions have been developed) and it was designed for one thing only, we are attempting to create more portable, generic code to demonstrate ideas).

Part 1:

In this issue we will be looking at getting a basic death match going, with a few vehicles, classes and pickups and introduce you to a few known issues with the basic ‘new’ script.

Firstly open pawno (or your editor of choice, however you should note that this tutorial as written with pawno, as the default and standard, in mind and thus some things may be different) and click new.  This brings up the text in the file ‘new.pwn’ in your pawno directory as a start point to your mode.  Now press F5, you will be prompted to save your mode, do so and click ok, a dialogue box should then appear saying something similar to:

Pawn compiler 3.2.3664	 	 	Copyright (c) 1997-2006, ITB CompuPhase

(versions and dates may be different)

The text may take a while to come up as the code is compiled however it should be almost instant in the code you have so far (the delay only really starts becoming noticeable when you get into the thousands of lines, although there are other factors).  Now you need to go to where you saved the code in your file browser and select the “<filename>.amx” file (where <filename> is what you saved the .pwn (which should also be present) as).  If you saved this in “<server>/gamemodes“ (where <server> is the directory with your SA:MP server in) you don’t need to do anything more as this is where the .amx files need to be for the server to see them, otherwise you need to copy it into this directory.

Now we need to run our mode, the easiest way to do this is to run the server and when everything is loaded type:

changemode <filename>

(note the lack of extension) and press enter, this should, if you’ve done everything correctly, pop up a piece of text after 12 seconds (the server mode reload time) saying:

GameModeInit()

----------------------------------
  This is a blank GameModeScript
----------------------------------

If you connect to your server now (either by clicking “Connect localhost” in samp_debug,exe if your server is running on port 7777 (configured in server.cfg) or by adding 127.0.0.1:<port> (where <port> is the port you’ve set in server.cfg) as a favourite in the server browser and connecting to that normally) you won’t see a lot as not a lot is happening.  You will notice a few things appear in the server window (in real time if you‘re lucky enough to have two screens), but ingame you will only see a few hands until you press shift to spawn when there still won’t be a lot to do.

Before we get modifying the mode itself we’re going to make a few changes to the default file.

Firstly we need to edit some callbacks.  Callbacks are public functions (i.e. functions which the server itself can see and call, rather than just functions you can only call from within the script), and they are called when certain events happen (easily identifiable by their name).  When a player connects to the server OnPlayerConnect is called (all SA:MP functions and callbacks are named to be easily identifiable so you know what they’re doing), when a player spawns OnPlayerSpawn is called.  Guess what’s called (by looking at the callbacks in your file) what is called when a player enters a command.

Firstly go through every callback and remove the printf or print line in it (note: there are prints in main() but this isn’t a callback it’s a special function called the “main” function (for some obscure reason :p) however, despite what it’s name implies it is almost never used but is required to be in the script, so just leave it for now).  Now you should have functions looking something like this (OnPlayerConnect example):

public OnPlayerConnect(playerid)
{
	return 1;
}

The return lines are important (not all are, players connect regarless of what you return from OnPlayerConnect however other returns are important and will be explained later), so leave them.  The {}s are also important as everything between those two is in the function (to make it easier to tell what’s in and what isn’t indentation is used, this will also be explained later).  For more information on general functions, not SA:MP mode coding, refer to pawn-lang.pdf in your pawno folder (this is a VERY good resource and it is highly recommended you always have it open for reference and reading (not for reading cover to cover - that’s just silly)).

Now change:

public OnPlayerText(playerid)

To:

public OnPlayerText(playerid, text[])

This is the only callback who’s parameters you can change, and that’s just because they’re wrong in the first place.  There are also a couple of missing callbacks which need adding:

public OnPlayerRequestSpawn(playerid)
{
	return 1;
}

public OnPlayerPrivmsg(playerid, senderid, text[])
{
	return 1;
}

The first is called when you press shift, the second when you get a private message (“/pm <id> <text>“).  You also need to remove the “/mycommand” part of OnPlayerCommandText (everything from the “if” to it’s closing brace - recognisable by it’s indentation being at the same level as the if).  This should now look like this:

public OnPlayerCommandText(playerid, cmdtext[])
{
	return 0;
}

Finally you can if you want remove the OnPlayerInfoChange callback as it does nothing.  It is also advisable to save this and copy it over the old “new.pwn” in your pawno directory to save repeating this every time you start a new mode.

Now that all that’s out the way we can start modifying the mode itself.

First we’re going to add a few different characters for you to choose from and set their starting positions (where you spawn) and starting weapons.  These things are all accomplished by one function - AddPlayerClass and can be easily done from debug mode.  Start samp_debug.exe and click “Launch Debug”, when SA loads you will appear as CJ in the middle of the night near the Vinewood sign - try not to die as if you do you won’t be able to get in any vehicles.  Using F11 and F12 change your skin until you get a character you want to appear in your mode, walk to where you want them to spawn and type:

/save my first character

The text after the “/save” can be anything and will not affect the code at all as it’s in comments (see pawn-lang.pdf for more information on comments).  Repeat this as many times as you like with as many skins and positions as you like, omitting or changing the comment text if you like.  Once you’re happy exit and go to your SA:MP directory (usually your SA directory as well).  There should be a file called savedpositions.txt there, this contains all the data you just got in AddPlayerClass format (if the file is not there you need to make sure you have permission to write to the folder).  Copy these lines and paste them in the OnGameModeInit callback of your code, between the {}s and above the return, also be sure to indent them using tab to the same level as the return line (you may also want to remove the existing AddPlayerClass line).  Now if you go in game you will have a number of people to choose from (although you still can‘t see them, but that‘s a bit later).  The last six numbers of those lines are the weapons and ammo to spawn with (obviously there are currently no weapons) the format it:

weapon 1, ammo 1, weapon 2, ammo 2, weapon 3, ammo3

A list of weapon numbers can be found in the first post of the general reference topic in the scripting forum, the ammo can be whatever you want (must be at least 1 on melee weapons due to an SA feature).  Your callback should now look something like this (you may notice I changed the game mode text, this can be anything you want and is what appears in the mode column in the server browser for your server):


public OnGameModeInit()
{
	SetGameModeText("Deathmatch");
	AddPlayerClass(1, -1643.2673, -2245.1335, 31.4766, 1.2814, 7, 1, 22, 100, 0, 0); // my first character
	AddPlayerClass(2, -1360.4752, -2112.6875, 30.2348, 224.2845, 6, 1, 23, 50, 0, 0); //
	AddPlayerClass(121, -1740.3165, -2090.4006, 39.7106, 256.3793, 5, 1, 24, 30, 0, 0); //
	return 1;
}

Now we’ll add vehicles for your people to drive - go back into SA:MP debug and type “/vsel” (in the text box thing), this will bring up a vehicle selection menu, find one you want, get in, park it where you want it and type “/save” again (while in the vehicle).  Open up savedpositions.txt again and get the new lines (the AddStaticVehicle lines) and put them with your player class lines, recompile, reload and rerun and your vehicles should appear.

public OnGameModeInit()
{
	SetGameModeText("Deathmatch");

	AddPlayerClass(1, -1643.2673, -2245.1335, 31.4766, 1.2814, 7, 1, 22, 100, 0, 0); // my first character
	AddPlayerClass(2, -1360.4752, -2112.6875, 30.2348, 224.2845, 6, 1, 23, 50, 0, 0); //
	AddPlayerClass(121, -1740.3165, -2090.4006, 39.7106, 256.3793, 5, 1, 24, 30, 0, 0); //

	AddStaticVehicle(401, -1764.6294, -2086.7019, 47.1236, 257.8369, 113, 113); // my first car
	AddStaticVehicle(401, -1633.3375, -2251.4619, 28.7141, 89.0023, 113, 113); // This vehicle is parked under a roof so was dropped a bit
	AddStaticVehicle(403, -1303.2861, -2121.0093, 25.5832, 176.7224, 28, 1); //
	return 1;
}

Adding pickups is not quite so simple as you can’t be or be in a pickup in debug mode but you can still get the co-ordinates.  Go into debug, stand where you want the pickup to be and type:

/save pickup co-ordinates

Then open up savedpositions.txt and look at the line you just made (marked by the comment “pickup co-ordinates”).  It as an AddPlayerClass line but still holds most of the information we need.  If you click on the AddPlayerClass function in the function list at the right of pawno it’s parameters will be displayed in the status bar at the bottom of pawno, you will see something like this (it may be cut off as this is a long function):

[a_samp.inc] native AddPlayerClass(modelid, Float:spawn_x, Float:spawn_y, Float:spawn_z, Float:z_angle, weapon1, weapon1_ammo, weapon2, weapon2_ammo, weapon3, weapon3_ammo);

Our pickup doesn’t have an angle or weapons but it does have a position (x, y and z) (it also has a modelid but this isn’t the same modelid as the one in the AddPlayerClass line).  We can see from the parameter list that the position is the second, third and fourth parameters in the function (the Float: part just means they’re floats (i.e. not whole numbers).  In this example the saved line is:

AddPlayerClass(0,-1673.1672,-2165.0496,35.7388,271.8464,0,0,0,0,0,0); // pickup co-ordinates

The first parameter (parameters are separated by commas as you should know from reading pawn-lang.pdf) is 0, the second is -1673.1672, the third is -2165.0496 and so on.  We want the second third and fourth so we end up with our location as:

X = -1673.1672
Y = -2165.0496
Z = 35.7388

Now we need a pickup modelid.  We’re going to add a weapon, but weaponids and modelids are not the same thing, you give a weapon to a player, you give a model to a pickup.  Weapon modelids are either in weapon.dat under column E or possibly somewhere in the general reference topic.  We’re going to add a minigun, who’s modelid is 362 and we want it pickup able and to respawn after a bit, so we want pickup type 2 (again, the types are listed in the general reference topic).  This makes out final AddStaticPickup line:

AddStaticPickup(362, 2, -1673.1672, -2165.0496, 35.7388);

And out final OnGameModeInit:


public OnGameModeInit()
{
	SetGameModeText("Deathmatch");

	AddPlayerClass(1, -1643.2673, -2245.1335, 31.4766, 1.2814, 7, 1, 22, 100, 0, 0); // my first character
	AddPlayerClass(2, -1360.4752, -2112.6875, 30.2348, 224.2845, 6, 1, 23, 50, 0, 0); //
	AddPlayerClass(121, -1740.3165, -2090.4006, 39.7106, 256.3793, 5, 1, 24, 30, 0, 0); //

	AddStaticVehicle(401, -1764.6294, -2086.7019, 47.1236, 257.8369, 113, 113); // my first car
	AddStaticVehicle(401, -1633.3375, -2251.4619, 28.7141, 89.0023, 113, 113); // This vehicle is parked under a roof so was dropped a bit
	AddStaticVehicle(403, -1303.2861, -2121.0093, 25.5832, 176.7224, 28, 1); //
	
	AddStaticPickup(362, 2, -1673.1672, -2165.0496, 35.7388);

	return 1;
}

Note: all these things (vehicles, players and pickups) must go in OnGameModeInit as they must be set up before any players connect to the mode so they can be sent on a player’s connection.

Now we’re going to look at sorting out that annoying camera position problem.  You will need an x, y and z for the cameras position, x, y and z for where the camera is looking, x, y, and z for where the player is standing (usually the same as the position the camera is looking at) and an angle for the player to face (to make them face the camera).  As angle is the fifth number in an AddPlayerClass line and the camera target and player position are the same that’s just two points - dead easy.  Go into debug and stand where you want the player to be, facing in the direction you want and save this position.  Then walk a little bit forward and save this position for the camera (this may need tweaking but you can easily do this manually by increasing and decreasing the co-ordinates).

Now get the first x, y and z and go into your mode.  In there you will find a couple of functions to do with the camera (the default values - the annoying LV ones).  Now the first set of co-ordinates you got should be where the player is going and where the camera is looking.  Look through that group of 3 functions for the two to do these things (as stated earlier, SA:MP functions are not ambiguously named) and change the co-ordinates.  Now alter the other function there with your second set of co-ordinates.

SetPlayerPos(playerid, -1798.7191, -2270.0239, 67.1363);
SetPlayerCameraPos(playerid, -1801.9762, -2272.5999, 67.8387);
SetPlayerCameraLookAt(playerid, -1798.7191, -2270.0239, 67.1363);

We also mentioned the player’s facing angle (pay attention to those three words), there is no function there already to set this so we need to add one.  Look through the list on the right and you should find one to set the players angle (if you don’t look again it is there and obviously named, if you still don’t read every function carefully one by one till you get it!)  Now add this with your angle taken from the fifth parameter of the first AddPlayerClass line you got for the camera data and you’re done.   Compile test and enjoy.

There’s just one more thing to mention - interiors.  The SA world is split up into lots of pieces and when you go from one piece to another you change interior id, fortunately most of the world is all interior 0 and you don’t need to worry about this, it’s only when you go into most buildings via the yellow markers that your interior changes.  The only reason this is mentioned is that when SA:MP moves a person it updates their location but has no knowledge of interiors, so if you place them somewhere there should be land but you’re in the wrong id you’ll just see grey/blue and fall.  This includes when people respawn - if they were in a building when they died and they respawn outside and you don’t set the interior back to 0 they won’t see anything.  Read this paragraph a few times, compare key words in it to the callbacks and functions in pawno and add a thing to protect players when they respawn from seeing nothing (there is a function to set your interior id and a callback to detect when people respawn).

Other challenges/activities:

Place more vehicles, pickups and player classes around the world/your DM area.

Important: there is a limit of 250 vehicles of 50 (sometimes 49 or 48) different types.  So three infernuses’ are three vehicles but only one type, an infernus and a cheetah are two vehicles and two types.  If you go over the 250 limit the rest simply won’t show up.  If you go over the type limit your game will crash.  There is also a limit of 100 pickups and 500 classes but you’re unlikely to go over this second limit.