mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-10 17:52:36 +00:00
## About The Pull Request ok so `REMOVE_TRAITS_IN` would sometimes run with like `type mismatch: null -= /list (/list)` credit to @RikuTheKiller for actually figuring this out and fixing it, here's their explaination on what caused the issue: > okay so > its due to linked traits > like knocked out which adds other traits > when knocked out is removed, it sends a removed signal > but sending that signal modifies the list mid for loop > so now when it tries to index it on the next iteration with a trait key thats already gone > it returns null, and tries to remove a list from a null > and it runtimes ## Why It's Good For The Game `REMOVE_TRAITS_IN` is a handy macro, and it'd be nice if it reliably worked ## Changelog no user-facing changes
127 lines
3.8 KiB
Plaintext
127 lines
3.8 KiB
Plaintext
#define SIGNAL_ADDTRAIT(trait_ref) ("addtrait " + trait_ref)
|
|
#define SIGNAL_REMOVETRAIT(trait_ref) ("removetrait " + trait_ref)
|
|
|
|
// trait accessor defines
|
|
#define ADD_TRAIT(target, trait, source) \
|
|
do { \
|
|
var/list/_L; \
|
|
if (!target._status_traits) { \
|
|
target._status_traits = list(); \
|
|
_L = target._status_traits; \
|
|
_L[trait] = list(source); \
|
|
SEND_SIGNAL(target, SIGNAL_ADDTRAIT(trait), trait); \
|
|
} else { \
|
|
_L = target._status_traits; \
|
|
if (_L[trait]) { \
|
|
_L[trait] |= list(source); \
|
|
} else { \
|
|
_L[trait] = list(source); \
|
|
SEND_SIGNAL(target, SIGNAL_ADDTRAIT(trait), trait); \
|
|
} \
|
|
} \
|
|
} while (0)
|
|
#define REMOVE_TRAIT(target, trait, sources) \
|
|
do { \
|
|
var/list/_L = target._status_traits; \
|
|
var/list/_S; \
|
|
if (sources && !islist(sources)) { \
|
|
_S = list(sources); \
|
|
} else { \
|
|
_S = sources\
|
|
}; \
|
|
if (_L?[trait]) { \
|
|
for (var/_T in _L[trait]) { \
|
|
if ((!_S && (_T != ROUNDSTART_TRAIT)) || (_T in _S)) { \
|
|
_L[trait] -= _T \
|
|
} \
|
|
};\
|
|
if (!length(_L[trait])) { \
|
|
_L -= trait; \
|
|
SEND_SIGNAL(target, SIGNAL_REMOVETRAIT(trait), trait); \
|
|
}; \
|
|
if (!length(_L)) { \
|
|
target._status_traits = null \
|
|
}; \
|
|
} \
|
|
} while (0)
|
|
#define REMOVE_TRAIT_NOT_FROM(target, trait, sources) \
|
|
do { \
|
|
var/list/_traits_list = target._status_traits; \
|
|
var/list/_sources_list; \
|
|
if (sources && !islist(sources)) { \
|
|
_sources_list = list(sources); \
|
|
} else { \
|
|
_sources_list = sources\
|
|
}; \
|
|
if (_traits_list?[trait]) { \
|
|
for (var/_trait_source in _traits_list[trait]) { \
|
|
if (!(_trait_source in _sources_list)) { \
|
|
_traits_list[trait] -= _trait_source \
|
|
} \
|
|
};\
|
|
if (!length(_traits_list[trait])) { \
|
|
_traits_list -= trait; \
|
|
SEND_SIGNAL(target, SIGNAL_REMOVETRAIT(trait), trait); \
|
|
}; \
|
|
if (!length(_traits_list)) { \
|
|
target._status_traits = null \
|
|
}; \
|
|
} \
|
|
} while (0)
|
|
#define REMOVE_TRAITS_NOT_IN(target, sources) \
|
|
do { \
|
|
var/list/_L = target._status_traits; \
|
|
var/list/_S = sources; \
|
|
if (_L) { \
|
|
for (var/_T in _L) { \
|
|
if (_L[_T]) { \
|
|
_L[_T] &= _S; \
|
|
}; \
|
|
if (!length(_L[_T])) { \
|
|
_L -= _T; \
|
|
SEND_SIGNAL(target, SIGNAL_REMOVETRAIT(_T), _T); \
|
|
}; \
|
|
};\
|
|
if (!length(_L)) { \
|
|
target._status_traits = null\
|
|
};\
|
|
}\
|
|
} while (0)
|
|
|
|
#define REMOVE_TRAITS_IN(target, sources) \
|
|
do { \
|
|
var/list/_L = target._status_traits; \
|
|
var/list/_S = sources; \
|
|
if (sources && !islist(sources)) { \
|
|
_S = list(sources); \
|
|
} else { \
|
|
_S = sources\
|
|
}; \
|
|
if (_L) { \
|
|
for (var/_T in _L) { \
|
|
if (_L[_T]) { \
|
|
_L[_T] -= _S; \
|
|
}; \
|
|
if (!length(_L[_T])) { \
|
|
_L -= _T; \
|
|
SEND_SIGNAL(target, SIGNAL_REMOVETRAIT(_T)); \
|
|
}; \
|
|
};\
|
|
if (!length(_L)) { \
|
|
target._status_traits = null\
|
|
};\
|
|
}\
|
|
} while (0)
|
|
|
|
#define HAS_TRAIT(target, trait) (target._status_traits?[trait] ? TRUE : FALSE)
|
|
#define HAS_TRAIT_FROM(target, trait, source) (HAS_TRAIT(target, trait) && (source in target._status_traits[trait]))
|
|
#define HAS_TRAIT_FROM_ONLY(target, trait, source) (HAS_TRAIT(target, trait) && (source in target._status_traits[trait]) && (length(target._status_traits[trait]) == 1))
|
|
#define HAS_TRAIT_NOT_FROM(target, trait, source) (HAS_TRAIT(target, trait) && (length(target._status_traits[trait] - source) > 0))
|
|
/// Returns a list of trait sources for this trait. Only useful for wacko cases and internal futzing
|
|
/// You should not be using this
|
|
#define GET_TRAIT_SOURCES(target, trait) (target._status_traits?[trait] || list())
|
|
/// Returns the amount of sources for a trait. useful if you don't want to have a "thing counter" stuck around all the time
|
|
#define COUNT_TRAIT_SOURCES(target, trait) length(GET_TRAIT_SOURCES(target, trait))
|
|
/// A simple helper for checking traits in a mob's mind
|
|
#define HAS_MIND_TRAIT(target, trait) (HAS_TRAIT(target, trait) || (target.mind ? HAS_TRAIT(target.mind, trait) : FALSE))
|