Reddit

Twitch.Tv

Ustream.Tv

Duxter

Instagram

Location

Interests

Interests

Occupation

SQF Classes for ArmA 3
Edited - release updated with a couple of bugfixes - if you downloaded prior to 6pm GMT on 29 October then please re-download to get the corrected files.
"If . . . [the] fact [that brutes abstract not] be made the distinguishing property of that sort of animal, I fear a great many of those that pass for men must be reckoned into their number." -- George Berkeley
Many times when scripting in SQF it may occur that implementing object-oriented techniques can simplify or enhance certain abstractions. The technique of using getVariable/setVariable on a unit or gamelogic to store function code or references specific to that unit's situation is a common pattern found in many missions and modules. Here, that idea is taken one step farther: instead of storing functions on game objects, we store an array of class names (representing a chain of inheritance or a mixture of interfaces). Meanwhile, a master Classes array holds a subarray for each defined class, containing a function definition for each class method. With this arrangement and just a handful of primitive functions, an unlimited variety of classes and methods can be declared on-the-fly while a mission is running.
Release (.zip): https://github.com/dwringer/a3system/releases/tag/v1.0
Code: http://github.com/dwringer/a3system/tree/master/ClassDemo.Tanoa
This is a selection of modules drawn from a larger repository I keep at http://www.github.com/dwringer/a3system/. There, more recent versions of these modules can often be found. I also placed other modules I created over the years, which are of variable quality and may or may not be worth a look.
Class layout
Lambda
Macros
Example overview
This will demonstrate how to create abstract instances and send messages (method calls) to them. The included example is a mission with four men (crew_1..crew_4) and two vehicles (car_1, car_2). You may easily duplicate it in a different map if you don't have Tanoa available. There is a single Radio Alpha trigger, upon whose activation the following scripts are executed:
CG = ["CrewUnitGroup"] call fnc_new;
[CG, "assign", crew_1, "driver"] call fnc_tell;
[CG, "assign", crew_2, "gunner"] call fnc_tell;
[CG, "assign", crew_3, "driver"] call fnc_tell;
[CG, "assign", crew_4, "gunner"] call fnc_tell;
[CG, "assign", car_1, "vehicle"] call fnc_tell;
[CG, "assign", car_2, "vehicle"] call fnc_tell;
[CG, "board_instant"] call fnc_tell;
Here, fnc_new is how we create a new instance. It accepts the class name and any init parameters appended to it (here there are none).
We could also put a Game Logic in the editor instead of using fnc_new, and in its init use the following:
_nil = this spawn {
waitUntil {not isNil "ClassesInitialized"};
[_this, "CrewUnitGroup"] call fnc_instance;
.. rest of code ..
};
The method calls are actually made with fnc_tell, which takes as parameters the class instance, method name, and subsequently each method parameter. Thus, all methods to all classes are defined and called using a standardized syntax and set of functions which have been precompiled.
Since fnc_instance makes an instance out of an existing object, we can also use it for creating class inheritance. Consider the following:
DEFCLASS("MySubClass") ["_self"] DO {
[_self, "SuperClass"] call fnc_instance;
.. rest of code ..
_self
} ENDCLASS;
Now, MySubClass inherits all the methods from SuperClass. Each game object keeps an ordered list of its class assignments, so if a method is not found on MySubClass it will be looked up on SuperClass. I have provided the macros SUPER and SUPER_ARGS in include\classes.hpp to facilitate subclassing from within classdef header files.
If you want to create a subclass method that implements a superclass method under a different name, that can be done by looking up the class alist in the Classes global alist and using the function contained there as a new method. In classdef files, this has a macro called ALIAS(subclass, subclass_method, superclass, superclass_method).
Another example
Without further ado, the link to the repository containing the above example mission folder and all required modules is:
Release (.zip): https://github.com/dwringer/a3system/releases/tag/v1.0
Code: http://github.com/dwringer/a3system/tree/master/ClassDemo.Tanoa
Good luck, and if anyone creates some useful classes or a cool class tree, I'd love to hear about it. Even if this just serves as an example of what can be done to (ab)use SQF, I am satisfied.
"No point in mentioning these bats, I thought. Poor bastard will see them soon enough." -- Raoul Duke
Edited - release updated with a couple of bugfixes - if you downloaded prior to 6pm GMT on 29 October then please redownload to get the corrected files. There were changes made to fnc_tell and fnc_filter related to nil values being passed as parameters.
Edited - added another example section