Object-oriented programming (OOP) is a programming paradigm based on the concept of "objects", which are data structures that contain data, in the form of fields, often known as attributes; and code, in the form of procedures, often known as methods. A distinguishing feature of objects is that an object's procedures can access and often modify the data fields of the object with which they are associated (objects have a notion of "this" or "self"). |
/******************** class ClassExample *******************/
#define ClassExample. ClassExample_
#define ClassExample_max ClassExample:1024
// Fields
stock ClassExample.myInteger[ClassExample.max];
stock Float:ClassExample.myFloat[ClassExample.max];
stock ClassExample.myString[ClassExample.max][64];
// Constructor
stock ClassExample:ClassExample(i, Float:f, s[])
{
static ClassExample:this = ClassExample:-1;
this++;
//
ClassExample.myInteger[this] = i;
ClassExample.myFloat[this] = f;
format(ClassExample.myString[this], 64, s);
//
return this;
}
// Methods
stock ClassExample.toString(ClassExample:this)
{
new ret[128];
format(
ret,
128,
"ClassExample %d\n\t\
myInteger: %d\n\t\
myFloat: %.4f\n\t\
myString: %s\n\n",
_:this, // _: removes the ClassExample: tag, transforming it to a printable integer
ClassExample.myInteger[this],
ClassExample.myFloat[this],
ClassExample.myString[this]
);
return ret;
}
// Getter/Setter methods
stock ClassExample.getMyInteger(ClassExample:this)
{
return ClassExample.myInteger[this];
}
stock ClassExample.setMyInteger(ClassExample:this, i)
{
ClassExample.myInteger[this] = i;
}
stock Float:ClassExample.getMyFloat(ClassExample:this)
{
return ClassExample.myFloat[this];
}
stock ClassExample.setMyFloat(ClassExample:this, Float:f)
{
ClassExample.myFloat[this] = f;
}
stock ClassExample.getMyString(ClassExample:this)
{
return ClassExample.myString[this];
}
stock ClassExample.setMyString(ClassExample:this, s[])
{
format(ClassExample.myString[this], 64, s);
}
/************************************************************/
main()
{
// creating instances
new ClassExample:a = ClassExample(2015, 25.524, "Hello World!");
new ClassExample:b = ClassExample(125, 7.52, "Goodbye World!");
new ClassExample:c = ClassExample(521, 2.52, "Hello Again World!");
// calling toString
printf(ClassExample.toString(a));
printf(ClassExample.toString(b));
printf(ClassExample.toString(c));
// changing and testing fields directly
printf("We incremented a's integer directly\n");
ClassExample.myInteger[a] ++;
format(ClassExample.myString[a], 64, "Happy new year!");
printf(ClassExample.toString(a));
// changing and testing fields by getter and setter methods
printf("b.getMyString: '%s'", ClassExample.getMyString(b));
printf("We are now setting b's string value by calling its setter method\n");
ClassExample.setMyString(b, "Changed value!");
printf("b.getMyString: '%s'", ClassExample.getMyString(b));
}
[15:08:16] ClassExample 0 myInteger: 2015 myFloat: 25.5240 myString: Hello World! [15:08:16] ClassExample 1 myInteger: 125 myFloat: 7.5199 myString: Goodbye World! [15:08:16] ClassExample 2 myInteger: 521 myFloat: 2.5199 myString: Hello Again World! [15:08:16] We incremented a's integer directly [15:08:16] ClassExample 0 myInteger: 2016 myFloat: 25.5240 myString: Happy new year! [15:08:16] b.getMyString: 'Goodbye World!' [15:08:16] We are now setting b's string value by calling its setter method [15:08:16] b.getMyString: 'Changed value!'
/*
* This is an example on how to mimic a very basic Object-Oriented programming in the PAWN language
* by SaSiNO97_ Aka Sasinosoft
*/
#include <a_samp>
/******************** class House *******************/
#define House. House_
#define House_max House:256
// Fields
stock House.owner[House.max][MAX_PLAYER_NAME];
stock House.price[House.max];
stock Float:House.x[House.max];
stock Float:House.y[House.max];
stock Float:House.z[House.max];
// Static final field example
// - static because it's not depending on a single House object (no [House.max])
// - final because it's defined as "const" and can't be changed
stock const House.invalidOwnerName[MAX_PLAYER_NAME] = "#@!/*-";
// Constructor
stock House:House(price, Float:x, Float:y, Float:z)
{
static House:this = House:-1;
this++;
//
format(House.owner[this], MAX_PLAYER_NAME, House.invalidOwnerName);
House.price[this] = price;
House.x[this] = x;
House.y[this] = y;
House.z[this] = z;
Create3DTextLabel("House", 0x33AA33FF, x, y, z, 5.0, 0, true);
//
return this;
}
// Methods
stock House.toString(House:this)
{
new ret[128];
format(
ret,
128,
"House %d\n\t\
Owner: %s\n\t\
Price: $%d\n\t\
Position: (%.4f, %.4f, %.4f)\n\n",
_:this,
House.owner[this],
House.price[this],
House.x[this],
House.y[this],
House.z[this]
);
return ret;
}
stock bool:House.buy(House:this, playerid)
{
if(!IsPlayerConnected(playerid))
return false;
if(!strcmp(House.owner[this], House.invalidOwnerName))
{
SendClientMessage(playerid, 0xFFFFFFFF, "[ERROR]This house is already owned.");
return false;
}
if(GetPlayerMoney(playerid) < House.price[this])
{
SendClientMessage(playerid, 0xFFFFFFFF, "[ERROR]You can't afford this house.");
return false;
}
if(!IsPlayerInRangeOfPoint(playerid, 1.5, House.x[this], House.y[this], House.z[this]))
{
SendClientMessage(playerid, 0xFFFFFFFF, "[ERROR]You aren't close to this house.");
return false;
}
new nickname[MAX_PLAYER_NAME];
GetPlayerName(playerid, nickname, MAX_PLAYER_NAME);
GivePlayerMoney(playerid, -House.price[this]); //
format(House.owner[this], MAX_PLAYER_NAME, nickname);
SendClientMessage(playerid, 0xFFFFFFFF, "[CONGRATULATIONS]You now own this house!");
return true;
}
stock bool:House.sell(House:this, playerid)
{
if(!IsPlayerConnected(playerid))
return false;
new nickname[MAX_PLAYER_NAME];
GetPlayerName(playerid, nickname, MAX_PLAYER_NAME);
if(strcmp(House.owner[this], nickname) != 0)
{
SendClientMessage(playerid, 0xFFFFFFFF, "[ERROR]This house is not yours.");
return false;
}
if(!IsPlayerInRangeOfPoint(playerid, 1.5, House.x[this], House.y[this], House.z[this]))
{
SendClientMessage(playerid, 0xFFFFFFFF, "[ERROR]You aren't close to this house.");
return false;
}
GivePlayerMoney(playerid, floatround(House.price[this]*0.7, floatround_ceil)); //
format(House.owner[this], MAX_PLAYER_NAME, House.invalidOwnerName);
SendClientMessage(playerid, 0xFFFFFFFF, "[CONGRATULATIONS]You sold your house!");
return true;
}
// Example of a static method (a method that is not linked to a specific object of the class)
stock House.printAll()
{
for(new House:i=House:0; i<House.max; i++) // Loop through all Houses
{
if(House.x[i] != 0.0) // check if it was created
{
printf(House.toString(i)); // prints it state
}
}
}
/************************************************************/
main()
{
printf("House Class Example by SaSiNO97_!");
}
public OnGameModeInit()
{
// Let's create some anonymous objects of the class House (positions are totally random, so don't look for them inside the game :P)
House(15000, 1520.0, 214.0, 15.0);
House(25000, 1620.0, 244.0, 12.0);
House(50000, 1120.0, 714.0, 14.0);
House(36000, 1120.0, 714.0, 14.0);
House(14000, 1220.0, 614.0, 24.0);
House.printAll();
}
public OnPlayerCommandText(playerid, cmdtext[])
{
if(!strcmp(cmdtext, "/buy", true))
{
for(new House:i=House:0; i<House.max; i++) // Loop through all Houses
{
if(IsPlayerInRangeOfPoint(playerid, 1.5, House.x[i], House.y[i], House.z[i])) // If player is in range of a house
{
House.buy(i, playerid); // Call the method "buy"
break; // Exit the loop
}
}
return 1;
}
if(!strcmp(cmdtext, "/sell", true)) // Similar to previous
{
for(new House:i=House:0; i<House.max; i++)
{
if(IsPlayerInRangeOfPoint(playerid, 1.5, House.x[i], House.y[i], House.z[i]))
{
House.sell(i, playerid);
break;
}
}
return 1;
}
return 0;
}
list<Float> float_list; //equivalent to new new List:lst_float_list = STL_List_DT_Template_Float; //STL_List_DT_Template has a unique negative number which is of course invalid but it is used to identify the type when a method is used on the list for the first time //Acts as a explicit constructor list::float_list(); //has 3 overloads For local lists, one can have following syntax (Work in progress, having some issue with it) list<String> strings(params); //For local variables, implicit constructor //translates to new List:lst_strings = STL_List_DT_Template_String; //list::strings(params) - basically calls the init function automatically list::strings.push_back("String"); //This translates to _epl_list_push_back(lst_strings, "String");
True OOP in SA-MP.
https://sampforum.blast.hk/showthread.php?tid=511686 |
#include <a_samp>
const MAX_STRING = 256;
new lastId;
stock _getNewClassObjectId(objectIds[], size) {
for(lastId = 0; lastId < size; lastId++) {
if(!objectIds[lastId]) {
objectIds[lastId] = true;
return lastId;
}
}
#if defined ThrowError
new string[MAX_STRING];
format(string, sizeof string, "Ran out of objects, max: %d", size);
ThrowError(string);
#endif
return -1;
}
stock _countInstances(objectIds[], size) {
new counter = 0;
for(new i = 0; i < size; i++) {
if(objectIds[i]) {
counter++;
}
}
return counter;
}
stock _getInstance(objectIds[], size, number) {
new counter = 0;
for(new i = 0; i < size; i++) {
if(objectIds[i]) {
if(counter == number) {
return i;
}
counter++;
}
}
return -1;
}
#define class(%0,%1) \
stock _%0_tag_check(%0:objid) { return int:objid; } \
new bool:_%0_objects[%1] = false
#define delete(%0,%1) _%0_objects[_%0_tag_check(%1)] = false
#define method(%0).%1(%2) _%0_%1(%0:this,%2)
#define methodb(%0).%1() _%0_%1(%0:this)
#define var(%0){%1} _%0_%1[sizeof _%0_objects]
#define val(%0){%1} _%0_%1[_%0_tag_check(this)]
#define callb(%0,%1).%2() _%0_%2(%1)
#define call(%0,%1).%2(%3) _%0_%2(%1, %3)
#define object(%0) %0:_getNewClassObjectId(_%0_objects, sizeof _%0_objects)
#define instances(%0) _countInstances(_%0_objects, sizeof _%0_objects)
#define instance(%0,%1) %0:_getInstance(_%0_objects, sizeof _%0_objects, %1)
class(User, 100);
new var(User){name}[MAX_STRING];
method(User).init(name[]) {
for(new i = 0; i < strlen(name); i++) {
val(User){name}[i] = name[i];
}
}
methodb(User).getName() {
return val(User){name};
}
main()
{
new User:u = object(User);
printf("User id: %d", int:u);
call(User, u).init("foo bar");
print(callb(User, u).getName());
printf("User instances: %d", instances(User)); // 1
delete(User, u);
printf("User instances: %d", instances(User)); // 0
}
I can't believe I never found this tutorial until now, god bless you, I can get some use to this.
|
#if defined function
#undef function
#endif
#define function%0::%1(%2) %0_%1(%2)
#if defined call
#undef call
#endif
#define call::%0->%1(%2) %0_%1(%2)
enum e_PLAYER_INFO
{
PlayerID,
Nome[MAX_PLAYERS],
//...
}
new Player[MAX_PLAYERS][e_PLAYER_INFO];
// ================== [ FUNCTIONS ] ================== //
function PLAYER::SetPlayerVarInt(playerid, e_PLAYER_INFO:param, value){
Jogador[playerid][param] = value;
return true;
}
function PLAYER::GetPlayerVarInt(playerid, e_PLAYER_INFO:param){
return Jogador[playerid][param];
}
// ================== [ PUBLICs ] ================== //
public OnPlayerConnect(playerid)
{
call::PLAYER->SetPlayerVarInt(playerid, PlayerID, 1);
call::PLAYER->GetPlayerVarInt(playerid, PlayerID);
}