[MIRROR] Ports Cryopods (#4880)

* Ports Cryopods (#58025)

Co-authored-by: Mothblocks <35135081+Mothblocks@ users.noreply.github.com>
Co-authored-by: Kokonut <38844529+maxymax13@ users.noreply.github.com>
Co-authored-by: Aleksej Komarov <stylemistake@ gmail.com>

* Ports Cryopods

* aaaa

* Update cryopod.dm

Co-authored-by: Jeremiah <42397676+jlsnow301@users.noreply.github.com>
Co-authored-by: Mothblocks <35135081+Mothblocks@ users.noreply.github.com>
Co-authored-by: Kokonut <38844529+maxymax13@ users.noreply.github.com>
Co-authored-by: Aleksej Komarov <stylemistake@ gmail.com>
Co-authored-by: Gandalf <jzo123@hotmail.com>
This commit is contained in:
SkyratBot
2021-04-13 11:53:56 +01:00
committed by GitHub
co-authored by Mothblocks Kokonut Aleksej Komarov Jeremiah Gandalf
parent da714da60e
commit ef50ca23cb
13 changed files with 547 additions and 534 deletions
+8
View File
@@ -145,6 +145,14 @@ SUBSYSTEM_DEF(job)
JobDebug("AR has failed, Player: [player], Rank: [rank]")
return FALSE
/datum/controller/subsystem/job/proc/FreeRole(rank)
if(!rank)
return
JobDebug("Freeing role: [rank]")
var/datum/job/job = GetJob(rank)
if(!job)
return FALSE
job.current_positions = max(0, job.current_positions - 1)
/datum/controller/subsystem/job/proc/FindOccupationCandidates(datum/job/job, level, flag)
JobDebug("Running FOC, Job: [job], Level: [level], Flag: [flag]")
+1
View File
@@ -41,6 +41,7 @@
var/assigned_role
var/special_role
var/list/restricted_roles = list()
var/list/datum/objective/objectives = list()
var/list/spell_list = list() // Wizard mode & "Give Spell" badmin button.
+4
View File
@@ -608,6 +608,10 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
name = "Recreation Area"
icon_state = "rec"
/area/commons/cryopods
name = "Cryopod Room"
icon_state = "cryopod"
// Commons - Vacant Rooms
/area/commons/vacant_room
+2
View File
@@ -1,4 +1,5 @@
GLOBAL_LIST(admin_objective_list) //Prefilled admin assignable objective list
GLOBAL_LIST_EMPTY(objectives)
/datum/objective
var/datum/mind/owner //The primary owner of the objective. !!SOMEWHAT DEPRECATED!! Prefer using 'team' for new code.
@@ -14,6 +15,7 @@ GLOBAL_LIST(admin_objective_list) //Prefilled admin assignable objective list
var/martyr_compatible = FALSE //If the objective is compatible with martyr objective, i.e. if you can still do it while dead.
/datum/objective/New(text)
GLOB.objectives += src
if(text)
explanation_text = text
+2 -4
View File
@@ -83,12 +83,10 @@ GLOBAL_LIST_EMPTY(announcement_systems)
message = CompileText(arrival, user, rank)
else if(message_type == "NEWHEAD" && newheadToggle)
message = CompileText(newhead, user, rank)
else if(message_type == "CRYOSTORAGE")
message = "[user][rank ? ", [rank]" : ""] has been moved to cryo storage."
else if(message_type == "ARRIVALS_BROKEN")
message = "The arrivals shuttle has been damaged. Docking for repairs..."
//SKYRAT EDIT ADDITION BEGIN - CRYOSLEEP
else if(message_type == "CRYOSTORAGE")
message = CompileText("%PERSON, %RANK has been moved to cryo storage.", user, rank)
//SKYRAT EDIT ADDITION END
broadcast(message, channels)
+401
View File
@@ -0,0 +1,401 @@
/*
* Cryogenic refrigeration unit. Basically a despawner.
* Stealing a lot of concepts/code from sleepers due to massive laziness.
* The despawn tick will only fire if it's been more than time_till_despawned ticks
* since time_entered, which is world.time when the occupant moves in.
* ~ Zuhayr
*/
GLOBAL_LIST_EMPTY(cryopod_computers)
//Main cryopod console.
/obj/machinery/computer/cryopod
name = "cryogenic oversight console"
desc = "An interface between crew and the cryogenic storage oversight systems."
icon = 'modular_skyrat/modules/cryosleep/icons/cryogenics.dmi' //SKYRAT EDIT CHANGE - ORIGINAL: 'icons/obj/machines/cryopod.dmi'
icon_state = "cellconsole_1"
// circuit = /obj/item/circuitboard/cryopodcontrol
density = FALSE
interaction_flags_machine = INTERACT_MACHINE_OFFLINE
req_one_access = list(ACCESS_HEADS, ACCESS_ARMORY) // Heads of staff or the warden can go here to claim recover items from their department that people went were cryodormed with.
var/mode = null
// Used for logging people entering cryosleep and important items they are carrying.
var/list/frozen_crew = list()
var/list/frozen_items = list()
var/storage_type = "crewmembers"
var/storage_name = "Cryogenic Oversight Control"
var/allow_items = TRUE
/obj/machinery/computer/cryopod/Initialize()
. = ..()
GLOB.cryopod_computers += src
/obj/machinery/computer/cryopod/Destroy()
GLOB.cryopod_computers -= src
..()
/obj/machinery/computer/cryopod/update_icon_state()
if(machine_stat & (NOPOWER|BROKEN))
icon_state = "cellconsole"
return ..()
icon_state = "cellconsole_1"
return ..()
/obj/machinery/computer/cryopod/ui_interact(mob/user, datum/tgui/ui)
if(machine_stat & (NOPOWER|BROKEN))
return
add_fingerprint(user)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "CryopodConsole", name)
ui.open()
/obj/machinery/computer/cryopod/ui_data(mob/user)
var/list/data = list()
data["allow_items"] = allow_items
data["frozen_crew"] = frozen_crew
data["frozen_items"] = list()
if(allow_items)
data["frozen_items"] = frozen_items
var/obj/item/card/id/id_card
var/datum/bank_account/current_user
if(isliving(user))
var/mob/living/person = user
id_card = person.get_idcard()
if(id_card?.registered_account)
current_user = id_card.registered_account
if(current_user)
data["account_name"] = current_user.account_holder
return data
/obj/machinery/computer/cryopod/ui_act(action, params)
. = ..()
if(.)
return
var/mob/user = usr
add_fingerprint(user)
switch(action)
if("one_item")
if(!allowed(user))
to_chat(user, "<span class='warning'>Access Denied.</span>")
return
if(!allow_items) return
if(!params["item"])
return
var/obj/item/item = frozen_items[text2num(params["item"])]
if(!item)
to_chat(user, "<span class='notice'>[item] is no longer in storage.</span>")
return
visible_message("<span class='notice'>[src] beeps happily as it disgorges [item].</span>")
item.forceMove(get_turf(src))
frozen_items -= item
if("all_items")
if(!allowed(user))
to_chat(user, "<span class='warning'>Access Denied.</span>")
return
if(!allow_items) return
visible_message("<span class='notice'>[src] beeps happily as it disgorges the desired objects.</span>")
for(var/obj/item/item in frozen_items)
item.forceMove(get_turf(src))
frozen_items -= item
return TRUE
// Cryopods themselves.
/obj/machinery/cryopod
name = "cryogenic freezer"
desc = "Suited for Cyborgs and Humanoids, the pod is a safe place for personnel affected by the Space Sleep Disorder to get some rest."
icon = 'icons/obj/machines/cryopod.dmi'
icon_state = "cryopod-open"
density = TRUE
anchored = TRUE
state_open = TRUE
var/on_store_message = "has entered long-term storage."
var/on_store_name = "Cryogenic Oversight"
// 3 minutes-ish safe period before being despawned.
var/time_till_despawn = 3 MINUTES // This is reduced to 30 seconds if a player manually enters cryo
var/fast_despawn = 30 SECONDS
var/despawn_world_time = null // Used to keep track of the safe period.
var/obj/machinery/computer/cryopod/control_computer
COOLDOWN_DECLARE(last_no_computer_message)
/obj/machinery/cryopod/Initialize()
..()
return INITIALIZE_HINT_LATELOAD //Gotta populate the cryopod computer GLOB first
/obj/machinery/cryopod/LateInitialize()
update_icon()
find_control_computer()
// This is not a good situation
/obj/machinery/cryopod/Destroy()
control_computer = null
return ..()
/obj/machinery/cryopod/proc/find_control_computer(urgent = FALSE)
for(var/cryo_console as anything in GLOB.cryopod_computers)
var/obj/machinery/computer/cryopod/console = cryo_console
if(get_area(console) == get_area(src))
control_computer = console
break
// Don't send messages unless we *need* the computer, and less than five minutes have passed since last time we messaged
if(!control_computer && urgent && COOLDOWN_FINISHED(src, last_no_computer_message))
COOLDOWN_START(src, last_no_computer_message, 5 MINUTES)
log_admin("Cryopod in [get_area(src)] could not find control computer!")
message_admins("Cryopod in [get_area(src)] could not find control computer!")
last_no_computer_message = world.time
return control_computer != null
/obj/machinery/cryopod/close_machine(mob/user)
if(!control_computer)
find_control_computer(TRUE)
if((isnull(user) || istype(user)) && state_open && !panel_open)
..(user)
var/mob/living/mob_occupant = occupant
if(mob_occupant && mob_occupant.stat != DEAD)
to_chat(occupant, "<span class='boldnotice'>You feel cool air surround you. You go numb as your senses turn inward.</span>")
if(mob_occupant.client || !mob_occupant.key) // Self cryos and SSD
despawn_world_time = world.time + (fast_despawn) // This gives them 30 seconds
else
despawn_world_time = world.time + time_till_despawn
icon_state = "cryopod"
/obj/machinery/cryopod/open_machine()
..()
icon_state = "cryopod-open"
density = TRUE
name = initial(name)
/obj/machinery/cryopod/container_resist_act(mob/living/user)
visible_message("<span class='notice'>[occupant] emerges from [src]!</span>",
"<span class='notice'>You climb out of [src]!</span>")
open_machine()
/obj/machinery/cryopod/relaymove(mob/user)
container_resist_act(user)
/obj/machinery/cryopod/process()
if(!occupant)
return
var/mob/living/mob_occupant = occupant
if(mob_occupant)
// Eject dead people
if(mob_occupant.stat == DEAD)
open_machine()
if(world.time <= despawn_world_time)
return
if(!mob_occupant.client && mob_occupant.stat <= SOFT_CRIT) // Occupant is living and has no client.
if(!control_computer)
find_control_computer(urgent = TRUE) // better hope you found it this time
despawn_occupant()
/obj/machinery/cryopod/proc/handle_objectives()
var/mob/living/mob_occupant = occupant
// Update any existing objectives involving this mob.
for(var/datum/objective/objective in GLOB.objectives)
// We don't want revs to get objectives that aren't for heads of staff. Letting
// them win or lose based on cryo is silly so we remove the objective.
if(istype(objective,/datum/objective/mutiny) && objective.target == mob_occupant.mind)
objective.team.objectives -= objective
qdel(objective)
for(var/datum/mind/mind in objective.team.members)
to_chat(mind.current, "<BR><span class='userdanger'>Your target is no longer within reach. Objective removed!</span>")
mind.announce_objectives()
else if(objective.target && istype(objective.target, /datum/mind))
if(objective.target == mob_occupant.mind)
var/old_target = objective.target
objective.target = null
if(!objective)
return
objective.find_target()
if(!objective.target && objective.owner)
to_chat(objective.owner.current, "<BR><span class='userdanger'>Your target is no longer within reach. Objective removed!</span>")
for(var/datum/antagonist/antag in objective.owner.antag_datums)
antag.objectives -= objective
if (!objective.team)
objective.update_explanation_text()
objective.owner.announce_objectives()
to_chat(objective.owner.current, "<BR><span class='userdanger'>You get the feeling your target is no longer within reach. Time for Plan [pick("A","B","C","D","X","Y","Z")]. Objectives updated!</span>")
else
var/list/objectivestoupdate
for(var/datum/mind/objective_owner in objective.get_owners())
to_chat(objective_owner.current, "<BR><span class='userdanger'>You get the feeling your target is no longer within reach. Time for Plan [pick("A","B","C","D","X","Y","Z")]. Objectives updated!</span>")
for(var/datum/objective/update_target_objective in objective_owner.get_all_objectives())
LAZYADD(objectivestoupdate, update_target_objective)
objectivestoupdate += objective.team.objectives
for(var/datum/objective/update_objective in objectivestoupdate)
if(update_objective.target != old_target || !istype(update_objective,objective.type))
continue
update_objective.target = objective.target
update_objective.update_explanation_text()
to_chat(objective.owner.current, "<BR><span class='userdanger'>You get the feeling your target is no longer within reach. Time for Plan [pick("A","B","C","D","X","Y","Z")]. Objectives updated!</span>")
update_objective.owner.announce_objectives()
qdel(objective)
/obj/machinery/cryopod/proc/should_preserve_item(obj/item/item)
for(var/datum/objective_item/steal/possible_item in GLOB.possible_items)
if(istype(item, possible_item.targetitem))
return TRUE
return FALSE
// This function can not be undone; do not call this unless you are sure
/obj/machinery/cryopod/proc/despawn_occupant()
var/mob/living/mob_occupant = occupant
var/list/crew_member = list()
crew_member["name"] = mob_occupant.real_name
if(mob_occupant.mind && mob_occupant.mind.assigned_role)
// Handle job slot/tater cleanup.
var/job = mob_occupant.mind.assigned_role
crew_member["job"] = job
SSjob.FreeRole(job)
if(LAZYLEN(mob_occupant.mind.objectives))
mob_occupant.mind.objectives.Cut()
mob_occupant.mind.special_role = null
//SKYRAT EDIT ADDITION
if(SSticker.mode.name == "assaultops")
if(is_assaultops_target(mob_occupant.mind))
remove_assaultops_target(mob_occupant.mind) //Remove them from the list of targets for the assops.
//SKYRAT EDIT END
else
crew_member["job"] = "N/A"
// Delete them from datacore.
var/announce_rank = null
for(var/datum/data/record/medical_record in GLOB.data_core.medical)
if(medical_record.fields["name"] == mob_occupant.real_name)
qdel(medical_record)
for(var/datum/data/record/security_record in GLOB.data_core.security)
if(security_record.fields["name"] == mob_occupant.real_name)
qdel(security_record)
for(var/datum/data/record/general_record in GLOB.data_core.general)
if(general_record.fields["name"] == mob_occupant.real_name)
announce_rank = general_record.fields["rank"]
qdel(general_record)
control_computer?.frozen_crew += list(crew_member)
// Make an announcement and log the person entering storage.
if(GLOB.announcement_systems.len)
var/obj/machinery/announcement_system/announcer = pick(GLOB.announcement_systems)
announcer.announce("CRYOSTORAGE", mob_occupant.real_name, announce_rank, list())
visible_message("<span class='notice'>[src] hums and hisses as it moves [mob_occupant.real_name] into storage.</span>")
for(var/obj/item/item in mob_occupant.GetAllContents())
if(item.loc.loc && (item.loc.loc == loc || item.loc.loc == control_computer))
continue // means we already moved whatever this thing was in
// I'm a professional, okay
if(!should_preserve_item(item))
continue
if(control_computer && control_computer.allow_items)
control_computer.frozen_items += item
mob_occupant.transferItemToLoc(item, control_computer, TRUE)
else
mob_occupant.transferItemToLoc(item, loc, TRUE)
var/list/contents = mob_occupant.GetAllContents()
QDEL_LIST(contents)
// Ghost and delete the mob.
if(!mob_occupant.get_ghost(TRUE))
if(world.time < 15 MINUTES) // before the 15 minute mark
mob_occupant.ghostize(FALSE) // Players despawned too early may not re-enter the game
else
mob_occupant.ghostize(TRUE)
handle_objectives()
QDEL_NULL(occupant)
open_machine()
name = initial(name)
/obj/machinery/cryopod/MouseDrop_T(mob/living/target, mob/user)
if(!istype(target) || !can_interact(user) || !target.Adjacent(user) || !ismob(target) || isanimal(target) || !istype(user.loc, /turf) || target.buckled)
return
if(occupant)
to_chat(user, "<span class='notice'>[src] is already occupied!</span>")
return
if(target.stat == DEAD)
to_chat(user, "<span class='notice'>Dead people can not be put into cryo.</span>")
return
if(target.client && user != target)
if(iscyborg(target))
to_chat(user, "<span class='danger'>You can't put [target] into [src]. [target.p_theyre(capitalized = TRUE)] online.</span>")
else
to_chat(user, "<span class='danger'>You can't put [target] into [src]. [target.p_theyre(capitalized = TRUE)] conscious.</span>")
return
else if(target.client)
if(alert(target,"Would you like to enter cryosleep?",,"Yes","No") == "No")
return
var/generic_plsnoleave_message = " Please adminhelp before leaving the round, even if there are no administrators online!"
if(target == user && COOLDOWN_FINISHED(target.client, cryo_warned))
var/caught = FALSE
var/datum/antagonist/antag = target.mind.has_antag_datum(/datum/antagonist)
var/datum/job/target_job = SSjob.GetJob(target.mind.assigned_role)
if(target_job.req_admin_notify)
alert("You're an important role![generic_plsnoleave_message]")
caught = TRUE
if(antag)
alert("You're \a [antag.name]![generic_plsnoleave_message]")
caught = TRUE
if(caught)
COOLDOWN_START(target.client, cryo_warned, 5 MINUTES)
return
if(!istype(target) || !can_interact(user) || !target.Adjacent(user) || !ismob(target) || isanimal(target) || !istype(user.loc, /turf) || target.buckled)
return
// rerun the checks in case of shenanigans
if(target == user)
visible_message("[user] starts climbing into the cryo pod.")
else
visible_message("[user] starts putting [target] into the cryo pod.")
if(occupant)
to_chat(user, "<span class='notice'>[src] is in use.</span>")
return
close_machine(target)
to_chat(target, "<span class='boldnotice'>If you ghost, log out or close your client now, your character will shortly be permanently removed from the round.</span>")
name = "[name] ([occupant.name])"
log_admin("[key_name(target)] entered a stasis pod.")
message_admins("[key_name_admin(target)] entered a stasis pod. [ADMIN_JMP(src)]")
add_fingerprint(target)
// Attacks/effects.
/obj/machinery/cryopod/blob_act()
return // Sorta gamey, but we don't really want these to be destroyed.
+31 -27
View File
@@ -283,23 +283,31 @@
/datum/team/cult/proc/ascend(cultist)
if(ishuman(cultist))
var/mob/living/carbon/human/H = cultist
new /obj/effect/temp_visual/cult/sparks(get_turf(H), H.dir)
var/mob/living/carbon/human/human = cultist
new /obj/effect/temp_visual/cult/sparks(get_turf(human), human.dir)
var/istate = pick("halo1","halo2","halo3","halo4","halo5","halo6")
var/mutable_appearance/new_halo_overlay = mutable_appearance('icons/effects/32x64.dmi', istate, -HALO_LAYER)
H.overlays_standing[HALO_LAYER] = new_halo_overlay
H.apply_overlay(HALO_LAYER)
human.overlays_standing[HALO_LAYER] = new_halo_overlay
human.apply_overlay(HALO_LAYER)
/datum/team/cult/proc/setup_objectives()
//SAC OBJECTIVE , todo: move this to objective internals
/datum/team/cult/proc/make_image(datum/objective/sacrifice/sac_objective)
var/datum/job/job_of_sacrifice = SSjob.GetJob(sac_objective.target.assigned_role)
var/datum/preferences/prefs_of_sacrifice = sac_objective.target.current.client.prefs
var/icon/reshape = get_flat_human_icon(null, job_of_sacrifice, prefs_of_sacrifice, list(SOUTH))
reshape.Shift(SOUTH, 4)
reshape.Shift(EAST, 1)
reshape.Crop(7,4,26,31)
reshape.Crop(-5,-3,26,30)
sac_objective.sac_image = reshape
/datum/objective/sacrifice/find_target(dupe_search_range)
if(!istype(team, /datum/team/cult))
return
var/datum/team/cult/cult = team
var/list/target_candidates = list()
var/datum/objective/sacrifice/sac_objective = new
sac_objective.team = src
for(var/mob/living/carbon/human/player in GLOB.player_list)
if(player.mind && !player.mind.has_antag_datum(/datum/antagonist/cult) && !is_convertable_to_cult(player) && player.stat != DEAD)
target_candidates += player.mind
if(target_candidates.len == 0)
message_admins("Cult Sacrifice: Could not find unconvertible target, checking for convertible target.")
for(var/mob/living/carbon/human/player in GLOB.player_list)
@@ -307,30 +315,26 @@
target_candidates += player.mind
listclearnulls(target_candidates)
if(LAZYLEN(target_candidates))
sac_objective.target = pick(target_candidates)
sac_objective.update_explanation_text()
var/datum/job/sacjob = SSjob.GetJob(sac_objective.target.assigned_role)
var/datum/preferences/sacface = sac_objective.target.current.client.prefs
var/icon/reshape = get_flat_human_icon(null, sacjob, sacface, list(SOUTH))
reshape.Shift(SOUTH, 4)
reshape.Shift(EAST, 1)
reshape.Crop(7,4,26,31)
reshape.Crop(-5,-3,26,30)
sac_objective.sac_image = reshape
objectives += sac_objective
target = pick(target_candidates)
update_explanation_text()
else
message_admins("Cult Sacrifice: Could not find unconvertible or convertible target. WELP!")
cult.make_image(src)
for(var/datum/mind/mind in cult.members)
if(mind.current)
mind.current.clear_alert("bloodsense")
mind.current.throw_alert("bloodsense", /atom/movable/screen/alert/bloodsense)
/datum/team/cult/proc/setup_objectives()
var/datum/objective/sacrifice/sacrifice_objective = new
sacrifice_objective.team = src
sacrifice_objective.find_target()
objectives += sacrifice_objective
//SUMMON OBJECTIVE
var/datum/objective/eldergod/summon_objective = new()
var/datum/objective/eldergod/summon_objective = new
summon_objective.team = src
objectives += summon_objective
/datum/objective/sacrifice
var/sacced = FALSE
var/sac_image
+2 -1
View File
@@ -30,7 +30,8 @@
var/total_count_reset = 0
///Internal counter for clients sending external (IRC/Discord) relay messages via ahelp to prevent spamming. Set to a number every time an admin reply is sent, decremented for every client send.
var/externalreplyamount = 0
///When was the last time we warned them about not cryoing without an ahelp, set to -5 minutes so that rounstart cryo still warns
COOLDOWN_DECLARE(cryo_warned)
/////////
//OTHER//
/////////
Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

@@ -1,493 +0,0 @@
/client
var/cryo_warned = 0
/*
* Cryogenic refrigeration unit. Basically a despawner.
* Stealing a lot of concepts/code from sleepers due to massive laziness.
* The despawn tick will only fire if it's been more than time_till_despawned ticks
* since time_entered, which is world.time when the occupant moves in.
* ~ Zuhayr
*/
//Main cryopod console.
/obj/machinery/computer/cryopod
name = "cryogenic oversight console"
desc = "An interface between crew and the cryogenic storage oversight systems."
icon = 'modular_skyrat/modules/cryosleep/icons/cryogenics.dmi'
icon_state = "cellconsole_1"
circuit = /obj/item/circuitboard/cryopodcontrol
density = FALSE
interaction_flags_machine = INTERACT_MACHINE_OFFLINE
req_one_access = list(ACCESS_HEADS, ACCESS_ARMORY) //Heads of staff or the warden can go here to claim recover items from their department that people went were cryodormed with.
var/menu = 1 //Which menu screen to display
//Used for logging people entering cryosleep and important items they are carrying.
var/list/frozen_crew = list()
var/list/frozen_items = list()
// Used for containing rare items traitors need to steal, so it's not
// game-over if they get iced
var/list/objective_items = list()
// A cache of theft datums so you don't have to re-create them for
// each item check
var/list/theft_cache = list()
var/allow_items = TRUE
/obj/machinery/computer/cryopod/attack_ai()
attack_hand()
/obj/machinery/computer/cryopod/ui_interact(mob/user = usr)
. = ..()
user.set_machine(src)
add_fingerprint(user)
var/dat = ""
dat += "<h2>Welcome, [user.real_name].</h2><hr/>"
dat += "<br><br>"
switch(src.menu)
if(1)
dat += "<a href='byond://?src=[REF(src)];menu=2'>View crew storage log</a><br><br>"
if(allow_items)
dat += "<a href='byond://?src=[REF(src)];menu=3'>View objects storage log</a><br><br>"
dat += "<a href='byond://?src=[REF(src)];item=1'>Recover object</a><br><br>"
dat += "<a href='byond://?src=[REF(src)];allitems=1'>Recover all objects</a><br>"
if(2)
dat += "<a href='byond://?src=[REF(src)];menu=1'><< Back</a><br><br>"
dat += "<h3>Recently stored Crew</h3><br/><hr/><br/>"
if(!frozen_crew.len)
dat += "There has been no storage usage at this terminal.<br/>"
else
for(var/person in frozen_crew)
dat += "[person]<br/>"
dat += "<hr/>"
if(3)
dat += "<a href='byond://?src=[REF(src)];menu=1'><< Back</a><br><br>"
dat += "<h3>Recently stored objects</h3><br/><hr/><br/>"
if(!frozen_items.len)
dat += "There has been no storage usage at this terminal.<br/>"
else
for(var/obj/item/I in frozen_items)
dat += "[I.name]<br/>"
dat += "<hr/>"
var/datum/browser/popup = new(user, "cryopod_console", "Cryogenic System Control")
popup.set_content(dat)
popup.open()
/obj/machinery/computer/cryopod/Topic(href, href_list)
if(..())
return TRUE
var/mob/user = usr
add_fingerprint(user)
if(href_list["item"])
if(!allowed(user))
to_chat(user, "<span class='warning'>Access Denied.</span>")
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
updateUsrDialog()
return
if(!allow_items) return
if(frozen_items.len == 0)
to_chat(user, "<span class='notice'>There is nothing to recover from storage.</span>")
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
updateUsrDialog()
return
var/obj/item/I = input(user, "Please choose which object to retrieve.","Object recovery",null) as null|anything in frozen_items
playsound(src, "terminal_type", 25, 0)
if(!I)
return
if(!(I in frozen_items))
to_chat(user, "<span class='notice'>\The [I] is no longer in storage.</span>")
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
updateUsrDialog()
return
visible_message("<span class='notice'>The console beeps happily as it disgorges \the [I].</span>")
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
I.forceMove(drop_location())
if(user && Adjacent(user) && user.can_hold_items())
user.put_in_hands(I)
frozen_items -= I
updateUsrDialog()
else if(href_list["allitems"])
playsound(src, "terminal_type", 25, 0)
if(!allowed(user))
to_chat(user, "<span class='warning'>Access Denied.</span>")
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
updateUsrDialog()
return
if(!allow_items)
return
if(frozen_items.len == 0)
to_chat(user, "<span class='notice'>There is nothing to recover from storage.</span>")
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
visible_message("<span class='notice'>The console beeps happily as it disgorges the desired objects.</span>")
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
for(var/obj/item/I in frozen_items)
I.forceMove(drop_location())
frozen_items -= I
updateUsrDialog()
else if (href_list["menu"])
src.menu = text2num(href_list["menu"])
playsound(src, "terminal_type", 25, 0)
updateUsrDialog()
ui_interact(usr)
updateUsrDialog()
return
/obj/item/circuitboard/cryopodcontrol
name = "Circuit board (Cryogenic Oversight Console)"
build_path = "/obj/machinery/computer/cryopod"
/obj/machinery/computer/cryopod/contents_explosion()
return
//Cryopods themselves.
/obj/machinery/cryopod
name = "cryogenic freezer"
desc = "Suited for Cyborgs and Humanoids, the pod is a safe place for personnel affected by the Space Sleep Disorder to get some rest."
icon = 'modular_skyrat/modules/cryosleep/icons/cryogenics.dmi'
icon_state = "cryopod-open"
density = TRUE
anchored = TRUE
state_open = TRUE
var/on_store_message = "has entered long-term storage."
var/on_store_name = "Cryogenic Oversight"
// 15 minutes-ish safe period before being despawned.
var/time_till_despawn = 15 * 600 // This is reduced by 90% if a player manually enters cryo
var/despawn_world_time // Used to keep track of the safe period.
var/obj/machinery/computer/cryopod/control_computer
var/last_no_computer_message = 0
// These items are preserved when the process() despawn proc occurs.
var/static/list/preserve_items = typecacheof(list(
/obj/item/hand_tele,
/obj/item/card/id/advanced/gold/captains_spare,
/obj/item/aicard,
/obj/item/mmi,
/obj/item/paicard,
/obj/item/gun,
/obj/item/pinpointer,
/obj/item/clothing/shoes/magboots,
/obj/item/areaeditor/blueprints,
/obj/item/clothing/head/helmet/space,
/obj/item/clothing/suit/space,
/obj/item/clothing/suit/armor,
/obj/item/defibrillator/compact,
/obj/item/reagent_containers/hypospray/cmo,
/obj/item/clothing/accessory/medal/gold/captain,
/obj/item/clothing/gloves/krav_maga,
/obj/item/nullrod,
/obj/item/tank/jetpack,
/obj/item/documents,
/obj/item/nuke_core_container
))
// These items will NOT be preserved
var/static/list/do_not_preserve_items = typecacheof(list(
/obj/item/mmi/posibrain,
/obj/item/gun/energy/laser/mounted,
/obj/item/gun/energy/e_gun/advtaser/mounted,
/obj/item/gun/ballistic/revolver/grenadelauncher/cyborg,
/obj/item/gun/energy/disabler/cyborg,
/obj/item/gun/energy/e_gun/advtaser/cyborg,
/obj/item/gun/energy/printer,
/obj/item/gun/energy/kinetic_accelerator/cyborg,
/obj/item/gun/energy/laser/cyborg
))
/obj/machinery/cryopod/Initialize(mapload)
. = ..()
update_icon()
find_control_computer(mapload)
/obj/machinery/cryopod/proc/find_control_computer(urgent = FALSE)
for(var/obj/machinery/computer/cryopod/C in get_area(src))
control_computer = C
if(C)
return C
break
// Don't send messages unless we *need* the computer, and less than five minutes have passed since last time we messaged
if(!control_computer && urgent && last_no_computer_message + 5*60*10 < world.time)
log_admin("Cryopod in [get_area(src)] could not find control computer!")
message_admins("Cryopod in [get_area(src)] could not find control computer!")
last_no_computer_message = world.time
return control_computer != null
/obj/machinery/cryopod/close_machine(mob/user)
if(!control_computer)
find_control_computer(TRUE)
if((isnull(user) || istype(user)) && state_open && !panel_open)
START_PROCESSING(SSmachines, src)
..(user)
var/mob/living/mob_occupant = occupant
if(mob_occupant && mob_occupant.stat != DEAD)
to_chat(occupant, "<span class='boldnotice'>You feel cool air surround you. You go numb as your senses turn inward.</span>")
if(mob_occupant.client)//if they're logged in
despawn_world_time = world.time + (time_till_despawn * 0.1)
else
despawn_world_time = world.time + time_till_despawn
icon_state = "cryopod"
/obj/machinery/cryopod/open_machine()
..()
STOP_PROCESSING(SSmachines, src)
icon_state = "cryopod-open"
density = TRUE
name = initial(name)
/obj/machinery/cryopod/container_resist_act(mob/living/user)
visible_message("<span class='notice'>[occupant] emerges from [src]!</span>",
"<span class='notice'>You climb out of [src]!</span>")
open_machine()
/obj/machinery/cryopod/relaymove(mob/user)
container_resist_act(user)
/obj/machinery/cryopod/process()
if(!occupant)
return
var/mob/living/mob_occupant = occupant
if(mob_occupant)
// Eject dead people
if(mob_occupant.stat == DEAD)
open_machine()
if(!(world.time > despawn_world_time + 100))//+ 10 seconds
return
if(!mob_occupant.client && mob_occupant.stat < 2) //Occupant is living and has no client.
if(!control_computer)
find_control_computer(urgent = TRUE)//better hope you found it this time
despawn_occupant()
#define CRYO_DESTROY 0
#define CRYO_PRESERVE 1
#define CRYO_OBJECTIVE 2
#define CRYO_IGNORE 3
#define CRYO_DESTROY_LATER 4
/obj/machinery/cryopod/proc/should_preserve_item(obj/item/I)
for(var/datum/objective_item/steal/T in control_computer.theft_cache)
if(istype(I, T.targetitem) && T.check_special_completion(I))
return CRYO_OBJECTIVE
if(preserve_items[I] && !do_not_preserve_items[I])
return CRYO_PRESERVE
return CRYO_DESTROY
// This function can not be undone; do not call this unless you are sure
/obj/machinery/cryopod/proc/despawn_occupant()
if(!control_computer)
find_control_computer()
var/mob/living/mob_occupant = occupant
var/list/obj/item/cryo_items = list()
//Handle Borg stuff first
if(iscyborg(mob_occupant))
var/mob/living/silicon/robot/R = mob_occupant
if(R.mmi?.brain)
cryo_items[R.mmi] = CRYO_DESTROY_LATER
cryo_items[R.mmi.brain] = CRYO_DESTROY_LATER
for(var/obj/item/I in R.model) // the tools the borg has; metal, glass, guns etc
for(var/obj/item/O in I) // the things inside the tools, if anything; mainly for janiborg trash bags
cryo_items[O] = should_preserve_item(O)
O.forceMove(src)
R.model.remove_module(I, TRUE) //delete the module itself so it doesn't transfer over.
//Drop all items into the pod.
for(var/obj/item/I in mob_occupant)
if(cryo_items[I] == CRYO_IGNORE || cryo_items[I] ==CRYO_DESTROY_LATER)
continue
cryo_items[I] = should_preserve_item(I)
mob_occupant.transferItemToLoc(I, src, TRUE)
if(I.contents.len) //Make sure we catch anything not handled by qdel() on the items.
if(cryo_items[I] != CRYO_DESTROY) // Don't remove the contents of things that need preservation
continue
for(var/obj/item/O in I.contents)
cryo_items[O] = should_preserve_item(O)
O.forceMove(src)
for(var/A in cryo_items)
var/obj/item/I = A
if(QDELETED(I)) //edge cases and DROPDEL.
continue
var/preserve = cryo_items[I]
if(preserve == CRYO_DESTROY_LATER)
continue
if(preserve != CRYO_IGNORE)
if(preserve == CRYO_DESTROY)
qdel(I)
else if(control_computer?.allow_items)
control_computer.frozen_items += I
if(preserve == CRYO_OBJECTIVE)
control_computer.objective_items += I
I.moveToNullspace()
else
I.forceMove(loc)
cryo_items -= I
/*
//Update any existing objectives involving this mob.
for(var/datum/objective/O in GLOB.objectives)
// We don't want revs to get objectives that aren't for heads of staff. Letting
// them win or lose based on cryo is silly so we remove the objective.
if(istype(O,/datum/objective/mutiny) && O.target == mob_occupant.mind)
qdel(O)
else if(O.target && istype(O.target, /datum/mind))
if(O.target == mob_occupant.mind)
if(O.owner && O.owner.current)
to_chat(O.owner.current, "<BR><span class='userdanger'>You get the feeling your target is no longer within reach. Time for Plan [pick("A","B","C","D","X","Y","Z")]. Objectives updated!</span>")
O.target = null
spawn(10) //This should ideally fire after the occupant is deleted.
if(!O)
return
O.find_target()
O.update_explanation_text()
if(!(O.target))
qdel(O)*/
if(mob_occupant.mind)
//Handle job slot/tater cleanup.
if(mob_occupant.mind.assigned_role)
SSjob.FreeRole(mob_occupant.mind.assigned_role)
mob_occupant.mind.special_role = null
if(SSticker.mode.name == "assaultops")
if(is_assaultops_target(mob_occupant.mind))
remove_assaultops_target(mob_occupant.mind) //Remove them from the list of targets for the assops.
// Delete them from datacore.
var/announce_rank = null
for(var/datum/data/record/R in GLOB.data_core.medical)
if((R.fields["name"] == mob_occupant.real_name))
qdel(R)
break
for(var/datum/data/record/T in GLOB.data_core.security)
if((T.fields["name"] == mob_occupant.real_name))
qdel(T)
break
for(var/datum/data/record/G in GLOB.data_core.general)
if((G.fields["name"] == mob_occupant.real_name))
announce_rank = G.fields["rank"]
qdel(G)
break
//Make an announcement and log the person entering storage.
if(control_computer)
control_computer.frozen_crew += "[mob_occupant.real_name]"
if(GLOB.announcement_systems.len)
var/obj/machinery/announcement_system/announcer = pick(GLOB.announcement_systems)
announcer.announce("CRYOSTORAGE", mob_occupant.real_name, announce_rank, list())
visible_message("<span class='notice'>\The [src] hums and hisses as it moves [mob_occupant.real_name] into storage.</span>")
// Ghost and delete the mob.
if(!mob_occupant.get_ghost(TRUE))
mob_occupant.ghostize(FALSE)
QDEL_NULL(occupant)
for(var/I in cryo_items) //only "CRYO_DESTROY_LATER" atoms are left)
var/atom/A = I
if(!QDELETED(A))
qdel(A)
open_machine()
name = initial(name)
#undef CRYO_DESTROY
#undef CRYO_PRESERVE
#undef CRYO_OBJECTIVE
#undef CRYO_IGNORE
#undef CRYO_DESTROY_LATER
/obj/machinery/cryopod/MouseDrop_T(mob/living/target, mob/user)
if(!istype(target) || user.incapacitated() || !target.Adjacent(user) || !Adjacent(user) || !ismob(target) || (!ishuman(user) && !iscyborg(user)) || !istype(user.loc, /turf) || target.buckled)
return
if(occupant)
to_chat(user, "<span class='warning'>The cryo pod is already occupied!</span>")
return
if(target.stat == DEAD)
to_chat(user, "<span class='notice'>Dead people can not be put into cryo.</span>")
return
if(target.client && user != target)
if(iscyborg(target))
to_chat(user, "<span class='danger'>You can't put [target] into [src]. They're online.</span>")
else
to_chat(user, "<span class='danger'>You can't put [target] into [src]. They're conscious.</span>")
return
else if(target.client)
if(alert(target,"Would you like to enter cryosleep?",,"Yes","No") == "No")
return
if (user != target && round(((world.time - target.lastclienttime) / (1 MINUTES)),1) <= CONFIG_GET(number/cryo_min_ssd_time))
to_chat(user, "<span class='danger'>You can't put [target] into [src]. They might wake up soon.</span>")
return
var/generic_plsnoleave_message = " Please adminhelp before leaving the round, even if there are no administrators online!"
if(target == user && world.time - target.client.cryo_warned > 5 MINUTES)//if we haven't warned them in the last 5 minutes
var/list/caught_string
var/addendum = ""
if(target.mind.assigned_role in GLOB.command_positions)
LAZYADD(caught_string, "Head of Staff")
addendum = " Be sure to put your locker items back into your locker!"
if(iscultist(target))
LAZYADD(caught_string, "Cultist")
if(target.mind.has_antag_datum(/datum/antagonist/gang))
LAZYADD(caught_string, "Gangster")
if(target.mind.has_antag_datum(/datum/antagonist/rev/head))
LAZYADD(caught_string, "Head Revolutionary")
if(target.mind.has_antag_datum(/datum/antagonist/rev))
LAZYADD(caught_string, "Revolutionary")
if(caught_string)
alert(target, "You're a [english_list(caught_string)]![generic_plsnoleave_message][addendum]")
target.client.cryo_warned = world.time
return
if(!target || user.incapacitated() || !target.Adjacent(user) || !Adjacent(user) || (!ishuman(user) && !iscyborg(user)) || !istype(user.loc, /turf) || target.buckled)
return
//rerun the checks in case of shenanigans
if(occupant)
to_chat(user, "<span class='warning'>\The [src] is in use.</span>")
return
if(target == user)
visible_message("<span class='notice'>[user] starts climbing into the cryo pod.</span>")
else
visible_message("<span class='notice'>[user] starts putting [target] into the cryo pod.</span>")
if(do_after(user, 3 SECONDS, target = target))
if(occupant)
return
close_machine(target)
to_chat(target, "<span class='boldnotice'>If you ghost, log out or close your client now, your character will shortly be permanently removed from the round.</span>")
name = "[name] ([occupant.name])"
if(target == user)
log_admin("<span class='notice'>[key_name(target)] entered a stasis pod.</span>")
message_admins("[key_name_admin(target)] entered a stasis pod. (<A HREF='?_src_=holder;[HrefToken()];adminplayerobservecoodjump=1;X=[x];Y=[y];Z=[z]'>JMP</a>)")
else
log_admin("<span class='notice'>[key_name(user)] put [key_name(target)] inside a stasis pod.</span>")
message_admins("[key_name_admin(user)] put [key_name_admin(target)] inside a stasis pod. (<A HREF='?_src_=holder;[HrefToken()];adminplayerobservecoodjump=1;X=[x];Y=[y];Z=[z]'>JMP</a>)")
add_fingerprint(target)
//Attacks/effects.
/obj/machinery/cryopod/blob_act()
return //Sorta gamey, but we don't really want these to be destroyed.
@@ -1,7 +0,0 @@
/datum/controller/subsystem/job/proc/FreeRole(rank)
if(!rank)
return
var/datum/job/job = GetJob(rank)
if(!job)
return FALSE
job.current_positions = max(0, job.current_positions - 1)
+1 -2
View File
@@ -929,6 +929,7 @@
#include "code\game\machinery\cell_charger.dm"
#include "code\game\machinery\civilian_bounties.dm"
#include "code\game\machinery\constructable_frame.dm"
#include "code\game\machinery\cryopod.dm"
#include "code\game\machinery\dance_machine.dm"
#include "code\game\machinery\defibrillator_mount.dm"
#include "code\game\machinery\deployable.dm"
@@ -3747,8 +3748,6 @@
#include "modular_skyrat\modules\cryosleep\code\ai.dm"
#include "modular_skyrat\modules\cryosleep\code\area.dm"
#include "modular_skyrat\modules\cryosleep\code\config.dm"
#include "modular_skyrat\modules\cryosleep\code\cryopod.dm"
#include "modular_skyrat\modules\cryosleep\code\job.dm"
#include "modular_skyrat\modules\cum\jerkoff_verb.dm"
#include "modular_skyrat\modules\cum\seaofmen_keg.dm"
#include "modular_skyrat\modules\cum\chemistry\reagents\cum_reagent.dm"
@@ -0,0 +1,95 @@
import { useBackend } from '../backend';
import { Stack, Button, Section, NoticeBox, LabeledList, Collapsible } from '../components';
import { Window } from '../layouts';
export const CryopodConsole = (props, context) => {
const { data } = useBackend(context);
const { account_name, allow_items } = data;
const welcomeTitle = `Hello, ${account_name || '[REDACTED]'}!`;
return (
<Window title="Cryopod Console" width={400} height={480}>
<Window.Content>
<Stack vertical>
<Section title={welcomeTitle}>
This automated cryogenic freezing unit will safely store your
corporeal form until your next assignment.
</Section>
<CrewList />
{!!allow_items && <ItemList />}
</Stack>
</Window.Content>
</Window>
);
};
const CrewList = (props, context) => {
const { data } = useBackend(context);
const { frozen_crew } = data;
return (
<Collapsible title="Stored Crew">
{!frozen_crew.length ? (
<NoticeBox>No stored crew!</NoticeBox>
) : (
<Section height={10} fill scrollable>
<LabeledList>
{frozen_crew.map((person) => (
<LabeledList.Item key={person} label={person.name}>
{person.job}
</LabeledList.Item>
))}
</LabeledList>
</Section>
)}
</Collapsible>
);
};
const ItemList = (props, context) => {
const { act, data } = useBackend(context);
const { frozen_items } = data;
const replaceItemName = (item) => {
let itemName = item.toString();
if (itemName.startsWith('the')) {
itemName = itemName.slice(4, itemName.length);
}
return itemName.replace(/^\w/, (c) => c.toUpperCase());
};
return (
<Collapsible title="Stored Items">
{!frozen_items.length ? (
<NoticeBox>No stored items!</NoticeBox>
) : (
<>
<Section height={12} fill scrollable>
<LabeledList>
{frozen_items.map((item, index) => (
<LabeledList.Item
key={item}
label={replaceItemName(item)}
buttons={
<Button
icon="arrow-down"
content="Drop"
mr={1}
onClick={() => act('one_item', { item: index + 1 })}
/>
}
/>
))}
</LabeledList>
</Section>
<Button
content="Drop All Items"
color="red"
onClick={() => act('all_items')}
/>
</>
)}
</Collapsible>
);
};