-#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;
* return false;
* }
*/
- ATTRIB(Callback, cbc_func, bool(), func_null)
+ ATTRIB(Callback, cbc_func, bool());
CONSTRUCTOR(Callback, bool() func) {
CONSTRUCT(Callback);
this.cbc_func = func;
*/
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;
}
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;
#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;
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); \
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,
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;
}
ENDCLASS(Mutator)
-REGISTRY(Mutators, BITS(6))
+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;
-bool Mutator_Add(Mutator mut)
+#ifdef GAMEQC
+/** server mutators activate corresponding client mutators for all clients */
+REGISTER_NET_LINKED(Mutator)
+
+#ifdef SVQC
+bool Mutator_SendEntity(entity this, entity to, int sf)
{
- 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;
+ int chan = MSG_ENTITY;
+ WriteHeader(chan, Mutator);
+ WriteString(chan, this.registered_id);
+ return true;
+}
+#endif
+
+#ifdef CSQC
+void NET_Mutator_Remove(entity this)
+{
+ string s = this.netname;
+ 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, {
+ FOREACH(Mutators, it.registered_id == s, { Mutator_Add(it); ++added; });
+ });
+ if (added > 1) LOG_WARNF("Added more than one mutator for %s", s);
}
- loaded_mutators[j] = mut;
+}
+#endif
+
+#endif
+
+bool Mutator_Add(Mutator 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", mut.m_name);
+#ifdef SVQC
+ Net_LinkEntity(mut, false, 0, Mutator_SendEntity);
+#endif
return true;
}
backtrace("WARNING: when adding mutator: adding failed, rolling back\n");
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", mut.m_name);
+#ifdef SVQC
+ Net_UnlinkEntity(mut);
+#endif
}
#define REGISTER_MUTATOR(id, dependence) \
bool ret = MUTATORFUNCTION_##id##_hooks(mode); if (ret) return ret; \
} \
bool MUTATOR_##id##_check() { return dependence; } \
- REGISTER(RegisterMutators, MUTATOR, Mutators, id, m_id, NEW(Mutator, #id, MUTATORFUNCTION_##id)) \
+ REGISTER(Mutators, MUTATOR, id, m_id, NEW(Mutator, #id, MUTATORFUNCTION_##id)) \
{ this.mutatorcheck = MUTATOR_##id##_check; } \
[[accumulate]] bool MUTATORFUNCTION_##id(int mode)
}
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
[[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)
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