From b9964b76f6a1f3bf2530ceabad08212d39dd3f58 Mon Sep 17 00:00:00 2001
From: TimePath <andrew.hardaker1995@gmail.com>
Date: Wed, 19 Aug 2015 20:55:21 +1000
Subject: [PATCH] Mutator registry

---
 mod/server/main.qc                | 24 +++--------------
 qcsrc/Makefile                    |  2 +-
 qcsrc/common/mutators/base.qh     | 45 ++++++++++++++++++++++++++++---
 qcsrc/server/mutators/mutators.qc |  4 +++
 4 files changed, 50 insertions(+), 25 deletions(-)

diff --git a/mod/server/main.qc b/mod/server/main.qc
index f6c94ca65..d84239c0b 100644
--- a/mod/server/main.qc
+++ b/mod/server/main.qc
@@ -1,25 +1,9 @@
-MUTATOR_HOOKFUNCTION(mod_BuildMutatorsString)
-{
+REGISTER_MUTATOR(mutator_mod, cvar("g_mod"));
+
+MUTATOR_HOOKFUNCTION(mutator_mod, BuildMutatorsString) {
     ret_string = strcat(ret_string, ":mod");
-    return false;
 }
 
-MUTATOR_HOOKFUNCTION(mod_BuildMutatorsPrettyString)
-{
+MUTATOR_HOOKFUNCTION(mutator_mod, BuildMutatorsPrettyString) {
     ret_string = strcat(ret_string, ", Mod");
-    return false;
-}
-
-MUTATOR_DECLARATION(mutator_mod);
-MUTATOR_DEFINITION(mutator_mod)
-{
-    MUTATOR_HOOK(BuildMutatorsString, mod_BuildMutatorsString, CBC_ORDER_ANY);
-    MUTATOR_HOOK(BuildMutatorsPrettyString, mod_BuildMutatorsPrettyString, CBC_ORDER_ANY);
-    return false;
-}
-
-[[accumulate]]
-void mutators_add()
-{
-    MUTATOR_ADD(mutator_mod);
 }
diff --git a/qcsrc/Makefile b/qcsrc/Makefile
index 0ccf4f971..3f58e672c 100644
--- a/qcsrc/Makefile
+++ b/qcsrc/Makefile
@@ -13,7 +13,7 @@ QCCFLAGS ?= \
 	-std=gmqcc \
 	-O3 -flno \
 	-Werror -fno-bail-on-werror -Wall \
-	-fftepp -fftepp-predefs -Wcpp -futf8 \
+	-fftepp -fftepp-predefs -Wcpp -futf8 -freturn-assignments \
 	$(QCCFLAGS_WTFS) \
 	$(QCCFLAGS_FEATURES) \
 	$(QCCFLAGS_EXTRA) $(QCCFLAGS_WATERMARK)
diff --git a/qcsrc/common/mutators/base.qh b/qcsrc/common/mutators/base.qh
index dfd73a7ed..270e1d874 100644
--- a/qcsrc/common/mutators/base.qh
+++ b/qcsrc/common/mutators/base.qh
@@ -143,8 +143,10 @@ enum {
 typedef bool(int) mutatorfunc_t;
 
 CLASS(Mutator, Object)
+    ATTRIB(Mutator, m_id, int, 0)
     ATTRIB(Mutator, mutatorname, string, string_null)
     ATTRIB(Mutator, mutatorfunc, mutatorfunc_t, func_null)
+    METHOD(Mutator, mutatorcheck, bool())
     CONSTRUCTOR(Mutator, string name, mutatorfunc_t func) {
         CONSTRUCT(Mutator);
         this.mutatorname = name;
@@ -206,17 +208,52 @@ void Mutator_Remove(Mutator mut)
 #define MUTATOR_DEFINITION(name) \
     bool MUTATORFUNCTION_##name(int mode); \
     STATIC_INIT(MUTATOR_##name) { MUTATOR_##name = NEW(Mutator, #name, MUTATORFUNCTION_##name); } \
-    bool MUTATORFUNCTION_##name(int mode)
+    [[last]] bool MUTATORFUNCTION_##name(int mode)
+
+void RegisterMutators();
+const int MUTATORS_MAX = MAX_MUTATORS;
+entity MUTATORS[MUTATORS_MAX], MUTATORS_first, MUTATORS_last;
+int MUTATORS_COUNT;
+#define REGISTER_MUTATOR(id, dependence) \
+    bool MUTATORFUNCTION_##id##_hooks(int mode) { return = false; } \
+    bool MUTATORFUNCTION_##id(int mode) { \
+        return = false; \
+        bool ret = MUTATORFUNCTION_##id##_hooks(mode); if (ret) return ret; \
+    } \
+    bool MUTATOR_##id##_check() { return dependence; } \
+    REGISTER(RegisterMutators, MUTATOR, MUTATORS, MUTATORS_COUNT, id, m_id, NEW(Mutator, #id, MUTATORFUNCTION_##id)) \
+    { this.mutatorcheck = MUTATOR_##id##_check; } \
+    [[accumulate]] bool MUTATORFUNCTION_##id(int mode)
+REGISTER_REGISTRY(RegisterMutators)
+
 #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_ADD(name)               Mutator_Add(MUTATOR_##name)
 #define MUTATOR_REMOVE(name)            Mutator_Remove(MUTATOR_##name)
 #define MUTATOR_RETURNVALUE             CallbackChain_ReturnValue
-#define MUTATOR_HOOKFUNCTION(name) \
-    bool HOOKFUNCTION_##name(); \
-    Callback CALLBACK_##name; STATIC_INIT(CALLBACK_##name) { CALLBACK_##name = NEW(Callback, HOOKFUNCTION_##name); } \
+
+#define _MUTATOR_CALLBACK(name, func) \
+    Callback CALLBACK_##name; \
+    bool func(); \
+    STATIC_INIT(CALLBACK_##name) { CALLBACK_##name = NEW(Callback, func); }
+
+#define MUTATOR_HOOKFUNCTION(...) \
+    OVERLOAD(MUTATOR_HOOKFUNCTION, __VA_ARGS__)
+
+#define MUTATOR_HOOKFUNCTION_1(name) \
+    _MUTATOR_CALLBACK(name, HOOKFUNCTION_##name) \
     bool HOOKFUNCTION_##name()
+
+#define MUTATOR_HOOKFUNCTION_2(mut, cb) \
+    MUTATOR_HOOKFUNCTION(mut, cb, CBC_ORDER_ANY)
+
+#define MUTATOR_HOOKFUNCTION_3(mut, cb, order) \
+    _MUTATOR_CALLBACK(mut##_##cb, mut##_##cb) \
+    [[accumulate]] bool MUTATORFUNCTION_##mut##_hooks(int mode) { MUTATOR_HOOK(cb, mut##_##cb, order); } \
+    bool mut##_##cb() { return = false; } \
+    [[accumulate]] bool mut##_##cb()
+
 #define MUTATOR_HOOK(cb, func, order) do {                              \
     MUTATOR_ONADD {                                                     \
         if (!CallbackChain_Add(HOOK_##cb, CALLBACK_##func, order)) {    \
diff --git a/qcsrc/server/mutators/mutators.qc b/qcsrc/server/mutators/mutators.qc
index 0c6301532..b039cf37f 100644
--- a/qcsrc/server/mutators/mutators.qc
+++ b/qcsrc/server/mutators/mutators.qc
@@ -34,5 +34,9 @@ void mutators_add()
 	CHECK_MUTATOR_ADD("g_overkill", mutator_overkill, !cvar("g_instagib") && !g_nexball && cvar_string("g_mod_balance") == "Overkill");
 	CHECK_MUTATOR_ADD("g_buffs", mutator_buffs, 1);
 
+	FOREACH(MUTATORS, it.mutatorcheck(), LAMBDA(
+		Mutator_Add(it)
+	));
+
 	#undef CHECK_MUTATOR_ADD
 }
-- 
2.39.5