diff --git a/code/__HELPERS/priority_announce.dm b/code/__HELPERS/priority_announce.dm index 374e89f715..1aaebc5f32 100644 --- a/code/__HELPERS/priority_announce.dm +++ b/code/__HELPERS/priority_announce.dm @@ -1,8 +1,10 @@ -/proc/priority_announce(text, title = "", sound = "attention", type , sender_override) +/proc/priority_announce(text, title = "", sound, type , sender_override, has_important_message) if(!text) return var/announcement + if(!sound) + sound = "attention" if(type == "Priority") announcement += "

Priority Announcement

" @@ -26,7 +28,11 @@ else GLOB.news_network.SubmitArticle(title + "

" + text, "Central Command", "Station Announcements", null) - announcement += "
[html_encode(text)]
" + ///If the announcer overrides alert messages, use that message. + // if(SSstation.announcer.custom_alert_message && !has_important_message) + // announcement += SSstation.announcer.custom_alert_message + // else + announcement += "
[span_alert("[html_encode(text)]")]
" announcement += "
" var/s = sound(get_announcer_sound(sound)) @@ -127,12 +133,44 @@ if("welcome") . = 'sound/announcer/medibot/welcome.ogg' +/** + * Summon the crew for an emergency meeting + * + * Teleports the crew to a specified area, and tells everyone (via an announcement) who called the meeting. Should only be used during april fools! + * Arguments: + * * user - Mob who called the meeting + * * button_zone - Area where the meeting was called and where everyone will get teleported to + */ +/proc/call_emergency_meeting(mob/living/user, area/button_zone) + var/meeting_sound = sound('sound/misc/emergency_meeting.ogg') + var/announcement + announcement += "

Captain Alert

" + announcement += "
[span_alert("[user] has called an Emergency Meeting!")]

" + + for(var/mob/mob_to_teleport in GLOB.player_list) //gotta make sure the whole crew's here! + if(isnewplayer(mob_to_teleport) || iscameramob(mob_to_teleport)) + continue + to_chat(mob_to_teleport, announcement) + SEND_SOUND(mob_to_teleport, meeting_sound) //no preferences here, you must hear the funny sound + mob_to_teleport.overlay_fullscreen("emergency_meeting", /atom/movable/screen/fullscreen/emergency_meeting, 1) + addtimer(CALLBACK(mob_to_teleport, /mob/.proc/clear_fullscreen, "emergency_meeting"), 3 SECONDS) + + if (is_station_level(mob_to_teleport.z)) //teleport the mob to the crew meeting + var/turf/target + var/list/turf_list = get_area_turfs(button_zone) + while (!target && turf_list.len) + target = pick_n_take(turf_list) + if (isclosedturf(target)) + target = null + continue + mob_to_teleport.forceMove(target) + /proc/print_command_report(text = "", title = null, announce=TRUE) if(!title) title = "Classified [command_name()] Update" if(announce) - priority_announce("A report has been downloaded and printed out at all communications consoles.", "Incoming Classified Message", "commandreport") + priority_announce("A report has been downloaded and printed out at all communications consoles.", "Incoming Classified Message", "commandreport", has_important_message = TRUE) var/datum/comm_message/M = new M.title = title @@ -140,13 +178,17 @@ SScommunications.send_message(M) -/proc/minor_announce(message, title = "Attention:", alert) +/proc/minor_announce(message, title = "Attention:", alert, html_encode = TRUE) if(!message) return + if (html_encode) + title = html_encode(title) + message = html_encode(message) + for(var/mob/M in GLOB.player_list) if(!isnewplayer(M) && M.can_hear()) - to_chat(M, "[html_encode(title)]
[html_encode(message)]

