Files
Bubberstation/code/__HELPERS/memory_helpers.dm
SkyratBot 25f4961156 [MIRROR] Refactors memories to be less painful to add and apply, moves memory detail / text to memory subtypes. Adds some new memories to demonstrate. [MDB IGNORE] (#18487)
* Refactors memories to be less painful to add and apply, moves memory detail / text to memory subtypes. Adds some new memories to demonstrate.  (#72110)

So, a huge issue with memories and - what I personally believe is the
reason why not many have been added since their inception is - they're
very annoying to add!

Normally, adding subtypes of stuff like traumas or hallucinations are as
easy as doing just that, adding a subtype.

But memories used this factory argument passing method combined with
holding all their strings in a JSON file which made it just frustrating
to add, debug, or just mess with.

It also made it much harder to organize new memories keep it clean for
stuff like downstreams.

So I refactored it. Memories are now handled on a subtype by subtype
basis, instead of all memories being a `/datum/memory`.

Any variety of arguments can be passed into memories like addcomponent
(KWARGS) so each subtype can have their own `new` parameters.

This makes it much much easier to add a new memory. All you need to do
is make your subtype and add it somewhere. Don't need to mess with jsons
or defines or anything.

To demonstrate this, I added a few memories. Some existing memories had
their story values tweak to compensate.

Makes it way simpler to add new memories. Maybe we'll get some more fun
ones now?

🆑 Melbert
add: Roundstart captains will now memorize the code to the spare ID
safe.
add: Traitors will now memorize the location and code to their uplink.
add: Heads of staff winning a revolution will now get a memory of their
success.
add: Heads of staff and head revolutionaries who lose their respective
sides of the revolution also get a memory of their failure.
add: Completing a ritual of knowledge as a heretic grants you a quality
memory.
add: Successfully defusing a bomb now grants you a cool memory. Failing
it will also grant you a memory, though you will likely not be alive to
see it.
add: Planting bombs now increase their memory quality depending on how
cool the bomb is.
refactor: Memories have been refactored to be much easier to add.
/🆑

* Modular!

Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com>
Co-authored-by: Funce <funce.973@gmail.com>
2023-01-17 12:51:58 +13:00

115 lines
4.5 KiB
Plaintext

/**
* Adds a memory to all carbon mobs in a certain range of a certain atom.
*
* The third argument should be a typepath of a /datum/memory.
*
* Two things of note when using this:
* * If the source atom is a mob, it will be added to that mob if possible.
* * The protagonist of the memory is set to the memorizer by default. If sourced from a mob, you need to set the protagonist manually.
*
* Beyond that, can be supplied with named arguments pertaining to your memory type.
* Common arguments include:
* * protagonist: The main subject of the memory
* * deuteragonist: The side subject of the memory. Doesn't necessarily have to be a mob!
* * antagonist: The main villain of the memory. Also doesn't necessarily have to be a mob!
*/
#define add_memory_in_range(source, range, arguments...) _add_memory_in_range(source, range, list(##arguments))
/// Unless you need to use this for an explicit reason, use the add_memory_in_range macro wrapper.
/proc/_add_memory_in_range(atom/source, range = 7, list/memory_args)
for(var/mob/living/carbon/memorizer in hearers(range, source))
memorizer.mind?._add_memory(memory_args.Copy()) // One copy for each memory, since it mutates the list
/**
* Adds a memory to the target mob.
*
* The first argument should be a typepath of a /datum/memory.
*
* If the mob already has a memory of that type, it will be deleted.
*
* Beyond that, can be supplied with named arguments pertaining to your memory type.
* Common arguments include:
* * protagonist: The main subject of the memory
* * deuteragonist: The side subject of the memory. Doesn't necessarily have to be a mob!
* * antagonist: The main villain of the memory. Also doesn't necessarily have to be a mob!
*
* Returns the datum memory created, or null otherwise.
*/
#define add_mob_memory(arguments...) mind?._add_memory(list(##arguments))
// Wrapper for _add_memory so we can used named arguments.
/**
* Adds a memory to the target mind.
*
* The first argument should be a typepath of a /datum/memory.
*
* If the mob already has a memory of that type, it will be deleted.
*
* Beyond that, can be supplied with named arguments pertaining to your memory type.
* Common arguments include:
* * protagonist: The main subject of the memory
* * deuteragonist: The side subject of the memory. Doesn't necessarily have to be a mob!
* * antagonist: The main villain of the memory. Also doesn't necessarily have to be a mob!
*
* Returns the datum memory created, or null otherwise.
*/
#define add_memory(arguments...) _add_memory(list(##arguments))
/// Unless you need to use this for an explicit reason, use the add_memory, add_mob_memory, or add_memory_in_range macro wrappers.
/datum/mind/proc/_add_memory(list/memory_args)
RETURN_TYPE(/datum/memory)
var/datum/memory/memory_type = memory_args[1]
if(!ispath(memory_type))
CRASH("add_memory called with an invalid memory type. (Got: [memory_type || "null"])")
if(current)
var/new_memory_flags = initial(memory_type.memory_flags)
if(!(new_memory_flags & MEMORY_SKIP_UNCONSCIOUS) && current.stat >= UNCONSCIOUS)
return
if(new_memory_flags & MEMORY_CHECK_BLINDNESS && current.is_blind())
return
if(new_memory_flags & MEMORY_CHECK_DEAFNESS && HAS_TRAIT(current, TRAIT_DEAF))
return
var/datum/memory/replaced_memory = memories[memory_type]
if(replaced_memory)
qdel(replaced_memory)
memory_args[1] = src
var/datum/memory/created_memory = new memory_type(arglist(memory_args))
memories[memory_type] = created_memory
return created_memory
/**
* Simple / sane proc for giving a mob the option to select one of their memories
* that do not have the flags [MEMORY_FLAG_ALREADY_USED] or [MEMORY_NO_STORY].
*
* Arguments
* * verbage: This is used in the tgui selection menu, explains what they're selecting a memory to do.
*
* Returns the memory selected, or null otherwise.
*/
/datum/mind/proc/select_memory(verbage = "use")
RETURN_TYPE(/datum/memory)
var/list/choice_list = list()
for(var/key in memories)
var/datum/memory/memory_iter = memories[key]
if(memory_iter.memory_flags & (MEMORY_FLAG_ALREADY_USED|MEMORY_NO_STORY)) //Can't use memories multiple times
continue
choice_list[memory_iter.name] = memory_iter
var/choice = tgui_input_list(usr, "Select a memory to [verbage]", "Memory Selection?", choice_list)
if(isnull(choice))
return FALSE
if(isnull(choice_list[choice]))
return FALSE
var/datum/memory/memory_choice = choice_list[choice]
return memory_choice
/// Small helper to clean out memories.
/datum/mind/proc/wipe_memory()
QDEL_LIST_ASSOC_VAL(memories)