Deprecated: Creation of dynamic property Wiki::$m_request_prefix is deprecated in /home/sa-mp/sa-mp/sa-mp.nl/Sources/Modules/Development/Wiki.php on line 18

Given the vast amount of code and the number of developers who will be working on it, it's important to have a clear, well defined style-guide covering the most frequently used programming patterns.

For questions or comments about this style-guide, either as a whole or on specific sections, please create a topic on our forums or send an e-mail to development@sa-mp.nl. This guide may be amended at any time by our Lead Developers.

Usage of white-space, curly brackets and indenting in your code is one of the most important parts of keeping your code consistent, as it defines the layout of the code. Within Las Venturas Playground code, we adhere to the following rules as for whitespace usage, curly brackets and indentation.

Use spaces to separate parameters, after the colon in a tag and after a closing parenthesis in a function declaration. No spaces should be inserted between a function name and the opening parenthesis, neither between a variable name and the opening square bracket for indexing. Scopes should be indented by either four spaces or a tab, where spaces have the preference. There should always be curly brackets encapsulating a function's body.

stock exampleFunction(parameter, &meter, Tag: parameter, parameter[]) {
    // Indent of four spaces.
}

For statements, such as if-statements and loops, we expect a space to follow the statement's name, and spaces to separate relational, equality and logical operators. The exception here is the NOT operator, which should not be surrounded by spaces. Curly brackets may be skipped for single line expressions, at your own consent.

if (condition && (!secondCondition))
    // Single line - no curly bracket
else {
    while (variable >= 50) {
        // Your while loop's content
    }
}

Each statement in the code should be written on a separate line. The only valid exception for this are mathematical-based inline methods, which in general are rare.

Spaces must be inserted around binary, bitwise and ternary operators, but not around unary operators. For variables, declaring multiple variables in the same "new" statement is preferred. Grouping similar-purpose variables on the same line is accepted, though generally use one line per variable.

For indexed variables, use the lowest possible index size, especially for variables expected to go on the stack. Never refer to the chosen size using a number, but use either an enum value or the sizeof() statement.

new positionX, positionY, positionZ,
    distanceToPirateShip; // good
new weaponCount, positionZ, buffer[9999]; // wrong

result *= 5; // good
result = 5+5; // wrong
result = 5 + 5; // good
result = conditional ? 5 : 10; // good
result = 5>>1*2; // wrong

new messageBuffer[64]; // good
new messageBuffer[999]; // wrong

The hard maximum line length for Las Venturas Playground code is a hundred characters, but advised is to keep your maximum around eighty. Exception to this rule are lines which cannot be cut, such as strings and includes. If your line is longer than a hundred characters, or becomes hard to read due to it's length, cut it in multiple lines and indent the next line.

if (Math->ceil(inversePlayerFacingAngle / pirateShipRampAccessibleAngle) > 15.0 &&
    !this->pirateShipRampAccessibleForPlayerInGang(m_gangId)) {
    SendClientMessage(GangManager->actualLeaderForOnlineGang(m_gangId), Colors::Warning,
        "A member of your gang tried to enter the pirate ship from a wrong angle.");
    return 1;
}

In programming as a whole, naming of variables, classes and constants is very hard. This is particularly an issue in the San Andreas: Multiplayer community, where it seems common to use short, non-descriptive names for variables and functions. We encourage you to write clear, self-documenting code which' behavior becomes obvious just by reading it.

Class names should start with a capital and clearly define what the class' purpose or subject is. Each class name may only occur once in a script, making this extra important. Camel-case the different words in a class, and don't use non-alphabetic characters or numbers.

class Player {}; // good
class VehicleManager {}; // good
class PlayerIterator {}; // good

class system {}; // wrong
class Minigame_Race_15 {}; // wrong
class __secret {}; // wrong

Constants are fixed values which are resolved at compile time. They should start with a capital and use camel casing, any may not contain any non-alphabetic characters or numbers. Constants may have simple expressions as their value.

