]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/common/mutators/base.qh
Merge branch 'master' into Lyberta/StandaloneOverkillWeapons
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / mutators / base.qh
index 6932db8bf99dce6c69de41dfdcf9d3ae2147dda1..4f940c42b3c016f3e9131e0c6d3b213bc4d5497a 100644 (file)
@@ -1,5 +1,8 @@
-#ifndef MUTATORS_BASE_H
-#define MUTATORS_BASE_H
+#pragma once
+
+#ifdef CSQC
+#include <client/main.qh>
+#endif
 
 const int CBC_ORDER_FIRST = 1;
 const int CBC_ORDER_LAST = 2;
@@ -20,7 +23,7 @@ CLASS(Callback, Object)
      *     return false;
      * }
      */
-    ATTRIB(Callback, cbc_func, bool(), func_null)
+    ATTRIB(Callback, cbc_func, bool());
     CONSTRUCTOR(Callback, bool() func) {
         CONSTRUCT(Callback);
         this.cbc_func = func;
@@ -32,9 +35,9 @@ ENDCLASS(Callback)
  */
 CLASS(CallbackChain, Object)
     CLASS(CallbackNode, Object)
-        ATTRIB(CallbackNode, cbc, Callback, NULL)
-        ATTRIB(CallbackNode, cbc_next, CallbackNode, NULL)
-        ATTRIB(CallbackNode, cbc_order, int, 0)
+        ATTRIB(CallbackNode, cbc, Callback);
+        ATTRIB(CallbackNode, cbc_next, CallbackNode);
+        ATTRIB(CallbackNode, cbc_order, int, 0);
         CONSTRUCTOR(CallbackNode, Callback it, int order) {
             CONSTRUCT(CallbackNode);
             this.cbc = it;
@@ -42,8 +45,8 @@ CLASS(CallbackChain, Object)
         }
     ENDCLASS(CallbackNode)
 
-    ATTRIB(CallbackChain, cbc_next, CallbackNode, NULL)
-    ATTRIB(CallbackChain, cbc_order, int, 0)
+    ATTRIB(CallbackChain, cbc_next, CallbackNode);
+    ATTRIB(CallbackChain, cbc_order, int, 0);
     CONSTRUCTOR(CallbackChain, string _name) {
         CONSTRUCT(CallbackChain);
         this.netname = _name;
@@ -112,7 +115,7 @@ ENDCLASS(CallbackChain)
 #define _MUTATOR_HANDLE_NOP(type, id)
 #define _MUTATOR_HANDLE_PARAMS(type, id) , type in_##id
 #define _MUTATOR_HANDLE_PREPARE(type, id) id = in_##id;
-#define _MUTATOR_HANDLE_PUSHTMP(type, id) type tmp_##id = id;
+#define _MUTATOR_HANDLE_PUSHTMP(type, id) TC(type, id); type tmp_##id = id;
 #define _MUTATOR_HANDLE_PUSHOUT(type, id) type out_##id = id;
 #define _MUTATOR_HANDLE_POPTMP(type, id) id = tmp_##id;
 #define _MUTATOR_HANDLE_POPOUT(type, id) id = out_##id;
@@ -120,9 +123,10 @@ ENDCLASS(CallbackChain)
 void RegisterHooks() {};
 void RegisterCallbacks() {};
 
-#define _MUTATOR_HOOKABLE(id, ...) CallbackChain HOOK_##id; bool __Mutator_Send_##id(__VA_ARGS__)
-#define MUTATOR_HOOKABLE(id, params) \
-    _MUTATOR_HOOKABLE(id, int params(_MUTATOR_HANDLE_PARAMS, _MUTATOR_HANDLE_NOP)) { \
+#define MUTATOR_HOOKABLE(id, params) _MUTATOR_HOOKABLE(id, params)
+#define _MUTATOR_HOOKABLE(id, params) \
+    CallbackChain HOOK_##id;  \
+    bool __Mutator_Send_##id(int params(_MUTATOR_HANDLE_PARAMS, _MUTATOR_HANDLE_NOP)) { \
         params(_MUTATOR_HANDLE_PUSHTMP, _MUTATOR_HANDLE_NOP) \
         params(_MUTATOR_HANDLE_PREPARE, _MUTATOR_HANDLE_NOP) \
         bool ret = CallbackChain_Call(HOOK_##id); \
@@ -132,7 +136,13 @@ void RegisterCallbacks() {};
         return ret; \
     } \
     [[accumulate]] void RegisterHooks() { HOOK_##id = NEW(CallbackChain, #id); }
-#define MUTATOR_CALLHOOK(id, ...) APPLY(__Mutator_Send_##id, 0, ##__VA_ARGS__)
+
+#define MUTATOR_CALLHOOK(id, ...) _MUTATOR_CALLHOOK(id, __VA_ARGS__)
+#ifdef __STDC__
+    #define _MUTATOR_CALLHOOK(id, ...) APPLY(__Mutator_Send_##id, 0 P99_IF_EMPTY(__VA_ARGS__)()(, __VA_ARGS__))
+#else
+    #define _MUTATOR_CALLHOOK(id, ...) APPLY(__Mutator_Send_##id, 0, ##__VA_ARGS__)
+#endif
 
 enum {
     MUTATOR_REMOVING,
@@ -140,13 +150,13 @@ enum {
     MUTATOR_ROLLING_BACK
 };
 
-typedef bool(int) mutatorfunc_t;
+USING(mutatorfunc_t, bool(int));
 
 CLASS(Mutator, Object)
-    ATTRIB(Mutator, m_id, int, 0)
-    ATTRIB(Mutator, m_name, string, string_null)
-    ATTRIB(Mutator, mutatorfunc, mutatorfunc_t, func_null)
-    ATTRIB(Mutator, mutatorcheck, bool(), func_null)
+    ATTRIB(Mutator, m_id, int, 0);
+    ATTRIB(Mutator, m_name, string);
+    ATTRIB(Mutator, mutatorfunc, mutatorfunc_t);
+    ATTRIB(Mutator, mutatorcheck, bool());
     CONSTRUCTOR(Mutator, string _name, mutatorfunc_t func) {
         CONSTRUCT(Mutator);
         this.m_name = _name;
@@ -156,12 +166,13 @@ ENDCLASS(Mutator)
 
 REGISTRY(Mutators, BITS(7))
 #define Mutators_from(i) _Mutators_from(i, NULL)
-Mutator loaded_mutators[Mutators_MAX];
 bool Mutator_Add(Mutator mut);
 void Mutator_Remove(Mutator mut);
 bool mutator_log = false;
+.bool m_added;
 
-#ifndef MENUQC
+#ifdef GAMEQC
+/** server mutators activate corresponding client mutators for all clients */
 REGISTER_NET_LINKED(Mutator)
 
 #ifdef SVQC
@@ -175,26 +186,27 @@ bool Mutator_SendEntity(entity this, entity to, int sf)
 #endif
 
 #ifdef CSQC
-void NET_Mutator_Remove()
+void NET_Mutator_Remove(entity this)
 {
-    SELFPARAM();
     string s = this.netname;
-    WITH(bool, mutator_log, true, LAMBDA(
-        FOREACH(Mutators, it.registered_id == s, LAMBDA(Mutator_Remove(it)));
-    ));
+    WITH(bool, mutator_log, true, {
+        FOREACH(Mutators, it.registered_id == s, Mutator_Remove(it));
+    });
 }
 NET_HANDLE(Mutator, bool isNew)
 {
+    make_pure(this);
     string s = this.netname = ReadString();
     return = true;
     if (isNew)
     {
+        make_pure(this);
         this.entremove = NET_Mutator_Remove;
         int added = 0;
-        WITH(bool, mutator_log, true, LAMBDA(
-            FOREACH(Mutators, it.registered_id == s, LAMBDA(Mutator_Add(it); ++added));
-        ));
-        if (added > 1) LOG_WARNINGF("Added more than one mutator for %s\n", s);
+        WITH(bool, mutator_log, true, {
+            FOREACH(Mutators, it.registered_id == s, { Mutator_Add(it); ++added; });
+        });
+        if (added > 1) LOG_WARNF("Added more than one mutator for %s", s);
     }
 }
 #endif
@@ -203,22 +215,14 @@ NET_HANDLE(Mutator, bool isNew)
 
 bool Mutator_Add(Mutator mut)
 {
-    int j = -1;
-    for (int i = 0; i < Mutators_MAX; ++i) {
-        if (loaded_mutators[i] == mut)
-            return true; // already added
-        if (!(loaded_mutators[i]))
-            j = i;
-    }
-    if (j < 0) {
-        backtrace("WARNING: too many mutators, cannot add any more\n");
-        return false;
-    }
-    loaded_mutators[j] = mut;
+    if(mut.m_added)
+        return true; // already added
+
+    mut.m_added = true;
     mutatorfunc_t func = mut.mutatorfunc;
     if (!func(MUTATOR_ADDING)) {
         // good
-        if (mutator_log) LOG_TRACEF("Mutator: added %s\n", mut.m_name);
+        if (mutator_log) LOG_TRACEF("Mutator: added %s", mut.m_name);
 #ifdef SVQC
         Net_LinkEntity(mut, false, 0, Mutator_SendEntity);
 #endif
@@ -234,21 +238,19 @@ bool Mutator_Add(Mutator mut)
 
 void Mutator_Remove(Mutator mut)
 {
-    int i;
-    for (i = 0; i < Mutators_MAX; ++i)
-        if (loaded_mutators[i] == mut)
-            break;
-    if (i >= Mutators_MAX) {
+    if(!mut.m_added)
+    {
         backtrace("WARNING: removing not-added mutator\n");
         return;
     }
-    loaded_mutators[i] = NULL;
+
+    mut.m_added = false;
     mutatorfunc_t func = mut.mutatorfunc;
     if (func(MUTATOR_REMOVING)) {
         // baaaaad
         error("Mutator_Remove: removing mutator failed");
     }
-    if (mutator_log) LOG_TRACEF("Mutator: removed %s\n", mut.m_name);
+    if (mutator_log) LOG_TRACEF("Mutator: removed %s", mut.m_name);
 #ifdef SVQC
     Net_UnlinkEntity(mut);
 #endif
@@ -272,12 +274,26 @@ STATIC_INIT(Mutators) {
 }
 
 STATIC_INIT_LATE(Mutators) {
-    FOREACH(Mutators, it.mutatorcheck(), LAMBDA(Mutator_Add(it)));
+    FOREACH(Mutators, it.mutatorcheck(), Mutator_Add(it));
 }
 
 #define MUTATOR_ONADD                   if (mode == MUTATOR_ADDING)
 #define MUTATOR_ONREMOVE                if (mode == MUTATOR_REMOVING)
 #define MUTATOR_ONROLLBACK_OR_REMOVE    if (mode == MUTATOR_REMOVING || mode == MUTATOR_ROLLING_BACK)
+
+#define MUTATOR_STATIC() MACRO_BEGIN { \
+    MUTATOR_ONADD { \
+        /* game loads at time 1 */ \
+        if (time > 1) { \
+            error("This is a game type and it cannot be added at runtime."); \
+        } \
+    } \
+       MUTATOR_ONREMOVE { \
+               LOG_INFO("This is a game type and it cannot be removed at runtime."); \
+               return -1; \
+       } \
+} MACRO_END
+
 #define MUTATOR_ADD(name)               Mutator_Add(MUTATOR_##name)
 #define MUTATOR_REMOVE(name)            Mutator_Remove(MUTATOR_##name)
 #define MUTATOR_RETURNVALUE             CallbackChain_ReturnValue
@@ -288,7 +304,8 @@ STATIC_INIT_LATE(Mutators) {
     [[accumulate]] void RegisterCallbacks() { CALLBACK_##name = NEW(Callback, func); }
 
 #define MUTATOR_HOOKFUNCTION(...) \
-    EVAL(OVERLOAD(MUTATOR_HOOKFUNCTION, __VA_ARGS__))
+    EVAL_MUTATOR_HOOKFUNCTION(OVERLOAD(MUTATOR_HOOKFUNCTION, __VA_ARGS__))
+#define EVAL_MUTATOR_HOOKFUNCTION(...) __VA_ARGS__
 
 #define MUTATOR_HOOKFUNCTION_2(mut, cb) \
     MUTATOR_HOOKFUNCTION_3(mut, cb, CBC_ORDER_ANY)
@@ -299,18 +316,16 @@ STATIC_INIT_LATE(Mutators) {
     bool mut##_##cb() { return = false; } \
     [[accumulate]] bool mut##_##cb()
 
-#define MUTATOR_HOOK(cb, func, order) do {                              \
+#define MUTATOR_HOOK(cb, func, order) MACRO_BEGIN {                     \
     MUTATOR_ONADD {                                                     \
         if (!CallbackChain_Add(HOOK_##cb, CALLBACK_##func, order)) {    \
-            LOG_INFO("HOOK FAILED: ", #cb, ":", #func, "\n");           \
+            LOG_INFO("HOOK FAILED: ", #cb, ":", #func);                 \
             return true;                                                \
         }                                                               \
     }                                                                   \
     MUTATOR_ONROLLBACK_OR_REMOVE {                                      \
         CallbackChain_Remove(HOOK_##cb, CALLBACK_##func);               \
     }                                                                   \
-} while (0)
+} MACRO_END
 
 #include "events.qh"
-
-#endif