diff --git a/aurorastation.dme b/aurorastation.dme index a4b5cddfe62..efa7ecfef51 100644 --- a/aurorastation.dme +++ b/aurorastation.dme @@ -1587,6 +1587,7 @@ #include "code\modules\ghostroles\spawner\human\responseteams\response_team.dm" #include "code\modules\ghostroles\spawner\human\responseteams\syndicate.dm" #include "code\modules\ghostroles\spawner\human\responseteams\tcfl.dm" +#include "code\modules\ghostroles\spawner\simplemob\borer.dm" #include "code\modules\ghostroles\spawner\simplemob\maintdrone.dm" #include "code\modules\ghostroles\spawner\simplemob\rat.dm" #include "code\modules\ghostroles\spawner\simplemob\spider.dm" diff --git a/code/controllers/subsystems/ghostroles.dm b/code/controllers/subsystems/ghostroles.dm index f4077093f43..b6274eabe09 100644 --- a/code/controllers/subsystems/ghostroles.dm +++ b/code/controllers/subsystems/ghostroles.dm @@ -2,6 +2,7 @@ /datum/controller/subsystem/ghostroles name = "Ghost Roles" + init_order = SS_INIT_JOBS flags = SS_NO_FIRE var/list/list/spawnpoints = list() //List of the available spawnpoints by spawnpoint type @@ -10,6 +11,10 @@ var/list/spawners = list() //List of the available spawner datums + // For special spawners that have mobile or object spawnpoints + var/list/spawn_types = list("Golems", "Borers") + var/list/spawn_atom = list() + /datum/controller/subsystem/ghostroles/Recover() src.spawnpoints = SSghostroles.spawnpoints src.spawners = SSghostroles.spawners @@ -36,6 +41,9 @@ CHECK_TICK update_spawnpoint_status_by_identifier(identifier) + for(var/spawn_type in spawn_types) + spawn_atom[spawn_type] = list() + //Adds a spawnpoint to the spawnpoint list /datum/controller/subsystem/ghostroles/proc/add_spawnpoints(var/obj/effect/ghostspawpoint/P) if(!P.identifier) //If the spawnpoint has no identifier -> Abort @@ -177,3 +185,25 @@ for(var/i in S.spawnpoints) update_spawnpoint_status_by_identifier(i) return + +/datum/controller/subsystem/ghostroles/proc/add_spawn_atom(var/ghost_role_name, var/atom/spawn_atom) + if(ghost_role_name && spawn_atom) + var/datum/ghostspawner/G = spawners[ghost_role_name] + if(G) + G.spawn_atoms += spawn_atom + if(length(G.spawn_atoms) == 1) + G.enable() + +/datum/controller/subsystem/ghostroles/proc/remove_spawn_atom(var/ghost_role_name, var/atom/spawn_atom) + if(ghost_role_name && spawn_atom) + var/datum/ghostspawner/G = spawners[ghost_role_name] + if(G) + G.spawn_atoms -= spawn_atom + if(!length(G.spawn_atoms)) + G.disable() + +/datum/controller/subsystem/ghostroles/proc/get_spawn_atoms(var/ghost_role_name) + var/datum/ghostspawner/G = spawners[ghost_role_name] + if(G) + return G.spawn_atoms + return list() diff --git a/code/game/antagonist/alien/borer.dm b/code/game/antagonist/alien/borer.dm index 97fb9fc08e1..6487bdb8f39 100644 --- a/code/game/antagonist/alien/borer.dm +++ b/code/game/antagonist/alien/borer.dm @@ -4,7 +4,7 @@ var/datum/antagonist/xenos/borer/borers id = MODE_BORER role_text = "Cortical Borer" role_text_plural = "Cortical Borers" - mob_path = /mob/living/simple_animal/borer + mob_path = /mob/living/simple_animal/borer/roundstart bantype = "Borer" welcome_text = "Use your Infest power to crawl into the ear of a host and fuse with their brain. You can only take control temporarily, and at risk of hurting your host, so be clever and careful; your host is encouraged to help you however they can. Talk to your fellow borers with ,x." antag_indicator = "brainworm" @@ -65,4 +65,4 @@ var/datum/antagonist/xenos/borer/borers var/obj/item/organ/external/head = borer.host.get_organ(BP_HEAD) head.implants += borer else - ..() + ..() \ No newline at end of file diff --git a/code/game/jobs/whitelist.dm b/code/game/jobs/whitelist.dm index 272e94f203e..e5e651e99c4 100644 --- a/code/game/jobs/whitelist.dm +++ b/code/game/jobs/whitelist.dm @@ -122,6 +122,9 @@ var/list/whitelist = list() if (!istype(C) || C.holder) return 0 + if(!dbcon.IsConnected()) + return TRUE + var/age_to_beat = 0 // Assume it's an antag role. diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm index 0b04983db58..8c79e007bb0 100644 --- a/code/game/objects/items/devices/scanners.dm +++ b/code/game/objects/items/devices/scanners.dm @@ -68,18 +68,19 @@ BREATH ANALYZER else . = "moderate" -/proc/health_scan_mob(var/mob/M, var/mob/living/user, var/show_limb_damage = TRUE) - if (((user.is_clumsy()) || (DUMB in user.mutations)) && prob(50)) - user.visible_message("\The [user] runs the scanner over the floor.", "You run the scanner over the floor.", "You hear metal repeatedly clunking against the floor.") - to_chat(user, "Scan results for the floor:") - to_chat(user, "Overall Status: Healthy") - return +/proc/health_scan_mob(var/mob/M, var/mob/living/user, var/show_limb_damage = TRUE, var/just_scan = FALSE) + if(!just_scan) + if (((user.is_clumsy()) || (DUMB in user.mutations)) && prob(50)) + user.visible_message("\The [user] runs the scanner over the floor.", "You run the scanner over the floor.", "You hear metal repeatedly clunking against the floor.") + to_chat(user, "Scan results for the floor:") + to_chat(user, "Overall Status: Healthy") + return - if(!usr.IsAdvancedToolUser()) - to_chat(usr, "You don't have the dexterity to do this!") - return + if(!usr.IsAdvancedToolUser()) + to_chat(usr, "You don't have the dexterity to do this!") + return - user.visible_message("[user] runs the scanner over [M].","You run the scanner over [M].") + user.visible_message("[user] runs the scanner over [M].","You run the scanner over [M].") if(!istype(M, /mob/living/carbon/human)) to_chat(user, "This scanner is designed for humanoid patients only.") diff --git a/code/modules/ghostroles/spawner/base.dm b/code/modules/ghostroles/spawner/base.dm index be8ab0c54b4..27849a07342 100644 --- a/code/modules/ghostroles/spawner/base.dm +++ b/code/modules/ghostroles/spawner/base.dm @@ -8,6 +8,7 @@ //Vars regarding the spawnpoints and conditions of the spawner var/list/spawnpoints = null //List of the applicable spawnpoints (by name) + var/list/spawn_atoms = list() // List of atoms you can spawn at var/landmark_name = null //Alternatively you can specify a landmark name var/max_count = 0 //How often can this spawner be used var/count = 0 //How ofen has this spawner been used @@ -94,6 +95,11 @@ //This proc selects the spawnpoint to use. /datum/ghostspawner/proc/select_spawnpoint(var/use=TRUE) + if(length(spawn_atoms)) + var/chosen_spawn_atom = pick(spawn_atoms) + var/turf/T = get_turf(chosen_spawn_atom) + if(T) + return T if(!isnull(spawnpoints)) for(var/spawnpoint in spawnpoints) //Loop through the applicable spawnpoints var/turf/T = SSghostroles.get_spawnpoint(spawnpoint, use) //Gets the first matching spawnpoint or null if none are available diff --git a/code/modules/ghostroles/spawner/human/golem.dm b/code/modules/ghostroles/spawner/human/golem.dm index 6a03bd8c370..e1f484a2320 100644 --- a/code/modules/ghostroles/spawner/human/golem.dm +++ b/code/modules/ghostroles/spawner/human/golem.dm @@ -14,18 +14,12 @@ //The proc to actually spawn in the user /datum/ghostspawner/human/golem/spawn_mob(mob/user) - var/obj/effect/golemrune/rune - var/list/global_runes = list() - - for(var/obj/effect/golemrune/eligible_rune in golem_runes) - global_runes += eligible_rune - - if(!length(global_runes)) + if(!length(spawn_atoms)) to_chat(user, span("danger", "There are no available golem runes to spawn at!")) return FALSE - rune = pick(global_runes) + var/obj/effect/golemrune/rune = pick(spawn_atoms) - if(user) + if(user && rune) return rune.spawn_golem(user) return FALSE \ No newline at end of file diff --git a/code/modules/ghostroles/spawner/simplemob/borer.dm b/code/modules/ghostroles/spawner/simplemob/borer.dm new file mode 100644 index 00000000000..14f43abb5d1 --- /dev/null +++ b/code/modules/ghostroles/spawner/simplemob/borer.dm @@ -0,0 +1,24 @@ +/datum/ghostspawner/simplemob/borer + short_name = "borer" + name = "Cortical Borer" + desc = "Infest crew, reproduce, repeat." + tags = list("Antagonist") + + enabled = FALSE + + spawn_mob = /mob/living/simple_animal/borer + +/datum/ghostspawner/simplemob/borer/select_spawnpoint(var/use) + return TRUE //We just fake it here, since the spawnpoint is selected if someone is spawned in. + +//The proc to actually spawn in the user +/datum/ghostspawner/simplemob/borer/spawn_mob(mob/user) + if(!length(spawn_atoms)) + to_chat(user, SPAN_DANGER("There are no available borers to spawn at!")) + return FALSE + + var/mob/living/simple_animal/borer/spawn_borer = pick(spawn_atoms) + + if(user && spawn_borer) + return spawn_borer.spawn_into_borer(user) + return FALSE \ No newline at end of file diff --git a/code/modules/mob/living/carbon/slime/items.dm b/code/modules/mob/living/carbon/slime/items.dm index 87f8cf02f35..fea57c6be4f 100644 --- a/code/modules/mob/living/carbon/slime/items.dm +++ b/code/modules/mob/living/carbon/slime/items.dm @@ -216,8 +216,6 @@ icon = 'icons/obj/chemical.dmi' icon_state = "bottle17" -var/list/global/golem_runes = list() - /obj/effect/golemrune anchored = TRUE desc = "A strange rune used to create golems. It glows when spirits are nearby." @@ -233,25 +231,15 @@ var/list/global/golem_runes = list() . = ..() START_PROCESSING(SSprocessing, src) announce_to_ghosts() - golem_runes += src - if(length(golem_runes) == 1) - for(var/role_spawner in SSghostroles.spawners) - if(role_spawner == "golem") - var/datum/ghostspawner/human/golem/golem_spawner = SSghostroles.spawners[role_spawner] - golem_spawner.enable() + SSghostroles.add_spawn_atom("golem", src) /obj/effect/golemrune/random_type/Initialize() . = ..() golem_type = pick(golem_types) /obj/effect/golemrune/Destroy() - . = ..() - golem_runes -= src - if(!length(golem_runes)) - for(var/role_spawner in SSghostroles.spawners) - if(role_spawner == "golem") - var/datum/ghostspawner/human/golem/golem_spawner = SSghostroles.spawners[role_spawner] - golem_spawner.disable() + SSghostroles.remove_spawn_atom("golem", src) + return ..() /obj/effect/golemrune/process() var/mob/abstract/observer/ghost diff --git a/code/modules/mob/living/simple_animal/borer/borer.dm b/code/modules/mob/living/simple_animal/borer/borer.dm index 5b15400ced1..d111ab63a8a 100644 --- a/code/modules/mob/living/simple_animal/borer/borer.dm +++ b/code/modules/mob/living/simple_animal/borer/borer.dm @@ -21,7 +21,7 @@ maxHealth = 40 health = 40 pass_flags = PASSTABLE - universal_understand = 1 + universal_understand = TRUE holder_type = /obj/item/holder/borer mob_size = 1 hunger_enabled = FALSE @@ -33,10 +33,10 @@ var/mob/living/captive_brain/host_brain // Used for swapping control of the body back and forth. var/controlling // Used in human death check. var/has_reproduced - var/roundstart + var/request_player = TRUE /mob/living/simple_animal/borer/roundstart - roundstart = TRUE + request_player = FALSE /mob/living/simple_animal/borer/LateLogin() ..() @@ -52,15 +52,23 @@ verbs += /mob/living/proc/hide truename = "[pick("Primary","Secondary","Tertiary","Quaternary")]-[rand(1000,9999)]" - if(!roundstart) - request_player() + if(request_player && !ckey && !client) + SSghostroles.add_spawn_atom("borer", src) + var/area/A = get_area(src) + if(A) + say_dead_direct("A borer has been birthed in [A.name]! Spawn in as it by using the ghost spawner menu in the ghost tab.") + +/mob/living/simple_animal/borer/death(gibbed, deathmessage) + SSghostroles.remove_spawn_atom("borer", src) + return ..(gibbed,deathmessage) /mob/living/simple_animal/borer/Life() ..() if(host) - if(!stat && !host.stat) + if(!stat && host.stat != DEAD) if(chemicals < 250) chemicals++ + if(host && !host.stat) if(controlling && prob(host.getBrainLoss()/20)) host.say("*[pick(list("blink","blink_r","choke","drool","twitch","twitch_s","gasp"))]") @@ -152,10 +160,10 @@ host = null return -//Procs for grabbing players. -/mob/living/simple_animal/borer/proc/request_player() - var/datum/ghosttrap/G = get_ghost_trap("cortical borer") - G.request_player(src, "A cortical borer needs a player.") +/mob/living/simple_animal/borer/proc/spawn_into_borer(var/mob/user) + ckey = user.ckey + qdel(user) + SSghostroles.remove_spawn_atom("borer", src) /mob/living/simple_animal/borer/cannot_use_vents() return diff --git a/code/modules/mob/living/simple_animal/borer/borer_powers.dm b/code/modules/mob/living/simple_animal/borer/borer_powers.dm index 4ee1ace42f7..996089d7b68 100644 --- a/code/modules/mob/living/simple_animal/borer/borer_powers.dm +++ b/code/modules/mob/living/simple_animal/borer/borer_powers.dm @@ -414,7 +414,7 @@ /mob/living/simple_animal/borer/verb/awaken_psionics() set category = "Abilities" set name = "Awaken Host Psionics (150)" - set desc = "Probe into your host an unlock their psionic potential." + set desc = "Probe into your host and unlock their psionic potential. Note, it will give them a seizure as their brain realizes its potential." if(!host) to_chat(src, span("notice", "You are not inside a host body.")) @@ -437,7 +437,8 @@ chemicals -= 150 to_chat(src, span("notice", "You probe your tendrils deep within your host's zona bovinae, seeking to unleash their potential.")) to_chat(host, span("danger", "You feel some tendrils probe at the back of your head...")) - addtimer(CALLBACK(src, .proc/jumpstart_psi), 100) + to_chat(host, FONT_LARGE(SPAN_WARNING("You feel something terrible coming on..."))) + addtimer(CALLBACK(src, .proc/jumpstart_psi), 150) /mob/living/simple_animal/borer/proc/jumpstart_psi() to_chat(src, span("notice", "You succeed in interfacing with the host's zona bovinae, this will be a painful process for them.")) @@ -486,3 +487,17 @@ to_chat(src, span("notice", "You successfully manage to upgrade your host's [selected_faculty] faculty.")) to_chat(host, span("good", "A breeze of fresh air washes over your mind, you feel powerful!")) to_chat(host, span("notice", "You have been psionically enlightened. You are now a [psychic_ranks_to_strings[host.psi.ranks[selected_faculty]]] in the [selected_faculty] faculty.")) + +/mob/living/simple_animal/borer/verb/host_health_scan() + set category = "Abilities" + set name = "Inspect Host Health" + set desc = "Survey your host for injuries, allowing you to better treat them." + + if(!host) + to_chat(src, SPAN_WARNING("You have no host to scan.")) + return + if(stat) + to_chat(src, SPAN_WARNING("You cannot do that in your current state.")) + return + + health_scan_mob(host, src, TRUE, TRUE) \ No newline at end of file diff --git a/code/modules/shareddream/dream_entry.dm b/code/modules/shareddream/dream_entry.dm index 8ef626d173f..be94d60815f 100644 --- a/code/modules/shareddream/dream_entry.dm +++ b/code/modules/shareddream/dream_entry.dm @@ -8,7 +8,9 @@ var/list/dream_entries = list() // If either changes, they should be nocked back to the real world. if(can_commune() && stat == UNCONSCIOUS && sleeping > 1) if(!istype(bg) && client) // Don't spawn a brainghost if we're not logged in. - bg = new(src) // Generate a new brainghost. + bg = new /mob/living/brain_ghost(src) // Generate a new brainghost. + if(isnull(bg)) // Prevents you from getting kicked if the brain ghost didn't spawn - geeves + return bg.ckey = ckey bg.client = client ckey = "@[bg.ckey]" @@ -27,8 +29,17 @@ var/list/dream_entries = list() log_and_message_admins("has left the shared dream",bg) var/mob/living/brain_ghost/old_bg = bg bg = null - ckey = old_bg.ckey + + var/return_text = "You are ripped from the Srom as your body awakens." + var/mob/return_mob = src + + var/mob/living/simple_animal/borer/B = has_brain_worms() + if(B?.host_brain) + return_mob = B.host_brain + return_text = "You are ripped from the Srom as you return to the captivity of your own mind." + + return_mob.ckey = old_bg.ckey old_bg.show_message("[bg] fades as their connection is severed.") animate(old_bg, alpha=0, time = 200) QDEL_IN(old_bg, 20) - to_chat(src, "You are ripped from the Srom as your body awakens.") \ No newline at end of file + to_chat(return_mob, SPAN_WARNING("[return_text]")) \ No newline at end of file diff --git a/html/changelogs/geeves-borer_stuff.yml b/html/changelogs/geeves-borer_stuff.yml new file mode 100644 index 00000000000..832273e9bb7 --- /dev/null +++ b/html/changelogs/geeves-borer_stuff.yml @@ -0,0 +1,11 @@ +author: Geeves + +delete-after: True + +changes: + - rscadd: "Spawned borers now get added to the Ghostspawner menu, allowing players to inhabit them even if they didn't catch the original request." + - rscadd: "Borers have gained the ability to survey their host's health, allowing them to better choose when to administer certain chemicals." + - tweak: "Borers now regenerate chemicals even if their host is unconscious." + - rscadd: "Awakening psionics now take 15 seconds instead of 10, and the host now gets a message about feeling something bad coming on, allowing them to make a dash to safety and or seclusion." + - bugfix: "Skrell returning from Srom no longer eject controlling borers to the lobby by replacing their ckey into the aether." + - bugfix: "Skrell no longer spontaneously die when entering Srom on a map that doesn't have a Srom location." \ No newline at end of file