") + to_chat(M, "[span_minorannounce("[title]
[message]")]
") if(M.client.prefs.toggles & SOUND_ANNOUNCEMENTS) if(alert) SEND_SOUND(M, sound('sound/misc/notice1.ogg')) diff --git a/code/_onclick/hud/fullscreen.dm b/code/_onclick/hud/fullscreen.dm index a7247ccf09..81442b602f 100644 --- a/code/_onclick/hud/fullscreen.dm +++ b/code/_onclick/hud/fullscreen.dm @@ -82,6 +82,12 @@ severity = 0 . = ..() +/atom/movable/screen/fullscreen/emergency_meeting + icon_state = "emergency_meeting" + show_when_dead = TRUE + layer = CURSE_LAYER + plane = SPLASHSCREEN_PLANE + /atom/movable/screen/fullscreen/brute icon_state = "brutedamageoverlay" layer = UI_DAMAGE_LAYER diff --git a/code/controllers/subsystem/communications.dm b/code/controllers/subsystem/communications.dm index 718357b8bb..58a88890dd 100644 --- a/code/controllers/subsystem/communications.dm +++ b/code/controllers/subsystem/communications.dm @@ -1,33 +1,67 @@ -#define COMMUNICATION_COOLDOWN 300 -#define COMMUNICATION_COOLDOWN_AI 300 +#define COMMUNICATION_COOLDOWN (30 SECONDS) +#define COMMUNICATION_COOLDOWN_AI (30 SECONDS) +#define COMMUNICATION_COOLDOWN_MEETING (5 MINUTES) SUBSYSTEM_DEF(communications) name = "Communications" flags = SS_NO_INIT | SS_NO_FIRE - var/silicon_message_cooldown - var/nonsilicon_message_cooldown + COOLDOWN_DECLARE(silicon_message_cooldown) + COOLDOWN_DECLARE(nonsilicon_message_cooldown) + COOLDOWN_DECLARE(emergency_meeting_cooldown) /datum/controller/subsystem/communications/proc/can_announce(mob/living/user, is_silicon) - if(is_silicon && silicon_message_cooldown > world.time) - . = FALSE - else if(!is_silicon && nonsilicon_message_cooldown > world.time) - . = FALSE + if(is_silicon && COOLDOWN_FINISHED(src, silicon_message_cooldown)) + return TRUE + else if(!is_silicon && COOLDOWN_FINISHED(src, nonsilicon_message_cooldown)) + return TRUE else - . = TRUE + return FALSE /datum/controller/subsystem/communications/proc/make_announcement(mob/living/user, is_silicon, input) if(!can_announce(user, is_silicon)) return FALSE if(is_silicon) minor_announce(html_decode(input),"[user.name] Announces:") - silicon_message_cooldown = world.time + COMMUNICATION_COOLDOWN_AI + COOLDOWN_START(src, silicon_message_cooldown, COMMUNICATION_COOLDOWN_AI) else - priority_announce(html_decode(user.treat_message(input)), null, 'sound/misc/announce.ogg', "Captain") - nonsilicon_message_cooldown = world.time + COMMUNICATION_COOLDOWN + priority_announce(html_decode(user.treat_message(input)), null, 'sound/misc/announce.ogg', "Captain", has_important_message = TRUE) + COOLDOWN_START(src, nonsilicon_message_cooldown, COMMUNICATION_COOLDOWN) user.log_talk(input, LOG_SAY, tag="priority announcement") message_admins("[ADMIN_LOOKUPFLW(user)] has made a priority announcement.") +/** + * Check if a mob can call an emergency meeting + * + * Should only really happen during april fools. + * Checks to see that it's been at least 5 minutes since the last emergency meeting call. + * Arguments: + * * user - Mob who called the meeting + */ +/datum/controller/subsystem/communications/proc/can_make_emergency_meeting(mob/living/user) + if(!(SSevents.holidays && SSevents.holidays[APRIL_FOOLS])) + return FALSE + else if(COOLDOWN_FINISHED(src, emergency_meeting_cooldown)) + return TRUE + else + return FALSE + +/** + * Call an emergency meeting + * + * Communications subsystem wrapper for the call_emergency_meeting world proc. + * Checks to make sure the proc can be called, and handles + * relevant logging and timing. See that proc definition for more detail. + * Arguments: + * * user - Mob who called the meeting + */ +/datum/controller/subsystem/communications/proc/emergency_meeting(mob/living/user) + if(!can_make_emergency_meeting(user)) + return FALSE + call_emergency_meeting(user, get_area(user)) + COOLDOWN_START(src, emergency_meeting_cooldown, COMMUNICATION_COOLDOWN_MEETING) + message_admins("[ADMIN_LOOKUPFLW(user)] has called an emergency meeting.") + /datum/controller/subsystem/communications/proc/send_message(datum/comm_message/sending,print = TRUE,unique = FALSE) for(var/obj/machinery/computer/communications/C in GLOB.machines) if(!(C.stat & (BROKEN|NOPOWER)) && is_station_level(C.z)) @@ -40,7 +74,7 @@ SUBSYSTEM_DEF(communications) var/obj/item/paper/P = new /obj/item/paper(C.loc) P.name = "paper - '[sending.title]'" P.info = sending.content - P.update_icon() + P.update_appearance() #undef COMMUNICATION_COOLDOWN #undef COMMUNICATION_COOLDOWN_AI diff --git a/code/datums/mind.dm b/code/datums/mind.dm index b33f7532df..73e3a65145 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -272,7 +272,6 @@ * * A mind proc for giving anyone an uplink. * arguments: - * * traitor_class: (cit specific) the type of antag the user is. * * silent: if this should send a message to the mind getting the uplink. traitors do not use this silence, but the silence var on their antag datum. * * antag_datum: the antag datum of the uplink owner, for storing it in antag memory. optional! */ diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm index e05991dd8a..0c9c6f0321 100644 --- a/code/game/machinery/_machinery.dm +++ b/code/game/machinery/_machinery.dm @@ -247,61 +247,94 @@ Class Procs: /obj/machinery/proc/auto_use_power() if(!powered(power_channel)) - return 0 + return FALSE if(use_power == 1) use_power(idle_power_usage,power_channel) else if(use_power >= 2) use_power(active_power_usage,power_channel) - return 1 + return TRUE /obj/machinery/proc/is_operational() return !(stat & (NOPOWER|BROKEN|MAINT)) /obj/machinery/can_interact(mob/user) - var/silicon = hasSiliconAccessInArea(user) || IsAdminGhost(user) - if((stat & (NOPOWER|BROKEN)) && !(interaction_flags_machine & INTERACT_MACHINE_OFFLINE)) + if((stat & (NOPOWER|BROKEN)) && !(interaction_flags_machine & INTERACT_MACHINE_OFFLINE)) // Check if the machine is broken, and if we can still interact with it if so return FALSE - if(panel_open && !(interaction_flags_machine & INTERACT_MACHINE_OPEN)) - if(!silicon || !(interaction_flags_machine & INTERACT_MACHINE_OPEN_SILICON)) - return FALSE - if(silicon) + if(IsAdminGhost(user)) + return TRUE //if you're an admin, you probably know what you're doing (or at least have permission to do what you're doing) + + if(!isliving(user)) + return FALSE //no ghosts in the machine allowed, sorry + + // if(SEND_SIGNAL(user, COMSIG_TRY_USE_MACHINE, src) & COMPONENT_CANT_USE_MACHINE_INTERACT) + // return FALSE + + var/mob/living/living_user = user + + var/is_dextrous = FALSE + if(isanimal(user)) + var/mob/living/simple_animal/user_as_animal = user + if (user_as_animal.dextrous) + is_dextrous = TRUE + + if(!issilicon(user) && !is_dextrous && !user.can_hold_items()) + return FALSE //spiders gtfo + + if(issilicon(user)) // If we are a silicon, make sure the machine allows silicons to interact with it if(!(interaction_flags_machine & INTERACT_MACHINE_ALLOW_SILICON)) return FALSE - else - if(interaction_flags_machine & INTERACT_MACHINE_REQUIRES_SILICON) + + if(panel_open && !(interaction_flags_machine & INTERACT_MACHINE_OPEN) && !(interaction_flags_machine & INTERACT_MACHINE_OPEN_SILICON)) return FALSE - if(!Adjacent(user)) - var/mob/living/carbon/H = user - if(!(istype(H) && H.has_dna() && H.dna.check_mutation(TK))) - return FALSE - return TRUE + + return TRUE //silicons don't care about petty mortal concerns like needing to be next to a machine to use it + + if(living_user.incapacitated()) //idk why silicons aren't supposed to care about incapacitation when interacting with machines, but it was apparently like this before + return FALSE + + // TODO: nerf blind people + // if((interaction_flags_machine & INTERACT_MACHINE_REQUIRES_SIGHT) && user.is_blind()) + // to_chat(user, span_warning("This machine requires sight to use.")) + // return FALSE + + if(panel_open && !(interaction_flags_machine & INTERACT_MACHINE_OPEN)) + return FALSE + + if(interaction_flags_machine & INTERACT_MACHINE_REQUIRES_SILICON) //if the user was a silicon, we'd have returned out earlier, so the user must not be a silicon + return FALSE + + if(!Adjacent(user)) // Next make sure we are next to the machine unless we have telekinesis + var/mob/living/carbon/carbon_user = living_user + if(!istype(carbon_user) || !carbon_user.has_dna() || !carbon_user.dna.check_mutation(TK)) + return FALSE + + return TRUE // If we passed all of those checks, woohoo! We can interact with this machine. /obj/machinery/proc/check_nap_violations() if(!SSeconomy.full_ancap) return TRUE if(occupant && !state_open) - if(ishuman(occupant)) - var/mob/living/carbon/human/H = occupant - var/obj/item/card/id/I = H.get_idcard() - if(I) - var/datum/bank_account/insurance = I.registered_account - if(!insurance) - say("[market_verb] NAP Violation: No bank account found.") - nap_violation() - return FALSE - else - if(!insurance.adjust_money(-fair_market_price)) - say("[market_verb] NAP Violation: Unable to pay.") - nap_violation() - return FALSE - var/datum/bank_account/D = SSeconomy.get_dep_account(payment_department) - if(D) - D.adjust_money(fair_market_price) - else - say("[market_verb] NAP Violation: No ID card found.") - nap_violation() + var/mob/living/L = occupant + var/obj/item/card/id/I = L.get_idcard(TRUE) + if(I) + var/datum/bank_account/insurance = I.registered_account + if(!insurance) + say("[market_verb] NAP Violation: No bank account found.") + nap_violation(L) return FALSE + else + if(!insurance.adjust_money(-fair_market_price)) + say("[market_verb] NAP Violation: Unable to pay.") + nap_violation(L) + return FALSE + var/datum/bank_account/D = SSeconomy.get_dep_account(payment_department) + if(D) + D.adjust_money(fair_market_price) + else + say("[market_verb] NAP Violation: No ID card found.") + nap_violation(L) + return FALSE return TRUE /obj/machinery/proc/nap_violation(mob/violator) @@ -322,11 +355,11 @@ Class Procs: /obj/machinery/Topic(href, href_list) ..() if(!can_interact(usr)) - return 1 + return TRUE if(!usr.canUseTopic(src)) - return 1 + return TRUE add_fingerprint(usr) - return 0 + return FALSE //////////////////////////////////////////////////////////////////////////////////////////// diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm index 5dcbd9430b..b81507024c 100755 --- a/code/game/machinery/computer/communications.dm +++ b/code/game/machinery/computer/communications.dm @@ -173,7 +173,7 @@ return if (!authenticated_as_silicon_or_captain(usr)) return - // emergency_meeting(usr) + emergency_meeting(usr) if ("makePriorityAnnouncement") if (!authenticated_as_silicon_or_captain(usr)) return @@ -531,11 +531,11 @@ * * 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) + 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) diff --git a/code/game/objects/structures/manned_turret.dm b/code/game/objects/structures/manned_turret.dm index 3d0b28d2f3..cdbf19367b 100644 --- a/code/game/objects/structures/manned_turret.dm +++ b/code/game/objects/structures/manned_turret.dm @@ -25,7 +25,7 @@ /obj/machinery/manned_turret/Destroy() target = null target_turf = null - ..() + return ..() //BUCKLE HOOKS diff --git a/code/game/turfs/open/floor/catwalk_plating.dm b/code/game/turfs/open/floor/catwalk_plating.dm index c6bfdc0448..cbcbade5d4 100644 --- a/code/game/turfs/open/floor/catwalk_plating.dm +++ b/code/game/turfs/open/floor/catwalk_plating.dm @@ -34,11 +34,11 @@ /turf/open/floor/plating/catwalk_floor/screwdriver_act(mob/living/user, obj/item/tool) . = ..() covered = !covered - to_chat(user, span_notice("[!covered ? "You removed the cover!" : "You added the cover!"]")) + user.balloon_alert(user, "[!covered ? "cover removed" : "cover added"]") update_icon(UPDATE_OVERLAYS) /turf/open/floor/plating/catwalk_floor/pry_tile(obj/item/crowbar, mob/user, silent) if(covered) - to_chat(user, span_notice("You need to remove the cover first!")) + user.balloon_alert(user, "remove cover first!") return FALSE . = ..() diff --git a/code/modules/antagonists/clockcult/clock_items/clockwork_slab.dm b/code/modules/antagonists/clockcult/clock_items/clockwork_slab.dm index 8060b7b0cd..d5c9b2cd2f 100644 --- a/code/modules/antagonists/clockcult/clock_items/clockwork_slab.dm +++ b/code/modules/antagonists/clockcult/clock_items/clockwork_slab.dm @@ -264,7 +264,9 @@ ui.open() /obj/item/clockwork/slab/ui_data(mob/user) //we display a lot of data via TGUI - . = list() + . = ..() + if(!.) + return .["recollection"] = recollecting .["power"] = DisplayPower(get_clockwork_power()) .["power_unformatted"] = get_clockwork_power() @@ -275,6 +277,7 @@ if(S.tier == SCRIPTURE_PERIPHERAL) // This tier is skiped because this contains basetype stuff continue + // FUTURE IMPL: cache these perhaps? var/list/data = list() data["name"] = S.name data["descname"] = S.descname diff --git a/code/modules/antagonists/clockcult/clockcult.dm b/code/modules/antagonists/clockcult/clockcult.dm index de34b031d9..ab1a5543d8 100644 --- a/code/modules/antagonists/clockcult/clockcult.dm +++ b/code/modules/antagonists/clockcult/clockcult.dm @@ -15,11 +15,11 @@ var/ignore_eligibility_check = FALSE var/ignore_holy_water = FALSE -/datum/antagonist/brainwashed/ui_static_data(mob/user) +/datum/antagonist/clockcult/ui_data(mob/user) . = ..() - var/list/data = list() - data["objectives"] = get_objectives() - return data + if(!.) + return + .["HONOR_RATVAR"] = GLOB.ratvar_awakens /datum/antagonist/clockcult/silent name = "Silent Clock Cultist" @@ -66,14 +66,6 @@ if(. && !ignore_eligibility_check) . = is_eligible_servant(new_owner.current) -/datum/antagonist/clockcult/greet() - if(!owner.current || silent) - return - owner.current.visible_message("[owner.current]'s eyes glow a blazing yellow!", null, null, 7, owner.current) //don't show the owner this message - to_chat(owner.current, "Assist your new companions in their righteous efforts. Your goal is theirs, and theirs yours. You serve the Clockwork \ - Justiciar above all else. Perform his every whim without hesitation.") - owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/clockcultalr.ogg', 70, FALSE, pressure_affected = FALSE) - /datum/antagonist/clockcult/on_gain() var/mob/living/current = owner.current SSticker.mode.servants_of_ratvar += owner diff --git a/code/modules/atmospherics/machinery/components/binary_devices/passive_gate.dm b/code/modules/atmospherics/machinery/components/binary_devices/passive_gate.dm index 56a7d78288..ac8ed537b5 100644 --- a/code/modules/atmospherics/machinery/components/binary_devices/passive_gate.dm +++ b/code/modules/atmospherics/machinery/components/binary_devices/passive_gate.dm @@ -29,13 +29,16 @@ Passive gate is similar to the regular pump except: /obj/machinery/atmospherics/components/binary/passive_gate/CtrlClick(mob/user) if(can_interact(user)) on = !on + investigate_log("was turned [on ? "on" : "off"] by [key_name(user)]", INVESTIGATE_ATMOS) update_icon() return ..() /obj/machinery/atmospherics/components/binary/passive_gate/AltClick(mob/user) if(can_interact(user)) target_pressure = MAX_OUTPUT_PRESSURE - update_icon() + investigate_log("was set to [target_pressure] kPa by [key_name(user)]", INVESTIGATE_ATMOS) + balloon_alert(user, "pressure output set to [target_pressure] kPa") + update_appearance() return ..() /obj/machinery/atmospherics/components/binary/passive_gate/Destroy() diff --git a/code/modules/atmospherics/machinery/components/binary_devices/pump.dm b/code/modules/atmospherics/machinery/components/binary_devices/pump.dm index dc5a6eccd4..a8d82282d6 100644 --- a/code/modules/atmospherics/machinery/components/binary_devices/pump.dm +++ b/code/modules/atmospherics/machinery/components/binary_devices/pump.dm @@ -33,25 +33,19 @@ . += "You can hold Alt and click on it to maximize its pressure." /obj/machinery/atmospherics/components/binary/pump/CtrlClick(mob/user) - var/area/A = get_area(src) - var/turf/T = get_turf(src) - if(user.canUseTopic(src, BE_CLOSE, FALSE,)) + if(can_interact(user)) on = !on - update_icon() - investigate_log("Pump, [src.name], turned on by [key_name(usr)] at [x], [y], [z], [A]", INVESTIGATE_ATMOS) - message_admins("Pump, [src.name], turned [on ? "on" : "off"] by [ADMIN_LOOKUPFLW(usr)] at [ADMIN_COORDJMP(T)], [A]") - return ..() + investigate_log("was turned [on ? "on" : "off"] by [key_name(user)]", INVESTIGATE_ATMOS) + update_appearance() + return ..() /obj/machinery/atmospherics/components/binary/pump/AltClick(mob/user) - . = ..() - var/area/A = get_area(src) - var/turf/T = get_turf(src) - if(user.canUseTopic(src, BE_CLOSE, FALSE,)) + if(can_interact(user)) target_pressure = MAX_OUTPUT_PRESSURE - to_chat(user,"You maximize the pressure on the [src].") - investigate_log("Pump, [src.name], was maximized by [key_name(usr)] at [x], [y], [z], [A]", INVESTIGATE_ATMOS) - message_admins("Pump, [src.name], was maximized by [ADMIN_LOOKUPFLW(usr)] at [ADMIN_COORDJMP(T)], [A]") - return TRUE + investigate_log("was set to [target_pressure] kPa by [key_name(user)]", INVESTIGATE_ATMOS) + balloon_alert(user, "pressure output set to [target_pressure] kPa") + update_appearance() + return ..() /obj/machinery/atmospherics/components/binary/pump/Destroy() SSradio.remove_object(src,frequency) diff --git a/code/modules/atmospherics/machinery/components/binary_devices/volume_pump.dm b/code/modules/atmospherics/machinery/components/binary_devices/volume_pump.dm index 46d584339b..f5f0064558 100644 --- a/code/modules/atmospherics/machinery/components/binary_devices/volume_pump.dm +++ b/code/modules/atmospherics/machinery/components/binary_devices/volume_pump.dm @@ -33,15 +33,20 @@ . += "You can hold Alt and click on it to maximize its pressure." /obj/machinery/atmospherics/components/binary/volume_pump/CtrlClick(mob/user) - var/area/A = get_area(src) - var/turf/T = get_turf(src) if(user.canUseTopic(src, BE_CLOSE, FALSE,)) on = !on - update_icon() - investigate_log("Volume Pump, [src.name], turned on by [key_name(usr)] at [x], [y], [z], [A]", INVESTIGATE_ATMOS) - message_admins("Volume Pump, [src.name], turned [on ? "on" : "off"] by [ADMIN_LOOKUPFLW(usr)] at [ADMIN_COORDJMP(T)], [A]") + investigate_log("was turned [on ? "on" : "off"] by [key_name(user)]", INVESTIGATE_ATMOS) + update_appearance() return ..() +/obj/machinery/atmospherics/components/binary/volume_pump/AltClick(mob/user) + if(can_interact(user)) + transfer_rate = MAX_TRANSFER_RATE + investigate_log("was set to [transfer_rate] L/s by [key_name(user)]", INVESTIGATE_ATMOS) + balloon_alert(user, "volume output set to [transfer_rate] L/s") + update_appearance() + return ..() + /obj/machinery/atmospherics/components/binary/volume_pump/Destroy() SSradio.remove_object(src,frequency) return ..() diff --git a/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm b/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm index 4182f5ceca..0814b46993 100644 --- a/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm +++ b/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm @@ -20,25 +20,19 @@ . += "You can hold Alt and click on it to maximize its flow rate." /obj/machinery/atmospherics/components/trinary/filter/CtrlClick(mob/user) - var/area/A = get_area(src) - var/turf/T = get_turf(src) if(user.canUseTopic(src, BE_CLOSE, FALSE,)) on = !on - update_icon() - investigate_log("Filter, [src.name], turned on by [key_name(usr)] at [x], [y], [z], [A]", INVESTIGATE_ATMOS) - message_admins("Filter, [src.name], turned [on ? "on" : "off"] by [ADMIN_LOOKUPFLW(usr)] at [ADMIN_COORDJMP(T)], [A]") + investigate_log("was turned [on ? "on" : "off"] by [key_name(user)]", INVESTIGATE_ATMOS) + update_appearance() return ..() /obj/machinery/atmospherics/components/trinary/filter/AltClick(mob/user) - . = ..() - var/area/A = get_area(src) - var/turf/T = get_turf(src) - if(user.canUseTopic(src, BE_CLOSE, FALSE,)) + if(can_interact(user)) transfer_rate = MAX_TRANSFER_RATE - to_chat(user,"You maximize the flow rate on the [src].") - investigate_log("Filter, [src.name], was maximized by [key_name(usr)] at [x], [y], [z], [A]", INVESTIGATE_ATMOS) - message_admins("Filter, [src.name], was maximized by [ADMIN_LOOKUPFLW(usr)] at [ADMIN_COORDJMP(T)], [A]") - return TRUE + investigate_log("was set to [transfer_rate] L/s by [key_name(user)]", INVESTIGATE_ATMOS) + balloon_alert(user, "volume output set to [transfer_rate] L/s") + update_appearance() + return ..() /obj/machinery/atmospherics/components/trinary/filter/proc/set_frequency(new_frequency) SSradio.remove_object(src, frequency) diff --git a/code/modules/atmospherics/machinery/components/trinary_devices/mixer.dm b/code/modules/atmospherics/machinery/components/trinary_devices/mixer.dm index 3296981e5e..49d6a71f78 100644 --- a/code/modules/atmospherics/machinery/components/trinary_devices/mixer.dm +++ b/code/modules/atmospherics/machinery/components/trinary_devices/mixer.dm @@ -17,35 +17,27 @@ //node 3 is the outlet, nodes 1 & 2 are intakes /obj/machinery/atmospherics/components/trinary/mixer/CtrlClick(mob/user) - if(user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK)) + if(can_interact(user)) on = !on - update_icon() + investigate_log("was turned [on ? "on" : "off"] by [key_name(user)]", INVESTIGATE_ATMOS) + update_appearance() return ..() /obj/machinery/atmospherics/components/trinary/mixer/AltClick(mob/user) - if(user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK)) + if(can_interact(user)) target_pressure = MAX_OUTPUT_PRESSURE - update_icon() + investigate_log("was set to [target_pressure] kPa by [key_name(user)]", INVESTIGATE_ATMOS) + balloon_alert(user, "pressure output on set to [target_pressure] kPa") + update_appearance() return ..() - //node 3 is the outlet, nodes 1 & 2 are intakes - -/obj/machinery/atmospherics/components/trinary/mixer/update_icon() - cut_overlays() +/obj/machinery/atmospherics/components/trinary/mixer/update_overlays() + . = ..() for(var/direction in GLOB.cardinals) if(!(direction & initialize_directions)) continue - var/obj/machinery/atmospherics/node = findConnecting(direction) - var/image/cap - if(node) - cap = getpipeimage(icon, "cap", direction, node.pipe_color, piping_layer = piping_layer) - else - cap = getpipeimage(icon, "cap", direction, piping_layer = piping_layer) - - add_overlay(cap) - - return ..() + . += getpipeimage(icon, "cap", direction, pipe_color, piping_layer, TRUE) /obj/machinery/atmospherics/components/trinary/mixer/update_icon_nopipes() var/on_state = on && nodes[1] && nodes[2] && nodes[3] && is_operational() diff --git a/code/modules/atmospherics/machinery/components/unary_devices/outlet_injector.dm b/code/modules/atmospherics/machinery/components/unary_devices/outlet_injector.dm index b2fa26edba..c1990a0ffe 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/outlet_injector.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/outlet_injector.dm @@ -24,13 +24,16 @@ /obj/machinery/atmospherics/components/unary/outlet_injector/CtrlClick(mob/user) if(can_interact(user)) on = !on - update_icon() + investigate_log("was turned [on ? "on" : "off"] by [key_name(user)]", INVESTIGATE_ATMOS) + update_appearance() return ..() /obj/machinery/atmospherics/components/unary/outlet_injector/AltClick(mob/user) if(can_interact(user)) volume_rate = MAX_TRANSFER_RATE - update_icon() + investigate_log("was set to [volume_rate] L/s by [key_name(user)]", INVESTIGATE_ATMOS) + balloon_alert(user, "volume output set to [volume_rate] L/s") + update_appearance() return ..() /obj/machinery/atmospherics/components/unary/outlet_injector/Destroy() diff --git a/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm b/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm index 8456c0b346..257e312701 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm @@ -217,16 +217,11 @@ min_temperature = max(T0C - (initial(min_temperature) + L * 15), TCMB) //73.15K with T1 stock parts /obj/machinery/atmospherics/components/unary/thermomachine/freezer/AltClick(mob/living/user) - . = ..() - var/area/A = get_area(src) - var/turf/T = get_turf(src) - if(!istype(user) || !user.canUseTopic(src, BE_CLOSE)) + if(!can_interact(user)) return target_temperature = min_temperature - to_chat(user,"You minimize the temperature on the [src].") - investigate_log("was set to [target_temperature] K by [key_name(usr)]", INVESTIGATE_ATMOS) - message_admins("[src.name] was minimized by [ADMIN_LOOKUPFLW(usr)] at [ADMIN_COORDJMP(T)], [A]") - return TRUE + investigate_log("was set to [target_temperature] K by [key_name(user)]", INVESTIGATE_ATMOS) + balloon_alert(user, "temperature reset to [target_temperature] K") /obj/machinery/atmospherics/components/unary/thermomachine/heater name = "heater" diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm index 04b643e532..ccca7c93cb 100644 --- a/code/modules/client/client_procs.dm +++ b/code/modules/client/client_procs.dm @@ -79,15 +79,16 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( // Tgui Topic middleware if(tgui_Topic(href_list)) - if(CONFIG_GET(flag/emergency_tgui_logging)) - log_href("[src] (usr:[usr]\[[COORD(usr)]\]) : [hsrc ? "[hsrc] " : ""][href]") return + if(href_list["reload_tguipanel"]) + nuke_chat() + if(href_list["reload_statbrowser"]) + src << browse(file('html/statbrowser.html'), "window=statbrowser") + // Log all hrefs + log_href("[src] (usr:[usr]\[[COORD(usr)]\]) : [hsrc ? "[hsrc] " : ""][href]") last_activity = world.time - //Logs all hrefs - log_href("[src] (usr:[usr]\[[COORD(usr)]\]) : [hsrc ? "[hsrc] " : ""][href]") - //byond bug ID:2256651 if (asset_cache_job && (asset_cache_job in completed_asset_jobs)) to_chat(src, "An error has been detected in how your client is receiving resources. Attempting to correct.... (If you keep seeing these messages you might want to close byond and reconnect)") @@ -353,13 +354,19 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( return // Initialize tgui panel - tgui_panel.initialize() src << browse(file('html/statbrowser.html'), "window=statbrowser") + addtimer(CALLBACK(src, .proc/check_panel_loaded), 30 SECONDS) + tgui_panel.initialize() - - if(alert_mob_dupe_login) - spawn() - alert(mob, "You have logged in already with another key this round, please log out of this one NOW or risk being banned!") + if(alert_mob_dupe_login && !holder) + var/dupe_login_message = "Your ComputerID has already logged in with another key this round, please log out of this one NOW or risk being banned!" + // if (alert_admin_multikey) + // dupe_login_message += "\nAdmins have been informed." + // message_admins(span_danger("MULTIKEYING: [key_name_admin(src)] has a matching CID+IP with another player and is clearly multikeying. They have been warned to leave the server or risk getting banned.")) + // log_admin_private("MULTIKEYING: [key_name(src)] has a matching CID+IP with another player and is clearly multikeying. They have been warned to leave the server or risk getting banned.") + spawn(0.5 SECONDS) //needs to run during world init, do not convert to add timer + alert(mob, dupe_login_message) //players get banned if they don't see this message, do not convert to tgui_alert (or even tg_alert) please. + to_chat(mob, span_danger(dupe_login_message)) connection_time = world.time connection_realtime = world.realtime @@ -1031,18 +1038,27 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( if(prefs && prefs.chat_toggles & CHAT_PULLR) to_chat(src, announcement) -/client/proc/show_character_previews(mutable_appearance/MA) +/client/proc/show_character_previews(mutable_appearance/source) + LAZYINITLIST(char_render_holders) + if(!LAZYLEN(char_render_holders)) + for(var/plane_master_path as anything in subtypesof(/atom/movable/screen/plane_master)) + var/atom/movable/screen/plane_master/plane_master = new plane_master_path() + char_render_holders["plane_master-[plane_master.plane]"] = plane_master + plane_master.backdrop(mob) + screen |= plane_master + plane_master.screen_loc = "character_preview_map:0,CENTER" + var/pos = 0 - for(var/D in GLOB.cardinals) + for(var/dir in GLOB.cardinals) pos++ - var/atom/movable/screen/O = LAZYACCESS(char_render_holders, "[D]") - if(!O) - O = new - LAZYSET(char_render_holders, "[D]", O) - screen |= O - O.appearance = MA - O.dir = D - O.screen_loc = "character_preview_map:0,[pos]" + var/atom/movable/screen/preview = char_render_holders["preview-[dir]"] + if(!preview) + preview = new + char_render_holders["preview-[dir]"] = preview + screen |= preview + preview.appearance = source + preview.dir = dir + preview.screen_loc = "character_preview_map:0,[pos]" /client/proc/clear_character_previews() for(var/index in char_render_holders) @@ -1078,8 +1094,14 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( if(IsAdminAdvancedProcCall()) return var/list/verblist = list() - verb_tabs.Cut() - for(var/thing in (verbs + mob?.verbs)) + var/list/verbstoprocess = verbs.Copy() + if(mob) + verbstoprocess += mob.verbs + for(var/AM in mob.contents) + var/atom/movable/thing = AM + verbstoprocess += thing.verbs + panel_tabs.Cut() // panel_tabs get reset in init_verbs on JS side anyway + for(var/thing in verbstoprocess) var/procpath/verb_to_init = thing if(!verb_to_init) continue @@ -1087,9 +1109,14 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( continue if(!istext(verb_to_init.category)) continue - verb_tabs |= verb_to_init.category + panel_tabs |= verb_to_init.category verblist[++verblist.len] = list(verb_to_init.category, verb_to_init.name) - src << output("[url_encode(json_encode(verb_tabs))];[url_encode(json_encode(verblist))]", "statbrowser:init_verbs") + src << output("[url_encode(json_encode(panel_tabs))];[url_encode(json_encode(verblist))]", "statbrowser:init_verbs") + +/client/proc/check_panel_loaded() + if(statbrowser_ready) + return + to_chat(src, span_userdanger("Statpanel failed to load, click here to reload the panel ")) //increment progress for an unlockable loadout item /client/proc/increment_progress(key, amount) diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm index 2e530226c8..a3c6294aec 100644 --- a/code/modules/mob/living/carbon/human/human_helpers.dm +++ b/code/modules/mob/living/carbon/human/human_helpers.dm @@ -115,13 +115,13 @@ . = ..() if(!.) return - if(HAS_TRAIT(src, TRAIT_NOGUNS)) - to_chat(src, "You can't bring yourself to use a ranged weapon!") - return FALSE if(G.trigger_guard == TRIGGER_GUARD_NORMAL) if(HAS_TRAIT(src, TRAIT_CHUNKYFINGERS)) - to_chat(src, "Your meaty finger is much too large for the trigger guard!") + balloon_alert(src, "fingers are too big!") return FALSE + if(HAS_TRAIT(src, TRAIT_NOGUNS)) + to_chat(src, span_warning("You can't bring yourself to use a ranged weapon!")) + return FALSE /mob/living/carbon/human/proc/get_bank_account() RETURN_TYPE(/datum/bank_account) diff --git a/icons/mob/screen_full.dmi b/icons/mob/screen_full.dmi index 502e9ad3f9..975cbf3fe4 100644 Binary files a/icons/mob/screen_full.dmi and b/icons/mob/screen_full.dmi differ diff --git a/sound/misc/emergency_meeting.ogg b/sound/misc/emergency_meeting.ogg new file mode 100644 index 0000000000..ad27236ef0 Binary files /dev/null and b/sound/misc/emergency_meeting.ogg differ diff --git a/sound/misc/license.txt b/sound/misc/license.txt new file mode 100644 index 0000000000..b92a4a279a --- /dev/null +++ b/sound/misc/license.txt @@ -0,0 +1,5 @@ +bloop.ogg by my man Tim Khan +(https://freesound.org/people/tim.kahn/sounds/130377/) + +knuckles.ogg by CGEffex. Shortened and cut. +https://freesound.org/people/CGEffex/sounds/93981/ \ No newline at end of file diff --git a/tgui/packages/tgui/interfaces/AntagInfoClockwork.tsx b/tgui/packages/tgui/interfaces/AntagInfoClockwork.tsx index 35039ca595..2d03d8f74d 100644 --- a/tgui/packages/tgui/interfaces/AntagInfoClockwork.tsx +++ b/tgui/packages/tgui/interfaces/AntagInfoClockwork.tsx @@ -1,17 +1,10 @@ import { BooleanLike } from 'common/react'; -import { useBackend, useLocalState } from '../backend'; -import { BlockQuote, Button, Dimmer, Section, Stack } from '../components'; +import { useBackend } from '../backend'; +import { Section, Stack } from '../components'; import { Window } from '../layouts'; -interface Objective { - count: number; - name: string; - explanation: string; -} - interface Info { HONOR_RATVAR: BooleanLike; - objectives: Objective[]; } let REC_RATVAR = ""; @@ -79,30 +72,3 @@ export const AntagInfoClockwork = (props, context) => { ); }; - -const ObjectivePrintout = (props, context) => { - const { data } = useBackend(context); - const { - objectives, - } = data; - return ( - - - Your current objectives: - - - {!objectives && "None!" - || objectives.map((objective: Objective) => ( - <> - - #{objective.count}: {objective.explanation} - - - This Directive must be followed. - - - )) } - - - ); -}; diff --git a/tgui/packages/tgui/styles/themes/clockcult.scss b/tgui/packages/tgui/styles/themes/clockcult.scss index 36a0149fbe..7888b3aee2 100644 --- a/tgui/packages/tgui/styles/themes/clockcult.scss +++ b/tgui/packages/tgui/styles/themes/clockcult.scss @@ -6,6 +6,12 @@ @use 'sass:color'; @use 'sass:meta'; + +@use '../base.scss' with ( + $color-bg: #c9b12a, + $color-bg-grad-spread: 6%, + $border-radius: 2px, +); @use '../colors.scss' with ( $primary: #B18B25, $good: #CFBA47, @@ -14,16 +20,8 @@ $fg-map-keys: (), $bg-map-keys: (), ); -@use '../base.scss' with ( - $color-bg: #c9b12a, - $color-bg-grad-spread: 6%, - $border-radius: 2px, -); .theme-clockcult { - // Atomic classes - @include meta.load-css('../atomic/color.scss'); - // Components @include meta.load-css('../components/Button.scss', $with: ( 'color-default': #5F380E, //wrong.