frontend
This commit is contained in:
@@ -48,8 +48,17 @@
|
||||
continue
|
||||
var/atom/movable/thing = i
|
||||
thing.Crossed(src)
|
||||
//
|
||||
////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* meant for movement with zero side effects. only use for objects that are supposed to move "invisibly" (like camera mobs or ghosts)
|
||||
* if you want something to move onto a tile with a beartrap or recycler or tripmine or mouse without that object knowing about it at all, use this
|
||||
* most of the time you want forceMove()
|
||||
*/
|
||||
/atom/movable/proc/abstract_move(atom/new_loc)
|
||||
var/atom/old_loc = loc
|
||||
// move_stacks++
|
||||
loc = new_loc
|
||||
Moved(old_loc)
|
||||
|
||||
/atom/movable/Move(atom/newloc, direct, glide_size_override = 0)
|
||||
var/atom/movable/pullee = pulling
|
||||
|
||||
@@ -193,7 +193,9 @@ GLOBAL_LIST_INIT(reverseradiochannels, list(
|
||||
var/frequency = 0
|
||||
var/transmission_method
|
||||
var/list/data
|
||||
var/logging_data
|
||||
|
||||
/datum/signal/New(data, transmission_method = TRANSMISSION_RADIO)
|
||||
/datum/signal/New(data, transmission_method = TRANSMISSION_RADIO, logging_data = null)
|
||||
src.data = data || list()
|
||||
src.transmission_method = transmission_method
|
||||
src.logging_data = logging_data
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
/obj/machinery/computer/communications/Initialize()
|
||||
. = ..()
|
||||
GLOB.shuttle_caller_list += src
|
||||
AddComponent(/datum/component/gps, "Secured Communications Signal")
|
||||
|
||||
/// Are we NOT a silicon, AND we're logged in as the captain?
|
||||
/obj/machinery/computer/communications/proc/authenticated_as_non_silicon_captain(mob/user)
|
||||
@@ -79,13 +80,11 @@
|
||||
if (obj_flags & EMAGGED)
|
||||
return
|
||||
obj_flags |= EMAGGED
|
||||
SSshuttle.shuttle_purchase_requirements_met |= "emagged"
|
||||
if (authenticated)
|
||||
authorize_access = get_all_accesses()
|
||||
to_chat(user, "<span class='danger'>You scramble the communication routing circuits!</span>")
|
||||
to_chat(user, span_danger("You scramble the communication routing circuits!"))
|
||||
playsound(src, 'sound/machines/terminal_alert.ogg', 50, FALSE)
|
||||
SSshuttle.shuttle_purchase_requirements_met["emagged"] = TRUE
|
||||
return
|
||||
|
||||
/obj/machinery/computer/communications/ui_act(action, list/params)
|
||||
var/static/list/approved_states = list(STATE_BUYING_SHUTTLE, STATE_CHANGING_STATUS, STATE_MAIN, STATE_MESSAGES)
|
||||
@@ -104,6 +103,7 @@
|
||||
if ("answerMessage")
|
||||
if (!authenticated(usr))
|
||||
return
|
||||
|
||||
var/answer_index = params["answer"]
|
||||
var/message_index = params["message"]
|
||||
|
||||
@@ -136,11 +136,11 @@
|
||||
var/obj/item/held_item = usr.get_active_held_item()
|
||||
var/obj/item/card/id/id_card = held_item?.GetID()
|
||||
if (!istype(id_card))
|
||||
to_chat(usr, "<span class='warning'>You need to swipe your ID!</span>")
|
||||
to_chat(usr, span_warning("You need to swipe your ID!"))
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, FALSE)
|
||||
return
|
||||
if (!(ACCESS_CAPTAIN in id_card.access))
|
||||
to_chat(usr, "<span class='warning'>You are not authorized to do this!</span>")
|
||||
to_chat(usr, span_warning("You are not authorized to do this!"))
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, FALSE)
|
||||
return
|
||||
|
||||
@@ -152,26 +152,28 @@
|
||||
|
||||
set_security_level(new_sec_level)
|
||||
|
||||
to_chat(usr, "<span class='notice'>Authorization confirmed. Modifying security level.</span>")
|
||||
to_chat(usr, span_notice("Authorization confirmed. Modifying security level."))
|
||||
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE)
|
||||
|
||||
// Only notify people if an actual change happened
|
||||
log_game("[key_name(usr)] has changed the security level to [params["newSecurityLevel"]] with [src] at [AREACOORD(usr)].")
|
||||
message_admins("[ADMIN_LOOKUPFLW(usr)] has changed the security level to [params["newSecurityLevel"]] with [src] at [AREACOORD(usr)].")
|
||||
deadchat_broadcast(" has changed the security level to [params["newSecurityLevel"]] with [src] at <span class='name'>[get_area_name(usr, TRUE)]</span>.", "<span class='name'>[usr.real_name]</span>", usr)
|
||||
deadchat_broadcast(" has changed the security level to [params["newSecurityLevel"]] with [src] at [span_name("[get_area_name(usr, TRUE)]")].", usr, src.loc, message_type=DEADCHAT_ANNOUNCEMENT)
|
||||
|
||||
alert_level_tick += 1
|
||||
if ("deleteMessage")
|
||||
if (!authenticated(usr))
|
||||
return
|
||||
var/message_index = params["message"]
|
||||
|
||||
if(!isnum(message_index))
|
||||
message_admins("[ADMIN_LOOKUPFLW(usr)] provided an invalid index type when deleting a message on [src] [ADMIN_JMP(src)]. This should not happen. Please check with a maintainer and/or consult tgui logs.")
|
||||
CRASH("Non-numeric index provided when deleting comms console message.")
|
||||
var/message_index = text2num(params["message"])
|
||||
if (!message_index)
|
||||
return
|
||||
LAZYREMOVE(messages, LAZYACCESS(messages, message_index))
|
||||
if ("emergency_meeting")
|
||||
if(!(SSevents.holidays && SSevents.holidays[APRIL_FOOLS]))
|
||||
return
|
||||
if (!authenticated_as_silicon_or_captain(usr))
|
||||
return
|
||||
// emergency_meeting(usr)
|
||||
if ("makePriorityAnnouncement")
|
||||
if (!authenticated_as_silicon_or_captain(usr))
|
||||
return
|
||||
@@ -188,32 +190,36 @@
|
||||
var/emagged = obj_flags & EMAGGED
|
||||
if (emagged)
|
||||
message_syndicate(message, usr)
|
||||
to_chat(usr, "<span class='danger'>SYSERR @l(19833)of(transmit.dm): !@$ MESSAGE TRANSMITTED TO SYNDICATE COMMAND.</span>")
|
||||
to_chat(usr, span_danger("SYSERR @l(19833)of(transmit.dm): !@$ MESSAGE TRANSMITTED TO SYNDICATE COMMAND."))
|
||||
else
|
||||
message_centcom(message, usr)
|
||||
to_chat(usr, "<span class='notice'>Message transmitted to Central Command.</span>")
|
||||
to_chat(usr, span_notice("Message transmitted to Central Command."))
|
||||
|
||||
var/associates = emagged ? "the Syndicate": "CentCom"
|
||||
usr.log_talk(message, LOG_SAY, tag = "message to [associates]")
|
||||
deadchat_broadcast(" has messaged [associates], \"[message]\" at <span class='name'>[get_area_name(usr, TRUE)]</span>.", "<span class='name'>[usr.real_name]</span>", usr)
|
||||
deadchat_broadcast(" has messaged [associates], \"[message]\" at [span_name("[get_area_name(usr, TRUE)]")].", usr, src.loc, message_type = DEADCHAT_ANNOUNCEMENT)
|
||||
COOLDOWN_START(src, important_action_cooldown, IMPORTANT_ACTION_COOLDOWN)
|
||||
if ("purchaseShuttle")
|
||||
var/can_buy_shuttles_or_fail_reason = can_buy_shuttles(usr)
|
||||
if (can_buy_shuttles_or_fail_reason != TRUE)
|
||||
if (can_buy_shuttles_or_fail_reason != FALSE)
|
||||
to_chat(usr, "<span class='alert'>[can_buy_shuttles_or_fail_reason]</span>")
|
||||
to_chat(usr, span_alert("[can_buy_shuttles_or_fail_reason]"))
|
||||
return
|
||||
var/list/shuttles = flatten_list(SSmapping.shuttle_templates)
|
||||
var/datum/map_template/shuttle/shuttle = locate(params["shuttle"]) in shuttles
|
||||
if (!istype(shuttle))
|
||||
return
|
||||
// if (!can_purchase_this_shuttle(shuttle))
|
||||
// return
|
||||
if (!shuttle.prerequisites_met())
|
||||
to_chat(usr, "<span class='alert'>You have not met the requirements for purchasing this shuttle.</span>")
|
||||
to_chat(usr, span_alert("You have not met the requirements for purchasing this shuttle."))
|
||||
return
|
||||
var/datum/bank_account/bank_account = SSeconomy.get_dep_account(ACCOUNT_CAR)
|
||||
if (bank_account.account_balance < shuttle.credit_cost)
|
||||
return
|
||||
SSshuttle.shuttle_purchased = SHUTTLEPURCHASE_PURCHASED
|
||||
// for(var/datum/round_event_control/shuttle_insurance/insurance_event in SSevents.control)
|
||||
// insurance_event.weight *= 20
|
||||
SSshuttle.unload_preview()
|
||||
SSshuttle.existing_shuttle = SSshuttle.emergency
|
||||
SSshuttle.action_load(shuttle, replace = TRUE)
|
||||
@@ -235,7 +241,7 @@
|
||||
return
|
||||
var/reason = trim(html_encode(params["reason"]), MAX_MESSAGE_LEN)
|
||||
nuke_request(reason, usr)
|
||||
to_chat(usr, "<span class='notice'>Request sent.</span>")
|
||||
to_chat(usr, span_notice("Request sent."))
|
||||
usr.log_message("has requested the nuclear codes from CentCom with reason \"[reason]\"", LOG_SAY)
|
||||
priority_announce("The codes for the on-station nuclear self-destruct have been requested by [usr]. Confirmation or denial of this request will be sent shortly.", "Nuclear Self-Destruct Codes Requested", "commandreport")
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, FALSE)
|
||||
@@ -245,7 +251,7 @@
|
||||
return
|
||||
if (!(obj_flags & EMAGGED))
|
||||
return
|
||||
to_chat(usr, "<span class='notice'>Backup routing data restored.</span>")
|
||||
to_chat(usr, span_notice("Backup routing data restored."))
|
||||
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE)
|
||||
obj_flags &= ~EMAGGED
|
||||
if ("sendToOtherSector")
|
||||
@@ -256,7 +262,7 @@
|
||||
if (!COOLDOWN_FINISHED(src, important_action_cooldown))
|
||||
return
|
||||
|
||||
var/message = trim(html_encode(params["message"]), MAX_MESSAGE_LEN)
|
||||
var/message = trim(params["message"], MAX_MESSAGE_LEN)
|
||||
if (!message)
|
||||
return
|
||||
|
||||
@@ -268,12 +274,13 @@
|
||||
var/network_name = CONFIG_GET(string/cross_comms_network)
|
||||
if (network_name)
|
||||
payload["network"] = network_name
|
||||
payload["sender_ckey"] = usr.ckey
|
||||
|
||||
send2otherserver(station_name(), message, "Comms_Console", destination == "all" ? null : list(destination), additional_data = payload)
|
||||
send2otherserver(html_decode(station_name()), message, "Comms_Console", destination == "all" ? null : list(destination), additional_data = payload)
|
||||
minor_announce(message, title = "Outgoing message to allied station")
|
||||
usr.log_talk(message, LOG_SAY, tag = "message to the other server")
|
||||
message_admins("[ADMIN_LOOKUPFLW(usr)] has sent a message to the other server\[s].")
|
||||
deadchat_broadcast(" has sent an outgoing message to the other station(s).</span>", "<span class='bold'>[usr.real_name]", usr)
|
||||
deadchat_broadcast(" has sent an outgoing message to the other station(s).</span>", usr, src.loc, message_type = DEADCHAT_ANNOUNCEMENT)
|
||||
|
||||
COOLDOWN_START(src, important_action_cooldown, IMPORTANT_ACTION_COOLDOWN)
|
||||
if ("setState")
|
||||
@@ -315,7 +322,7 @@
|
||||
authenticated = TRUE
|
||||
authorize_access = get_all_accesses()
|
||||
authorize_name = "Unknown"
|
||||
to_chat(usr, "<span class='warning'>[src] lets out a quiet alarm as its login is overridden.</span>")
|
||||
to_chat(usr, span_warning("[src] lets out a quiet alarm as its login is overridden."))
|
||||
playsound(src, 'sound/machines/terminal_alert.ogg', 25, FALSE)
|
||||
else if(isliving(usr))
|
||||
var/mob/living/L = usr
|
||||
@@ -334,22 +341,36 @@
|
||||
revoke_maint_all_access()
|
||||
log_game("[key_name(usr)] disabled emergency maintenance access.")
|
||||
message_admins("[ADMIN_LOOKUPFLW(usr)] disabled emergency maintenance access.")
|
||||
deadchat_broadcast(" disabled emergency maintenance access at <span class='name'>[get_area_name(usr, TRUE)]</span>.", "<span class='name'>[usr.real_name]</span>", usr)
|
||||
deadchat_broadcast(" disabled emergency maintenance access at [span_name("[get_area_name(usr, TRUE)]")].", usr, src.loc, message_type = DEADCHAT_ANNOUNCEMENT)
|
||||
else
|
||||
make_maint_all_access()
|
||||
log_game("[key_name(usr)] enabled emergency maintenance access.")
|
||||
message_admins("[ADMIN_LOOKUPFLW(usr)] enabled emergency maintenance access.")
|
||||
deadchat_broadcast(" enabled emergency maintenance access at <span class='name'>[get_area_name(usr, TRUE)]</span>.", "<span class='name'>[usr.real_name]</span>", usr)
|
||||
deadchat_broadcast(" enabled emergency maintenance access at [span_name("[get_area_name(usr, TRUE)]")].", usr, src.loc, message_type = DEADCHAT_ANNOUNCEMENT)
|
||||
|
||||
/obj/machinery/computer/communications/ui_data(mob/user)
|
||||
var/list/data = list(
|
||||
"authenticated" = FALSE,
|
||||
"emagged" = FALSE,
|
||||
"hasConnection" = has_communication(),
|
||||
)
|
||||
|
||||
var/ui_state = issilicon(user) ? cyborg_state : state
|
||||
|
||||
var/has_connection = has_communication()
|
||||
data["hasConnection"] = has_connection
|
||||
|
||||
// if(!SSjob.assigned_captain && !SSjob.safe_code_requested && SSid_access.spare_id_safe_code && has_connection)
|
||||
// data["canRequestSafeCode"] = TRUE
|
||||
// data["safeCodeDeliveryWait"] = 0
|
||||
// else
|
||||
// data["canRequestSafeCode"] = FALSE
|
||||
// if(SSjob.safe_code_timer_id && has_connection)
|
||||
// data["safeCodeDeliveryWait"] = timeleft(SSjob.safe_code_timer_id)
|
||||
// data["safeCodeDeliveryArea"] = get_area(SSjob.safe_code_request_loc)
|
||||
// else
|
||||
// data["safeCodeDeliveryWait"] = 0
|
||||
// data["safeCodeDeliveryArea"] = null
|
||||
|
||||
if (authenticated || issilicon(user))
|
||||
data["authenticated"] = TRUE
|
||||
data["canLogOut"] = !issilicon(user)
|
||||
@@ -371,16 +392,17 @@
|
||||
data["importantActionReady"] = COOLDOWN_FINISHED(src, important_action_cooldown)
|
||||
data["shuttleCalled"] = FALSE
|
||||
data["shuttleLastCalled"] = FALSE
|
||||
|
||||
data["aprilFools"] = SSevents.holidays && SSevents.holidays[APRIL_FOOLS]
|
||||
data["alertLevel"] = NUM2SECLEVEL(GLOB.security_level)
|
||||
data["authorizeName"] = authorize_name
|
||||
data["canLogOut"] = !issilicon(user)
|
||||
data["shuttleCanEvacOrFailReason"] = SSshuttle.canEvac(user, TRUE)
|
||||
data["shuttleCanEvacOrFailReason"] = SSshuttle.canEvac(user)
|
||||
|
||||
if (authenticated_as_non_silicon_captain(user))
|
||||
data["canRequestNuke"] = TRUE
|
||||
if (authenticated_as_non_silicon_command(user))
|
||||
data["canMessageAssociates"] = TRUE
|
||||
|
||||
if (can_send_messages_to_other_sectors(user))
|
||||
data["canSendToSectors"] = TRUE
|
||||
|
||||
@@ -428,8 +450,13 @@
|
||||
|
||||
for (var/shuttle_id in SSmapping.shuttle_templates)
|
||||
var/datum/map_template/shuttle/shuttle_template = SSmapping.shuttle_templates[shuttle_id]
|
||||
if (!shuttle_template.can_be_bought || shuttle_template.credit_cost == INFINITY)
|
||||
|
||||
if (shuttle_template.credit_cost == INFINITY)
|
||||
continue
|
||||
|
||||
if (!shuttle_template.can_be_bought)
|
||||
continue
|
||||
|
||||
shuttles += list(list(
|
||||
"name" = shuttle_template.name,
|
||||
"description" = shuttle_template.description,
|
||||
@@ -478,6 +505,7 @@
|
||||
return FALSE
|
||||
if (!authenticated_as_non_silicon_captain(user))
|
||||
return FALSE
|
||||
|
||||
if (SSshuttle.emergency.mode != SHUTTLE_RECALL && SSshuttle.emergency.mode != SHUTTLE_IDLE)
|
||||
return "The shuttle is already in transit."
|
||||
if (SSshuttle.shuttle_purchased == SHUTTLEPURCHASE_PURCHASED)
|
||||
@@ -492,21 +520,38 @@
|
||||
|
||||
return length(CONFIG_GET(keyed_list/cross_server)) > 0
|
||||
|
||||
/**
|
||||
* Call an emergency meeting
|
||||
*
|
||||
* Comm Console wrapper for the Communications subsystem wrapper for the call_emergency_meeting world proc.
|
||||
* Checks to make sure the proc can be called, and handles relevant feedback, logging and timing.
|
||||
* See the SScommunications proc definition for more detail, in short, teleports the entire crew to
|
||||
* the bridge for a meetup. Should only really happen during april fools.
|
||||
* Arguments:
|
||||
* * user - Mob who called the meeting
|
||||
*/
|
||||
/obj/machinery/computer/communications/proc/emergency_meeting(mob/living/user)
|
||||
// if(!SScommunications.can_make_emergency_meeting(user))
|
||||
// to_chat(user, span_alert("The emergency meeting button doesn't seem to work right now. Please stand by."))
|
||||
// return
|
||||
// SScommunications.emergency_meeting(user)
|
||||
// deadchat_broadcast(" called an emergency meeting from [span_name("[get_area_name(usr, TRUE)]")].", span_name("[user.real_name]"), user, message_type=DEADCHAT_ANNOUNCEMENT)
|
||||
|
||||
/obj/machinery/computer/communications/proc/make_announcement(mob/living/user)
|
||||
var/is_ai = issilicon(user)
|
||||
if(!SScommunications.can_announce(user, is_ai))
|
||||
to_chat(user, "<span class='alert'>Intercomms recharging. Please stand by.</span>")
|
||||
to_chat(user, span_alert("Intercomms recharging. Please stand by."))
|
||||
return
|
||||
var/input = stripped_input(user, "Please choose a message to announce to the station crew.", "What?")
|
||||
if(!input || !user.canUseTopic(src, !issilicon(usr)))
|
||||
return
|
||||
if(!(user.can_speak())) //No more cheating, mime/random mute guy!
|
||||
input = "..."
|
||||
to_chat(user, "<span class='warning'>You find yourself unable to speak.</span>")
|
||||
to_chat(user, span_warning("You find yourself unable to speak."))
|
||||
else
|
||||
input = user.treat_message(input) //Adds slurs and so on. Someone should make this use languages too.
|
||||
SScommunications.make_announcement(user, is_ai, input)
|
||||
deadchat_broadcast(" made a priority announcement from <span class='name'>[get_area_name(usr, TRUE)]</span>.", "<span class='name'>[user.real_name]</span>", user)
|
||||
deadchat_broadcast(" made a priority announcement from [span_name("[get_area_name(usr, TRUE)]")].", user, src.loc, message_type=DEADCHAT_ANNOUNCEMENT)
|
||||
|
||||
/obj/machinery/computer/communications/proc/post_status(command, data1, data2)
|
||||
|
||||
|
||||
+205
-344
@@ -1,3 +1,5 @@
|
||||
#define AHELP_FIRST_MESSAGE "Please adminhelp before leaving the round, even if there are no administrators online!"
|
||||
|
||||
/*
|
||||
* Cryogenic refrigeration unit. Basically a despawner.
|
||||
* Stealing a lot of concepts/code from sleepers due to massive laziness.
|
||||
@@ -5,170 +7,71 @@
|
||||
* 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 = 'icons/obj/Cryogenic2.dmi'
|
||||
icon = 'icons/obj/machines/cryopod.dmi'
|
||||
icon_state = "cellconsole_1"
|
||||
circuit = /obj/item/circuitboard/cryopodcontrol
|
||||
icon_keyboard = null
|
||||
// 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.
|
||||
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
|
||||
|
||||
var/menu = 1 //Which menu screen to display
|
||||
|
||||
//Used for logging people entering cryosleep and important items they are carrying.
|
||||
// Used for logging people entering cryosleep and important items they are carrying.
|
||||
var/list/frozen_crew = list()
|
||||
var/list/obj/stored_packages = list()
|
||||
|
||||
var/allow_items = TRUE
|
||||
var/storage_type = "crewmembers"
|
||||
var/storage_name = "Cryogenic Oversight Control"
|
||||
|
||||
/obj/machinery/computer/cryopod/deconstruct()
|
||||
/obj/machinery/computer/cryopod/Initialize()
|
||||
. = ..()
|
||||
for(var/i in stored_packages)
|
||||
var/obj/O = i
|
||||
O.forceMove(drop_location())
|
||||
GLOB.cryopod_computers += src
|
||||
|
||||
/obj/machinery/computer/cryopod/attack_ai()
|
||||
attack_hand()
|
||||
/obj/machinery/computer/cryopod/Destroy()
|
||||
GLOB.cryopod_computers -= src
|
||||
return ..()
|
||||
|
||||
/obj/machinery/computer/cryopod/ui_interact(mob/user = usr)
|
||||
if(!is_operational())
|
||||
/obj/machinery/computer/cryopod/update_icon_state()
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
icon_state = "cellconsole"
|
||||
return ..()
|
||||
icon_state = "cellconsole_1"
|
||||
return ..()
|
||||
|
||||
/obj/machinery/computer/cryopod/ui_interact(mob/user, datum/tgui/ui)
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
|
||||
user.set_machine(src)
|
||||
add_fingerprint(user)
|
||||
|
||||
var/dat = ""
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "CryopodConsole", name)
|
||||
ui.open()
|
||||
|
||||
dat += "<h2>Welcome, [user.real_name].</h2><hr/>"
|
||||
dat += "<br><br>"
|
||||
/obj/machinery/computer/cryopod/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["frozen_crew"] = frozen_crew
|
||||
|
||||
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(!stored_packages.len)
|
||||
dat += "There has been no storage usage at this terminal.<br/>"
|
||||
else
|
||||
for(var/obj/O in stored_packages)
|
||||
dat += "[O.name]<br/>"
|
||||
dat += "<hr/>"
|
||||
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
|
||||
|
||||
var/datum/browser/popup = new(user, "cryopod_console", "Cryogenic System Control")
|
||||
popup.set_content(dat)
|
||||
popup.open()
|
||||
return data
|
||||
|
||||
/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) && !(obj_flags & EMAGGED))
|
||||
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(stored_packages.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/I = tgui_input_list(user, "Please choose which object to retrieve.","Object recovery", stored_packages)
|
||||
playsound(src, "terminal_type", 25, 0)
|
||||
if(!I)
|
||||
return
|
||||
|
||||
if(!(I in stored_packages))
|
||||
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)
|
||||
stored_packages -= I
|
||||
updateUsrDialog()
|
||||
|
||||
else if(href_list["allitems"])
|
||||
playsound(src, "terminal_type", 25, 0)
|
||||
if(!allowed(user) && !(obj_flags & EMAGGED))
|
||||
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(stored_packages.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/O in stored_packages)
|
||||
O.forceMove(get_turf(src))
|
||||
stored_packages.Cut()
|
||||
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
|
||||
|
||||
/obj/machinery/computer/cryopod/contents_explosion()
|
||||
return //don't blow everyone's shit up.
|
||||
|
||||
/// The box
|
||||
/obj/item/storage/box/blue/cryostorage_items
|
||||
w_class = WEIGHT_CLASS_HUGE
|
||||
|
||||
//Cryopods themselves.
|
||||
// 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."
|
||||
@@ -181,47 +84,55 @@
|
||||
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 = null // Used to keep track of the safe period.
|
||||
/// Time until despawn when a mob enters a cryopod. You cannot other people in pods unless they're catatonic.
|
||||
var/time_till_despawn = 30 SECONDS
|
||||
/// Cooldown for when it's now safe to try an despawn the player.
|
||||
COOLDOWN_DECLARE(despawn_world_time)
|
||||
|
||||
var/obj/machinery/computer/cryopod/control_computer
|
||||
var/item_storage_type = /obj/item/storage/box/blue/cryostorage_items //with how storage components work this can be anything the player can open or anything with a storage component.
|
||||
var/last_no_computer_message = 0
|
||||
///Weakref to our controller
|
||||
var/datum/weakref/control_computer_weakref
|
||||
COOLDOWN_DECLARE(last_no_computer_message)
|
||||
|
||||
/obj/machinery/cryopod/Initialize(mapload)
|
||||
. = ..()
|
||||
/obj/machinery/cryopod/Initialize()
|
||||
..()
|
||||
return INITIALIZE_HINT_LATELOAD //Gotta populate the cryopod computer GLOB first
|
||||
|
||||
/obj/machinery/cryopod/LateInitialize()
|
||||
update_icon()
|
||||
find_control_computer(mapload)
|
||||
find_control_computer()
|
||||
|
||||
// This is not a good situation
|
||||
/obj/machinery/cryopod/Destroy()
|
||||
control_computer_weakref = null
|
||||
return ..()
|
||||
|
||||
/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
|
||||
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_weakref = WEAKREF(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 && last_no_computer_message + 5*60*10 < world.time)
|
||||
if(!control_computer_weakref && 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
|
||||
return control_computer_weakref != null
|
||||
|
||||
/obj/machinery/cryopod/close_machine(mob/user)
|
||||
if(!control_computer)
|
||||
/obj/machinery/cryopod/close_machine(atom/movable/target)
|
||||
if(!control_computer_weakref)
|
||||
find_control_computer(TRUE)
|
||||
if((isnull(user) || istype(user)) && state_open && !panel_open)
|
||||
..(user)
|
||||
if((isnull(target) || isliving(target)) && state_open && !panel_open)
|
||||
..(target)
|
||||
var/mob/living/mob_occupant = occupant
|
||||
investigate_log("Cryogenics machine closed with occupant [key_name(occupant)] by user [key_name(user)].", INVESTIGATE_CRYOGENICS)
|
||||
investigate_log("Cryogenics machine closed with occupant [key_name(occupant)] by user [key_name(target)].", INVESTIGATE_CRYOGENICS)
|
||||
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
|
||||
to_chat(occupant, span_notice("<b>You feel cool air surround you. You go numb as your senses turn inward.</b>"))
|
||||
|
||||
COOLDOWN_START(src, despawn_world_time, time_till_despawn)
|
||||
icon_state = "cryopod"
|
||||
|
||||
/obj/machinery/cryopod/open_machine()
|
||||
@@ -234,8 +145,8 @@
|
||||
|
||||
/obj/machinery/cryopod/container_resist(mob/living/user)
|
||||
investigate_log("Cryogenics machine container resisted by [key_name(user)] with occupant [key_name(occupant)].", INVESTIGATE_CRYOGENICS)
|
||||
visible_message("<span class='notice'>[occupant] emerges from [src]!</span>",
|
||||
"<span class='notice'>You climb out of [src]!</span>")
|
||||
visible_message(span_notice("[occupant] emerges from [src]!"),
|
||||
span_notice("You climb out of [src]!"))
|
||||
open_machine()
|
||||
|
||||
/obj/machinery/cryopod/relaymove(mob/user)
|
||||
@@ -246,205 +157,151 @@
|
||||
return
|
||||
|
||||
var/mob/living/mob_occupant = occupant
|
||||
if(mob_occupant)
|
||||
// Eject dead people
|
||||
if(mob_occupant.stat == DEAD)
|
||||
open_machine()
|
||||
if(mob_occupant.stat == DEAD)
|
||||
open_machine()
|
||||
|
||||
if(!(world.time > despawn_world_time + 100))//+ 10 seconds
|
||||
return
|
||||
if(!mob_occupant.client && COOLDOWN_FINISHED(src, despawn_world_time))
|
||||
if(!control_computer_weakref)
|
||||
find_control_computer(urgent = TRUE)
|
||||
|
||||
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()
|
||||
|
||||
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_userdanger("Your target is no longer within reach. Objective removed!")]")
|
||||
mind.announce_objectives()
|
||||
else if(istype(objective.target) && objective.target == mob_occupant.mind)
|
||||
if(istype(objective, /datum/objective/contract))
|
||||
var/datum/antagonist/traitor/affected_traitor = objective.owner.has_antag_datum(/datum/antagonist/traitor)
|
||||
var/datum/contractor_hub/affected_contractor_hub = affected_traitor.contractor_hub
|
||||
for(var/datum/syndicate_contract/affected_contract as anything in affected_contractor_hub.assigned_contracts)
|
||||
if(affected_contract.contract == objective)
|
||||
affected_contract.generate(affected_contractor_hub.assigned_targets)
|
||||
affected_contractor_hub.assigned_targets.Add(affected_contract.contract.target)
|
||||
to_chat(objective.owner.current, "<BR>[span_userdanger("Contract target out of reach. Contract rerolled.")]")
|
||||
break
|
||||
else
|
||||
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_userdanger("Your target is no longer within reach. Objective removed!")]")
|
||||
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_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!")]")
|
||||
else
|
||||
var/list/objectivestoupdate
|
||||
for(var/datum/mind/objective_owner in objective.get_owners())
|
||||
to_chat(objective_owner.current, "<BR>[span_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!")]")
|
||||
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_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!")]")
|
||||
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()
|
||||
if(!control_computer)
|
||||
find_control_computer()
|
||||
|
||||
var/mob/living/mob_occupant = occupant
|
||||
var/list/crew_member = list()
|
||||
|
||||
var/list/obj/item/storing = list()
|
||||
var/list/obj/item/destroying = list()
|
||||
var/list/obj/item/destroy_later = list()
|
||||
|
||||
investigate_log("Despawning [key_name(mob_occupant)].", INVESTIGATE_CRYOGENICS)
|
||||
|
||||
var/atom/target_store = (control_computer?.allow_items && control_computer) || src //the double control computer check makes it return the control computer.
|
||||
var/drop_to_ground = !istype(target_store, /obj/machinery/computer/cryopod)
|
||||
|
||||
var/mind_identity = mob_occupant.mind?.name
|
||||
var/occupant_identity = mob_occupant.real_name
|
||||
|
||||
if(iscyborg(mob_occupant))
|
||||
var/mob/living/silicon/robot/R = mob_occupant
|
||||
if(R.mmi?.brain)
|
||||
destroy_later += R.mmi
|
||||
destroy_later += R.mmi.brain
|
||||
for(var/i in R.module)
|
||||
if(!isitem(i))
|
||||
destroying += i
|
||||
continue
|
||||
var/obj/item/I = i
|
||||
// let's be honest we only care about the trash bag don't beat around the bush
|
||||
if(SEND_SIGNAL(I, COMSIG_CONTAINS_STORAGE))
|
||||
storing += I.contents
|
||||
for(var/atom/movable/AM in I.contents)
|
||||
AM.forceMove(src)
|
||||
R.module.remove_module(I, TRUE)
|
||||
else
|
||||
|
||||
if(ishuman(mob_occupant))
|
||||
var/mob/living/carbon/human/H = mob_occupant
|
||||
if(H.mind && H.client && H.client.prefs && H == H.mind.original_character)
|
||||
H.SaveTCGCards()
|
||||
|
||||
var/list/gear = list()
|
||||
if(iscarbon(mob_occupant)) // sorry simp-le-mobs deserve no mercy
|
||||
var/mob/living/carbon/C = mob_occupant
|
||||
gear = C.get_all_gear()
|
||||
for(var/i in gear)
|
||||
var/obj/item/I = i
|
||||
I.forceMove(src)
|
||||
if(!istype(I))
|
||||
destroying += I
|
||||
continue
|
||||
if(I.item_flags & (DROPDEL | ABSTRACT))
|
||||
destroying += I
|
||||
continue
|
||||
if(HAS_TRAIT(I, TRAIT_NODROP))
|
||||
destroying += I
|
||||
continue
|
||||
// WEE WOO SNOWFLAKE TIME
|
||||
if(istype(I, /obj/item/pda))
|
||||
var/obj/item/pda/P = I
|
||||
if((P.owner == mind_identity) || (P.owner == occupant_identity))
|
||||
destroying += P
|
||||
else
|
||||
storing += P
|
||||
else if(istype(I, /obj/item/card/id))
|
||||
var/obj/item/card/id/idcard = I
|
||||
if((idcard.registered_name == mind_identity) || (idcard.registered_name == occupant_identity))
|
||||
destroying += idcard
|
||||
else
|
||||
storing += idcard
|
||||
else
|
||||
storing += I
|
||||
|
||||
// get rid of mobs
|
||||
for(var/mob/living/L in mob_occupant.GetAllContents() - mob_occupant)
|
||||
L.forceMove(drop_location())
|
||||
|
||||
if(storing.len)
|
||||
var/obj/O = new item_storage_type
|
||||
O.name = "cryogenic retrieval package: [mob_occupant.real_name]"
|
||||
for(var/i in storing)
|
||||
var/obj/item/I = i
|
||||
I.forceMove(O)
|
||||
O.forceMove(drop_to_ground? target_store.drop_location() : target_store)
|
||||
if((target_store == control_computer) && !drop_to_ground)
|
||||
control_computer.stored_packages += O
|
||||
|
||||
QDEL_LIST(destroying)
|
||||
|
||||
//Update any existing objectives involving this mob.
|
||||
for(var/i in GLOB.objectives)
|
||||
var/datum/objective/O = i
|
||||
// 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)
|
||||
continue
|
||||
if(O.check_midround_completion())
|
||||
continue
|
||||
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)
|
||||
crew_member["name"] = mob_occupant.real_name
|
||||
|
||||
if(mob_occupant.mind)
|
||||
//Handle job slot/tater cleanup.
|
||||
if(mob_occupant.mind.assigned_role)
|
||||
var/job = mob_occupant.mind.assigned_role
|
||||
SSjob.FreeRole(job)
|
||||
// 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
|
||||
else
|
||||
crew_member["job"] = "N/A"
|
||||
|
||||
// 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)
|
||||
for(var/datum/data/record/T in GLOB.data_core.security)
|
||||
if((T.fields["name"] == mob_occupant.real_name))
|
||||
qdel(T)
|
||||
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)
|
||||
for(var/datum/data/record/medical_record as anything in GLOB.data_core.medical)
|
||||
if(medical_record.fields["name"] == mob_occupant.real_name)
|
||||
qdel(medical_record)
|
||||
for(var/datum/data/record/security_record as anything in GLOB.data_core.security)
|
||||
if(security_record.fields["name"] == mob_occupant.real_name)
|
||||
qdel(security_record)
|
||||
for(var/datum/data/record/general_record as anything in GLOB.data_core.general)
|
||||
if(general_record.fields["name"] == mob_occupant.real_name)
|
||||
announce_rank = general_record.fields["rank"]
|
||||
qdel(general_record)
|
||||
|
||||
for(var/obj/machinery/computer/cloning/cloner in world)
|
||||
for(var/datum/data/record/R in cloner.records)
|
||||
if(R.fields["name"] == mob_occupant.real_name)
|
||||
cloner.records.Remove(R)
|
||||
|
||||
//Make an announcement and log the person entering storage.
|
||||
if(control_computer)
|
||||
control_computer.frozen_crew += "[mob_occupant.real_name]"
|
||||
var/obj/machinery/computer/cryopod/control_computer = control_computer_weakref?.resolve()
|
||||
if(!control_computer)
|
||||
control_computer_weakref = null
|
||||
else
|
||||
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'>\The [src] hums and hisses as it moves [mob_occupant.real_name] into storage.</span>")
|
||||
|
||||
// Ghost and delete the mob.
|
||||
var/mob/dead/observer/G = mob_occupant.get_ghost(TRUE)
|
||||
if(G)
|
||||
G.voluntary_ghosted = TRUE
|
||||
else
|
||||
mob_occupant.ghostize(FALSE, penalize = TRUE, voluntary = TRUE, cryo = TRUE)
|
||||
visible_message(span_notice("[src] hums and hisses as it moves [mob_occupant.real_name] into storage."))
|
||||
|
||||
for(var/obj/item/item_content as anything in mob_occupant)
|
||||
if(!istype(item_content) || HAS_TRAIT(item_content, TRAIT_NODROP))
|
||||
continue
|
||||
|
||||
mob_occupant.transferItemToLoc(item_content, drop_location(), force = TRUE, silent = TRUE)
|
||||
|
||||
handle_objectives()
|
||||
QDEL_NULL(occupant)
|
||||
QDEL_LIST(destroy_later)
|
||||
open_machine()
|
||||
name = initial(name)
|
||||
|
||||
/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)
|
||||
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='boldnotice'>The cryo pod is already occupied!</span>")
|
||||
to_chat(user, span_notice("[src] is already occupied!"))
|
||||
return
|
||||
|
||||
if(target.stat == DEAD)
|
||||
to_chat(user, "<span class='notice'>Dead people can not be put into cryo.</span>")
|
||||
to_chat(user, span_notice("Dead people can not be put into cryo."))
|
||||
return
|
||||
|
||||
if(target.client && user != target)
|
||||
if(target.key && user != target)
|
||||
if(iscyborg(target))
|
||||
to_chat(user, "<span class='danger'>You can't put [target] into [src]. They're online.</span>")
|
||||
to_chat(user, span_danger("You can't put [target] into [src]. [target.p_theyre(capitalized = TRUE)] online."))
|
||||
else
|
||||
to_chat(user, "<span class='danger'>You can't put [target] into [src]. They're conscious.</span>")
|
||||
to_chat(user, span_danger("You can't put [target] into [src]. [target.p_theyre(capitalized = TRUE)] conscious."))
|
||||
return
|
||||
else if(target.client)
|
||||
if(tgui_alert(target,"Would you like to enter cryosleep?",,list("Yes","No")) == "No")
|
||||
return
|
||||
|
||||
var/generic_plsnoleave_message = " Please adminhelp before leaving the round, even if there are no administrators online!"
|
||||
if(target == user && (tgalert(target, "Would you like to enter cryosleep?", "Enter Cryopod?", "Yes", "No") != "Yes"))
|
||||
return
|
||||
|
||||
if(target == user && world.time - target.client.cryo_warned > 5 MINUTES)//if we haven't warned them in the last 5 minutes
|
||||
if(target == user)
|
||||
var/list/caught_string
|
||||
var/addendum = ""
|
||||
if(target.mind.assigned_role in GLOB.command_positions)
|
||||
@@ -462,30 +319,34 @@
|
||||
LAZYADD(caught_string, "Revolutionary")
|
||||
|
||||
if(caught_string)
|
||||
tgui_alert(target, "You're a [english_list(caught_string)]![generic_plsnoleave_message][addendum]")
|
||||
tgui_alert(target, "You're a [english_list(caught_string)]! [AHELP_FIRST_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)
|
||||
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.")
|
||||
// rerun the checks in case of shenanigans
|
||||
|
||||
if(occupant)
|
||||
to_chat(user, "<span class='boldnotice'>\The [src] is in use.</span>")
|
||||
to_chat(user, span_notice("[src] is already occupied!"))
|
||||
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("<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>)")
|
||||
if(target == user)
|
||||
visible_message("<span class='infoplain'>[user] starts climbing into the cryo pod.</span>")
|
||||
else
|
||||
visible_message("<span class='infoplain'>[user] starts putting [target] into the cryo pod.</span>")
|
||||
|
||||
to_chat(target, span_warning("<b>If you ghost, log out or close your client now, your character will shortly be permanently removed from the round.</b>"))
|
||||
|
||||
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.
|
||||
close_machine(target)
|
||||
name = "[name] ([target.name])"
|
||||
|
||||
// Attacks/effects.
|
||||
/obj/machinery/cryopod/blob_act()
|
||||
return //Sorta gamey, but we don't really want these to be destroyed.
|
||||
return // Sorta gamey, but we don't really want these to be destroyed.
|
||||
|
||||
#undef AHELP_FIRST_MESSAGE
|
||||
|
||||
+101
-51
@@ -1,8 +1,8 @@
|
||||
/* Holograms!
|
||||
* Contains:
|
||||
* Holopad
|
||||
* Hologram
|
||||
* Other stuff
|
||||
* Holopad
|
||||
* Hologram
|
||||
* Other stuff
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -24,7 +24,6 @@ Possible to do for anyone motivated enough:
|
||||
* Holopad
|
||||
*/
|
||||
|
||||
GLOBAL_LIST_EMPTY(network_holopads)
|
||||
#define HOLOPAD_PASSIVE_POWER_USAGE 1
|
||||
#define HOLOGRAM_POWER_USAGE 2
|
||||
|
||||
@@ -32,6 +31,7 @@ GLOBAL_LIST_EMPTY(network_holopads)
|
||||
name = "holopad"
|
||||
desc = "It's a floor-mounted device for projecting holographic images."
|
||||
icon_state = "holopad0"
|
||||
base_icon_state = "holopad"
|
||||
layer = LOW_OBJ_LAYER
|
||||
plane = FLOOR_PLANE
|
||||
flags_1 = HEAR_1
|
||||
@@ -70,7 +70,7 @@ GLOBAL_LIST_EMPTY(network_holopads)
|
||||
var/obj/effect/overlay/holo_pad_hologram/replay_holo
|
||||
/// Calls will be automatically answered after a couple rings, here for debugging
|
||||
var/static/force_answer_call = FALSE
|
||||
// var/static/list/holopads = list()
|
||||
var/static/list/holopads = list()
|
||||
var/obj/effect/overlay/holoray/ray
|
||||
var/ringing = FALSE
|
||||
var/offset = FALSE
|
||||
@@ -107,26 +107,47 @@ GLOBAL_LIST_EMPTY(network_holopads)
|
||||
new_disk.forceMove(src)
|
||||
disk = new_disk
|
||||
|
||||
/obj/machinery/holopad/tutorial/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
/obj/machinery/holopad/Moved(atom/OldLoc, Dir)
|
||||
. = ..()
|
||||
if(!loc)
|
||||
return
|
||||
// move any relevant holograms, basically non-AI, and rays with the pad
|
||||
if(replay_holo)
|
||||
replay_holo.abstract_move(loc)
|
||||
for(var/i in holorays)
|
||||
var/obj/effect/overlay/holoray/ray = holorays[i]
|
||||
ray.abstract_move(loc)
|
||||
var/list/non_call_masters = masters?.Copy()
|
||||
for(var/datum/holocall/holocall as anything in holo_calls)
|
||||
if(!holocall.user || !LAZYACCESS(masters, holocall.user))
|
||||
continue
|
||||
non_call_masters -= holocall.user
|
||||
// moving the eye moves the holo which updates the ray too
|
||||
holocall.eye.setLoc(locate(clamp(x + (holocall.hologram.x - OldLoc.x), 1, world.maxx), clamp(y + (holocall.hologram.y - OldLoc.y), 1, world.maxy), z))
|
||||
for(var/mob/living/holo_master as anything in non_call_masters)
|
||||
var/obj/effect/holo = masters[holo_master]
|
||||
update_holoray(holo_master, holo.loc)
|
||||
|
||||
/obj/machinery/holopad/tutorial/attack_hand(mob/user, list/modifiers)
|
||||
if(!istype(user))
|
||||
return
|
||||
if(user.incapacitated() || !is_operational())
|
||||
return
|
||||
if(replay_mode)
|
||||
replay_stop()
|
||||
else if(disk && disk.record)
|
||||
else if(disk?.record)
|
||||
replay_start()
|
||||
|
||||
/obj/machinery/holopad/tutorial/HasProximity(atom/movable/AM)
|
||||
if (!isliving(AM))
|
||||
return
|
||||
if(!replay_mode && (disk && disk.record))
|
||||
if(!replay_mode && (disk?.record))
|
||||
replay_start()
|
||||
|
||||
/obj/machinery/holopad/Initialize()
|
||||
. = ..()
|
||||
if(on_network)
|
||||
GLOB.network_holopads += src
|
||||
holopads += src
|
||||
|
||||
/obj/machinery/holopad/Destroy()
|
||||
if(outgoing_call)
|
||||
@@ -146,7 +167,7 @@ GLOBAL_LIST_EMPTY(network_holopads)
|
||||
|
||||
QDEL_NULL(disk)
|
||||
|
||||
GLOB.network_holopads -= src
|
||||
holopads -= src
|
||||
return ..()
|
||||
|
||||
/obj/machinery/holopad/power_change()
|
||||
@@ -172,8 +193,10 @@ GLOBAL_LIST_EMPTY(network_holopads)
|
||||
|
||||
/obj/machinery/holopad/examine(mob/user)
|
||||
. = ..()
|
||||
if(in_range(user, src) || isobserver(user))
|
||||
. += "<span class='notice'>The status display reads: Current projection range: <b>[holo_range]</b> units.</span>"
|
||||
if(isAI(user))
|
||||
. += span_notice("The status display reads: Current projection range: <b>[holo_range]</b> units. Use :h to speak through the projection. Right-click to project or cancel a projection. Alt-click to hangup all active and incomming calls. Ctrl-click to end projection without jumping to your last location.")
|
||||
else if(in_range(user, src) || isobserver(user))
|
||||
. += span_notice("The status display reads: Current projection range: <b>[holo_range]</b> units.")
|
||||
|
||||
/obj/machinery/holopad/attackby(obj/item/P, mob/user, params)
|
||||
if(default_deconstruction_screwdriver(user, "holopad_open", "holopad0", P))
|
||||
@@ -190,11 +213,11 @@ GLOBAL_LIST_EMPTY(network_holopads)
|
||||
|
||||
if(istype(P,/obj/item/disk/holodisk))
|
||||
if(disk)
|
||||
to_chat(user,"<span class='warning'>There's already a disk inside [src]!</span>")
|
||||
to_chat(user,span_warning("There's already a disk inside [src]!"))
|
||||
return
|
||||
if (!user.transferItemToLoc(P,src))
|
||||
return
|
||||
to_chat(user,"<span class='notice'>You insert [P] into [src].</span>")
|
||||
to_chat(user,span_notice("You insert [P] into [src]."))
|
||||
disk = P
|
||||
return
|
||||
|
||||
@@ -242,24 +265,29 @@ GLOBAL_LIST_EMPTY(network_holopads)
|
||||
|
||||
switch(action)
|
||||
if("AIrequest")
|
||||
if(isAI(usr))
|
||||
var/mob/living/silicon/ai/ai_user = usr
|
||||
ai_user.eyeobj.setLoc(get_turf(src))
|
||||
to_chat(usr, span_info("AIs can not request AI presence. Jumping instead."))
|
||||
return
|
||||
if(last_request + 200 < world.time)
|
||||
last_request = world.time
|
||||
to_chat(usr, "<span class='info'>You requested an AI's presence.</span>")
|
||||
to_chat(usr, span_info("You requested an AI's presence."))
|
||||
var/area/area = get_area(src)
|
||||
for(var/mob/living/silicon/ai/AI in GLOB.silicon_mobs)
|
||||
if(!AI.client)
|
||||
continue
|
||||
to_chat(AI, "<span class='info'>Your presence is requested at <a href='?src=[REF(AI)];jumptoholopad=[REF(src)]'>\the [area]</a>.</span>")
|
||||
to_chat(AI, span_info("Your presence is requested at <a href='?src=[REF(AI)];jumptoholopad=[REF(src)]'>\the [area]</a>.</span>")) // <a href='?src=[REF(AI)];project_to_holopad=[REF(src)]'>Project Hologram?</a>"))
|
||||
return TRUE
|
||||
else
|
||||
to_chat(usr, "<span class='info'>A request for AI presence was already sent recently.</span>")
|
||||
to_chat(usr, span_info("A request for AI presence was already sent recently."))
|
||||
return
|
||||
if("holocall")
|
||||
if(outgoing_call)
|
||||
return
|
||||
if(usr.loc == loc)
|
||||
var/list/callnames = list()
|
||||
for(var/I in GLOB.network_holopads)
|
||||
for(var/I in holopads)
|
||||
var/area/A = get_area(I)
|
||||
if(A)
|
||||
LAZYADD(callnames[A], I)
|
||||
@@ -274,7 +302,7 @@ GLOBAL_LIST_EMPTY(network_holopads)
|
||||
calling = TRUE
|
||||
return TRUE
|
||||
else
|
||||
to_chat(usr, "<span class='warning'>You must stand on the holopad to make a call!</span>")
|
||||
to_chat(usr, span_warning("You must stand on the holopad to make a call!"))
|
||||
if("connectcall")
|
||||
var/datum/holocall/call_to_connect = locate(params["holopad"]) in holo_calls
|
||||
if(!QDELETED(call_to_connect))
|
||||
@@ -285,6 +313,12 @@ GLOBAL_LIST_EMPTY(network_holopads)
|
||||
if(!QDELETED(call_to_disconnect))
|
||||
call_to_disconnect.Disconnect(src)
|
||||
return TRUE
|
||||
if("rejectall")
|
||||
for(var/datum/holocall/call_to_reject as anything in holo_calls)
|
||||
if(call_to_reject.connected_holopad == src) // do not kill the current connection
|
||||
continue
|
||||
call_to_reject.Disconnect(src)
|
||||
return TRUE
|
||||
if("disk_eject")
|
||||
if(disk && !replay_mode)
|
||||
disk.forceMove(drop_location())
|
||||
@@ -327,14 +361,13 @@ GLOBAL_LIST_EMPTY(network_holopads)
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* hangup_all_calls: Disconnects all current holocalls from the holopad
|
||||
*/
|
||||
* hangup_all_calls: Disconnects all current holocalls from the holopad
|
||||
*/
|
||||
/obj/machinery/holopad/proc/hangup_all_calls()
|
||||
for(var/I in holo_calls)
|
||||
var/datum/holocall/HC = I
|
||||
HC.Disconnect(src)
|
||||
|
||||
//do not allow AIs to answer calls or people will use it to meta the AI sattelite
|
||||
/obj/machinery/holopad/attack_ai(mob/living/silicon/ai/user)
|
||||
if (!istype(user))
|
||||
return
|
||||
@@ -343,12 +376,25 @@ GLOBAL_LIST_EMPTY(network_holopads)
|
||||
/*There are pretty much only three ways to interact here.
|
||||
I don't need to check for client since they're clicking on an object.
|
||||
This may change in the future but for now will suffice.*/
|
||||
if(user.eyeobj.loc != src.loc)//Set client eye on the object if it's not already.
|
||||
user.eyeobj.setLoc(get_turf(src))
|
||||
else if(!LAZYLEN(masters) || !masters[user])//If there is no hologram, possibly make one.
|
||||
if(!LAZYLEN(masters) || !masters[user])//If there is no hologram, possibly make one.
|
||||
activate_holo(user)
|
||||
else//If there is a hologram, remove it.
|
||||
else//If there is a hologram, remove it, and jump to your last location.
|
||||
clear_holo(user)
|
||||
// if(user.lastloc)//only jump to your last location if your lastloc is set, which only sets if you projected from a request message.
|
||||
// user.eyeobj.setLoc(user.lastloc)
|
||||
// user.lastloc = null
|
||||
|
||||
/obj/machinery/holopad/AICtrlClick(mob/living/silicon/ai/user)
|
||||
if (!istype(user))
|
||||
return
|
||||
if (!on_network)
|
||||
return
|
||||
if(!LAZYLEN(masters) || !masters[user])//If there is no hologram, then this button does nothing.
|
||||
return
|
||||
else//If there is a hologram, remove it, but dont jump to your last location.
|
||||
// user.lastloc = null
|
||||
clear_holo(user)
|
||||
return
|
||||
|
||||
/obj/machinery/holopad/process()
|
||||
if(LAZYLEN(masters))
|
||||
@@ -378,25 +424,26 @@ GLOBAL_LIST_EMPTY(network_holopads)
|
||||
if(outgoing_call)
|
||||
HC.Disconnect(src)//can't answer calls while calling
|
||||
else
|
||||
playsound(src, 'sound/machines/twobeep.ogg', 100) //bring, bring!
|
||||
playsound(src, 'sound/machines/twobeep.ogg', 100) //bring, bring!
|
||||
ringing = TRUE
|
||||
|
||||
update_icon()
|
||||
update_appearance()
|
||||
|
||||
/obj/machinery/holopad/proc/activate_holo(mob/living/user)
|
||||
var/mob/living/silicon/ai/AI = user
|
||||
if(!istype(AI))
|
||||
AI = null
|
||||
|
||||
if(is_operational() && (!AI || AI.eyeobj.loc == loc))//If the projector has power and client eye is on it
|
||||
if (AI && istype(AI.current, /obj/machinery/holopad))
|
||||
to_chat(user, "<span class='danger'>ERROR:</span> \black Image feed in progress.")
|
||||
if(is_operational())//If the projector has power
|
||||
if(AI && istype(AI.current, /obj/machinery/holopad))
|
||||
to_chat(user, "[span_danger("ERROR:")] \black Image feed in progress.")
|
||||
return
|
||||
|
||||
var/obj/effect/overlay/holo_pad_hologram/Hologram = new(loc)//Spawn a blank effect at the location.
|
||||
if(AI)
|
||||
Hologram.icon = AI.holo_icon
|
||||
else //make it like real life
|
||||
AI.eyeobj.setLoc(get_turf(src)) //ensure the AI camera moves to the holopad
|
||||
else //make it like real life
|
||||
Hologram.icon = user.icon
|
||||
Hologram.icon_state = user.icon_state
|
||||
Hologram.copy_overlays(user, TRUE)
|
||||
@@ -407,17 +454,17 @@ GLOBAL_LIST_EMPTY(network_holopads)
|
||||
|
||||
Hologram.mouse_opacity = MOUSE_OPACITY_TRANSPARENT//So you can't click on it.
|
||||
Hologram.layer = FLY_LAYER//Above all the other objects/mobs. Or the vast majority of them.
|
||||
Hologram.setAnchored(TRUE)//So space wind cannot drag it.
|
||||
Hologram.set_anchored(TRUE)//So space wind cannot drag it.
|
||||
Hologram.name = "[user.name] (Hologram)"//If someone decides to right click.
|
||||
Hologram.set_light(2) //hologram lighting
|
||||
Hologram.set_light(2) //hologram lighting
|
||||
move_hologram()
|
||||
|
||||
set_holo(user, Hologram)
|
||||
visible_message("<span class='notice'>A holographic image of [user] flickers to life before your eyes!</span>")
|
||||
visible_message(span_notice("A holographic image of [user] flickers to life before your eyes!"))
|
||||
|
||||
return Hologram
|
||||
else
|
||||
to_chat(user, "<span class='danger'>ERROR:</span> Unable to project hologram.")
|
||||
to_chat(user, "[span_danger("ERROR:")] Unable to project hologram.")
|
||||
|
||||
/*This is the proc for special two-way communication between AI and holopad/people talking near holopad.
|
||||
For the other part of the code, check silicon say.dm. Particularly robot talk.*/
|
||||
@@ -430,10 +477,13 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
|
||||
|
||||
for(var/I in holo_calls)
|
||||
var/datum/holocall/HC = I
|
||||
if(HC.connected_holopad == src && speaker != HC.hologram)
|
||||
HC.user.Hear(message, speaker, message_language, raw_message, radio_freq, spans, message_mods)
|
||||
if(HC.connected_holopad == src)
|
||||
if(speaker == HC.hologram && HC.user.client?.prefs.chat_on_map)
|
||||
HC.user.create_chat_message(speaker, message_language, raw_message, spans)
|
||||
else
|
||||
HC.user.Hear(message, speaker, message_language, raw_message, radio_freq, spans, message_mods)
|
||||
|
||||
if(outgoing_call && speaker == outgoing_call.user)
|
||||
if(outgoing_call?.hologram && speaker == outgoing_call.user)
|
||||
outgoing_call.hologram.say(raw_message)
|
||||
|
||||
if(record_mode && speaker == record_user)
|
||||
@@ -447,16 +497,15 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
|
||||
set_light(2)
|
||||
else
|
||||
set_light(0)
|
||||
update_icon()
|
||||
update_appearance()
|
||||
|
||||
/obj/machinery/holopad/update_icon_state()
|
||||
var/total_users = LAZYLEN(masters) + LAZYLEN(holo_calls)
|
||||
if(ringing)
|
||||
icon_state = "holopad_ringing"
|
||||
else if(total_users || replay_mode)
|
||||
icon_state = "holopad1"
|
||||
else
|
||||
icon_state = "holopad0"
|
||||
icon_state = "[base_icon_state]_ringing"
|
||||
return ..()
|
||||
icon_state = "[base_icon_state][(total_users || replay_mode) ? 1 : 0]"
|
||||
return ..()
|
||||
|
||||
/obj/machinery/holopad/proc/set_holo(mob/living/user, obj/effect/overlay/holo_pad_hologram/h)
|
||||
LAZYSET(masters, user, h)
|
||||
@@ -488,7 +537,7 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
|
||||
var/obj/effect/overlay/holo_pad_hologram/h = masters[holo_owner]
|
||||
if(!h || h.HC) //Holocalls can't change source.
|
||||
return FALSE
|
||||
for(var/pad in GLOB.network_holopads)
|
||||
for(var/pad in holopads)
|
||||
var/obj/machinery/holopad/another = pad
|
||||
if(another == src)
|
||||
continue
|
||||
@@ -524,7 +573,7 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
|
||||
else
|
||||
transfered = TRUE
|
||||
//All is good.
|
||||
holo.forceMove(new_turf)
|
||||
holo.abstract_move(new_turf)
|
||||
if(!transfered)
|
||||
update_holoray(user,new_turf)
|
||||
return TRUE
|
||||
@@ -565,10 +614,10 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
|
||||
holder.selected_language = record.language
|
||||
Hologram.mouse_opacity = MOUSE_OPACITY_TRANSPARENT//So you can't click on it.
|
||||
Hologram.layer = FLY_LAYER//Above all the other objects/mobs. Or the vast majority of them.
|
||||
Hologram.setAnchored(TRUE)//So space wind cannot drag it.
|
||||
Hologram.set_anchored(TRUE)//So space wind cannot drag it.
|
||||
Hologram.name = "[record.caller_name] (Hologram)"//If someone decides to right click.
|
||||
Hologram.set_light(2) //hologram lighting
|
||||
visible_message("<span class='notice'>A holographic image of [record.caller_name] flickers to life before your eyes!</span>")
|
||||
Hologram.set_light(2) //hologram lighting
|
||||
visible_message(span_notice("A holographic image of [record.caller_name] flickers to life before your eyes!"))
|
||||
return Hologram
|
||||
|
||||
/obj/machinery/holopad/proc/replay_start()
|
||||
@@ -661,7 +710,7 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
|
||||
record_user = null
|
||||
|
||||
/obj/machinery/holopad/proc/record_clear()
|
||||
if(disk && disk.record)
|
||||
if(disk?.record)
|
||||
QDEL_NULL(disk.record)
|
||||
|
||||
/obj/effect/overlay/holo_pad_hologram
|
||||
@@ -673,6 +722,7 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
|
||||
Impersonation = null
|
||||
if(!QDELETED(HC))
|
||||
HC.Disconnect(HC.calling_holopad)
|
||||
HC = null
|
||||
return ..()
|
||||
|
||||
/obj/effect/overlay/holo_pad_hologram/Process_Spacemove(movement_dir = 0)
|
||||
|
||||
@@ -52,6 +52,8 @@
|
||||
var/author_ckey
|
||||
var/icon_generated = FALSE
|
||||
var/icon/generated_icon
|
||||
///boolean that blocks persistence from saving it. enabled from printing copies, because we do not want to save copies.
|
||||
var/no_save = FALSE
|
||||
|
||||
// Painting overlay offset when framed
|
||||
var/framed_offset_x = 11
|
||||
@@ -370,7 +372,7 @@
|
||||
update_icon()
|
||||
|
||||
/obj/structure/sign/painting/proc/save_persistent()
|
||||
if(!persistence_id || !current_canvas)
|
||||
if(!persistence_id || !current_canvas || current_canvas.no_save)
|
||||
return
|
||||
if(sanitize_filename(persistence_id) != persistence_id)
|
||||
stack_trace("Invalid persistence_id - [persistence_id]")
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#define MAX_NOTICES 5
|
||||
|
||||
/obj/structure/noticeboard
|
||||
name = "notice board"
|
||||
desc = "A board for pinning important notices upon."
|
||||
@@ -7,8 +9,25 @@
|
||||
density = FALSE
|
||||
anchored = TRUE
|
||||
max_integrity = 150
|
||||
/// Current number of a pinned notices
|
||||
var/notices = 0
|
||||
|
||||
/obj/structure/noticeboard/directional/north
|
||||
dir = SOUTH
|
||||
pixel_y = 32
|
||||
|
||||
/obj/structure/noticeboard/directional/south
|
||||
dir = NORTH
|
||||
pixel_y = -32
|
||||
|
||||
/obj/structure/noticeboard/directional/east
|
||||
dir = WEST
|
||||
pixel_x = 32
|
||||
|
||||
/obj/structure/noticeboard/directional/west
|
||||
dir = EAST
|
||||
pixel_x = -32
|
||||
|
||||
/obj/structure/noticeboard/Initialize(mapload)
|
||||
. = ..()
|
||||
|
||||
@@ -16,7 +35,7 @@
|
||||
return
|
||||
|
||||
for(var/obj/item/I in loc)
|
||||
if(notices > 4)
|
||||
if(notices >= MAX_NOTICES)
|
||||
break
|
||||
if(istype(I, /obj/item/paper))
|
||||
I.forceMove(src)
|
||||
@@ -27,67 +46,84 @@
|
||||
/obj/structure/noticeboard/attackby(obj/item/O, mob/user, params)
|
||||
if(istype(O, /obj/item/paper) || istype(O, /obj/item/photo))
|
||||
if(!allowed(user))
|
||||
to_chat(user, "<span class='info'>You are not authorized to add notices</span>")
|
||||
to_chat(user, span_warning("You are not authorized to add notices!"))
|
||||
return
|
||||
if(notices < 5)
|
||||
if(notices < MAX_NOTICES)
|
||||
if(!user.transferItemToLoc(O, src))
|
||||
return
|
||||
notices++
|
||||
icon_state = "nboard0[notices]"
|
||||
to_chat(user, "<span class='notice'>You pin the [O] to the noticeboard.</span>")
|
||||
to_chat(user, span_notice("You pin the [O] to the noticeboard."))
|
||||
else
|
||||
to_chat(user, "<span class='notice'>The notice board is full</span>")
|
||||
to_chat(user, span_warning("The notice board is full!"))
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/structure/noticeboard/interact(mob/user)
|
||||
ui_interact(user)
|
||||
/obj/structure/noticeboard/ui_state(mob/user)
|
||||
return GLOB.physical_state
|
||||
|
||||
/obj/structure/noticeboard/ui_interact(mob/user)
|
||||
/obj/structure/noticeboard/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "NoticeBoard", name)
|
||||
ui.open()
|
||||
|
||||
/obj/structure/noticeboard/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["allowed"] = allowed(user)
|
||||
data["items"] = list()
|
||||
for(var/obj/item/content in contents)
|
||||
var/list/content_data = list(
|
||||
name = content.name,
|
||||
ref = REF(content)
|
||||
)
|
||||
data["items"] += list(content_data)
|
||||
return data
|
||||
|
||||
/obj/structure/noticeboard/ui_act(action, params)
|
||||
. = ..()
|
||||
var/auth = allowed(user)
|
||||
var/dat = "<B>[name]</B><BR>"
|
||||
for(var/obj/item/P in src)
|
||||
if(istype(P, /obj/item/paper))
|
||||
dat += "<A href='?src=[REF(src)];read=[REF(P)]'>[P.name]</A> [auth ? "<A href='?src=[REF(src)];write=[REF(P)]'>Write</A> <A href='?src=[REF(src)];remove=[REF(P)]'>Remove</A>" : ""]<BR>"
|
||||
else
|
||||
dat += "<A href='?src=[REF(src)];read=[REF(P)]'>[P.name]</A> [auth ? "<A href='?src=[REF(src)];remove=[REF(P)]'>Remove</A>" : ""]<BR>"
|
||||
user << browse("<HEAD><TITLE>Notices</TITLE></HEAD>[dat]","window=noticeboard")
|
||||
onclose(user, "noticeboard")
|
||||
if(.)
|
||||
return
|
||||
|
||||
/obj/structure/noticeboard/Topic(href, href_list)
|
||||
..()
|
||||
usr.set_machine(src)
|
||||
if(href_list["remove"])
|
||||
if((usr.stat || usr.restrained())) //For when a player is handcuffed while they have the notice window open
|
||||
return
|
||||
var/obj/item/I = locate(href_list["remove"]) in contents
|
||||
if(istype(I) && I.loc == src)
|
||||
I.forceMove(usr.loc)
|
||||
usr.put_in_hands(I)
|
||||
notices--
|
||||
icon_state = "nboard0[notices]"
|
||||
var/obj/item/item = locate(params["ref"]) in contents
|
||||
if(!istype(item) || item.loc != src)
|
||||
return
|
||||
|
||||
if(href_list["write"])
|
||||
if((usr.stat || usr.restrained())) //For when a player is handcuffed while they have the notice window open
|
||||
return
|
||||
var/obj/item/P = locate(href_list["write"]) in contents
|
||||
if(istype(P) && P.loc == src)
|
||||
var/obj/item/I = usr.is_holding_item_of_type(/obj/item/pen)
|
||||
if(I)
|
||||
add_fingerprint(usr)
|
||||
P.attackby(I, usr)
|
||||
var/mob/user = usr
|
||||
|
||||
switch(action)
|
||||
if("examine")
|
||||
if(istype(item, /obj/item/paper))
|
||||
item.ui_interact(user)
|
||||
else
|
||||
to_chat(usr, "<span class='notice'>You'll need something to write with!</span>")
|
||||
user.examinate(item)
|
||||
return TRUE
|
||||
if("remove")
|
||||
if(!allowed(user))
|
||||
return
|
||||
remove_item(item, user)
|
||||
return TRUE
|
||||
|
||||
if(href_list["read"])
|
||||
var/obj/item/I = locate(href_list["read"]) in contents
|
||||
if(istype(I) && I.loc == src)
|
||||
usr.examinate(I)
|
||||
/**
|
||||
* Removes an item from the notice board
|
||||
*
|
||||
* Arguments:
|
||||
* * item - The item that is to be removed
|
||||
* * user - The mob that is trying to get the item removed, if there is one
|
||||
*/
|
||||
/obj/structure/noticeboard/proc/remove_item(obj/item/item, mob/user)
|
||||
item.forceMove(drop_location())
|
||||
if(user)
|
||||
user.put_in_hands(item)
|
||||
balloon_alert(user, "removed from board")
|
||||
notices--
|
||||
icon_state = "nboard0[notices]"
|
||||
|
||||
/obj/structure/noticeboard/deconstruct(disassembled = TRUE)
|
||||
if(!(flags_1 & NODECONSTRUCT_1))
|
||||
new /obj/item/stack/sheet/metal (loc, 1)
|
||||
new /obj/item/stack/sheet/iron (loc, 1)
|
||||
for(var/obj/item/content in contents)
|
||||
remove_item(content)
|
||||
qdel(src)
|
||||
|
||||
// Notice boards for the heads of staff (plus the qm)
|
||||
@@ -131,3 +167,5 @@
|
||||
name = "Staff Notice Board"
|
||||
desc = "Important notices from the heads of staff."
|
||||
req_access = list(ACCESS_HEADS)
|
||||
|
||||
#undef MAX_NOTICES
|
||||
|
||||
Reference in New Issue
Block a user