More Ghostspawners (#8909)

Posibrains are now in the ghost spawner menu. Activating them is now a one-and-done deal, as they remain open in the ghost spawner until someone disables it or someone spawns in.
    Syndicate Cyborgs have been added to the ghost spawner menu, and will remain in a boot-up state until someone spawns into it.
    Syndicate Cyborg eye overlays have been fixed.
    Wizard Familiars have been added to the ghost spawner menu, same as above.
    Mining Drones have been added to the ghost spawner menu, one swipe is all you need, until someone joins in as them.
This commit is contained in:
Geeves
2020-05-25 18:22:53 +02:00
committed by GitHub
parent 344630ea29
commit 52923bc322
16 changed files with 233 additions and 91 deletions

View File

@@ -22,22 +22,17 @@
icon_state = "locator"
/obj/item/antag_spawner/borg_tele/attack_self(mob/user)
if(uses == 0)
to_chat(usr, "This teleporter is out of uses.")
if(uses <= 0)
to_chat(user, SPAN_WARNING("This teleporter is out of uses."))
return
to_chat(user, "<span class='notice'>The syndicate robot teleporter is attempting to locate an available cyborg.</span>")
var/datum/ghosttrap/ghost = get_ghost_trap("syndicate cyborg")
uses--
var/mob/living/silicon/robot/syndicate/F = new(get_turf(usr))
var/mob/living/silicon/robot/syndicate/F = new /mob/living/silicon/robot/syndicate(get_turf(user))
F.faction = user.faction
F.say("Initiating boot-up sequence!")
spark(F, 4, alldirs)
ghost.request_player(F,"An operative is requesting a syndicate cyborg.", 60 SECONDS)
F.faction = usr.faction
spawn(600)
if(F)
if(!F.ckey || !F.client)
F.visible_message("With no working brain to keep \the [F] working, it is teleported back.")
qdel(F)
uses++
SSghostroles.add_spawn_atom("syndiborg", F)
var/area/A = get_area(src)
if(A)
say_dead_direct("A syndicate cyborg has started its boot process in [A.name]! Spawn in as it by using the ghost spawner menu in the ghost tab, and try to be good!")

View File

@@ -0,0 +1,26 @@
/datum/ghostspawner/mining_drone
short_name = "mining_drone"
name = "Mining Drone"
desc = "Join in as a Mining Drone, assist the miners, get lost on the asteroid and cry synthetic tears."
tags = list("Stationbound")
respawn_flag = MINISYNTH //Flag to check for when trying to spawn someone of that type (CREW, ANIMAL, MINISYNTH)
jobban_job = "Cyborg"
enabled = FALSE
spawn_mob = /mob/living/silicon/robot/drone/mining
/datum/ghostspawner/mining_drone/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/mining_drone/spawn_mob(mob/user)
if(!length(spawn_atoms))
to_chat(user, SPAN_DANGER("There are no available mining drones to spawn at!"))
return FALSE
var/mob/living/silicon/robot/drone/mining/spawn_mining_drone = pick(spawn_atoms)
if(user && spawn_mining_drone)
return spawn_mining_drone.spawn_into_mining_drone(user)
return FALSE

View File

@@ -0,0 +1,26 @@
/datum/ghostspawner/posibrain
short_name = "posibrain"
name = "Positronic Brain"
desc = "Enter a synthetic brain, capable of piloting a spiderbrain, operating an android, becoming an AI, or being a pocketbuddy."
tags = list("Stationbound")
respawn_flag = MINISYNTH //Flag to check for when trying to spawn someone of that type (CREW, ANIMAL, MINISYNTH)
jobban_job = "Cyborg"
enabled = FALSE
spawn_mob = /mob/living/carbon/brain
/datum/ghostspawner/posibrain/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/posibrain/spawn_mob(mob/user)
if(!length(spawn_atoms))
to_chat(user, SPAN_DANGER("There are no available posibrains to spawn at!"))
return FALSE
var/obj/item/device/mmi/digital/posibrain/spawn_posibrain = pick(spawn_atoms)
if(user && spawn_posibrain)
return spawn_posibrain.spawn_into_posibrain(user)
return FALSE

View File

@@ -0,0 +1,26 @@
/datum/ghostspawner/syndiborg
short_name = "syndiborg"
name = "Syndicate Cyborg"
desc = "Join in as a Syndicate Cyborg, assist your summoner in their goals, try and make the round fun for the people you're overequipped to deal with."
tags = list("Antagonist")
respawn_flag = MINISYNTH //Flag to check for when trying to spawn someone of that type (CREW, ANIMAL, MINISYNTH)
jobban_job = "Cyborg"
enabled = FALSE
spawn_mob = /mob/living/silicon/robot/syndicate
/datum/ghostspawner/syndiborg/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/syndiborg/spawn_mob(mob/user)
if(!length(spawn_atoms))
to_chat(user, SPAN_DANGER("There are no available syndiborgs to spawn at!"))
return FALSE
var/mob/living/silicon/robot/syndicate/spawn_syndiborg = pick(spawn_atoms)
if(user && spawn_syndiborg)
return spawn_syndiborg.spawn_into_syndiborg(user)
return FALSE

View File

@@ -0,0 +1,23 @@
/datum/ghostspawner/simplemob/wizard_familiar
short_name = "wizard_familiar"
name = "Wizard Familiar"
desc = "Be a Familiar, act cute, probably end up killing many people somehow."
tags = list("Antagonist")
enabled = FALSE
spawn_mob = /mob/living/simple_animal
/datum/ghostspawner/simplemob/wizard_familiar/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/wizard_familiar/spawn_mob(mob/user)
if(!length(spawn_atoms))
to_chat(user, SPAN_DANGER("There are no available wizard familiars to spawn at!"))
return FALSE
var/mob/living/simple_animal/spawn_wizard_familiar = pick(spawn_atoms)
if(user && spawn_wizard_familiar)
return spawn_wizard_familiar.spawn_into_wizard_familiar(user)
return FALSE

View File

@@ -9,6 +9,7 @@
req_access = list(access_mining, access_robotics)
id_card_type = /obj/item/card/id/minedrone
speed = -1
var/seeking_player = FALSE
var/health_upgrade
var/ranged_upgrade
var/melee_upgrade
@@ -60,11 +61,22 @@
/mob/living/silicon/robot/drone/mining/request_player()
if(too_many_active_drones())
return
var/datum/ghosttrap/G = get_ghost_trap("mining drone")
G.request_player(src, "Someone is attempting to reboot a mining drone.", 30 SECONDS)
seeking_player = TRUE
SSghostroles.add_spawn_atom("mining_drone", src)
var/area/A = get_area(src)
if(A)
say_dead_direct("Someone is attempting to reboot a mining drone in [A.name]! Spawn in as it by using the ghost spawner menu in the ghost tab.")
/mob/living/silicon/robot/drone/mining/proc/spawn_into_mining_drone(var/mob/user)
if(src.ckey)
return
src.ckey = user.ckey
SSghostroles.remove_spawn_atom("mining_drone", src)
seeking_player = FALSE
welcome_drone()
/mob/living/silicon/robot/drone/mining/welcome_drone()
to_chat(src, span("danger", "<b>You are a mining drone, a tiny-brained robotic industrial machine</b>."))
to_chat(src, span("danger", "<b>You are a mining drone, a tiny-brained robotic industrial machine.</b>"))
to_chat(src, span("danger", "You have little individual will, some personality, and no drives or urges other than your laws and the art of mining."))
to_chat(src, span("danger", "Remember, <b>you DO NOT take orders from the AI.</b>"))
@@ -77,7 +89,9 @@
if(!allowed(user))
to_chat(user, span("warning", "Access denied."))
return
if(seeking_player)
to_chat(user, SPAN_WARNING("\The [src] is already in the reboot process."))
return
if(!config.allow_drone_spawn || emagged || health < -maxHealth) //It's dead, Dave.
to_chat(user, span("warning", "The interface is fried, and a distressing burned smell wafts from the robot's interior. You're not rebooting this one."))
return

View File

@@ -3,46 +3,51 @@
desc = "A cube of shining metal, four inches to a side and covered in shallow grooves."
icon = 'icons/obj/assemblies.dmi'
icon_state = "posibrain"
w_class = 3
w_class = ITEMSIZE_NORMAL
origin_tech = list(TECH_ENGINEERING = 4, TECH_MATERIAL = 4, TECH_BLUESPACE = 2, TECH_DATA = 4)
var/searching = 0
var/askDelay = 10 * 60 * 1
var/searching = FALSE
req_access = list(access_robotics)
locked = 0
locked = FALSE
/obj/item/device/mmi/digital/posibrain/Initialize()
. = ..()
brainmob.name = "[pick(list("PBU","HIU","SINA","ARMA","OSI"))]-[rand(100, 999)]"
brainmob.real_name = brainmob.name
/obj/item/device/mmi/digital/posibrain/attack_self(mob/user as mob)
if(brainmob && !brainmob.key && searching == 0)
//Start the process of searching for a new user.
to_chat(user, "<span class='notice'>You carefully locate the manual activation switch and start the positronic brain's boot process.</span>")
icon_state = "posibrain-searching"
src.searching = 1
var/datum/ghosttrap/G = get_ghost_trap("positronic brain")
G.request_player(brainmob, "Someone is requesting a personality for a positronic brain.", 60 SECONDS)
spawn(600) reset_search()
/obj/item/device/mmi/digital/posibrain/proc/reset_search() //We give the players sixty seconds to decide, then reset the timer.
if(src.brainmob && src.brainmob.key) return
src.searching = 0
icon_state = "posibrain"
var/turf/T = get_turf_or_move(src.loc)
for (var/mob/M in viewers(T))
M.show_message("<span class='notice'>The positronic brain buzzes quietly, and the golden lights fade away. Perhaps you could try again?</span>")
/obj/item/device/mmi/digital/posibrain/attack_ghost(var/mob/abstract/observer/user)
if(!searching || (src.brainmob && src.brainmob.key))
/obj/item/device/mmi/digital/posibrain/attack_self(mob/user)
if(brainmob.ckey)
to_chat(user, SPAN_WARNING("\The [src] already has an active occupant!"))
return
var/area/A = get_area(src)
if(brainmob && !brainmob.key)
if(!searching)
to_chat(user, SPAN_NOTICE("You carefully locate the manual activation switch and start \the [src]'s boot process."))
icon_state = "posibrain-searching"
searching = TRUE
SSghostroles.add_spawn_atom("posibrain", src)
if(A)
say_dead_direct("A posibrain has started its boot process in [A.name]! Spawn in as it by using the ghost spawner menu in the ghost tab.")
else
to_chat(user, SPAN_NOTICE("You carefully locate the manual activation switch and disable \the [src]'s boot process."))
icon_state = initial(icon_state)
searching = FALSE
SSghostroles.remove_spawn_atom("posibrain", src)
if(A)
say_dead_direct("A posibrain is no longer booting up in [A.name]. Seems someone disabled it.")
var/datum/ghosttrap/G = get_ghost_trap("positronic brain")
if(!G.assess_candidate(user))
/obj/item/device/mmi/digital/posibrain/proc/spawn_into_posibrain(var/mob/user)
if(brainmob.ckey)
return
var/response = alert(user, "Are you sure you wish to possess this [src]?", "Possess [src]", "Yes", "No")
if(response == "Yes")
G.transfer_personality(user, brainmob)
return
brainmob.ckey = user.ckey
name = "positronic brain ([brainmob.name])"
icon_state = "posibrain-occupied"
searching = FALSE
SSghostroles.remove_spawn_atom("posibrain", src)
to_chat(brainmob, "<b>You are a positronic brain, brought into existence on [station_name()].</b>")
to_chat(brainmob, "<b>As a synthetic intelligence, you answer to all crewmembers, as well as the AI.</b>")
to_chat(brainmob, "<b>Remember, the purpose of your existence is to serve the crew and the station. Above all else, do no harm.</b>")
visible_message(SPAN_NOTICE("\The [src] chimes quietly."))
/obj/item/device/mmi/digital/posibrain/examine(mob/user)
if(!..(user))
@@ -51,12 +56,15 @@
var/msg = "<span class='info'>*---------*</span>\nThis is \icon[src] \a <EM>[src]</EM>!\n[desc]\n"
msg += "<span class='warning'>"
if(src.brainmob && src.brainmob.key)
switch(src.brainmob.stat)
if(brainmob?.key)
switch(brainmob.stat)
if(CONSCIOUS)
if(!src.brainmob.client) msg += "It appears to be in stand-by mode.\n" //afk
if(UNCONSCIOUS) msg += "<span class='warning'>It doesn't seem to be responsive.</span>\n"
if(DEAD) msg += "<span class='deadsay'>It appears to be completely inactive.</span>\n"
if(!src.brainmob.client)
msg += "It appears to be in stand-by mode.\n" //afk
if(UNCONSCIOUS)
msg += "<span class='warning'>It doesn't seem to be responsive.</span>\n"
if(DEAD)
msg += "<span class='deadsay'>It appears to be completely inactive.</span>\n"
else
msg += "<span class='deadsay'>It appears to be completely inactive.</span>\n"
msg += "</span><span class='info'>*---------*</span>"
@@ -64,19 +72,14 @@
return
/obj/item/device/mmi/digital/posibrain/emp_act(severity)
if(!src.brainmob)
if(!brainmob)
return
else
switch(severity)
if(1)
src.brainmob.emp_damage += rand(20,30)
brainmob.emp_damage += rand(20,30)
if(2)
src.brainmob.emp_damage += rand(10,20)
brainmob.emp_damage += rand(10,20)
if(3)
src.brainmob.emp_damage += rand(0,10)
brainmob.emp_damage += rand(0,10)
..()
/obj/item/device/mmi/digital/posibrain/New()
..()
src.brainmob.name = "[pick(list("PBU","HIU","SINA","ARMA","OSI"))]-[rand(100, 999)]"
src.brainmob.real_name = src.brainmob.name

View File

@@ -740,7 +740,6 @@ var/global/list/robot_modules = list(
"Treadhound" = "syndie_treadhound",
"HD-MAD" = "mcspizzytronsyndi",
"Industrial" = "heavysyndi",
"Heph-Android" = "droid",
"Arachnotronic" = "arachnotronicsyndi",
"Toileto-tron" = "syndi-medi",
)

View File

@@ -31,8 +31,12 @@
/mob/living/silicon/robot/syndicate/updateicon() //because this was the only way I found out how to make their eyes and etc works
cut_overlays()
if(stat == 0)
add_overlay("eyes-[icon_state]")
if(stat == CONSCIOUS)
if(a_intent == I_HELP)
add_overlay(image(icon, "eyes-[module_sprites[icontype]]-help", layer = EFFECTS_ABOVE_LIGHTING_LAYER))
else
add_overlay(image(icon, "eyes-[module_sprites[icontype]]-harm", layer = EFFECTS_ABOVE_LIGHTING_LAYER))
if(opened)
var/panelprefix = custom_sprite ? src.ckey : "ov"
@@ -59,6 +63,13 @@
explosion(get_turf(src), 1, 2, 3, 5)
qdel(src)
/mob/living/silicon/robot/syndicate/proc/spawn_into_syndiborg(var/mob/user)
if(src.ckey)
return
src.ckey = user.ckey
SSghostroles.remove_spawn_atom("syndiborg", src)
say("Boot sequence complete!")
//syndicate borg gear
/obj/item/gun/energy/mountedsmg

View File

@@ -192,11 +192,9 @@
desc = "A small rodent. It looks very old."
body_color = "gray"
see_in_dark = 8
see_invisible = SEE_INVISIBLE_NOLIGHTING
health = 25
maxHealth = 25
melee_damage_lower = 1
@@ -204,6 +202,7 @@
attacktext = "nibbled"
universal_speak = 1
universal_understand = 1
stop_automated_movement = TRUE
min_oxy = 1 //still require a /bit/ of air.
max_co2 = 0

View File

@@ -67,6 +67,8 @@
var/environment_smash = 0
var/resistance = 0 // Damage reduction
var/wizard_master
//Null rod stuff
var/supernatural = 0
var/purge = 0
@@ -741,3 +743,12 @@ mob/living/simple_animal/bullet_act(var/obj/item/projectile/Proj)
var/matrix/M = new()
B.transform = M.Scale(scale)
B.update_icon()
/mob/living/simple_animal/proc/spawn_into_wizard_familiar(var/mob/user)
if(src.ckey)
return
src.ckey = user.ckey
SSghostroles.remove_spawn_atom("wizard_familiar", src)
if(wizard_master)
add_spell(new /spell/contract/return_master(wizard_master), "const_spell_ready")
to_chat(src, "<B>You are [src], a familiar to [wizard_master]. He is your master and your friend. Aid him in his wizarding duties to the best of your ability.</B>")

View File

@@ -23,19 +23,19 @@
"The more carnivorous and knowledge hungry cousin of the space carp. Keep away from books."
)
/obj/item/monster_manual/attack_self(mob/living/user as mob)
/obj/item/monster_manual/attack_self(mob/living/user)
if(!user)
return
if(!user.is_wizard())
to_chat(user, "<span class='warning'>When you try to open the book, horrors pours out from among the pages!</span>")
new /mob/living/simple_animal/hostile/creature(user.loc)
to_chat(user, SPAN_WARNING("When you try to open the book, horrors pours out from among the pages!"))
new /mob/living/simple_animal/hostile/creature(get_turf(user))
playsound(user, 'sound/magic/Summon_Karp.ogg', 100, 1)
return
else
user.set_machine(src)
interact(user)
/obj/item/monster_manual/interact(mob/user as mob)
/obj/item/monster_manual/interact(mob/user)
var/dat
if(temp)
dat = "[temp]<br><a href='byond://?src=\ref[src];temp=1'>Return</a>"
@@ -56,12 +56,11 @@
if(href_list["temp"])
temp = null
if(href_list["path"])
if(uses == 0)
to_chat(usr, "This book is out of uses.")
if(uses <= 0)
to_chat(usr, SPAN_WARNING("This book is out of uses."))
return
var/datum/ghosttrap/ghost = get_ghost_trap("wizard familiar")
var path = text2path(href_list["path"])
var/path = text2path(href_list["path"])
if(!ispath(path))
to_chat(usr, "Invalid mob path in [src]. Contact a coder.")
return
@@ -70,22 +69,16 @@
return
var/mob/living/simple_animal/F = new path(get_turf(src))
F.wizard_master = usr
F.faction = usr.faction
temp = "You have attempted summoning \the [F]"
ghost.request_player(F,"A wizard is requesting a familiar.", 60 SECONDS)
SSghostroles.add_spawn_atom("wizard_familiar", F)
var/area/A = get_area(src)
if(A)
say_dead_direct("A wizard familiar has been summoned in [A.name]! Spawn in as it by using the ghost spawner menu in the ghost tab.")
uses--
spawn(600)
if(F)
if(!F.ckey || !F.client)
F.visible_message("With no soul to keep \the [F] linked to this plane, it fades away.")
qdel(F)
uses++
else
F.faction = usr.faction
F.add_spell(new /spell/contract/return_master(usr), "const_spell_ready")
to_chat(F, "<B>You are [F], a familiar to [usr]. He is your master and your friend. Aid him in his wizarding duties to the best of your ability.</B>")
if(Adjacent(usr))
src.interact(usr)
else
usr << browse(null,"window=monstermanual")
usr << browse(null,"window=monstermanual")

View File

@@ -34,6 +34,8 @@
H.add_spell(spell_to_add)
/mob/proc/add_spell(var/spell/spell_to_add, var/spell_base = "wiz_spell_ready", var/master_type = /obj/screen/movable/spell_master)
if(isobserver(usr)) // we spawned in via ghost spawner, so set our thing to this so we don't screw up
usr = src
if(!spell_masters)
spell_masters = list()