mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-07-14 17:45:02 +01:00
Fixes runtime in golem body swap, Fixes some hard deletes assocaited with golems and mind masters (#73373)
## About The Pull Request Fixes #73368 Golems didn't mind transfer on body swap until after the body was finished creating, this created an issue as golems also did mind assignment business while creating the body. So the `mind.enslave_to_creator()` part runtime error'd and caused the create to fail, which in turn caused the shell to not be consumed. While sorting this out, I noticed that shells and golems hold a hard reference to their owner. Yep, hard deletes. Changes mind `enslaved_to` to a weakref, changes golem `owner` to a weakref, straight up removes golem `owner` tracking on species because it was ONLY used for card board golems when it could've just grabbed mind master ## Why It's Good For The Game No more infinite golem shells ## Changelog 🆑 Melbert fix: Transferring golem shells no longer make you a free man and also results in infinite golem shells fix: Servant golems are considerably less free fix: Fixes some hard deletes related to mob minds being enslaved to other mobs /🆑
This commit is contained in:
@@ -14,11 +14,16 @@
|
||||
prompt_name = "a free golem"
|
||||
you_are_text = "You are a Free Golem. Your family worships The Liberator."
|
||||
flavour_text = "In his infinite and divine wisdom, he set your clan free to travel the stars with a single declaration: \"Yeah go do whatever.\""
|
||||
var/has_owner = FALSE
|
||||
var/can_transfer = TRUE //if golems can switch bodies to this new shell
|
||||
var/mob/living/owner = null //golem's owner if it has one
|
||||
spawner_job_path = /datum/job/free_golem
|
||||
/// If TRUE, other golems can touch us to swap into this shell.
|
||||
var/can_transfer = TRUE
|
||||
/// Weakref to the creator of this golem shell.
|
||||
var/datum/weakref/owner_ref
|
||||
|
||||
/obj/effect/mob_spawn/ghost_role/human/golem/Initialize(mapload, datum/species/golem/species = null, mob/creator = null)
|
||||
/obj/effect/mob_spawn/ghost_role/human/golem/Initialize(mapload, datum/species/golem/species, mob/creator)
|
||||
if(creator)
|
||||
name = "inert servant golem shell"
|
||||
prompt_name = "servant golem"
|
||||
if(species) //spawners list uses object name to register so this goes before ..()
|
||||
name += " ([initial(species.prefix)])"
|
||||
mob_species = species
|
||||
@@ -26,44 +31,47 @@
|
||||
var/area/init_area = get_area(src)
|
||||
if(!mapload && init_area)
|
||||
notify_ghosts("\A [initial(species.prefix)] golem shell has been completed in \the [init_area.name].", source = src, action=NOTIFY_ATTACK, flashwindow = FALSE, ignore_key = POLL_IGNORE_GOLEM)
|
||||
if(has_owner && creator)
|
||||
if(creator)
|
||||
you_are_text = "You are a golem."
|
||||
flavour_text = "You move slowly, but are highly resistant to heat and cold as well as blunt trauma. You are unable to wear clothes, but can still use most tools."
|
||||
important_text = "Serve [creator], and assist [creator.p_them()] in completing [creator.p_their()] goals at any cost."
|
||||
owner = creator
|
||||
owner_ref = WEAKREF(creator)
|
||||
spawner_job_path = /datum/job/servant_golem
|
||||
|
||||
|
||||
/obj/effect/mob_spawn/ghost_role/human/golem/name_mob(mob/living/spawned_mob, forced_name)
|
||||
if(!forced_name)
|
||||
var/datum/species/golem/golem_species = mob_species
|
||||
if(has_owner)
|
||||
if(owner_ref?.resolve())
|
||||
forced_name = "[initial(golem_species.prefix)] Golem ([rand(1,999)])"
|
||||
else
|
||||
golem_species = new mob_species
|
||||
forced_name = golem_species.random_name()
|
||||
. = ..()
|
||||
return ..()
|
||||
|
||||
/obj/effect/mob_spawn/ghost_role/human/golem/special(mob/living/new_spawn, mob/mob_possessor)
|
||||
. = ..()
|
||||
var/datum/species/golem/X = mob_species
|
||||
to_chat(new_spawn, "[initial(X.info_text)]")
|
||||
if(!owner)
|
||||
to_chat(new_spawn, "Build golem shells in the autolathe, and feed refined mineral sheets to the shells to bring them to life! You are generally a peaceful group unless provoked.")
|
||||
try_keep_home(new_spawn)
|
||||
var/mob/living/real_owner = owner_ref?.resolve()
|
||||
var/datum/species/golem/golem_species = mob_species
|
||||
to_chat(new_spawn, "[initial(golem_species.info_text)]")
|
||||
if(isnull(real_owner))
|
||||
if(!is_station_level(new_spawn.z))
|
||||
to_chat(new_spawn, "Build golem shells in the autolathe, and feed refined mineral sheets to the shells to bring them to life! \
|
||||
You are generally a peaceful group unless provoked.")
|
||||
try_keep_home(new_spawn)
|
||||
|
||||
else if(new_spawn.mind)
|
||||
new_spawn.mind.enslave_mind_to_creator(real_owner)
|
||||
|
||||
else
|
||||
new_spawn.mind.enslave_mind_to_creator(owner)
|
||||
new_spawn.log_message("possessed a golem shell enslaved to [key_name(owner)].", LOG_GAME)
|
||||
log_admin("[key_name(new_spawn)] possessed a golem shell enslaved to [key_name(owner)].")
|
||||
stack_trace("[type] created a golem without a mind.")
|
||||
|
||||
new_spawn.log_message("possessed a golem shell[real_owner ? " enslaved to [key_name(real_owner)]" : ""].", LOG_GAME)
|
||||
log_admin("[key_name(new_spawn)] possessed a golem shell[real_owner ? " enslaved to [key_name(real_owner)]" : ""].")
|
||||
|
||||
if(ishuman(new_spawn))
|
||||
var/mob/living/carbon/human/H = new_spawn
|
||||
if(has_owner)
|
||||
var/datum/species/golem/G = H.dna.species
|
||||
G.owner = owner
|
||||
H.set_cloned_appearance()
|
||||
if(has_owner && new_spawn.mind)
|
||||
new_spawn.mind.set_assigned_role_with_greeting(SSjob.GetJobType(/datum/job/servant_golem))
|
||||
else
|
||||
new_spawn.mind.set_assigned_role_with_greeting(SSjob.GetJobType(/datum/job/free_golem))
|
||||
var/mob/living/carbon/human/human_spawn = new_spawn
|
||||
human_spawn.set_cloned_appearance()
|
||||
|
||||
/obj/effect/mob_spawn/ghost_role/human/golem/proc/try_keep_home(mob/new_spawn)
|
||||
var/static/list/allowed_areas = typecacheof(list(/area/icemoon, /area/lavaland, /area/ruin)) + typecacheof(/area/misc/survivalpod)
|
||||
@@ -75,28 +83,32 @@
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
if(isgolem(user) && can_transfer)
|
||||
var/mob/living/carbon/human/H = user
|
||||
var/transfer_choice = tgui_alert(usr, "Transfer your soul to [src]? (Warning, your old body will die!)",,list("Yes","No"))
|
||||
if(transfer_choice != "Yes")
|
||||
return
|
||||
if(QDELETED(src) || uses <= 0)
|
||||
return
|
||||
H.log_message("golem-swapped into [src].", LOG_GAME)
|
||||
H.visible_message(span_notice("A faint light leaves [H], moving to [src] and animating it!"),span_notice("You leave your old body behind, and transfer into [src]!"))
|
||||
show_flavor = FALSE
|
||||
var/mob/living/carbon/human/newgolem = create(newname = H.real_name)
|
||||
H.transfer_quirk_datums(newgolem)
|
||||
H.mind.transfer_to(newgolem)
|
||||
H.death()
|
||||
if(!isgolem(user) || !can_transfer)
|
||||
return
|
||||
|
||||
var/mob/living/carbon/human/golem = user
|
||||
var/transfer_choice = tgui_alert(usr, "Transfer your soul to [src]? (Warning, your old body will die!)",,list("Yes","No"))
|
||||
if(transfer_choice != "Yes")
|
||||
return
|
||||
if(QDELETED(src) || uses <= 0)
|
||||
return
|
||||
uses -= 1
|
||||
golem.log_message("golem-swapped into [src].", LOG_GAME)
|
||||
golem.visible_message(
|
||||
span_notice("A faint light leaves [golem], moving to [src] and animating it!"),
|
||||
span_notice("You leave your old body behind, and transfer into [src]!"),
|
||||
)
|
||||
show_flavor = FALSE
|
||||
var/mob/living/carbon/human/newgolem = create(user, golem.real_name)
|
||||
golem.transfer_quirk_datums(newgolem)
|
||||
golem.death()
|
||||
check_uses()
|
||||
return TRUE
|
||||
|
||||
/obj/effect/mob_spawn/ghost_role/human/golem/servant
|
||||
has_owner = TRUE
|
||||
name = "inert servant golem shell"
|
||||
prompt_name = "servant golem"
|
||||
|
||||
|
||||
/obj/effect/mob_spawn/ghost_role/human/golem/adamantine
|
||||
name = "dust-caked free golem shell"
|
||||
desc = "A humanoid shape, empty, lifeless, and full of potential."
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
////Human specific stuff. Don't set these if you aren't using a human, the unit tests will put a stop to your sinful hand.
|
||||
|
||||
///sets the human as a species, use a typepath (example: /datum/species/skeleton)
|
||||
var/mob_species
|
||||
var/datum/species/mob_species
|
||||
///equips the human with an outfit.
|
||||
var/datum/outfit/outfit
|
||||
///for mappers to override parts of the outfit. really only in here for secret away missions, please try to refrain from using this out of laziness
|
||||
@@ -181,7 +181,15 @@
|
||||
/obj/effect/mob_spawn/ghost_role/special(mob/living/spawned_mob, mob/mob_possessor)
|
||||
. = ..()
|
||||
if(mob_possessor)
|
||||
spawned_mob.ckey = mob_possessor.ckey
|
||||
if(mob_possessor.mind)
|
||||
mob_possessor.mind.transfer_to(spawned_mob, force_key_move = TRUE)
|
||||
else
|
||||
spawned_mob.key = mob_possessor.key
|
||||
var/datum/mind/spawned_mind = spawned_mob.mind
|
||||
if(spawned_mind)
|
||||
spawned_mob.mind.set_assigned_role_with_greeting(SSjob.GetJobType(spawner_job_path))
|
||||
spawned_mind.name = spawned_mob.real_name
|
||||
|
||||
if(show_flavor)
|
||||
var/output_message = "<span class='infoplain'><span class='big bold'>[you_are_text]</span></span>"
|
||||
if(flavour_text != "")
|
||||
@@ -189,10 +197,6 @@
|
||||
if(important_text != "")
|
||||
output_message += "\n[span_userdanger("[important_text]")]"
|
||||
to_chat(spawned_mob, output_message)
|
||||
var/datum/mind/spawned_mind = spawned_mob.mind
|
||||
if(spawned_mind)
|
||||
spawned_mob.mind.set_assigned_role(SSjob.GetJobType(spawner_job_path))
|
||||
spawned_mind.name = spawned_mob.real_name
|
||||
|
||||
/// Checks if the spawner has zero uses left, if so, delete yourself... NOW!
|
||||
/obj/effect/mob_spawn/ghost_role/proc/check_uses()
|
||||
|
||||
Reference in New Issue
Block a user