#ifndef OO_H #define OO_H #include "misc.qh" #include "nil.qh" #ifdef MENUQC #define NULL (null_entity) #else #define NULL (world) #endif .string classname; /** Location entity was spawned from in source */ .string sourceLocFile; .int sourceLocLine; entity _spawn(); entity __spawn(string _classname, string _sourceFile, int _sourceLine) { entity this = _spawn(); this.classname = _classname; this.sourceLocFile = _sourceFile; this.sourceLocLine = _sourceLine; return this; } #define entityclass(...) EVAL(OVERLOAD(entityclass, __VA_ARGS__)) #define entityclass_1(name) entityclass_2(name, Object) #ifndef QCC_SUPPORT_ENTITYCLASS #define entityclass_2(name, base) typedef entity name #define class(name) #define new(class) __spawn( #class, __FILE__, __LINE__) #else #define entityclass_2(name, base) entityclass name : base {} #define class(name) [[class(name)]] #define new(class) ((class) __spawn( #class, __FILE__, __LINE__)) #endif #define spawn() new(entity) // Classes have a `spawn##cname(entity)` constructor // The parameter is used across [[accumulate]] functions // Macros to hide this implementation detail: #ifdef GMQCC #define NEW(cname, ...) \ OVERLOAD(spawn##cname, new(cname),##__VA_ARGS__) #define CONSTRUCT(cname, ...) \ OVERLOAD(spawn##cname, this,##__VA_ARGS__) #else #define NEW_(cname, ...) \ OVERLOAD_(spawn##cname, __VA_ARGS__) #define NEW(cname, ...) \ NEW_(cname, new(cname),##__VA_ARGS__)(new(cname),##__VA_ARGS__) #define CONSTRUCT_(cname, ...) \ OVERLOAD_(spawn##cname, __VA_ARGS__) #define CONSTRUCT(cname, ...) \ CONSTRUCT_(cname, this,##__VA_ARGS__)(this,##__VA_ARGS__) #endif #define CONSTRUCTOR(cname, ...) \ cname OVERLOAD(spawn##cname, cname this, __VA_ARGS__) \ { \ return = this; \ } \ [[accumulate]] cname OVERLOAD(spawn##cname, cname this, __VA_ARGS__) .string vtblname; .entity vtblbase; void RegisterClasses() {} STATIC_INIT(RegisterClasses) { RegisterClasses(); } #define VTBL(cname, base) \ INIT_STATIC(cname); \ entity cname##_vtbl; \ void cname##_vtbl_init() \ { \ cname e = new(vtbl); \ spawn##cname##_static(e); \ e.vtblname = #cname; \ /* Top level objects refer to themselves */ \ e.vtblbase = base##_vtbl ? base##_vtbl : e; \ cname##_vtbl = e; \ } \ ACCUMULATE_FUNCTION(RegisterClasses, cname##_vtbl_init) #define INIT_STATIC(cname) [[accumulate]] void spawn##cname##_static(cname this) #define INIT(cname) [[accumulate]] cname spawn##cname##_1(cname this) #define CLASS(cname, base) \ entityclass(cname, base); \ class(cname).bool instanceOf##cname; \ VTBL(cname, base) \ INIT_STATIC(cname) \ { \ if (cname##_vtbl) \ { \ copyentity(cname##_vtbl, this); \ return; \ } \ spawn##base##_static(this); \ this.instanceOf##cname = true; \ } \ INIT(cname) \ { \ /* Only statically initialize the current class, it contains everything it inherits */ \ if (cname##_vtbl.vtblname == this.classname) \ { \ spawn##cname##_static(this); \ this.classname = #cname; \ this.vtblname = string_null; \ this.vtblbase = cname##_vtbl; \ } \ spawn##base##_1(this); \ } #define METHOD(cname, name, prototype) \ class(cname).prototype name; \ prototype cname##_##name; \ INIT_STATIC(cname) \ { \ this.name = cname##_##name; \ } \ prototype cname##_##name #define ATTRIB(cname, name, type, val) \ class(cname).type name; \ INIT(cname) \ { \ this.name = val; \ } #define ATTRIBARRAY(cname, name, type, cnt) \ class(cname).type name[cnt]; #define ENDCLASS(cname) \ INIT(cname) \ { \ return this; \ } #define SUPER(cname) (cname##_vtbl.vtblbase) #define spawn_static(this) #define spawn_1(this) #define _vtbl NULL CLASS(Object, ); METHOD(Object, describe, string(entity this)) { string s = _("No description"); if (cvar("developer")) { for (int i = 0, n = numentityfields(); i < n; ++i) { string value = getentityfieldstring(i, this); if (value != "") s = sprintf("%s\n%s = %s", s, entityfieldname(i), value); } } return s; } METHOD(Object, display, void(entity this, void(string name, string icon)returns)) { returns(sprintf("entity %i", this), "nopreview_map"); } ENDCLASS(Object) #undef spawn_static #undef spawn_1 #undef _vtbl #endif