]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/lib/oo.qh
Fix a couple of setorigin pains
[xonotic/xonotic-data.pk3dir.git] / qcsrc / lib / oo.qh
index 6a9a2e3b7d317bea9cb6424ed77c9f15602760f5..2f871ccf17a3a6d73191dda69ea7d50f5fdfc7bc 100644 (file)
@@ -3,6 +3,7 @@
 
 #include "misc.qh"
 #include "nil.qh"
+#include "static.qh"
 
 #ifdef MENUQC
        #define NULL (null_entity)
        #define NULL (world)
 #endif
 
+.vector origin;
+.bool pure_data;
+/** deprecated, use new_pure or NEW(class) */
+#define make_pure(e) \
+       MACRO_BEGIN \
+       { \
+               (e).pure_data = true; \
+       } MACRO_END
+#define make_impure(e) \
+       MACRO_BEGIN \
+       { \
+               (e).pure_data = false; \
+       } MACRO_END
+#define is_pure(e) ((e).pure_data)
+
 .string classname;
 /** Location entity was spawned from in source */
 .string sourceLocFile;
 .int sourceLocLine;
 entity _spawn();
-entity __spawn(string _classname, string _sourceFile, int _sourceLine)
+entity __spawn(string _classname, string _sourceFile, int _sourceLine, bool pure)
 {
        entity this = _spawn();
        this.classname = _classname;
        this.sourceLocFile = _sourceFile;
        this.sourceLocLine = _sourceLine;
+       if (pure) {
+               make_pure(this);
+               #ifdef CSQC
+               setorigin(this, '0 0 10000');
+               #endif
+       }
        return this;
 }
 
@@ -30,13 +52,36 @@ entity __spawn(string _classname, string _sourceFile, int _sourceLine)
 #ifndef QCC_SUPPORT_ENTITYCLASS
        #define entityclass_2(name, base) typedef entity name
        #define class(name)
-       #define new(class) __spawn( #class, __FILE__, __LINE__)
+       #define _new(class, pure) __spawn( #class, __FILE__, __LINE__, pure)
 #else
        #define entityclass_2(name, base) entityclass name : base {}
        #define class(name) [[class(name)]]
-       #define new(class) ((class) __spawn( #class, __FILE__, __LINE__))
+       #define _new(class, pure) ((class) __spawn( #class, __FILE__, __LINE__, pure))
+#endif
+/** entities you care about seeing (.origin works) */
+#define new(class) _new(class, false)
+/** purely logical entities (.origin doesn't work) */
+#define new_pure(class) _new(class, true)
+#define spawn() __spawn("entity", __FILE__, __LINE__, false)
+
+entity _clearentity_ent;
+STATIC_INIT(clearentity)
+{
+       _clearentity_ent = new_pure(clearentity);
+       make_pure(_clearentity_ent);
+}
+void clearentity(entity e)
+{
+#ifdef CSQC
+               int n = e.entnum;
+#endif
+       bool was_pure = is_pure(e);
+       copyentity(_clearentity_ent, e);
+       if (!was_pure) make_impure(e);
+#ifdef CSQC
+               e.entnum = n;
 #endif
-#define spawn() new(entity)
+}
 
 // Classes have a `spawn##cname(entity)` constructor
 // The parameter is used across [[accumulate]] functions
@@ -44,7 +89,7 @@ entity __spawn(string _classname, string _sourceFile, int _sourceLine)
 // Macros to hide this implementation detail:
 #ifdef GMQCC
        #define NEW(cname, ...) \
-               OVERLOAD(spawn##cname, new(cname),##__VA_ARGS__)
+               OVERLOAD(spawn##cname, new_pure(cname),##__VA_ARGS__)
 
        #define CONSTRUCT(cname, ...) \
                OVERLOAD(spawn##cname, this,##__VA_ARGS__)
@@ -52,7 +97,7 @@ entity __spawn(string _classname, string _sourceFile, int _sourceLine)
        #define NEW_(cname, ...) \
                OVERLOAD_(spawn##cname, __VA_ARGS__)
        #define NEW(cname, ...) \
-               NEW_(cname, new(cname),##__VA_ARGS__)(new(cname),##__VA_ARGS__)
+               NEW_(cname, new_pure(cname),##__VA_ARGS__)(new_pure(cname),##__VA_ARGS__)
 
        #define CONSTRUCT_(cname, ...) \
                OVERLOAD_(spawn##cname, __VA_ARGS__)
@@ -81,7 +126,7 @@ STATIC_INIT(RegisterClasses)
        entity cname##_vtbl; \
        void cname##_vtbl_init() \
        { \
-               cname e = new(vtbl); \
+               cname e = new_pure(vtbl); \
                spawn##cname##_static(e); \
                e.vtblname = #cname; \
                /* Top level objects refer to themselves */ \
@@ -120,27 +165,43 @@ STATIC_INIT(RegisterClasses)
                spawn##base##_1(this);              \
        }
 
-#define METHOD(cname, name, prototype)      \
-       class(cname).prototype name;           \
-       prototype cname##_##name;               \
+#define METHOD_REFERENCE(cname, name) \
+       cname##_##name
+
+#define STATIC_METHOD(cname, name, prototype) \
+       prototype METHOD_REFERENCE(cname, name)
+
+#define METHOD(cname, name, prototype) \
+       STATIC_METHOD(cname, name, prototype); \
+       class(cname) .prototype name; \
        INIT_STATIC(cname) \
        { \
-               this.name = cname##_##name; \
+               this.name = METHOD_REFERENCE(cname, name); \
        } \
-       prototype cname##_##name
+       STATIC_METHOD(cname, name, prototype)
 
 #define ATTRIB(cname, name, type, val)      \
        class(cname).type name;                \
        INIT(cname) \
        { \
+               noref bool strzone; /* Error on strzone() calls. */ \
                this.name = val; \
        }
 
+#define ATTRIB_STRZONE(cname, name, type, val)      \
+       class(cname).type name;                \
+       INIT(cname) \
+       { \
+               if (this.name) \
+                       strunzone(this.name); \
+               this.name = strzone(val); \
+       }
+
 #define ATTRIBARRAY(cname, name, type, cnt) \
        class(cname).type name[cnt];
 
 #define ENDCLASS(cname) \
-       [[last]] INIT(cname) \
+       INIT(cname) \
        { \
                return this; \
        }
@@ -164,7 +225,7 @@ CLASS(Object, );
                }
                return s;
        }
-       METHOD(Object, display, void(entity this, void(string name, string icon)returns))
+       METHOD(Object, display, void(entity this, void(string name, string icon) returns))
        {
                returns(sprintf("entity %i", this), "nopreview_map");
        }