]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/lib/OO.qh
Expand /lib
[xonotic/xonotic-data.pk3dir.git] / qcsrc / lib / OO.qh
1 #ifndef OO_H
2 #define OO_H
3
4 #include "Nil.qh"
5 #include "Registry.qh"
6
7 #ifdef MENUQC
8     #define NULL (null_entity)
9 #else
10     #define NULL (world)
11 #endif
12
13 .string classname;
14 /** Location entity was spawned from in source */
15 .string sourceLocFile;
16 .int sourceLocLine;
17 entity _spawn();
18 entity __spawn(string _classname, string _sourceFile, int _sourceLine) {
19     entity this = _spawn();
20     this.classname = _classname;
21     this.sourceLocFile = _sourceFile;
22     this.sourceLocLine = _sourceLine;
23     return this;
24 }
25
26
27
28 #define entityclass(...) OVERLOAD(entityclass, __VA_ARGS__)
29 #define entityclass_1(name) entityclass_2(name, Object)
30 #ifndef QCC_SUPPORT_ENTITYCLASS
31     #define entityclass_2(name, base) typedef entity name
32     #define class(name)
33     #define new(class) __spawn(#class, __FILE__, __LINE__)
34 #else
35     #define entityclass_2(name, base) entityclass name : base {}
36     #define class(name) [[class(name)]]
37     #define new(class) ((class) __spawn(#class, __FILE__, __LINE__))
38 #endif
39
40 // Classes have a `spawn##cname(entity)` constructor
41 // The parameter is used across [[accumulate]] functions
42
43 // Macro to hide this implementation detail
44 #define NEW(cname, ...) \
45     OVERLOAD(spawn##cname, new(cname), ##__VA_ARGS__)
46
47 #define CONSTRUCT(cname, ...) \
48     OVERLOAD(spawn##cname, this, ##__VA_ARGS__)
49
50 #define CONSTRUCTOR(cname, ...) \
51     cname OVERLOAD(spawn##cname, cname this, __VA_ARGS__) { return = this; } \
52     [[accumulate]] cname OVERLOAD(spawn##cname, cname this, __VA_ARGS__)
53
54 .string vtblname;
55 .entity vtblbase;
56
57 void RegisterClasses() { }
58 STATIC_INIT(RegisterClasses) { RegisterClasses(); }
59
60 #define VTBL(cname, base) \
61     INIT_STATIC(cname); \
62     entity cname##_vtbl; \
63     void cname##_vtbl_init() { \
64         cname e = new(vtbl); \
65         spawn##cname##_static(e); \
66         e.vtblname = #cname; \
67         /* Top level objects refer to themselves */ \
68         e.vtblbase = base##_vtbl ? base##_vtbl : e; \
69         cname##_vtbl = e; \
70     } \
71     ACCUMULATE_FUNCTION(RegisterClasses, cname##_vtbl_init)
72
73 #define INIT_STATIC(cname) [[accumulate]] void spawn##cname##_static(cname this)
74 #define INIT(cname) [[accumulate]] cname spawn##cname##_1(cname this)
75
76 #define CLASS(cname, base)                  \
77     entityclass(cname, base);               \
78     class(cname) .bool instanceOf##cname;   \
79     VTBL(cname, base)                       \
80     INIT_STATIC(cname) {                    \
81         if (cname##_vtbl) {                 \
82             copyentity(cname##_vtbl, this); \
83             return;                         \
84         }                                   \
85         spawn##base##_static(this);         \
86         this.instanceOf##cname = true;      \
87     }                                       \
88     INIT(cname) {                           \
89         /* Only statically initialize the current class, it contains everything it inherits */ \
90         if (cname##_vtbl.vtblname == this.classname) { \
91             spawn##cname##_static(this);    \
92             this.classname = #cname;        \
93             this.vtblname = string_null;    \
94             this.vtblbase = cname##_vtbl;   \
95         }                                   \
96         spawn##base##_1(this);              \
97     }
98
99 #define METHOD(cname, name, prototype)      \
100     class(cname) .prototype name;           \
101     prototype cname##_##name;               \
102     INIT_STATIC(cname) { this.name = cname##_##name; } \
103     prototype cname##_##name
104
105 #define ATTRIB(cname, name, type, val)      \
106     class(cname) .type name;                \
107     INIT(cname) { this.name = val; }
108
109 #define ATTRIBARRAY(cname, name, type, cnt) \
110     class(cname) .type name[cnt];
111
112 #define ENDCLASS(cname) \
113     [[last]] INIT(cname) { return this; }
114
115 #define SUPER(cname) (cname##_vtbl.vtblbase)
116 #define super (this.vtblbase.vtblbase)
117
118 #define spawn_static(this)
119 #define spawn_1(this)
120 #define _vtbl NULL
121 CLASS(Object, );
122     METHOD(Object, describe, string(entity this)) {
123         string s = _("No description");
124         if (cvar("developer")) {
125             for (int i = 0, n = numentityfields(); i < n; ++i) {
126                 string value = getentityfieldstring(i, this);
127                 if (value != "") s = sprintf("%s\n%s = %s", s, entityfieldname(i), value);
128             }
129         }
130         return s;
131     }
132     METHOD(Object, display, void(entity this, void(string name, string icon) returns)) {
133         returns(sprintf("entity %i", this), "nopreview_map");
134     }
135 ENDCLASS(Object)
136 #undef spawn_static
137 #undef spawn_1
138 #undef _vtbl
139
140 #endif