From d537bb17b2ce415dd81825545f2b1f3cb04de612 Mon Sep 17 00:00:00 2001 From: Remie Richards Date: Thu, 16 Feb 2017 20:39:34 +0000 Subject: [PATCH] Adds a soullink datum (#23869) * Adds a soullink datum, used to tie one or more mobs together allowing actions that affect one to affect the other. Includes 3 examples. * why isn't runtimestation the default anyway --- code/datums/soullink.dm | 151 +++++++++++++++++++++++++++++++ code/modules/mob/living/death.dm | 8 ++ tgstation.dme | 1 + 3 files changed, 160 insertions(+) create mode 100644 code/datums/soullink.dm diff --git a/code/datums/soullink.dm b/code/datums/soullink.dm new file mode 100644 index 00000000000..ee99103c3dc --- /dev/null +++ b/code/datums/soullink.dm @@ -0,0 +1,151 @@ + + +/mob/living + var/list/ownedSoullinks //soullinks we are the owner of + var/list/sharedSoullinks //soullinks we are a/the sharer of + +/mob/living/Destroy() + for(var/s in ownedSoullinks) + var/datum/soullink/S = s + S.ownerDies(FALSE) + qdel(s) //If the owner is destroy()'d, the soullink is destroy()'d + ownedSoullinks = null + for(var/s in sharedSoullinks) + var/datum/soullink/S = s + S.sharerDies(FALSE) + S.removeSoulsharer(src) //If a sharer is destroy()'d, they are simply removed + sharedSoullinks = null + return ..() + + + +//Keeps track of a Mob->Mob (potentially Player->Player) connection +//Can be used to trigger actions on one party when events happen to another +//Eg: shared deaths +//Can be used to form a linked list of mob-hopping +//Does NOT transfer with minds +/datum/soullink + var/mob/living/soulowner + var/mob/living/soulsharer + var/id //Optional ID, for tagging and finding specific instances + +/datum/soullink/Destroy() + if(soulowner) + LAZYREMOVE(soulowner.ownedSoullinks, src) + soulowner = null + if(soulsharer) + LAZYREMOVE(soulsharer.sharedSoullinks, src) + soulsharer = null + return ..() + +/datum/soullink/proc/removeSoulsharer(mob/living/sharer) + if(soulsharer == sharer) + soulsharer = null + LAZYREMOVE(sharer.sharedSoullinks, src) + +//Used to assign variables, called primarily by soullink() +//Override this to create more unique soullinks (Eg: 1->Many relationships) +//Return TRUE/FALSE to return the soullink/null in soullink() +/datum/soullink/proc/parseArgs(mob/living/owner, mob/living/sharer) + if(!owner || !sharer) + return FALSE + soulowner = owner + soulsharer = sharer + LAZYADD(owner.ownedSoullinks, src) + LAZYADD(sharer.sharedSoullinks, src) + return TRUE + +//Runs after /living death() +//Override this for content +/datum/soullink/proc/ownerDies(gibbed, mob/living/owner) + +//Runs after /living death() +//Override this for content +/datum/soullink/proc/sharerDies(gibbed, mob/living/owner) + +//Quick-use helper +/proc/soullink(typepath, ...) + var/datum/soullink/S = new typepath() + if(S.parseArgs(arglist(args.Copy(2, 0)))) + return S + + + +///////////////// +// MULTISHARER // +///////////////// +//Abstract soullink for use with 1 Owner -> Many Sharer setups +/datum/soullink/multisharer + var/list/soulsharers + +/datum/soullink/multisharer/parseArgs(mob/living/owner, list/sharers) + if(!owner || !LAZYLEN(sharers)) + return FALSE + soulowner = owner + soulsharers = sharers + LAZYADD(owner.ownedSoullinks, src) + for(var/l in sharers) + var/mob/living/L = l + LAZYADD(L.sharedSoullinks, src) + return TRUE + +/datum/soullink/multisharer/removeSoulsharer(mob/living/sharer) + LAZYREMOVE(soulsharers, sharer) + + + +///////////////// +// SHARED FATE // +///////////////// +//When the soulowner dies, the soulsharer dies, and vice versa +//This is intended for two players(or AI) and two mobs + +/datum/soullink/sharedfate/ownerDies(gibbed, mob/living/owner) + if(soulsharer) + soulsharer.death(gibbed) + +/datum/soullink/sharedfate/sharerDies(gibbed, mob/living/sharer) + if(soulowner) + soulowner.death(gibbed) + + + +///////////////// +// SHARED BODY // +///////////////// +//When the soulsharer dies, they're placed in the soulowner, who remains alive +//If the soulowner dies, the soulsharer is killed and placed into the soulowner (who is still dying) +//This one is intended for one player moving between many mobs + +/datum/soullink/sharedbody/ownerDies(gibbed, mob/living/owner) + if(soulowner && soulsharer) + if(soulsharer.mind) + soulsharer.mind.transfer_to(soulowner) + soulsharer.death(gibbed) + +/datum/soullink/sharedbody/sharerDies(gibbed, mob/living/sharer) + if(soulowner && soulsharer && soulsharer.mind) + soulsharer.mind.transfer_to(soulowner) + + + +////////////////////// +// REPLACEMENT POOL // +////////////////////// +//When the owner dies, one of the sharers is placed in the owner's body, fully healed +//Sort of a "winner-stays-on" soullink +//Gibbing ends it immediately + +/datum/soullink/multisharer/replacementpool/ownerDies(gibbed, mob/living/owner) + if(LAZYLEN(soulsharers) && !gibbed) //let's not put them in some gibs + var/list/souls = shuffle(soulsharers.Copy()) + for(var/l in souls) + var/mob/living/L = l + if(L.stat != DEAD && L.mind) + L.mind.transfer_to(soulowner) + soulowner.revive(TRUE, TRUE) + L.death(FALSE) + +//Lose your claim to the throne! +/datum/soullink/multisharer/replacementpool/sharerDies(gibbed, mob/living/sharer) + removeSoulsharer(sharer) diff --git a/code/modules/mob/living/death.dm b/code/modules/mob/living/death.dm index 5c9554239de..0013c6d7830 100644 --- a/code/modules/mob/living/death.dm +++ b/code/modules/mob/living/death.dm @@ -72,4 +72,12 @@ update_canmove() med_hud_set_health() med_hud_set_status() + + for(var/s in ownedSoullinks) + var/datum/soullink/S = s + S.ownerDies(gibbed) + for(var/s in sharedSoullinks) + var/datum/soullink/S = s + S.sharerDies(gibbed) + return TRUE diff --git a/tgstation.dme b/tgstation.dme index e8d8ab67c48..5fd555ffe9a 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -210,6 +210,7 @@ #include "code\datums\riding.dm" #include "code\datums\ruins.dm" #include "code\datums\shuttles.dm" +#include "code\datums\soullink.dm" #include "code\datums\votablemap.dm" #include "code\datums\antagonists\antag_datum.dm" #include "code\datums\antagonists\datum_clockcult.dm"