In order for the scripting core to support classes would require whole new Pascal compiler and such in the server, which would require a lot of work that is probably not going to be done.
At one point I tried to mimic basic class-like object oriented programming thingy, generally with success. If you want it, I can try to go dig it and provide it, but it can't do custom syntax (class types are defined run-time). It takes a bit to get used to. I also have a much older version I believe on Soldat Central (which was a while ago, hard to remember), but that didn't support as much as this. Generally, it looked funny to try to make a class or instance of a class, and would take some getting used to (multiple files would be your friend to hide the "ugly" code). It did not have support for access modifiers. Anyways, I ran into an issue relating to virtual inheritance and replaced it with a different concept of instance inheritance (since everything was run-time, I made it possible to inherit an already existing class). I forget why I stopped working on it, but I believe I ran into another problem. No, before you ask, I do not plan on working on it much more.
More recently, I have been doing something that is similar to a method. The concept is pretty simple. You have yourself an "array of YOURTYPE" where YOURTYPE is a record with your variables inside, and "Active: boolean" or an equivalent. This is used to see which elements of the array are "in use" or "not in use". Indexing this array acts like a non-nullable "pointer" (unless you define a "null index", which I usually use -1 as an unsigned number, if I need to). For all your methods, simply pass the "pointer" index as the first parameter, and index the array.
type
TMyCoolClass = record
Active: boolean;
Id: byte;
end;
var
MyCoolClass_Instances: array of TMyCoolClass;
// should not be used by anything except the "constructors"
function CoolClass_GetNewSlot(): word;
begin
if (GetArrayLength(MyCoolClass_Instances) > 0) then
for Result := 0 to GetArrayLengt(MyCoolClass_Instances) - 1 do
if (not MyCoolClass_Instances[Result].Active) then begin
MyCoolClass_Instances[Result].Active := true;
exit;
end;
Result := GetArrayLength(MyCoolClass_Instances);
SetArrayLength(MyCoolClass_Instances, Result + 1);
MyCoolClass_Instances[Result].Active := true;
end;
// Constructor
function CoolClass_New(const Id: byte): word;
begin
Result := CoolClass_GetNewSlot();
MyCoolClass_Instances[Result].Id := Id;
end;
// Destructor
procedure CoolClass_Delete(const Instance: word);
begin
MyCoolClass_Instances[Instance].Active := false;
if (Instance + 1 = GetArrayLength(MyCoolClass_Instances)) then
SetArrayLength(MyCoolClass_Instances, Instance);
{
Can be better! Let Instances.Active be:
[true, false, false, true]
You are removing the last one, it SHOULD become:
[true]
not
[true, false, false]
like the current method does; I'm not sure how allocation of memory actually works with dynamic arrays, so this actually may be a bad idea, depending on your case.
}
end;
// Method - this is used to hide MyCoolClass_Instances from anything outside this class, so outside code (or even inside code) looks cleaner
function CoolClass_GetId(const Instance: word): byte;
begin
Result := MyCoolClass_Instances[CoolClassInstance].Id;
end;
// Method
procedure CoolClass_Die(const Instance: word);
begin
// Command('/kill ' + InttoStr(MyCoolClass_Instances[Instance].Id));
Command('/kill ' + InttoStr(MyCoolClass_GetId(Instance)));
end;
To keep yourself organized, it might be best to keep each "class" inside its own file. Here would be an example main file:
procedure AppOnIdle(Ticks: integer);
var
CoolClassInstance: word;
begin
CoolClassInstance := CoolClass_New(Random(1, 16));
// if (GetPlayerStat(MyCoolClass_Instances[CoolClassInstance].Id, 'Active') = true) then
if (GetPlayerStat(MyCoolClass_GetId(CoolClassInstance), 'Active') = true) then
CoolClass_Die(CoolClassInstance);
CoolClass_Delete(CoolClassInstance);
end;