const MaximumPlayersInMinigame = 16; // good
const RespawnDelay = 120; // good
const SecondsInOneDay = 60 * 60 * 24; // good

const day = 60 * 60 * 24; // wrong
const __LINE__ = 25; // wrong
const Vehicle5 = 5; // wrong

Properties and variables need to be descriptive in what they contain, using a clear, usually singular name. The name must start with a lowercase letter, while the rest of the name should be camel cased. Member properties must start with "m_", which is enforced by the PreCompiler. Single character variable names are strictly prohibited, use "index", or preferably a name that describes what you're iterating over.

new playerId; // good
new Float: m_currentWindDirection; // good
new localSpawnLocations[MAX_SPAWN_POINTS]; // good

new i; // wrong
new iPlayerID; // wrong
new playerid; // wrong
new dataarr; // wrong

The proper capitalization of ID is "Id".

One of the most important areas our code is the naming of methods and functions. Like variables, function names should start with a lower case letter and separate words by using camel casing. The names should very clearly reflect what the function does, while also maintaining a consistent order of parameters.

Special cases are getters and setters. A setter should always be prefixed with "set", while a getter should get no prefix unless it's returning values through its arguments, in which case it should be prefixed with "get". Functions do never return arrays in Las Venturas Playground's code, as these should be set through parameters.

stock calculateWeatherProgressionVector(); // good
public OnPlayerConnect(); // good - SA:MP native.
respawnVehicle(); // wrong

class Foo {
    public /* void */ getModelName(VehicleModel: model, nameBuffer[], nameLength);
    public Float: windDirection();
    public setWindDirection(Float: direction);
};

Functions which are neither stock or public are strictly prohibited, with the exception of main(). Methods should always use appropriate visibility keywords, using either public or private. Methods may be defined as inline if they only have a single statement.

Enumerations in Pawn are one of it's main features that are being abused. Originally, an enum is intended to group a series of sequential named values, which is exactly what Las Venturas Playground will use them for.

An enum should be a clear unique name suffixed by what it contains, for example a Type. The name must start with a capital and may contain only alphabetic characters. Values must be unique as well, given that they will be exposed to the entire script. Try to keep them specific for the current enum.

enum VehicleModel { Infernus, Cheetah }; // good
enum VisualElementType { VisualClock, VisualStatusBar }; // good
enum PlayerLevel { Management, Administrator, Player }; // good

enum Data { new Float: value, bool: isValid; }; // wrong
enum Minigame_25 { Playing, Leaving }; // wrong

The usage of non-obvious boolean parameters is discouraged in Las Venturas Playground's code. It's usually impossible to guess what the values mean, especially when multiple boolean values are expected. An exception to this case is for toggle-functions and ones in which the meaning is obvious. Use your own judgement here.

As for numbers, it's really hard to remember the Ids each of the vehicles have, for example. Therefore you should prefer declaring these as enums, so we can identify them by their name instead of by their number. This makes it immediately obvious which vehicle is being spawned.

setPlayerState(true, false, false, true, false, true); // wrong
setPlayerState(IsConnected | PlayingMinigame | PlayingRace); // good

createVehicle(520, ...); // wrong
createVehicle(Hydra, ...); // good

togglePlayerControllable(false); // good
setPlayerConnected(true); // good

We use tags to describe variables which' exact values we don't care about. If you create a vehicle or object in San Andreas: Multiplayer, do you care whether it's entity 56 or 57? No. Therefore these should be defined as tagged variables instead.

Variables which have a tag are per definition no longer an Id, but rather a thing on itself. Usually these values come from systems which can change during execution of the gamemode, such as Vehicles and Objects (which can be created on our own consent) and proprietary systems such as Zones (which also are dynamic). An exception here are players, which are used so frequently for array indexes that it would create too much casting noise.

new awesomeTruck = CreateVehicle(Trashmaster, ..); // wrong
new Vehicle: awesomeTruck = Vehicle: createVehicle(Trashmaster, ..); // good

public zoneCountForPlayer(playerId, zoneId); // wrong
public zoneCountForPlayer(playerId, Zone: zone); // good

TODO