diff --git a/aurorastation.dme b/aurorastation.dme index 0595e4f81de..15746c8dcef 100644 --- a/aurorastation.dme +++ b/aurorastation.dme @@ -1150,7 +1150,6 @@ #include "code\modules\admin\secrets\admin_secrets\list_dna.dm" #include "code\modules\admin\secrets\admin_secrets\list_fingerprints.dm" #include "code\modules\admin\secrets\admin_secrets\move_shuttle.dm" -#include "code\modules\admin\secrets\admin_secrets\replace_player.dm" #include "code\modules\admin\secrets\admin_secrets\show_ai_laws.dm" #include "code\modules\admin\secrets\admin_secrets\show_crew_manifest.dm" #include "code\modules\admin\secrets\admin_secrets\show_game_mode.dm" @@ -1622,10 +1621,14 @@ #include "code\modules\ghostroles\spawner\base.dm" #include "code\modules\ghostroles\spawner\antagonist\revenant.dm" #include "code\modules\ghostroles\spawner\atom\borer.dm" +#include "code\modules\ghostroles\spawner\atom\diona_nymph.dm" #include "code\modules\ghostroles\spawner\atom\golem.dm" +#include "code\modules\ghostroles\spawner\atom\imaginary_friend.dm" +#include "code\modules\ghostroles\spawner\atom\living_plant.dm" #include "code\modules\ghostroles\spawner\atom\mining_drone.dm" #include "code\modules\ghostroles\spawner\atom\posibrain.dm" #include "code\modules\ghostroles\spawner\atom\skeleton.dm" +#include "code\modules\ghostroles\spawner\atom\split_personality.dm" #include "code\modules\ghostroles\spawner\atom\syndicate_cyborg.dm" #include "code\modules\ghostroles\spawner\atom\wizard_familiar.dm" #include "code\modules\ghostroles\spawner\atom\wizardapprentice.dm" @@ -1648,10 +1651,10 @@ #include "code\modules\ghostroles\spawner\human\responseteams\tcfl.dm" #include "code\modules\ghostroles\spawner\simplemob\maintdrone.dm" #include "code\modules\ghostroles\spawner\simplemob\rat.dm" +#include "code\modules\ghostroles\spawner\simplemob\reboot_maintdrone.dm" #include "code\modules\ghostroles\spawner\simplemob\simplemob.dm" #include "code\modules\ghostroles\spawner\simplemob\spider_queen.dm" #include "code\modules\ghostroles\spawnpoint\spawnpoint.dm" -#include "code\modules\ghosttrap\trap.dm" #include "code\modules\global_listener\devices.dm" #include "code\modules\global_listener\interfaces.dm" #include "code\modules\goonchat\_helpers.dm" diff --git a/code/controllers/subsystems/garbage-debug.dm b/code/controllers/subsystems/garbage-debug.dm index 5497bb014c8..64e88438830 100644 --- a/code/controllers/subsystems/garbage-debug.dm +++ b/code/controllers/subsystems/garbage-debug.dm @@ -720,7 +720,6 @@ SearchVar(event_last_fired) SearchVar(dreams) SearchVar(non_fakeattack_weapons) - SearchVar(ghost_traps) SearchVar(current_map.holodeck_programs) SearchVar(fruit_icon_cache) SearchVar(plant_seed_sprites) diff --git a/code/datums/brain_damage/imaginary_friend.dm b/code/datums/brain_damage/imaginary_friend.dm index 727ef44af42..eb87a3eb891 100644 --- a/code/datums/brain_damage/imaginary_friend.dm +++ b/code/datums/brain_damage/imaginary_friend.dm @@ -10,7 +10,6 @@ /datum/brain_trauma/special/imaginary_friend/on_gain() ..() make_friend() - get_ghost() /datum/brain_trauma/special/imaginary_friend/on_life() if(get_dist(owner, friend) > 9) @@ -24,12 +23,7 @@ /datum/brain_trauma/special/imaginary_friend/proc/make_friend() friend = new(get_turf(src), src) - -/datum/brain_trauma/special/imaginary_friend/proc/get_ghost() - set waitfor = FALSE - var/datum/ghosttrap/G = get_ghost_trap("friend") - G.request_player(friend, "Would you like to play as [owner]'s imaginary friend?", 60 SECONDS) - addtimer(CALLBACK(src, .proc/reset_search), 60 SECONDS) + SSghostroles.add_spawn_atom("imaginary_friend", friend) /datum/brain_trauma/special/imaginary_friend/proc/reset_search() if(src.friend && src.friend.key) @@ -91,6 +85,7 @@ owner.client.images.Remove(human_image) if(client) client.images.Remove(human_image) + SSghostroles.remove_spawn_atom("imaginary_friend", src) return ..() /mob/abstract/mental/friend/proc/yank() diff --git a/code/datums/brain_damage/schizo.dm b/code/datums/brain_damage/schizo.dm index 83ffcb20564..47af1953176 100644 --- a/code/datums/brain_damage/schizo.dm +++ b/code/datums/brain_damage/schizo.dm @@ -16,24 +16,12 @@ /datum/brain_trauma/severe/split_personality/on_gain() ..() make_backseats() - get_ghost() /datum/brain_trauma/severe/split_personality/proc/make_backseats() stranger_backseat = new(owner, src) + SSghostroles.add_spawn_atom("split_personality", stranger_backseat) owner_backseat = new(owner, src) -/datum/brain_trauma/severe/split_personality/proc/get_ghost() - set waitfor = FALSE - var/datum/ghosttrap/G = get_ghost_trap("split personality") - G.request_player(stranger_backseat, "Would you like to play as [owner]'s split personality?", 60 SECONDS) - addtimer(CALLBACK(src, .proc/reset_search), 60 SECONDS) - -/datum/brain_trauma/severe/split_personality/proc/reset_search() - if(src.stranger_backseat && src.stranger_backseat.key) - return - else - qdel(src) - /datum/brain_trauma/severe/split_personality/on_life() if(owner.stat == DEAD) if(current_controller != OWNER) @@ -63,7 +51,7 @@ current_backseat = owner_backseat free_backseat = stranger_backseat - log_game("[current_backseat]/([current_backseat.ckey]) assumed control of [owner]/([owner.ckey] due to [src]. (Original owner: [current_controller == OWNER ? owner.ckey : current_backseat.ckey])") + log_game("[current_backseat]/([current_backseat.ckey]) assumed control of [owner]/([owner.ckey]) due to [src]. (Original owner: [current_controller == OWNER ? owner.ckey : current_backseat.ckey])") to_chat(owner, "You feel your control being taken away... your other personality is in charge now!") to_chat(current_backseat, "You manage to take control of your body!") @@ -146,6 +134,10 @@ /mob/living/mental/split_personality/emote(message) return +/mob/living/mental/split_personality/Destroy() + SSghostroles.remove_spawn_atom("split_personality", src) + return ..() + ///////////////BRAINWASHING//////////////////// /datum/brain_trauma/severe/split_personality/brainwashing @@ -180,13 +172,6 @@ stranger_backseat = new /mob/living/mental/split_personality/traitor(owner, src, codeword, objective) owner_backseat = new(owner, src) - -/datum/brain_trauma/severe/split_personality/brainwashing/get_ghost() - set waitfor = FALSE - var/datum/ghosttrap/G = get_ghost_trap("split personality") - G.request_player(stranger_backseat, "Would you like to play as [owner]'s split personality?", 60 SECONDS) - addtimer(CALLBACK(src, .proc/reset_search), 60 SECONDS) - /datum/brain_trauma/severe/split_personality/brainwashing/on_life() return //no random switching diff --git a/code/modules/admin/secrets/admin_secrets/replace_player.dm b/code/modules/admin/secrets/admin_secrets/replace_player.dm deleted file mode 100644 index 8dce7f5ad5b..00000000000 --- a/code/modules/admin/secrets/admin_secrets/replace_player.dm +++ /dev/null @@ -1,25 +0,0 @@ -/datum/admin_secret_item/admin_secret/replace_player_with_ghost - name = "Replace player with ghost" - -/datum/admin_secret_item/admin_secret/replace_player_with_ghost/can_execute(var/mob/user) - if(!ROUND_IS_STARTED) return 0 - return ..() - -/datum/admin_secret_item/admin_secret/replace_player_with_ghost/execute(var/mob/user) - . = ..() - if(!.) - return - var/list/targets = list() - targets += getmobs() - var/mob/T = input(user, "Which player do you want to replace?") as null|anything in targets - if (!T) - return - var/mob/player_to_replace = targets[T] - var/datum/ghosttrap/G = get_ghost_trap("[player_to_replace.mind.special_role]") - if(player_to_replace.client) - player_to_replace.ghostize(0) - if(G) - G.request_player(player_to_replace, "Would you like to play as a [player_to_replace.mind.special_role]?", 60 SECONDS) - else - G = ghost_traps["Special"] - G.request_player(player_to_replace, "Would you like to play as [player_to_replace.name]?", 60 SECONDS) \ No newline at end of file diff --git a/code/modules/client/preference_setup/antagonism/01_candidacy.dm b/code/modules/client/preference_setup/antagonism/01_candidacy.dm index e4eae1f4f28..58d8100e6de 100644 --- a/code/modules/client/preference_setup/antagonism/01_candidacy.dm +++ b/code/modules/client/preference_setup/antagonism/01_candidacy.dm @@ -57,42 +57,10 @@ else dat += "Yes / No
" dat += "" - - var/list/ghost_traps = get_ghost_traps() - for(var/ghost_trap_key in ghost_traps) - var/datum/ghosttrap/ghost_trap = ghost_traps[ghost_trap_key] - if(!ghost_trap.list_as_special_role) - continue - - dat += "[(ghost_trap.ghost_trap_role)]: " - var/ban_state = banned_from_ghost_role(preference_mob(), ghost_trap) - if(ban_state == AGEBAN) - var/age_to_beat = 0 - for (var/A in ghost_trap.ban_checks) - age_to_beat = player_old_enough_for_role(preference_mob(), A) - if (age_to_beat) - break - dat += "\[IN [age_to_beat] DAYS\]
" - else if (ban_state == RANBAN) - dat += "\[BANNED\]
" - else if(ghost_trap.pref_check in pref.be_special_role) - dat += "Yes / No
" - else - dat += "Yes / No
" - dat += "" dat += "" . = dat.Join() -/datum/category_item/player_setup_item/proc/banned_from_ghost_role(var/mob, var/datum/ghosttrap/ghost_trap) - for(var/ban_type in ghost_trap.ban_checks) - . = jobban_isbanned(mob, ban_type) - if(. == "AGE WHITELISTED") - return AGEBAN - else if (.) - return RANBAN - return NOBAN - /datum/category_item/player_setup_item/antagonism/candidacy/OnTopic(var/href,var/list/href_list, var/mob/user) if(href_list["add_special"]) if(!(href_list["add_special"] in valid_special_roles())) @@ -112,13 +80,6 @@ var/datum/antagonist/antag = all_antag_types[antag_type] private_valid_special_roles += antag.role_type - var/list/ghost_traps = get_ghost_traps() - for(var/ghost_trap_key in ghost_traps) - var/datum/ghosttrap/ghost_trap = ghost_traps[ghost_trap_key] - if(!ghost_trap.list_as_special_role) - continue - private_valid_special_roles += ghost_trap.pref_check - return private_valid_special_roles #undef AGEBAN diff --git a/code/modules/ghostroles/spawner/atom/diona_nymph.dm b/code/modules/ghostroles/spawner/atom/diona_nymph.dm new file mode 100644 index 00000000000..25fa86fa305 --- /dev/null +++ b/code/modules/ghostroles/spawner/atom/diona_nymph.dm @@ -0,0 +1,10 @@ +/datum/ghostspawner/diona_nymph + short_name = "diona_nymph" + name = "Diona Nymph" + desc = "Join in as a Diona Nymph. Suck blood, act cuter than you really are." + tags = list("Simple Mobs") + + loc_type = GS_LOC_ATOM + atom_add_message = "A Diona Nymph has sprung up somewhere on the station!" + + spawn_mob = /mob/living/carbon/alien/diona \ No newline at end of file diff --git a/code/modules/ghostroles/spawner/atom/imaginary_friend.dm b/code/modules/ghostroles/spawner/atom/imaginary_friend.dm new file mode 100644 index 00000000000..d3e36bf2f4f --- /dev/null +++ b/code/modules/ghostroles/spawner/atom/imaginary_friend.dm @@ -0,0 +1,10 @@ +/datum/ghostspawner/imaginary_friend + short_name = "imaginary_friend" + name = "Imaginary Friend" + desc = "Join in as a Imaginary Friend, help them find their way throughout the round." + tags = list("Mental Trauma") + + loc_type = GS_LOC_ATOM + atom_add_message = "Someone has conjured up an imaginary friend!" + + spawn_mob = /mob/abstract/mental/friend \ No newline at end of file diff --git a/code/modules/ghostroles/spawner/atom/living_plant.dm b/code/modules/ghostroles/spawner/atom/living_plant.dm new file mode 100644 index 00000000000..f7b74f88203 --- /dev/null +++ b/code/modules/ghostroles/spawner/atom/living_plant.dm @@ -0,0 +1,10 @@ +/datum/ghostspawner/living_plant + short_name = "living_plant" + name = "Living Plant" + desc = "Join in as a Living Plant. What do plants do?" + tags = list("Simple Mobs") + + loc_type = GS_LOC_ATOM + atom_add_message = "A Living Plant has sprung up somewhere on the station!" + + spawn_mob = /mob/living \ No newline at end of file diff --git a/code/modules/ghostroles/spawner/atom/split_personality.dm b/code/modules/ghostroles/spawner/atom/split_personality.dm new file mode 100644 index 00000000000..849e9c43885 --- /dev/null +++ b/code/modules/ghostroles/spawner/atom/split_personality.dm @@ -0,0 +1,10 @@ +/datum/ghostspawner/split_personality + short_name = "split_personality" + name = "Split Personality" + desc = "Join in as a Split Personality, play the alter ego of one poor crewmember." + tags = list("Mental Trauma") + + loc_type = GS_LOC_ATOM + atom_add_message = "Someone has developed a split personality!" + + spawn_mob = /mob/living/mental/split_personality \ No newline at end of file diff --git a/code/modules/ghostroles/spawner/simplemob/reboot_maintdrone.dm b/code/modules/ghostroles/spawner/simplemob/reboot_maintdrone.dm new file mode 100644 index 00000000000..57512b27707 --- /dev/null +++ b/code/modules/ghostroles/spawner/simplemob/reboot_maintdrone.dm @@ -0,0 +1,10 @@ +/datum/ghostspawner/rebooted_maint_drone + short_name = "rebooted_maint_drone" + name = "Rebooted Maint Drone" + desc = "Join in as a Rebooted Maintenance Drone. Do dronelike things." + tags = list("Simple Mobs") + + loc_type = GS_LOC_ATOM + atom_add_message = "A maintenance drone has started its rebooting procedure!" + + spawn_mob = /mob/living/silicon/robot/drone \ No newline at end of file diff --git a/code/modules/ghosttrap/trap.dm b/code/modules/ghosttrap/trap.dm deleted file mode 100644 index 06ebf8dee1e..00000000000 --- a/code/modules/ghosttrap/trap.dm +++ /dev/null @@ -1,433 +0,0 @@ -// This system is used to grab a ghost from observers with the required preferences and -// lack of bans set. See posibrain.dm for an example of how they are called/used. ~Z - -var/list/ghost_traps - -/proc/get_ghost_trap(var/trap_key) - if(!ghost_traps) - populate_ghost_traps() - return ghost_traps[trap_key] - -/proc/get_ghost_traps() - if(!ghost_traps) - populate_ghost_traps() - return ghost_traps - -/proc/populate_ghost_traps() - ghost_traps = list() - for(var/traptype in typesof(/datum/ghosttrap)) - var/datum/ghosttrap/G = new traptype - ghost_traps[G.object] = G - -/datum/ghosttrap - var/object = "positronic brain" - var/respawn_check = 0//Which respawning test we check against - var/list/ban_checks = list("AI","Cyborg") - var/pref_check = BE_SYNTH - var/ghost_trap_message = "They are occupying a positronic brain now." - var/ghost_trap_role = "Positronic Brain" - var/can_set_own_name = TRUE - var/list_as_special_role = TRUE // If true, this entry will be listed as a special role in the character setup - - var/list/request_timeouts - -/datum/ghosttrap/New() - request_timeouts = list() - ..() - -// Check for bans, proper atom types, etc. -/datum/ghosttrap/proc/assess_candidate(var/mob/abstract/observer/candidate, var/mob/target) - if(!candidate.MayRespawn(1, respawn_check)) - return 0 - if(islist(ban_checks)) - for(var/bantype in ban_checks) - if(jobban_isbanned(candidate, "[bantype]")) - to_chat(candidate, "You are banned from one or more required roles and hence cannot enter play as \a [object].") - return 0 - return 1 - -// Print a message to all ghosts with the right prefs/lack of bans. -/datum/ghosttrap/proc/request_player(var/mob/target, var/request_string, var/request_timeout) - if(request_timeout) - request_timeouts[target] = world.time + request_timeout - destroyed_event.register(target, src, /datum/ghosttrap/proc/target_destroyed) - else - request_timeouts -= target - - for(var/mob/abstract/observer/O in player_list) - if(!O.MayRespawn()) - continue - if(islist(ban_checks)) - for(var/bantype in ban_checks) - if(jobban_isbanned(O, "[bantype]")) - continue - if(pref_check && !(pref_check in O.client.prefs.be_special_role)) - continue - if(O.client) - to_chat(O, "[ghost_follow_link(target, O)] [request_string] (Occupy)") - -/datum/ghosttrap/proc/target_destroyed(var/destroyed_target) - request_timeouts -= destroyed_target - -// Handles a response to request_player(). -/datum/ghosttrap/Topic(href, href_list) - if(..()) - return 1 - if(href_list["candidate"] && href_list["target"]) - var/mob/abstract/observer/candidate = locate(href_list["candidate"]) // BYOND magic. - var/mob/target = locate(href_list["target"]) // So much BYOND magic. - if(!target || !candidate) - return - if(candidate != usr) - return - if(request_timeouts[target] && world.time > request_timeouts[target]) - to_chat(candidate, "This occupation request is no longer valid.") - return - if(target.key) - to_chat(candidate, "The target is already occupied.") - return - if(assess_candidate(candidate, target)) - transfer_personality(candidate,target) - return 1 - -// Shunts the ckey/mind into the target mob. -/datum/ghosttrap/proc/transfer_personality(var/mob/candidate, var/mob/target) - if(!assess_candidate(candidate)) - return 0 - target.ckey = candidate.ckey - if(target.mind) - target.mind.assigned_role = "[ghost_trap_role]" - announce_ghost_joinleave(candidate, 0, "[ghost_trap_message]") - welcome_candidate(target) - set_new_name(target) - return 1 - -// Fluff! -/datum/ghosttrap/proc/welcome_candidate(var/mob/target) - to_chat(target, "You are a positronic brain, brought into existence on [station_name()].") - to_chat(target, "As a synthetic intelligence, you answer to all crewmembers, as well as the AI.") - to_chat(target, "Remember, the purpose of your existence is to serve the crew and the station. Above all else, do no harm.") - to_chat(target, "Use say [target.get_language_prefix()]b to speak to other artificial intelligences.") - var/turf/T = get_turf(target) - T.visible_message("\The [target] chimes quietly.") - var/obj/item/device/mmi/digital/posibrain/P = target.loc - if(!istype(P)) //wat - return - P.searching = 0 - P.name = "positronic brain ([P.brainmob.name])" - P.icon_state = "posibrain-occupied" - -// Allows people to set their own name. May or may not need to be removed for posibrains if people are dumbasses. -/datum/ghosttrap/proc/set_new_name(var/mob/target) - if(!can_set_own_name) - return - - var/newname = sanitizeSafe(input(target,"Enter a name, or leave blank for the default name.", "Name change","") as text, MAX_NAME_LEN) - if (newname != "") - target.real_name = newname - target.name = target.real_name - -/*********************************** -* Diona pods and walking mushrooms * -***********************************/ -/datum/ghosttrap/plant - object = "living plant" - ban_checks = list("Dionaea") - pref_check = BE_PLANT - ghost_trap_message = "They are occupying a living plant now." - ghost_trap_role = "Plant" - -/datum/ghosttrap/plant/welcome_candidate(var/mob/target) - to_chat(target, "You awaken slowly, stirring into sluggish motion as the air caresses you.") - // This is a hack, replace with some kind of species blurb proc. - if(istype(target,/mob/living/carbon/alien/diona)) - to_chat(target, "You are \a [target], one of a race of drifting interstellar plantlike creatures that sometimes share their seeds with human traders.") - to_chat(target, "Too much darkness will send you into shock and starve you, but light will help you heal.") - -/***************** -* Cortical Borer * -*****************/ -/datum/ghosttrap/borer - object = "cortical borer" - ban_checks = list("Borer") - pref_check = MODE_BORER - ghost_trap_message = "They are occupying a borer now." - ghost_trap_role = "Cortical Borer" - can_set_own_name = FALSE - list_as_special_role = FALSE - -/datum/ghosttrap/borer/welcome_candidate(var/mob/target) - to_chat(target, "You are a cortical borer! You are a brain slug that worms its way into the head of its victim. Use stealth, persuasion and your powers of mind control to keep you, your host and your eventual spawn safe and warm.") - to_chat(target, "You can speak to your victim with say, to other borers with say [target.get_language_prefix()]x, and use your Abilities tab to access powers.") - -/******************** -* Maintenance Drone * -*********************/ -/datum/ghosttrap/drone - object = "maintenance drone" - pref_check = BE_PAI - ghost_trap_message = "They are occupying a maintenance drone now." - ghost_trap_role = "Maintenance Drone" - can_set_own_name = FALSE - list_as_special_role = FALSE - -/datum/ghosttrap/drone/New() - respawn_check = MINISYNTH - ..() - -datum/ghosttrap/drone/assess_candidate(var/mob/abstract/observer/candidate, var/mob/target) - . = ..() - if(. && !target.can_be_possessed_by(candidate)) - return 0 - -datum/ghosttrap/drone/transfer_personality(var/mob/candidate, var/mob/living/silicon/robot/drone/drone) - if(!assess_candidate(candidate)) - return 0 - drone.transfer_personality(candidate.client) - -/******************** -* Mining Drone * -*********************/ -/datum/ghosttrap/mdrone - object = "mining drone" - pref_check = BE_PAI - ghost_trap_message = "They are occupying a mining drone now." - ghost_trap_role = "Mining Drone" - can_set_own_name = FALSE - list_as_special_role = FALSE - -/datum/ghosttrap/mdrone/New() - respawn_check = MINISYNTH - ..() - -/datum/ghosttrap/mdrone/assess_candidate(var/mob/abstract/observer/candidate, var/mob/target) - . = ..() - if(. && !target.can_be_possessed_by(candidate)) - return 0 - -datum/ghosttrap/drone/transfer_personality(var/mob/candidate, var/mob/living/silicon/robot/drone/drone) - if(!assess_candidate(candidate)) - return 0 - drone.transfer_personality(candidate.client) - var/tmp_health = drone.health - drone.revive() - drone.health = tmp_health - drone.updatehealth() - -/*********************************** -* Syndicate Cyborg * -***********************************/ - -/datum/ghosttrap/syndicateborg - object = "syndicate cyborg" - ban_checks = list("Antagonist","AI","Cyborg") - pref_check = BE_SYNTH - ghost_trap_message = "They are occupying a syndicate cyborg now." - ghost_trap_role = "Syndicate Cyborg" - can_set_own_name = TRUE - list_as_special_role = FALSE - -/datum/ghosttrap/syndicateborg/welcome_candidate(var/mob/target) - to_chat(target, "You are a syndicate cyborg, bound to help and follow the orders of the mercenaries that are deploying you. Remember to speak to the other mercenaries to know more about their plans") - mercs.add_antagonist_mind(target.mind,1) - -/************** -* pAI * -**************/ -/datum/ghosttrap/pai - object = "pAI" - pref_check = BE_PAI - ghost_trap_message = "They are occupying a pAI now." - ghost_trap_role = "pAI" - -datum/ghosttrap/pai/assess_candidate(var/mob/candidate, var/mob/target) - return 0 - -datum/ghosttrap/pai/transfer_personality(var/mob/candidate, var/mob/living/silicon/robot/drone/drone) - return 0 - -/************** -* Wizard Familiar * -**************/ - -/datum/ghosttrap/familiar - object = "wizard familiar" - pref_check = MODE_WIZARD - ghost_trap_message = "They are occupying a familiar now." - ghost_trap_role = "Wizard Familiar" - ban_checks = list(MODE_WIZARD) - list_as_special_role = FALSE - -/datum/ghosttrap/familiar/welcome_candidate(var/mob/target) - return 0 - -/************** -* Skeleton minion * -**************/ - -/datum/ghosttrap/skeleton - object = "skeleton minion" - pref_check = MODE_WIZARD - ghost_trap_message = "They are occupying a skeleton minion." - ghost_trap_role = "Skeleton Minion" - ban_checks = list(MODE_WIZARD) - can_set_own_name = FALSE - list_as_special_role = FALSE - -/datum/ghosttrap/skeleton/welcome_candidate(var/mob/target) - return 0 - -//Gamemodes - -/datum/ghosttrap/merc - object = "Mercenary" - pref_check = MODE_MERCENARY - ghost_trap_message = "They are occupying a mercenary." - ghost_trap_role = "Mercenary" - ban_checks = list(MODE_MERCENARY) - can_set_own_name = FALSE - list_as_special_role = FALSE - -/datum/ghosttrap/merc/welcome_candidate(var/mob/target) - return 0 - -/datum/ghosttrap/raider - object = "Raider" - pref_check = MODE_RAIDER - ghost_trap_message = "They are occupying a raider." - ghost_trap_role = "Raider" - ban_checks = list(MODE_RAIDER) - can_set_own_name = FALSE - list_as_special_role = FALSE - -/datum/ghosttrap/raider/welcome_candidate(var/mob/target) - return 0 - -/datum/ghosttrap/ninja - object = "Ninja" - pref_check = MODE_NINJA - ghost_trap_message = "They are occupying a ninja." - ghost_trap_role = "Ninja" - ban_checks = list(MODE_NINJA) - can_set_own_name = FALSE - list_as_special_role = FALSE - -/datum/ghosttrap/ninja/welcome_candidate(var/mob/target) - return 0 - -/datum/ghosttrap/wizard - object = "Wizard" - pref_check = MODE_WIZARD - ghost_trap_message = "They are occupying a wizard." - ghost_trap_role = "Wizard" - ban_checks = list(MODE_WIZARD) - can_set_own_name = FALSE - list_as_special_role = FALSE - -/datum/ghosttrap/wizard/welcome_candidate(var/mob/target) - return 0 - -/datum/ghosttrap/malf - object = "AI Malfunction" - pref_check = MODE_MALFUNCTION - ghost_trap_message = "They are occupying a malfunctioning AI." - ghost_trap_role = "Malfuntioning AI" - ban_checks = list(MODE_MALFUNCTION) - can_set_own_name = FALSE - list_as_special_role = FALSE - -/datum/ghosttrap/malf/welcome_candidate(var/mob/target) - return 0 - -/datum/ghosttrap/ert - object = "Emergency Responder" - pref_check = MODE_ERT - ghost_trap_message = "They are occupying an ERT member." - ghost_trap_role = "ERT member" - ban_checks = list(MODE_ERT) - can_set_own_name = FALSE - list_as_special_role = FALSE - -/datum/ghosttrap/ert/welcome_candidate(var/mob/target) - return 0 - -/datum/ghosttrap/changeling - object = "Changeling" - pref_check = MODE_CHANGELING - ghost_trap_message = "They are occupying a changeling." - ghost_trap_role = "Changeling" - ban_checks = list(MODE_CHANGELING) - can_set_own_name = FALSE - list_as_special_role = FALSE - -/datum/ghosttrap/changeling/welcome_candidate(var/mob/target) - return 0 - -/datum/ghosttrap/cultist - object = "Cult" - pref_check = MODE_CULTIST - ghost_trap_message = "They are occupying a cultist." - ghost_trap_role = "Cultist" - ban_checks = list(MODE_CULTIST) - can_set_own_name = FALSE - list_as_special_role = FALSE - -/datum/ghosttrap/cultist/welcome_candidate(var/mob/target) - return 0 - -/datum/ghosttrap/traitor - object = "Traitor" - pref_check = MODE_TRAITOR - ghost_trap_message = "They are occupying a traitor." - ghost_trap_role = "Traitor" - ban_checks = list(MODE_TRAITOR) - can_set_own_name = FALSE - list_as_special_role = FALSE - -/datum/ghosttrap/traitor/welcome_candidate(var/mob/target) - to_chat(target, " Check your notes for your uplink code!") - return 1 - -/datum/ghosttrap/vampire - object = "Vampire" - pref_check = MODE_VAMPIRE - ghost_trap_message = "They are occupying a vampire." - ghost_trap_role = "Vampire" - ban_checks = list(MODE_VAMPIRE) - can_set_own_name = FALSE - list_as_special_role = FALSE - -/datum/ghosttrap/vampire/welcome_candidate(var/mob/target) - return 0 - -/datum/ghosttrap/special - object = "Special" - pref_check = null - ghost_trap_message = "They are occupying a person." - ghost_trap_role = "person" - ban_checks = list() - can_set_own_name = FALSE - list_as_special_role = FALSE - -/datum/ghosttrap/special/welcome_candidate(var/mob/target) - return 0 - -/datum/ghosttrap/brainwashed - object = "split personality" - ghost_trap_message = "They are a split personality now." - ghost_trap_role = "Split personality" - can_set_own_name = TRUE - list_as_special_role = TRUE - -/datum/ghosttrap/brainwashed/welcome_candidate(var/mob/target) - return 0 - -/datum/ghosttrap/friend - object = "friend" - ghost_trap_message = "They are an imaginary friend now." - ghost_trap_role = "Imaginary friend" - can_set_own_name = TRUE - list_as_special_role = TRUE - -/datum/ghosttrap/friend/welcome_candidate(var/mob/target) - return 0 diff --git a/code/modules/hydroponics/seed_mobs.dm b/code/modules/hydroponics/seed_mobs.dm index 3c2ee048a7f..82c5cd4dc83 100644 --- a/code/modules/hydroponics/seed_mobs.dm +++ b/code/modules/hydroponics/seed_mobs.dm @@ -1,19 +1,25 @@ // The following procs are used to grab players for mobs produced by a seed (mostly for dionaea). /datum/seed/proc/handle_living_product(var/mob/living/host) + if(!host || !istype(host)) + return - if(!host || !istype(host)) return + var/host_spawner_type = "living_plant" + if(istype(host, /mob/living/carbon/alien/diona)) + host_spawner_type = "diona_nymph" - var/datum/ghosttrap/plant/P = get_ghost_trap("living plant") - P.request_player(host, "Someone is harvesting \a [display_name].") + SSghostroles.add_spawn_atom(host_spawner_type, host) + addtimer(CALLBACK(src, .proc/kill_living_product, WEAKREF(host), host_spawner_type), 3 MINUTES) - spawn(75) - if(!host.ckey && !host.client) - host.death() // This seems redundant, but a lot of mobs don't - host.stat = DEAD // handle death() properly. Better safe than etc. - host.visible_message("[host] is malformed and unable to survive. It expires pitifully, leaving behind some seeds.") +/datum/seed/proc/kill_living_product(var/datum/weakref/host_ref, var/product_spawner_type = "living_plant") + var/mob/living/host = host_ref.resolve() + if(host && !host.ckey && !host.client) + SSghostroles.remove_spawn_atom(product_spawner_type, host) + host.death() // This seems redundant, but a lot of mobs don't + host.stat = DEAD // handle death() properly. Better safe than etc. + host.visible_message("[host] is malformed and unable to survive. It expires pitifully, leaving behind some seeds.") - var/total_yield = rand(1,3) - for(var/j = 0;j<=total_yield;j++) - var/obj/item/seeds/S = new(get_turf(host)) - S.seed_type = name - S.update_seed() + var/total_yield = rand(1,3) + for(var/j = 0;j<=total_yield;j++) + var/obj/item/seeds/S = new(get_turf(host)) + S.seed_type = name + S.update_seed() \ No newline at end of file diff --git a/code/modules/hydroponics/trays/tray.dm b/code/modules/hydroponics/trays/tray.dm index 80036df099b..d5789a67c6a 100644 --- a/code/modules/hydroponics/trays/tray.dm +++ b/code/modules/hydroponics/trays/tray.dm @@ -152,16 +152,18 @@ return ..() /obj/machinery/portable_atmospherics/hydroponics/attack_ghost(var/mob/abstract/observer/user) - if(!(harvest && seed && ispath(seed.product_type, /mob))) + if(!(seed && ispath(seed.product_type, /mob))) + to_chat(user, SPAN_WARNING("This tray doesn't have any seeds, or the planted seeds does not spawn a mob!")) return - - var/datum/ghosttrap/plant/G = get_ghost_trap("living plant") - if(!G.assess_candidate(user)) + if(!harvest) + to_chat(user, SPAN_WARNING("\The [src] isn't ready to harvest yet!")) return - var/response = alert(user, "Are you sure you want to harvest this [seed.display_name]?", "Living plant request", "Yes", "No") + if(jobban_isbanned(user, "Dionaea")) + to_chat(user, SPAN_WARNING("You are banned from playing Dionae and other living plants!")) + return + var/response = alert(user, "Are you sure you want to harvest this [seed.display_name]?", "Living Plant Request", "Yes", "No") if(response == "Yes") harvest() - return /obj/machinery/portable_atmospherics/hydroponics/attack_generic(var/mob/user) diff --git a/code/modules/mob/living/silicon/robot/drone/drone.dm b/code/modules/mob/living/silicon/robot/drone/drone.dm index f5d562b82e7..8a218dba9d5 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone.dm @@ -80,6 +80,8 @@ var/hat_x_offset = 0 var/hat_y_offset = -13 + var/rebooting = FALSE + /mob/living/silicon/robot/drone/can_be_possessed_by(var/mob/abstract/observer/possessor) if(!istype(possessor) || !possessor.client || !possessor.ckey) return FALSE @@ -239,6 +241,9 @@ if(!allowed(usr)) to_chat(user, SPAN_WARNING("Access denied.")) return + if(rebooting) + to_chat(user, SPAN_WARNING("\The [src] is already rebooting!")) + return user.visible_message(SPAN_NOTICE("\The [user] swipes [user.get_pronoun("his")] ID card through \the [src], attempting to reboot it."), SPAN_NOTICE("You swipe your ID card through \the [src], attempting to reboot it.")) request_player() return @@ -370,11 +375,17 @@ //Reboot procs. +/mob/living/silicon/robot/drone/Logout() + . = ..() + rebooting = FALSE + /mob/living/silicon/robot/drone/proc/request_player() if(too_many_active_drones()) return - var/datum/ghosttrap/G = get_ghost_trap("maintenance drone") - G.request_player(src, "Someone is attempting to reboot a maintenance drone.", 30 SECONDS) + if(rebooting) + return + stat = CONSCIOUS + SSghostroles.add_spawn_atom("rebooted_maint_drone", src) /mob/living/silicon/robot/drone/proc/transfer_personality(var/client/player) if(!player) diff --git a/code/modules/organs/subtypes/diona.dm b/code/modules/organs/subtypes/diona.dm index f9e7f8b0fbf..716eaa52ed1 100644 --- a/code/modules/organs/subtypes/diona.dm +++ b/code/modules/organs/subtypes/diona.dm @@ -8,12 +8,14 @@ /turf/proc/create_diona_nymph() var/mob/living/carbon/alien/diona/D = new(src) - var/datum/ghosttrap/plant/P = get_ghost_trap("living plant") - P.request_player(D, "A diona nymph has split off from its gestalt. ") - sleep(120) - if(D) - if(!D.ckey || !D.client) - D.death() + SSghostroles.add_spawn_atom("diona_nymph", D) + addtimer(CALLBACK(src, .proc/kill_diona_nymph, WEAKREF(D)), 3 MINUTES) + +/turf/proc/kill_diona_nymph(var/datum/weakref/diona_ref) + var/mob/living/carbon/alien/diona/D = diona_ref.resolve() + if(D && (!D.ckey || !D.client)) + SSghostroles.remove_spawn_atom("diona_nymph", D) + D.death() //Probable future TODO: Refactor diona organs to be /obj/item/organ/external/bodypart/diona //Having them not inherit from specific bodypart classes is a problem diff --git a/html/changelogs/geeves-die_ghosttrap.yml b/html/changelogs/geeves-die_ghosttrap.yml new file mode 100644 index 00000000000..8178b305f5d --- /dev/null +++ b/html/changelogs/geeves-die_ghosttrap.yml @@ -0,0 +1,7 @@ +author: Geeves + +delete-after: True + +changes: + - refactor: "Replaced the last of the ghosttrap system with the ghostspawner system. Rebooted drones, imaginary friends, split personalities, and grown mobs like diona now use it." + - tweak: "Grown mobs like diona nymphs now last three minutes after being born, instead of one minute." \ No newline at end of file