diff --git a/code/__DEFINES/dcs/signals/signals_global.dm b/code/__DEFINES/dcs/signals/signals_global.dm index f975a67824ef..306f37deb8cb 100644 --- a/code/__DEFINES/dcs/signals/signals_global.dm +++ b/code/__DEFINES/dcs/signals/signals_global.dm @@ -69,6 +69,9 @@ /// From /proc/biohazard_lockdown() #define COMSIG_GLOB_RESEARCH_LOCKDOWN "!research_lockdown_closed" #define COMSIG_GLOB_RESEARCH_LIFT "!research_lockdown_opened" +/// From /proc/aicore_lockdown() +#define COMSIG_GLOB_AICORE_LOCKDOWN "!aicore_lockdown_closed" +#define COMSIG_GLOB_AICORE_LIFT "!aicore_lockdown_opened" /// From /obj/structure/machinery/power/reactor/proc/set_overloading() : (set_overloading) #define COMSIG_GLOB_GENERATOR_SET_OVERLOADING "!generator_set_overloading" diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm index e2bd868f9a80..dbd8dbe7ce41 100644 --- a/code/__DEFINES/mobs.dm +++ b/code/__DEFINES/mobs.dm @@ -120,6 +120,7 @@ #define CANDAZE (1<<18) #define CANSLOW (1<<19) #define NO_PERMANENT_DAMAGE (1<<20) +#define CORRUPTED_ALLY (1<<21) // ============================= // hive types diff --git a/code/datums/mob_hud.dm b/code/datums/mob_hud.dm index 5e57b8f5616c..88785474bc23 100644 --- a/code/datums/mob_hud.dm +++ b/code/datums/mob_hud.dm @@ -422,6 +422,10 @@ GLOBAL_LIST_INIT_TYPED(huds, /datum/mob_hud, list( if(hive && hive.color) holder3.color = hive.color + if(status_flags & CORRUPTED_ALLY) + holder4.color = "#80ff80" + holder4.icon_state = "hudalien_ally" + if(stat == DEAD || status_flags & FAKEDEATH) if(revive_enabled) if(!client) diff --git a/code/defines/procs/announcement.dm b/code/defines/procs/announcement.dm index 2ebba6a774e8..d6251748f3a0 100644 --- a/code/defines/procs/announcement.dm +++ b/code/defines/procs/announcement.dm @@ -42,6 +42,11 @@ continue if(is_mainship_level(H.z)) // People on ship see everything continue + + // If they have iff AND a marine headset they will recieve announcements + if ((FACTION_MARINE in H.wear_id?.faction_group) && (istype(H.wear_l_ear, /obj/item/device/radio/headset/almayer) || istype(H.wear_r_ear, /obj/item/device/radio/headset/almayer))) + continue + if((H.faction != faction_to_display && !add_PMCs) || (H.faction != faction_to_display && add_PMCs && !(H.faction in FACTION_LIST_WY)) && !(faction_to_display in H.faction_group)) //faction checks targets.Remove(H) diff --git a/code/game/cas_manager/datums/cas_fire_envelope.dm b/code/game/cas_manager/datums/cas_fire_envelope.dm index cc38b034c764..864d7f23a3e8 100644 --- a/code/game/cas_manager/datums/cas_fire_envelope.dm +++ b/code/game/cas_manager/datums/cas_fire_envelope.dm @@ -3,7 +3,10 @@ var/list/datum/cas_fire_mission/missions var/fire_length var/grace_period //how much time you have after initiating fire mission and before you can't change firemissions - var/flyto_period //how much time it takes from sound alarm start to first hit. CAS is vulnerable here + var/first_warning + var/second_warning + var/third_warning + var/execution_start var/flyoff_period //how much time it takes after shots fired to get off the map. CAS is vulnerable here var/cooldown_period //how much time you have to wait before new Fire Mission run var/soundeffect //what sound effect to play @@ -36,10 +39,6 @@ for(var/datum/cas_fire_mission/mission in missions) .["missions"] += list(mission.ui_data(user)) - -/datum/cas_fire_envelope/proc/get_total_duration() - return grace_period+flyto_period+flyoff_period - /datum/cas_fire_envelope/proc/update_weapons(list/obj/structure/dropship_equipment/weapon/weapons) for(var/datum/cas_fire_mission/mission in missions) mission.update_weapons(weapons, fire_length) @@ -242,14 +241,60 @@ /datum/cas_fire_envelope/proc/check_firemission_loc(datum/cas_signal/target_turf) return TRUE //redefined in child class -/** - * Execute firemission. - */ +/// Step 1: Sets the stat to FIRE_MISSION_STATE_ON_TARGET and starts the sound effect for the fire mission. +/datum/cas_fire_envelope/proc/play_sound(atom/target_turf) + stat = FIRE_MISSION_STATE_ON_TARGET + change_current_loc(target_turf) + playsound(target_turf, soundeffect, vol = 70, vary = TRUE, sound_range = 50, falloff = 8) + +/// Step 2, 3, 4: Warns nearby mobs of the incoming fire mission. Warning as 1 is non-precise, whereas 2 and 3 are precise. +/datum/cas_fire_envelope/proc/chat_warning(atom/target_turf, range = 10, warning_number = 1) + var/ds_identifier = "LARGE BIRD" + var/fm_identifier = "SPIT FIRE" + var/relative_dir + for(var/mob/mob in range(15, target_turf)) + if (mob.mob_flags & KNOWS_TECHNOLOGY) + ds_identifier = "DROPSHIP" + fm_identifier = "FIRE" + if(get_turf(mob) == target_turf) + relative_dir = 0 + else + relative_dir = Get_Compass_Dir(mob, target_turf) + switch(warning_number) + if(1) + mob.show_message( \ + SPAN_HIGHDANGER("YOU HEAR THE [ds_identifier] ROAR AS IT PREPARES TO [fm_identifier] NEAR YOU!"),SHOW_MESSAGE_VISIBLE, \ + SPAN_HIGHDANGER("YOU HEAR SOMETHING FLYING CLOSER TO YOU!") , SHOW_MESSAGE_AUDIBLE \ + ) + if(2) + mob.show_message( \ + SPAN_HIGHDANGER("A [ds_identifier] FLIES [SPAN_UNDERLINE(relative_dir ? uppertext(("TO YOUR " + dir2text(relative_dir))) : uppertext("right above you"))]!"), SHOW_MESSAGE_VISIBLE, \ + SPAN_HIGHDANGER("YOU HEAR SOMETHING GO [SPAN_UNDERLINE(relative_dir ? uppertext(("TO YOUR " + dir2text(relative_dir))) : uppertext("right above you"))]!"), SHOW_MESSAGE_AUDIBLE \ + ) + if(3) + mob.show_message( \ + SPAN_HIGHDANGER("A [ds_identifier] FLIES [SPAN_UNDERLINE(relative_dir ? uppertext(("TO YOUR " + dir2text(relative_dir))) : uppertext("right above you"))]!"), SHOW_MESSAGE_VISIBLE, \ + SPAN_HIGHDANGER("YOU HEAR SOMETHING GO [SPAN_UNDERLINE(relative_dir ? uppertext(("TO YOUR " + dir2text(relative_dir))) : uppertext("right above you"))]!"), SHOW_MESSAGE_AUDIBLE \ + ) + +/// Step 5: Actually executes the fire mission updating stat to FIRE_MISSION_STATE_FIRING and then FIRE_MISSION_STATE_OFF_TARGET +/datum/cas_fire_envelope/proc/open_fire(atom/target_turf,datum/cas_fire_mission/mission,dir) + stat = FIRE_MISSION_STATE_FIRING + mission.execute_firemission(linked_console, target_turf, dir, fire_length, step_delay, src) + stat = FIRE_MISSION_STATE_OFF_TARGET + +/// Step 6: Sets the fire mission stat to FIRE_MISSION_STATE_COOLDOWN +/datum/cas_fire_envelope/proc/flyoff() + stat = FIRE_MISSION_STATE_COOLDOWN + +/// Step 7: Sets the fire mission stat to FIRE_MISSION_STATE_IDLE +/datum/cas_fire_envelope/proc/end_cooldown() + stat = FIRE_MISSION_STATE_IDLE + + /datum/cas_fire_envelope/proc/execute_firemission_unsafe(datum/cas_signal/signal, turf/target_turf, dir, datum/cas_fire_mission/mission) stat = FIRE_MISSION_STATE_IN_TRANSIT to_chat(usr, SPAN_ALERT("Firemission underway!")) - sleep(grace_period) - stat = FIRE_MISSION_STATE_ON_TARGET if(!target_turf) stat = FIRE_MISSION_STATE_IDLE mission_error = "Target Lost." @@ -258,29 +303,27 @@ stat = FIRE_MISSION_STATE_IDLE mission_error = "Target is off bounds or obstructed." return - change_current_loc(target_turf) - playsound(source = target_turf, soundin = soundeffect, vol = 70, vary = TRUE, sound_range = 50, falloff = 8) - for(var/mob/mob in range(15, target_turf)) - var/ds_identifier = "LARGE BIRD" - var/fm_identifier = "SPIT FIRE" - if (mob.mob_flags & KNOWS_TECHNOLOGY) - ds_identifier = "DROPSHIP" - fm_identifier = "FIRE" + var/obj/effect/firemission_effect = new(target_turf) - mob.show_message( \ - SPAN_HIGHDANGER("YOU HEAR THE [ds_identifier] ROAR AS IT PREPARES TO [fm_identifier] NEAR YOU!"),SHOW_MESSAGE_VISIBLE, \ - SPAN_HIGHDANGER("YOU HEAR SOMETHING FLYING CLOSER TO YOU!") , SHOW_MESSAGE_AUDIBLE \ - ) + firemission_effect.icon = 'icons/obj/items/weapons/projectiles.dmi' + firemission_effect.icon_state = "laser_target2" + firemission_effect.mouse_opacity = MOUSE_OPACITY_TRANSPARENT + firemission_effect.invisibility = INVISIBILITY_MAXIMUM + QDEL_IN(firemission_effect, 12 SECONDS) - sleep(flyto_period) - stat = FIRE_MISSION_STATE_FIRING - mission.execute_firemission(linked_console, target_turf, dir, fire_length, step_delay, src) - stat = FIRE_MISSION_STATE_OFF_TARGET - sleep(flyoff_period) - stat = FIRE_MISSION_STATE_COOLDOWN - sleep(cooldown_period) - stat = FIRE_MISSION_STATE_IDLE + + notify_ghosts(header = "CAS Fire Mission", message = "[usr ? usr : "Someone"] is launching Fire Mission '[mission.name]' at [get_area(target_turf)].", source = firemission_effect) + msg_admin_niche("[usr ? key_name(usr) : "Someone"] is launching Fire Mission '[mission.name]' at ([target_turf.x],[target_turf.y],[target_turf.z]) [ADMIN_JMP(target_turf)]") + + + addtimer(CALLBACK(src, PROC_REF(play_sound), target_turf), grace_period) + addtimer(CALLBACK(src, PROC_REF(chat_warning), target_turf, 15, 1), first_warning) + addtimer(CALLBACK(src, PROC_REF(chat_warning), target_turf, 15, 2), second_warning) + addtimer(CALLBACK(src, PROC_REF(chat_warning), target_turf, 10, 3), third_warning) + addtimer(CALLBACK(src, PROC_REF(open_fire), target_turf, mission,dir), execution_start) + addtimer(CALLBACK(src, PROC_REF(flyoff)), flyoff_period) + addtimer(CALLBACK(src, PROC_REF(end_cooldown)), cooldown_period) /** * Change attack vector for firemission @@ -324,10 +367,13 @@ /datum/cas_fire_envelope/uscm_dropship fire_length = 12 - grace_period = 5 SECONDS - flyto_period = 4 SECONDS //sleep in the FM itself has been increased by one more second - flyoff_period = 5 SECONDS - cooldown_period = 10 SECONDS + grace_period = 5 SECONDS + first_warning = 6 SECONDS + second_warning = 8 SECONDS + third_warning = 9 SECONDS + execution_start = 10 SECONDS + flyoff_period = 15 SECONDS + cooldown_period = 25 SECONDS soundeffect = 'sound/weapons/dropship_sonic_boom.ogg' //BOOM~WOOOOOSH~HSOOOOOW~BOOM step_delay = 3 max_offset = 12 diff --git a/code/game/cas_manager/datums/cas_fire_mission.dm b/code/game/cas_manager/datums/cas_fire_mission.dm index 927dded210f0..dc55e057edcd 100644 --- a/code/game/cas_manager/datums/cas_fire_mission.dm +++ b/code/game/cas_manager/datums/cas_fire_mission.dm @@ -164,51 +164,6 @@ if(initial_turf == null || check(linked_console) != FIRE_MISSION_ALL_GOOD) return FIRE_MISSION_NOT_EXECUTABLE - var/obj/effect/firemission_effect = new(initial_turf) - - firemission_effect.icon = 'icons/obj/items/weapons/projectiles.dmi' - firemission_effect.icon_state = "laser_target2" - firemission_effect.mouse_opacity = MOUSE_OPACITY_TRANSPARENT - firemission_effect.invisibility = INVISIBILITY_MAXIMUM - QDEL_IN(firemission_effect, 5 SECONDS) - - notify_ghosts(header = "CAS Fire Mission", message = "[usr ? usr : "Someone"] is launching Fire Mission '[name]' at [get_area(initial_turf)].", source = firemission_effect) - msg_admin_niche("[usr ? key_name(usr) : "Someone"] is launching Fire Mission '[name]' at ([initial_turf.x],[initial_turf.y],[initial_turf.z]) [ADMIN_JMP(initial_turf)]") - - var/relative_dir - for(var/mob/mob in range(15, initial_turf)) - if(get_turf(mob) == initial_turf) - relative_dir = 0 - else - relative_dir = Get_Compass_Dir(mob, initial_turf) - - var/ds_identifier = "LARGE BIRD" - if (mob.mob_flags & KNOWS_TECHNOLOGY) - ds_identifier = "DROPSHIP" - - mob.show_message( \ - SPAN_HIGHDANGER("A [ds_identifier] FLIES [SPAN_UNDERLINE(relative_dir ? uppertext(("TO YOUR " + dir2text(relative_dir))) : uppertext("right above you"))]!"), SHOW_MESSAGE_VISIBLE, \ - SPAN_HIGHDANGER("YOU HEAR SOMETHING GO [SPAN_UNDERLINE(relative_dir ? uppertext(("TO YOUR " + dir2text(relative_dir))) : uppertext("right above you"))]!"), SHOW_MESSAGE_AUDIBLE \ - ) - - // Xenos have time to react to the first message - sleep(1.5 SECONDS) - - for(var/mob/mob in range(10, initial_turf)) - if(get_turf(mob) == initial_turf) - relative_dir = 0 - else - relative_dir = Get_Compass_Dir(mob, initial_turf) - - var/ds_identifier = "LARGE BIRD" - if (mob.mob_flags & KNOWS_TECHNOLOGY) - ds_identifier = "DROPSHIP" - - mob.show_message( \ - SPAN_HIGHDANGER("A [ds_identifier] FIRES [SPAN_UNDERLINE(relative_dir ? uppertext(("TO YOUR " + dir2text(relative_dir))) : uppertext("right above you"))]!"), 1, \ - SPAN_HIGHDANGER("YOU HEAR SOMETHING FIRE [SPAN_UNDERLINE(relative_dir ? uppertext(("TO YOUR " + dir2text(relative_dir))) : uppertext("right above you"))]!"), 2 \ - ) - var/turf/current_turf = initial_turf var/tally_step = steps / mission_length //how much shots we need before moving to next turf var/next_step = tally_step //when we move to next turf diff --git a/code/game/machinery/ARES/ARES_interface.dm b/code/game/machinery/ARES/ARES_interface.dm index 341e6a05acf4..6905c47febb8 100644 --- a/code/game/machinery/ARES/ARES_interface.dm +++ b/code/game/machinery/ARES/ARES_interface.dm @@ -522,5 +522,12 @@ sec_vent.create_gas(VENT_GAS_CN20_XENO, 6, 5 SECONDS) log_admin("[key_name(user)] released nerve gas from Vent '[sec_vent.vent_tag]' via ARES.") + if("security_lockdown") + if(!COOLDOWN_FINISHED(datacore, aicore_lockdown)) + to_chat(user, SPAN_BOLDWARNING("AI Core Lockdown procedures are on cooldown! They will be ready in [COOLDOWN_SECONDSLEFT(datacore, aicore_lockdown)] seconds!")) + return FALSE + aicore_lockdown(user) + return TRUE + if(playsound) playsound(src, "keyboard_alt", 15, 1) diff --git a/code/game/machinery/ARES/ARES_interface_apollo.dm b/code/game/machinery/ARES/ARES_interface_apollo.dm index 48fcad588574..37b2fbda0ecb 100644 --- a/code/game/machinery/ARES/ARES_interface_apollo.dm +++ b/code/game/machinery/ARES/ARES_interface_apollo.dm @@ -158,29 +158,29 @@ return var/playsound = TRUE - var/mob/living/carbon/human/operator = ui.user + var/mob/living/carbon/human/user = ui.user switch (action) if("go_back") if(!last_menu) - return to_chat(operator, SPAN_WARNING("Error, no previous page detected.")) + return to_chat(user, SPAN_WARNING("Error, no previous page detected.")) var/temp_holder = current_menu current_menu = last_menu last_menu = temp_holder if("login") - var/obj/item/card/id/idcard = operator.get_active_hand() + var/obj/item/card/id/idcard = user.get_active_hand() if(istype(idcard)) authentication = get_ares_access(idcard) last_login = idcard.registered_name - else if(operator.wear_id) - idcard = operator.wear_id + else if(user.wear_id) + idcard = user.wear_id if(istype(idcard)) authentication = get_ares_access(idcard) last_login = idcard.registered_name else - to_chat(operator, SPAN_WARNING("You require an ID card to access this terminal!")) + to_chat(user, SPAN_WARNING("You require an ID card to access this terminal!")) playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) return FALSE if(authentication) @@ -222,23 +222,23 @@ if("new_report") var/priority_report = FALSE - var/maint_type = tgui_input_list(operator, "What is the type of maintenance item you wish to report?", "Report Category", GLOB.maintenance_categories, 30 SECONDS) + var/maint_type = tgui_input_list(user, "What is the type of maintenance item you wish to report?", "Report Category", GLOB.maintenance_categories, 30 SECONDS) switch(maint_type) if("Major Structural Damage", "Fire", "Communications Failure", "Power Generation Failure") priority_report = TRUE if(!maint_type) return FALSE - var/details = tgui_input_text(operator, "What are the details for this report?", "Ticket Details", encode = FALSE) + var/details = tgui_input_text(user, "What are the details for this report?", "Ticket Details", encode = FALSE) if(!details) return FALSE if((authentication >= APOLLO_ACCESS_REPORTER) && !priority_report) - var/is_priority = tgui_alert(operator, "Is this a priority report?", "Priority designation", list("Yes", "No")) + var/is_priority = tgui_alert(user, "Is this a priority report?", "Priority designation", list("Yes", "No")) if(is_priority == "Yes") priority_report = TRUE - var/confirm = alert(operator, "Please confirm the submission of your maintenance report. \n\n Priority: [priority_report ? "Yes" : "No"]\n Category: '[maint_type]'\n Details: '[details]'\n\n Is this correct?", "Confirmation", "Yes", "No") + var/confirm = alert(user, "Please confirm the submission of your maintenance report. \n\n Priority: [priority_report ? "Yes" : "No"]\n Category: '[maint_type]'\n Details: '[details]'\n\n Is this correct?", "Confirmation", "Yes", "No") if(confirm == "Yes") if(link) var/datum/ares_ticket/maintenance/maint_ticket = new(last_login, maint_type, details, priority_report) @@ -247,7 +247,7 @@ ares_apollo_talk("Priority Maintenance Report: [maint_type] - ID [maint_ticket.ticket_id]. Seek and resolve.") else send_notifcation() - log_game("ARES: Maintenance Ticket '\ref[maint_ticket]' created by [key_name(operator)] as [last_login] with Category '[maint_type]' and Details of '[details]'.") + log_game("ARES: Maintenance Ticket '\ref[maint_ticket]' created by [key_name(user)] as [last_login] with Category '[maint_type]' and Details of '[details]'.") return TRUE return FALSE @@ -259,14 +259,14 @@ var/assigned = ticket.ticket_assignee if(assigned) if(assigned == last_login) - var/prompt = tgui_alert(operator, "You already claimed this ticket! Do you wish to drop your claim?", "Unclaim ticket", list("Yes", "No")) + var/prompt = tgui_alert(user, "You already claimed this ticket! Do you wish to drop your claim?", "Unclaim ticket", list("Yes", "No")) if(prompt != "Yes") return FALSE /// set ticket back to pending ticket.ticket_assignee = null ticket.ticket_status = TICKET_PENDING return claim - var/choice = tgui_alert(operator, "This ticket has already been claimed by [assigned]! Do you wish to override their claim?", "Claim Override", list("Yes", "No")) + var/choice = tgui_alert(user, "This ticket has already been claimed by [assigned]! Do you wish to override their claim?", "Claim Override", list("Yes", "No")) if(choice != "Yes") claim = FALSE if(claim) @@ -279,9 +279,9 @@ if(!istype(ticket)) return FALSE if(ticket.ticket_submitter != last_login) - to_chat(operator, SPAN_WARNING("You cannot cancel a ticket that does not belong to you!")) + to_chat(user, SPAN_WARNING("You cannot cancel a ticket that does not belong to you!")) return FALSE - to_chat(operator, SPAN_WARNING("[ticket.ticket_type] [ticket.ticket_id] has been cancelled.")) + to_chat(user, SPAN_WARNING("[ticket.ticket_type] [ticket.ticket_id] has been cancelled.")) ticket.ticket_status = TICKET_CANCELLED if(ticket.ticket_priority) ares_apollo_talk("Priority [ticket.ticket_type] [ticket.ticket_id] has been cancelled.") @@ -294,9 +294,9 @@ if(!istype(ticket)) return FALSE if(ticket.ticket_assignee != last_login && ticket.ticket_assignee) //must be claimed by you or unclaimed.) - to_chat(operator, SPAN_WARNING("You cannot update a ticket that is not assigned to you!")) + to_chat(user, SPAN_WARNING("You cannot update a ticket that is not assigned to you!")) return FALSE - var/choice = tgui_alert(operator, "What do you wish to mark the ticket as?", "Mark", list(TICKET_COMPLETED, TICKET_REJECTED), 20 SECONDS) + var/choice = tgui_alert(user, "What do you wish to mark the ticket as?", "Mark", list(TICKET_COMPLETED, TICKET_REJECTED), 20 SECONDS) switch(choice) if(TICKET_COMPLETED) ticket.ticket_status = TICKET_COMPLETED @@ -308,39 +308,39 @@ ares_apollo_talk("Priority [ticket.ticket_type] [ticket.ticket_id] has been [choice] by [last_login].") else send_notifcation() - to_chat(operator, SPAN_NOTICE("[ticket.ticket_type] [ticket.ticket_id] marked as [choice].")) + to_chat(user, SPAN_NOTICE("[ticket.ticket_type] [ticket.ticket_id] marked as [choice].")) return TRUE if("new_access") - var/obj/item/card/id/idcard = operator.get_active_hand() + var/obj/item/card/id/idcard = user.get_active_hand() var/has_id = FALSE if(istype(idcard)) has_id = TRUE - else if(operator.wear_id) - idcard = operator.wear_id + else if(user.wear_id) + idcard = user.wear_id if(istype(idcard)) has_id = TRUE if(!has_id) - to_chat(operator, SPAN_WARNING("You require an ID card to request an access ticket!")) + to_chat(user, SPAN_WARNING("You require an ID card to request an access ticket!")) playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) return FALSE if(idcard.registered_name != last_login) - to_chat(operator, SPAN_WARNING("This ID card does not match the active login!")) + to_chat(user, SPAN_WARNING("This ID card does not match the active login!")) playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) return FALSE - var/details = tgui_input_text(operator, "What is the purpose of this access ticket?", "Ticket Details", encode = FALSE) + var/details = tgui_input_text(user, "What is the purpose of this access ticket?", "Ticket Details", encode = FALSE) if(!details) return FALSE - var/confirm = alert(operator, "Please confirm the submission of your access ticket request.\n\nHolder: '[last_login]'\nDetails: '[details]'\n\nIs this correct?", "Confirmation", "Yes", "No") + var/confirm = alert(user, "Please confirm the submission of your access ticket request.\n\nHolder: '[last_login]'\nDetails: '[details]'\n\nIs this correct?", "Confirmation", "Yes", "No") if(confirm != "Yes" || !link) return FALSE var/datum/ares_ticket/access/access_ticket = new(last_login, details, FALSE, idcard.registered_gid) link.waiting_ids += idcard link.tickets_access += access_ticket - log_game("ARES: Access Ticket '\ref[access_ticket]' created by [key_name(operator)] as [last_login] with Details of '[details]'.") - message_admins(SPAN_STAFF_IC("[key_name_admin(operator)] created a new ARES Access Ticket."), 1) + log_game("ARES: Access Ticket '\ref[access_ticket]' created by [key_name(user)] as [last_login] with Details of '[details]'.") + message_admins(SPAN_STAFF_IC("[key_name_admin(user)] created a new ARES Access Ticket."), 1) ares_apollo_talk("Access Ticket [access_ticket.ticket_id]: [access_ticket.ticket_submitter] requesting access for '[details].") return TRUE @@ -361,9 +361,9 @@ access_ticket.ticket_status = TICKET_RETURNED identification.access -= ACCESS_MARINE_AI_TEMP - identification.modification_log += "Temporary AI Access self-returned by [key_name(operator)]." + identification.modification_log += "Temporary AI Access self-returned by [key_name(user)]." - to_chat(operator, SPAN_NOTICE("Temporary Access Ticket surrendered.")) + to_chat(user, SPAN_NOTICE("Temporary Access Ticket surrendered.")) playsound(src, 'sound/machines/chime.ogg', 15, 1) ares_apollo_talk("Access Ticket [access_ticket.ticket_id]: [access_ticket.ticket_submitter] surrendered their access.") @@ -372,7 +372,7 @@ datacore.apollo_login_list += "[last_login] at [worldtime2text()], Surrendered Temporary Access Ticket." return TRUE - to_chat(operator, SPAN_WARNING("This ID card does not have an access ticket!")) + to_chat(user, SPAN_WARNING("This ID card does not have an access ticket!")) playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) return FALSE @@ -384,7 +384,7 @@ for(var/obj/item/card/id/identification in link.waiting_ids) if(identification.registered_gid != access_ticket.user_id_num) continue - identification.handle_ares_access(last_login, operator) + identification.handle_ares_access(last_login, user) access_ticket.ticket_status = TICKET_GRANTED playsound(src, 'sound/machines/chime.ogg', 15, 1) ares_apollo_talk("Access Ticket [access_ticket.ticket_id]: [access_ticket.ticket_submitter] was granted access by [last_login].") @@ -392,7 +392,7 @@ for(var/obj/item/card/id/identification in link.active_ids) if(identification.registered_gid != access_ticket.user_id_num) continue - identification.handle_ares_access(last_login, operator) + identification.handle_ares_access(last_login, user) access_ticket.ticket_status = TICKET_REVOKED playsound(src, 'sound/machines/chime.ogg', 15, 1) ares_apollo_talk("Access Ticket [access_ticket.ticket_id]: [access_ticket.ticket_submitter] had access revoked by [last_login].") @@ -404,10 +404,10 @@ if(!istype(access_ticket)) return FALSE if(access_ticket.ticket_assignee != last_login && access_ticket.ticket_assignee) //must be claimed by you or unclaimed.) - to_chat(operator, SPAN_WARNING("You cannot update a ticket that is not assigned to you!")) + to_chat(user, SPAN_WARNING("You cannot update a ticket that is not assigned to you!")) return FALSE access_ticket.ticket_status = TICKET_REJECTED - to_chat(operator, SPAN_NOTICE("[access_ticket.ticket_type] [access_ticket.ticket_id] marked as rejected.")) + to_chat(user, SPAN_NOTICE("[access_ticket.ticket_type] [access_ticket.ticket_id] marked as rejected.")) ares_apollo_talk("Access Ticket [access_ticket.ticket_id]: [access_ticket.ticket_submitter] was rejected access by [last_login].") for(var/obj/item/card/id/identification in link.waiting_ids) if(identification.registered_gid != access_ticket.user_id_num) @@ -422,36 +422,41 @@ playsound = FALSE var/obj/structure/pipes/vents/pump/no_boom/gas/sec_vent = locate(params["vent"]) if(!istype(sec_vent) || sec_vent.welded) - to_chat(operator, SPAN_WARNING("ERROR: Gas release failure.")) + to_chat(user, SPAN_WARNING("ERROR: Gas release failure.")) playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) return FALSE if(!COOLDOWN_FINISHED(sec_vent, vent_trigger_cooldown)) - to_chat(operator, SPAN_WARNING("ERROR: Insufficient gas reserve for this vent.")) + to_chat(user, SPAN_WARNING("ERROR: Insufficient gas reserve for this vent.")) playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) return FALSE - to_chat(operator, SPAN_WARNING("Initiating gas release from [sec_vent.vent_tag].")) + to_chat(user, SPAN_WARNING("Initiating gas release from [sec_vent.vent_tag].")) playsound(src, 'sound/machines/chime.ogg', 15, 1) COOLDOWN_START(sec_vent, vent_trigger_cooldown, COOLDOWN_ARES_VENT) ares_apollo_talk("Nerve Gas release imminent from [sec_vent.vent_tag].") log_ares_security("Nerve Gas Release", "[last_login] released Nerve Gas from Vent '[sec_vent.vent_tag]'.") sec_vent.create_gas(VENT_GAS_CN20_XENO, 6, 5 SECONDS) - log_admin("[key_name(operator)] released nerve gas from Vent '[sec_vent.vent_tag]' via ARES.") + log_admin("[key_name(user)] released nerve gas from Vent '[sec_vent.vent_tag]' via ARES.") + + if("security_lockdown") + if(!COOLDOWN_FINISHED(datacore, aicore_lockdown)) + to_chat(user, SPAN_BOLDWARNING("AI Core Lockdown procedures are on cooldown! They will be ready in [COOLDOWN_SECONDSLEFT(datacore, aicore_lockdown)] seconds!")) + return FALSE + aicore_lockdown(user) + return TRUE if(playsound) playsound(src, "keyboard_alt", 15, 1) /obj/item/card/id/proc/handle_ares_access(logged_in = MAIN_AI_SYSTEM, mob/user) - var/operator = key_name(user) + var/changer = logged_in + if(user) + changer = key_name(user) var/datum/ares_link/link = GLOB.ares_link - if(logged_in == MAIN_AI_SYSTEM) - if(!user) - operator = "[MAIN_AI_SYSTEM] (Automated)" - else - operator = "[user.ckey]/([MAIN_AI_SYSTEM])" + if(ACCESS_MARINE_AI_TEMP in access) access -= ACCESS_MARINE_AI_TEMP link.active_ids -= src - modification_log += "Temporary AI access revoked by [operator]" + log_idmod(src, "Temporary AI access revoked by [logged_in]", changer) to_chat(user, SPAN_NOTICE("Access revoked from [registered_name].")) var/mob/living/carbon/human/id_owner = registered_ref?.resolve() if(id_owner) @@ -459,7 +464,7 @@ playsound_client(id_owner?.client, 'sound/machines/pda_ping.ogg', src, 25, 0) else access += ACCESS_MARINE_AI_TEMP - modification_log += "Temporary AI access granted by [operator]" + log_idmod(src, "Temporary AI access granted by [logged_in]", changer) to_chat(user, SPAN_NOTICE("Access granted to [registered_name].")) link.waiting_ids -= src link.active_ids += src diff --git a/code/game/machinery/ARES/ARES_procs.dm b/code/game/machinery/ARES/ARES_procs.dm index 05f110ec1a0c..8ecb711e9fb7 100644 --- a/code/game/machinery/ARES/ARES_procs.dm +++ b/code/game/machinery/ARES/ARES_procs.dm @@ -106,9 +106,13 @@ GLOBAL_LIST_INIT(maintenance_categories, list( /// Is nuke request usable or not? var/nuke_available = TRUE + /// Status of the AI Core Lockdown + var/ai_lockdown_active = FALSE + COOLDOWN_DECLARE(ares_distress_cooldown) COOLDOWN_DECLARE(ares_nuclear_cooldown) COOLDOWN_DECLARE(ares_quarters_cooldown) + COOLDOWN_DECLARE(aicore_lockdown) // ------ ARES Logging Procs ------ // /proc/ares_is_active() diff --git a/code/game/machinery/ARES/apollo_pda.dm b/code/game/machinery/ARES/apollo_pda.dm index e447bb6f7ee7..2f18a5ba0522 100644 --- a/code/game/machinery/ARES/apollo_pda.dm +++ b/code/game/machinery/ARES/apollo_pda.dm @@ -181,29 +181,29 @@ return var/playsound = TRUE - var/mob/living/carbon/human/operator = ui.user + var/mob/living/carbon/human/user = ui.user switch (action) if("go_back") if(!last_menu) - return to_chat(operator, SPAN_WARNING("Error, no previous page detected.")) + return to_chat(user, SPAN_WARNING("Error, no previous page detected.")) var/temp_holder = current_menu current_menu = last_menu last_menu = temp_holder if("login") - var/obj/item/card/id/idcard = operator.get_active_hand() + var/obj/item/card/id/idcard = user.get_active_hand() if(istype(idcard)) authentication = get_ares_access(idcard) last_login = idcard.registered_name - else if(operator.wear_id) - idcard = operator.wear_id + else if(user.wear_id) + idcard = user.wear_id if(istype(idcard)) authentication = get_ares_access(idcard) last_login = idcard.registered_name else - to_chat(operator, SPAN_WARNING("You require an ID card to access this terminal!")) + to_chat(user, SPAN_WARNING("You require an ID card to access this terminal!")) playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) return FALSE if(authentication) @@ -248,23 +248,23 @@ if("new_report") var/priority_report = FALSE - var/maint_type = tgui_input_list(operator, "What is the type of maintenance item you wish to report?", "Report Category", GLOB.maintenance_categories, 30 SECONDS) + var/maint_type = tgui_input_list(user, "What is the type of maintenance item you wish to report?", "Report Category", GLOB.maintenance_categories, 30 SECONDS) switch(maint_type) if("Major Structural Damage", "Fire", "Communications Failure", "Power Generation Failure") priority_report = TRUE if(!maint_type) return FALSE - var/details = tgui_input_text(operator, "What are the details for this report?", "Ticket Details", encode = FALSE) + var/details = tgui_input_text(user, "What are the details for this report?", "Ticket Details", encode = FALSE) if(!details) return FALSE if((authentication >= APOLLO_ACCESS_REPORTER) && !priority_report) - var/is_priority = tgui_alert(operator, "Is this a priority report?", "Priority designation", list("Yes", "No")) + var/is_priority = tgui_alert(user, "Is this a priority report?", "Priority designation", list("Yes", "No")) if(is_priority == "Yes") priority_report = TRUE - var/confirm = alert(operator, "Please confirm the submission of your maintenance report. \n\n Priority: [priority_report ? "Yes" : "No"]\n Category: '[maint_type]'\n Details: '[details]'\n\n Is this correct?", "Confirmation", "Yes", "No") + var/confirm = alert(user, "Please confirm the submission of your maintenance report. \n\n Priority: [priority_report ? "Yes" : "No"]\n Category: '[maint_type]'\n Details: '[details]'\n\n Is this correct?", "Confirmation", "Yes", "No") if(confirm == "Yes") if(link) var/datum/ares_ticket/maintenance/maint_ticket = new(last_login, maint_type, details, priority_report) @@ -273,7 +273,7 @@ ares_apollo_talk("Priority Maintenance Report: [maint_type] - ID [maint_ticket.ticket_id]. Seek and resolve.") else send_notifcation() - log_game("ARES: Maintenance Ticket '\ref[maint_ticket]' created by [key_name(operator)] as [last_login] with Category '[maint_type]' and Details of '[details]'.") + log_game("ARES: Maintenance Ticket '\ref[maint_ticket]' created by [key_name(user)] as [last_login] with Category '[maint_type]' and Details of '[details]'.") return TRUE return FALSE @@ -285,14 +285,14 @@ var/assigned = ticket.ticket_assignee if(assigned) if(assigned == last_login) - var/prompt = tgui_alert(operator, "You already claimed this ticket! Do you wish to drop your claim?", "Unclaim ticket", list("Yes", "No")) + var/prompt = tgui_alert(user, "You already claimed this ticket! Do you wish to drop your claim?", "Unclaim ticket", list("Yes", "No")) if(prompt != "Yes") return FALSE /// set ticket back to pending ticket.ticket_assignee = null ticket.ticket_status = TICKET_PENDING return claim - var/choice = tgui_alert(operator, "This ticket has already been claimed by [assigned]! Do you wish to override their claim?", "Claim Override", list("Yes", "No")) + var/choice = tgui_alert(user, "This ticket has already been claimed by [assigned]! Do you wish to override their claim?", "Claim Override", list("Yes", "No")) if(choice != "Yes") claim = FALSE if(claim) @@ -305,9 +305,9 @@ if(!istype(ticket)) return FALSE if(ticket.ticket_submitter != last_login) - to_chat(operator, SPAN_WARNING("You cannot cancel a ticket that does not belong to you!")) + to_chat(user, SPAN_WARNING("You cannot cancel a ticket that does not belong to you!")) return FALSE - to_chat(operator, SPAN_WARNING("[ticket.ticket_type] [ticket.ticket_id] has been cancelled.")) + to_chat(user, SPAN_WARNING("[ticket.ticket_type] [ticket.ticket_id] has been cancelled.")) ticket.ticket_status = TICKET_CANCELLED if(ticket.ticket_priority) ares_apollo_talk("Priority [ticket.ticket_type] [ticket.ticket_id] has been cancelled.") @@ -320,9 +320,9 @@ if(!istype(ticket)) return FALSE if(ticket.ticket_assignee != last_login && ticket.ticket_assignee) //must be claimed by you or unclaimed.) - to_chat(operator, SPAN_WARNING("You cannot update a ticket that is not assigned to you!")) + to_chat(user, SPAN_WARNING("You cannot update a ticket that is not assigned to you!")) return FALSE - var/choice = tgui_alert(operator, "What do you wish to mark the ticket as?", "Mark", list(TICKET_COMPLETED, TICKET_REJECTED), 20 SECONDS) + var/choice = tgui_alert(user, "What do you wish to mark the ticket as?", "Mark", list(TICKET_COMPLETED, TICKET_REJECTED), 20 SECONDS) switch(choice) if(TICKET_COMPLETED) ticket.ticket_status = TICKET_COMPLETED @@ -334,39 +334,39 @@ ares_apollo_talk("Priority [ticket.ticket_type] [ticket.ticket_id] has been [choice] by [last_login].") else send_notifcation() - to_chat(operator, SPAN_NOTICE("[ticket.ticket_type] [ticket.ticket_id] marked as [choice].")) + to_chat(user, SPAN_NOTICE("[ticket.ticket_type] [ticket.ticket_id] marked as [choice].")) return TRUE if("new_access") - var/obj/item/card/id/idcard = operator.get_active_hand() + var/obj/item/card/id/idcard = user.get_active_hand() var/has_id = FALSE if(istype(idcard)) has_id = TRUE - else if(operator.wear_id) - idcard = operator.wear_id + else if(user.wear_id) + idcard = user.wear_id if(istype(idcard)) has_id = TRUE if(!has_id) - to_chat(operator, SPAN_WARNING("You require an ID card to request an access ticket!")) + to_chat(user, SPAN_WARNING("You require an ID card to request an access ticket!")) playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) return FALSE if(idcard.registered_name != last_login) - to_chat(operator, SPAN_WARNING("This ID card does not match the active login!")) + to_chat(user, SPAN_WARNING("This ID card does not match the active login!")) playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) return FALSE - var/details = tgui_input_text(operator, "What is the purpose of this access ticket?", "Ticket Details", encode = FALSE) + var/details = tgui_input_text(user, "What is the purpose of this access ticket?", "Ticket Details", encode = FALSE) if(!details) return FALSE - var/confirm = alert(operator, "Please confirm the submission of your access ticket request.\n\nHolder: '[last_login]'\nDetails: '[details]'\n\nIs this correct?", "Confirmation", "Yes", "No") + var/confirm = alert(user, "Please confirm the submission of your access ticket request.\n\nHolder: '[last_login]'\nDetails: '[details]'\n\nIs this correct?", "Confirmation", "Yes", "No") if(confirm != "Yes" || !link) return FALSE var/datum/ares_ticket/access/access_ticket = new(last_login, details, FALSE, idcard.registered_gid) link.waiting_ids += idcard link.tickets_access += access_ticket - log_game("ARES: Access Ticket '\ref[access_ticket]' created by [key_name(operator)] as [last_login] with Details of '[details]'.") - message_admins(SPAN_STAFF_IC("[key_name_admin(operator)] created a new ARES Access Ticket."), 1) + log_game("ARES: Access Ticket '\ref[access_ticket]' created by [key_name(user)] as [last_login] with Details of '[details]'.") + message_admins(SPAN_STAFF_IC("[key_name_admin(user)] created a new ARES Access Ticket."), 1) ares_apollo_talk("Access Ticket [access_ticket.ticket_id]: [access_ticket.ticket_submitter] requesting access for '[details].") return TRUE @@ -387,9 +387,9 @@ access_ticket.ticket_status = TICKET_RETURNED identification.access -= ACCESS_MARINE_AI_TEMP - identification.modification_log += "Temporary AI Access self-returned by [key_name(operator)]." + identification.modification_log += "Temporary AI Access self-returned by [key_name(user)]." - to_chat(operator, SPAN_NOTICE("Temporary Access Ticket surrendered.")) + to_chat(user, SPAN_NOTICE("Temporary Access Ticket surrendered.")) playsound(src, 'sound/machines/chime.ogg', 15, 1) ares_apollo_talk("Access Ticket [access_ticket.ticket_id]: [access_ticket.ticket_submitter] surrendered their access.") @@ -398,7 +398,7 @@ datacore.apollo_login_list += "[last_login] at [worldtime2text()], Surrendered Temporary Access Ticket." return TRUE - to_chat(operator, SPAN_WARNING("This ID card does not have an access ticket!")) + to_chat(user, SPAN_WARNING("This ID card does not have an access ticket!")) playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) return FALSE @@ -410,7 +410,7 @@ for(var/obj/item/card/id/identification in link.waiting_ids) if(identification.registered_gid != access_ticket.user_id_num) continue - identification.handle_ares_access(last_login, operator) + identification.handle_ares_access(last_login, user) access_ticket.ticket_status = TICKET_GRANTED playsound(src, 'sound/machines/chime.ogg', 15, 1) ares_apollo_talk("Access Ticket [access_ticket.ticket_id]: [access_ticket.ticket_submitter] was granted access by [last_login].") @@ -418,7 +418,7 @@ for(var/obj/item/card/id/identification in link.active_ids) if(identification.registered_gid != access_ticket.user_id_num) continue - identification.handle_ares_access(last_login, operator) + identification.handle_ares_access(last_login, user) access_ticket.ticket_status = TICKET_REVOKED playsound(src, 'sound/machines/chime.ogg', 15, 1) ares_apollo_talk("Access Ticket [access_ticket.ticket_id]: [access_ticket.ticket_submitter] had access revoked by [last_login].") @@ -430,10 +430,10 @@ if(!istype(access_ticket)) return FALSE if(access_ticket.ticket_assignee != last_login && access_ticket.ticket_assignee) //must be claimed by you or unclaimed.) - to_chat(operator, SPAN_WARNING("You cannot update a ticket that is not assigned to you!")) + to_chat(user, SPAN_WARNING("You cannot update a ticket that is not assigned to you!")) return FALSE access_ticket.ticket_status = TICKET_REJECTED - to_chat(operator, SPAN_NOTICE("[access_ticket.ticket_type] [access_ticket.ticket_id] marked as rejected.")) + to_chat(user, SPAN_NOTICE("[access_ticket.ticket_type] [access_ticket.ticket_id] marked as rejected.")) ares_apollo_talk("Access Ticket [access_ticket.ticket_id]: [access_ticket.ticket_submitter] was rejected access by [last_login].") for(var/obj/item/card/id/identification in link.waiting_ids) if(identification.registered_gid != access_ticket.user_id_num) @@ -448,20 +448,27 @@ playsound = FALSE var/obj/structure/pipes/vents/pump/no_boom/gas/sec_vent = locate(params["vent"]) if(!istype(sec_vent) || sec_vent.welded) - to_chat(operator, SPAN_WARNING("ERROR: Gas release failure.")) + to_chat(user, SPAN_WARNING("ERROR: Gas release failure.")) playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) return FALSE if(!COOLDOWN_FINISHED(sec_vent, vent_trigger_cooldown)) - to_chat(operator, SPAN_WARNING("ERROR: Insufficient gas reserve for this vent.")) + to_chat(user, SPAN_WARNING("ERROR: Insufficient gas reserve for this vent.")) playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) return FALSE - to_chat(operator, SPAN_WARNING("Initiating gas release from [sec_vent.vent_tag].")) + to_chat(user, SPAN_WARNING("Initiating gas release from [sec_vent.vent_tag].")) playsound(src, 'sound/machines/chime.ogg', 15, 1) COOLDOWN_START(sec_vent, vent_trigger_cooldown, COOLDOWN_ARES_VENT) ares_apollo_talk("Nerve Gas release imminent from [sec_vent.vent_tag].") log_ares_security("Nerve Gas Release", "[last_login] released Nerve Gas from Vent '[sec_vent.vent_tag]'.") sec_vent.create_gas(VENT_GAS_CN20_XENO, 6, 5 SECONDS) - log_admin("[key_name(operator)] released nerve gas from Vent '[sec_vent.vent_tag]' via ARES.") + log_admin("[key_name(user)] released nerve gas from Vent '[sec_vent.vent_tag]' via ARES.") + + if("security_lockdown") + if(!COOLDOWN_FINISHED(datacore, aicore_lockdown)) + to_chat(user, SPAN_BOLDWARNING("AI Core Lockdown procedures are on cooldown! They will be ready in [COOLDOWN_SECONDSLEFT(datacore, aicore_lockdown)] seconds!")) + return FALSE + aicore_lockdown(user) + return TRUE if(playsound) var/sound = pick('sound/machines/pda_button1.ogg', 'sound/machines/pda_button2.ogg') diff --git a/code/game/machinery/aicore_lockdown.dm b/code/game/machinery/aicore_lockdown.dm new file mode 100644 index 000000000000..aaedf0fbfd63 --- /dev/null +++ b/code/game/machinery/aicore_lockdown.dm @@ -0,0 +1,118 @@ +/obj/structure/machinery/aicore_lockdown + name = "AI Core Lockdown" + icon_state = "big_red_button_tablev" + unslashable = TRUE + unacidable = TRUE + +/obj/structure/machinery/aicore_lockdown/ex_act(severity) + return FALSE + +/obj/structure/machinery/aicore_lockdown/attack_remote(mob/user as mob) + return FALSE + +/obj/structure/machinery/aicore_lockdown/attack_alien(mob/user as mob) + return FALSE + +/obj/structure/machinery/aicore_lockdown/attackby(obj/item/attacking_item, mob/user) + return attack_hand(user) + +/obj/structure/machinery/aicore_lockdown/attack_hand(mob/living/user) + if(isxeno(user)) + return FALSE + if(!allowed(user)) + to_chat(user, SPAN_DANGER("Access Denied")) + flick(initial(icon_state) + "-denied", src) + return FALSE + + if(!COOLDOWN_FINISHED(GLOB.ares_datacore, aicore_lockdown)) + to_chat(user, SPAN_BOLDWARNING("AI Core Lockdown procedures are on cooldown! They will be ready in [COOLDOWN_SECONDSLEFT(GLOB.ares_datacore, aicore_lockdown)] seconds!")) + return FALSE + + add_fingerprint(user) + aicore_lockdown(user) + +/obj/structure/machinery/door/poddoor/almayer/blended/ai_lockdown + name = "ARES Emergency Lockdown Shutter" + density = FALSE + open_layer = 1.9 + plane = FLOOR_PLANE + +/obj/structure/machinery/door/poddoor/almayer/blended/ai_lockdown/aicore + icon_state = "aidoor1" + base_icon_state = "aidoor" + +/obj/structure/machinery/door/poddoor/almayer/blended/ai_lockdown/aicore/white + icon_state = "w_aidoor1" + base_icon_state = "w_aidoor" + +/obj/structure/machinery/door/poddoor/almayer/blended/ai_lockdown/white + icon_state = "w_almayer_pdoor1" + base_icon_state = "w_almayer_pdoor" + +/obj/structure/machinery/door/poddoor/almayer/blended/ai_lockdown/Initialize() + . = ..() + RegisterSignal(SSdcs, COMSIG_GLOB_AICORE_LOCKDOWN, PROC_REF(close)) + RegisterSignal(SSdcs, COMSIG_GLOB_AICORE_LIFT, PROC_REF(open)) + + +/client/proc/admin_aicore_alert() + set name = "AI Core Lockdown" + set category = "Admin.Ship" + + if(!admin_holder ||!check_rights(R_EVENT)) + return FALSE + + var/prompt = "Are you sure you want to trigger an AI Core lockdown? This will raise to red alert, and lockdown the AI Core." + + if(GLOB.ares_datacore.ai_lockdown_active == TRUE) + prompt = "Are you sure you want to lift the AI Core lockdown? This will lower to blue alert." + + var/choice = tgui_alert(src, prompt, "Choose.", list("Yes", "No"), 20 SECONDS) + if(choice != "Yes") + return FALSE + + choice = tgui_alert(src, "Do you want to use a custom announcement?", "Choose.", list("Yes", "No"), 20 SECONDS) + if(choice == "Yes") + var/message = tgui_input_text(src, "Please enter announcement text.", "what?") + aicore_lockdown(usr, message, admin = TRUE) + else + aicore_lockdown(usr, admin = TRUE) + return TRUE + +/proc/aicore_lockdown(mob/user, message, admin = FALSE) + if(IsAdminAdvancedProcCall()) + return PROC_BLOCKED + + var/log = "[key_name(user)] triggered AI core lockdown!" + var/ares_log = "[user.name] triggered triggered AI Core Emergency Lockdown." + if(message) + log = "[key_name(user)] triggered AI core emergency lockdown! (Using a custom announcement)." + if(admin) + log += " (Admin Triggered)." + ares_log = "[MAIN_AI_SYSTEM] triggered AI Core Emergency Lockdown." + + if(GLOB.ares_datacore.ai_lockdown_active) + GLOB.ares_datacore.ai_lockdown_active = FALSE + if(!message) + message = "ATTENTION! \n\nAI CORE EMERGENCY LOCKDOWN LIFTED." + log = "[key_name(user)] lifted AI core lockdown!" + ares_log = "[user.name] lifted AI Core Emergency Lockdown." + if(admin) + log += " (Admin Triggered)." + ares_log = "[MAIN_AI_SYSTEM] lifted AI Core Emergency Lockdown." + + if(GLOB.security_level > SEC_LEVEL_GREEN) + set_security_level(SEC_LEVEL_BLUE, TRUE, FALSE) + SEND_GLOBAL_SIGNAL(COMSIG_GLOB_AICORE_LIFT) + else + GLOB.ares_datacore.ai_lockdown_active = TRUE + if(!message) + message = "ATTENTION! \n\nCORE SECURITY ALERT. \n\nAI CORE UNDER LOCKDOWN." + if(GLOB.security_level < SEC_LEVEL_RED) + set_security_level(SEC_LEVEL_RED, TRUE, FALSE) + SEND_GLOBAL_SIGNAL(COMSIG_GLOB_AICORE_LOCKDOWN) + + COOLDOWN_START(GLOB.ares_datacore, aicore_lockdown, 2 MINUTES) + shipwide_ai_announcement(message, MAIN_AI_SYSTEM, 'sound/effects/biohazard.ogg') + message_admins(log) + log_ares_security("AI Core Lockdown", ares_log) diff --git a/code/game/machinery/biohazard_lockdown.dm b/code/game/machinery/biohazard_lockdown.dm index 2e3cbf6de234..fdf7c026185d 100644 --- a/code/game/machinery/biohazard_lockdown.dm +++ b/code/game/machinery/biohazard_lockdown.dm @@ -1,6 +1,6 @@ #define LOCKDOWN_READY 0 #define LOCKDOWN_ACTIVE 1 -GLOBAL_VAR_INIT(lockdown_state, LOCKDOWN_READY) +GLOBAL_VAR_INIT(med_lockdown_state, LOCKDOWN_READY) /obj/structure/machinery/biohazard_lockdown name = "Emergency Containment Breach" @@ -51,7 +51,7 @@ GLOBAL_VAR_INIT(lockdown_state, LOCKDOWN_READY) base_icon_state = "w_almayer_pdoor" /client/proc/admin_biohazard_alert() - set name = "Containment Breach Alert" + set name = "Research Containment Lockdown" set category = "Admin.Ship" if(!admin_holder ||!check_rights(R_EVENT)) @@ -63,8 +63,8 @@ GLOBAL_VAR_INIT(lockdown_state, LOCKDOWN_READY) prompt = tgui_alert(src, "Do you want to use a custom announcement?", "Choose.", list("Yes", "No"), 20 SECONDS) if(prompt == "Yes") - var/whattoannounce = tgui_input_text(src, "Please enter announcement text.", "what?") - biohazard_lockdown(usr, whattoannounce, TRUE) + var/message = tgui_input_text(src, "Please enter announcement text.", "what?") + biohazard_lockdown(usr, message, admin = TRUE) else biohazard_lockdown(usr, admin = TRUE) return TRUE @@ -83,13 +83,14 @@ GLOBAL_VAR_INIT(lockdown_state, LOCKDOWN_READY) log += " (Admin Triggered)." ares_log = "[MAIN_AI_SYSTEM] triggered Medical Research Biohazard Containment Lockdown." - switch(GLOB.lockdown_state) + switch(GLOB.med_lockdown_state) if(LOCKDOWN_READY) - GLOB.lockdown_state = LOCKDOWN_ACTIVE - set_security_level(SEC_LEVEL_RED, TRUE, FALSE) + GLOB.med_lockdown_state = LOCKDOWN_ACTIVE + if(GLOB.security_level < SEC_LEVEL_RED) + set_security_level(SEC_LEVEL_RED, TRUE, FALSE) SEND_GLOBAL_SIGNAL(COMSIG_GLOB_RESEARCH_LOCKDOWN) if(LOCKDOWN_ACTIVE) - GLOB.lockdown_state = LOCKDOWN_READY + GLOB.med_lockdown_state = LOCKDOWN_READY message = "ATTENTION! \n\nBIOHAZARD CONTAINMENT LOCKDOWN LIFTED." log = "[key_name(user)] lifted research bio lockdown!" ares_log = "[user.name] lifted Medical Research Biohazard Containment Lockdown." @@ -97,7 +98,8 @@ GLOBAL_VAR_INIT(lockdown_state, LOCKDOWN_READY) log += " (Admin Triggered)." ares_log = "[MAIN_AI_SYSTEM] lifted Medical Research Biohazard Containment Lockdown." - set_security_level(SEC_LEVEL_BLUE, TRUE, FALSE) + if(GLOB.security_level > SEC_LEVEL_GREEN) + set_security_level(SEC_LEVEL_BLUE, TRUE, FALSE) SEND_GLOBAL_SIGNAL(COMSIG_GLOB_RESEARCH_LIFT) shipwide_ai_announcement(message, MAIN_AI_SYSTEM, 'sound/effects/biohazard.ogg') diff --git a/code/game/machinery/computer/dropship_weapons.dm b/code/game/machinery/computer/dropship_weapons.dm index dce026f4ce33..017a5f0736ca 100644 --- a/code/game/machinery/computer/dropship_weapons.dm +++ b/code/game/machinery/computer/dropship_weapons.dm @@ -754,7 +754,7 @@ if (!dropship.in_flyby || dropship.mode != SHUTTLE_CALL) to_chat(user, SPAN_WARNING("Has to be in Fly By mode")) return FALSE - if (dropship.timer && dropship.timeLeft(1) < firemission_envelope.get_total_duration()) + if (dropship.timer && dropship.timeLeft(1) < firemission_envelope.flyoff_period) to_chat(user, SPAN_WARNING("Not enough time to complete the Fire Mission")) return FALSE var/datum/cas_signal/recorded_loc = firemission_envelope.recorded_loc diff --git a/code/game/objects/items/devices/binoculars.dm b/code/game/objects/items/devices/binoculars.dm index 84da7d9acff4..b39526e231b5 100644 --- a/code/game/objects/items/devices/binoculars.dm +++ b/code/game/objects/items/devices/binoculars.dm @@ -354,13 +354,16 @@ /obj/item/device/binoculars/range/designator/scout name = "scout laser designator" desc = "An improved laser designator, issued to USCM scouts, with two modes: target marking for CAS with IR laser and rangefinding. Ctrl + Click turf to target something. Ctrl + Click designator to stop lasing. Alt + Click designator to switch modes." + unacidable = TRUE + indestructible = TRUE cooldown_duration = 80 target_acquisition_delay = 30 /obj/item/device/binoculars/range/designator/spotter name = "spotter's laser designator" desc = "A specially-designed laser designator, issued to USCM spotters, with two modes: target marking for CAS with IR laser and rangefinding. Ctrl + Click turf to target something. Ctrl + Click designator to stop lasing. Alt + Click designator to switch modes. Additionally, a trained spotter can laze targets for a USCM marksman, increasing the speed of target acquisition. A targeting beam will connect the binoculars to the target, but it may inherit the user's cloak, if possible." - + unacidable = TRUE + indestructible = TRUE var/is_spotting = FALSE var/spotting_time = 10 SECONDS var/spotting_cooldown_delay = 5 SECONDS diff --git a/code/game/objects/items/storage/backpack.dm b/code/game/objects/items/storage/backpack.dm index 5e4bc8c726bd..4882db3b83ea 100644 --- a/code/game/objects/items/storage/backpack.dm +++ b/code/game/objects/items/storage/backpack.dm @@ -729,6 +729,8 @@ GLOBAL_LIST_EMPTY_TYPED(radio_packs, /obj/item/storage/backpack/marine/satchel/r name = "\improper M68 Thermal Cloak" desc = "The lightweight thermal dampeners and optical camouflage provided by this cloak are weaker than those found in standard USCM ghillie suits. In exchange, the cloak can be worn over combat armor and offers the wearer high maneuverability and adaptability to many environments." icon_state = "scout_cloak" + unacidable = TRUE + indestructible = TRUE uniform_restricted = list(/obj/item/clothing/suit/storage/marine/M3S) //Need to wear Scout armor and helmet to equip this. has_gamemode_skin = FALSE //same sprite for all gamemode. var/camo_active = FALSE diff --git a/code/game/turfs/floor_types.dm b/code/game/turfs/floor_types.dm index 8a8698d0c047..0a1842134480 100644 --- a/code/game/turfs/floor_types.dm +++ b/code/game/turfs/floor_types.dm @@ -325,12 +325,21 @@ /turf/open/floor/almayer/aicore/glowing icon_state = "ai_floor2" light_color = "#d69c46" - light_range = 2 + light_range = 3 /turf/open/floor/almayer/aicore/glowing/Initialize(mapload, ...) . = ..() set_light_on(TRUE) + RegisterSignal(SSdcs, COMSIG_GLOB_AICORE_LOCKDOWN, PROC_REF(start_emergency_light_on)) + RegisterSignal(SSdcs, COMSIG_GLOB_AICORE_LIFT, PROC_REF(start_emergency_light_off)) + +/turf/open/floor/almayer/aicore/glowing/proc/start_emergency_light_on() + set_light(l_color = "#c70f0f") + +/turf/open/floor/almayer/aicore/glowing/proc/start_emergency_light_off() + set_light(l_color = "#d69c46") + /turf/open/floor/almayer/aicore/no_build allow_construction = FALSE hull_floor = TRUE diff --git a/code/game/turfs/walls/walls.dm b/code/game/turfs/walls/walls.dm index 251b23ad9c57..1781739176b7 100644 --- a/code/game/turfs/walls/walls.dm +++ b/code/game/turfs/walls/walls.dm @@ -9,7 +9,7 @@ var/hull = 0 var/walltype = WALL_METAL /// when walls smooth with one another, the type of junction each wall is. - var/junctiontype + var/junctiontype var/thermite = 0 var/melting = FALSE var/claws_minimum = CLAW_TYPE_SHARP @@ -24,7 +24,7 @@ var/damage = 0 /// Wall will break down to girders if damage reaches this point - var/damage_cap = HEALTH_WALL + var/damage_cap = HEALTH_WALL var/damage_overlay var/global/damage_overlays[8] @@ -38,7 +38,7 @@ var/d_state = 0 //Normal walls are now as difficult to remove as reinforced walls /// the acid hole inside the wall - var/obj/effect/acid_hole/acided_hole + var/obj/effect/acid_hole/acided_hole var/acided_hole_dir = SOUTH var/special_icon = 0 @@ -178,7 +178,7 @@ switch(d_state) if(WALL_STATE_WELD) - . += SPAN_INFO("The outer plating is intact. A blowtorch should slice it open.") + . += SPAN_INFO("The outer plating is intact. If you are not on help intent, a blowtorch should slice it open.") if(WALL_STATE_SCREW) . += SPAN_INFO("The outer plating has been sliced open. A screwdriver should remove the support lines.") if(WALL_STATE_WIRECUTTER) @@ -482,6 +482,8 @@ /turf/closed/wall/proc/try_weldingtool_usage(obj/item/W, mob/user) if(!damage || !iswelder(W)) return FALSE + if(user.a_intent != INTENT_HELP) + return FALSE var/obj/item/tool/weldingtool/WT = W if(WT.remove_fuel(0, user)) @@ -504,6 +506,8 @@ if(!(WT.remove_fuel(0, user))) to_chat(user, SPAN_WARNING("You need more welding fuel!")) return + if(user.a_intent == INTENT_HELP) + return playsound(src, 'sound/items/Welder.ogg', 25, 1) user.visible_message(SPAN_NOTICE("[user] begins slicing through the outer plating."), diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 626758fc2a5a..da95fc090da8 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -138,6 +138,7 @@ GLOBAL_LIST_INIT(admin_verbs_minor_event, list( /client/proc/adminpanelweapons, /client/proc/admin_general_quarters, /client/proc/admin_biohazard_alert, + /client/proc/admin_aicore_alert, /client/proc/toggle_hardcore_perma, /client/proc/toggle_bypass_joe_restriction, /client/proc/toggle_joe_respawns, diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/queen/queen_powers.dm b/code/modules/mob/living/carbon/xenomorph/abilities/queen/queen_powers.dm index 1f37651b2c8e..38e643e0d25c 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/queen/queen_powers.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/queen/queen_powers.dm @@ -371,10 +371,17 @@ xeno.use_plasma(plasma_cost_jelly) return /datum/action/xeno_action/onclick/manage_hive/use_ability(atom/Atom) - var/mob/living/carbon/xenomorph/queen/queenbanish = owner + var/mob/living/carbon/xenomorph/queen/queen_manager = owner plasma_cost = 0 - - var/choice = tgui_input_list(queenbanish, "Manage The Hive", "Hive Management", list("Banish (500)", "Re-Admit (100)", "De-evolve (500)", "Reward Jelly (500)", "Exchange larva for evolution (100)",), theme="hive_status") + var/list/options = list("Banish (500)", "Re-Admit (100)", "De-evolve (500)", "Reward Jelly (500)", "Exchange larva for evolution (100)",) + if(queen_manager.hive.hivenumber == XENO_HIVE_CORRUPTED) + var/datum/hive_status/corrupted/hive = queen_manager.hive + options += "Add Personal Ally" + if(length(hive.personal_allies)) + options += "Remove Personal Ally" + options += "Clear Personal Allies" + + var/choice = tgui_input_list(queen_manager, "Manage The Hive", "Hive Management", options, theme="hive_status") switch(choice) if("Banish (500)") banish() @@ -383,9 +390,118 @@ if("De-evolve (500)") de_evolve_other() if("Reward Jelly (500)") - give_jelly_reward(queenbanish.hive) + give_jelly_reward(queen_manager.hive) if("Exchange larva for evolution (100)") give_evo_points() + if("Add Personal Ally") + add_personal_ally() + if("Remove Personal Ally") + remove_personal_ally() + if("Clear Personal Allies") + clear_personal_allies() + +/datum/action/xeno_action/onclick/manage_hive/proc/add_personal_ally() + var/mob/living/carbon/xenomorph/queen/user_xeno = owner + if(user_xeno.hive.hivenumber != XENO_HIVE_CORRUPTED) + return + + if(!user_xeno.check_state()) + return + + var/datum/hive_status/corrupted/hive = user_xeno.hive + var/list/target_list = list() + if(!user_xeno.client) + return + for(var/mob/living/carbon/human/possible_target in range(7, user_xeno.client.eye)) + if(possible_target.stat == DEAD) + continue + if(possible_target.status_flags & CORRUPTED_ALLY) + continue + if(possible_target.hivenumber) + continue + target_list += possible_target + + if(!length(target_list)) + to_chat(user_xeno, SPAN_WARNING("No talls in view.")) + return + var/mob/living/target_mob = tgui_input_list(usr, "Target", "Set Up a Personal Alliance With...", target_list, theme="hive_status") + + if(!user_xeno.check_state(TRUE)) + return + + if(!target_mob) + return + + if(target_mob.hivenumber) + to_chat(user_xeno, SPAN_WARNING("We cannot set up a personal alliance with a hive cultist.")) + return + + hive.add_personal_ally(target_mob) + +/datum/action/xeno_action/onclick/manage_hive/proc/remove_personal_ally() + var/mob/living/carbon/xenomorph/queen/user_xeno = owner + if(user_xeno.hive.hivenumber != XENO_HIVE_CORRUPTED) + return + + if(!user_xeno.check_state()) + return + + var/datum/hive_status/corrupted/hive = user_xeno.hive + + if(!length(hive.personal_allies)) + to_chat(user_xeno, SPAN_WARNING("We don't have personal allies.")) + return + + var/list/mob/living/allies = list() + var/list/datum/weakref/dead_refs = list() + for(var/datum/weakref/ally_ref as anything in hive.personal_allies) + var/mob/living/ally = ally_ref.resolve() + if(ally) + allies += ally + continue + dead_refs += ally_ref + + hive.personal_allies -= dead_refs + + if(!length(allies)) + to_chat(user_xeno, SPAN_WARNING("We don't have personal allies.")) + return + + var/mob/living/target_mob = tgui_input_list(usr, "Target", "Break the Personal Alliance With...", allies, theme="hive_status") + + if(!target_mob) + return + + var/target_mob_ref = WEAKREF(target_mob) + + if(!(target_mob_ref in hive.personal_allies)) + return + + if(!user_xeno.check_state(TRUE)) + return + + hive.remove_personal_ally(target_mob_ref) + +/datum/action/xeno_action/onclick/manage_hive/proc/clear_personal_allies() + var/mob/living/carbon/xenomorph/queen/user_xeno = owner + if(user_xeno.hive.hivenumber != XENO_HIVE_CORRUPTED) + return + + if(!user_xeno.check_state()) + return + + var/datum/hive_status/corrupted/hive = user_xeno.hive + if(!length(hive.personal_allies)) + to_chat(user_xeno, SPAN_WARNING("We don't have personal allies.")) + return + + if(tgui_alert(user_xeno, "Are you sure you want to clear personal allies?", "Clear Personal Allies", list("No", "Yes"), 10 SECONDS) != "Yes") + return + + if(!length(hive.personal_allies)) + return + + hive.clear_personal_allies() /datum/action/xeno_action/onclick/manage_hive/proc/banish() diff --git a/code/modules/mob/living/carbon/xenomorph/hive_status.dm b/code/modules/mob/living/carbon/xenomorph/hive_status.dm index 22b061715892..baa736382733 100644 --- a/code/modules/mob/living/carbon/xenomorph/hive_status.dm +++ b/code/modules/mob/living/carbon/xenomorph/hive_status.dm @@ -979,6 +979,7 @@ need_round_end_check = TRUE var/list/defectors = list() + var/list/datum/weakref/personal_allies = list() /datum/hive_status/corrupted/add_xeno(mob/living/carbon/xenomorph/xeno) . = ..() @@ -1253,9 +1254,9 @@ if(living_xeno_queen) if(allies[faction]) - xeno_message(SPAN_XENOANNOUNCE("Your Queen set up an alliance with [faction]!"), 3, hivenumber) + xeno_message(SPAN_XENOANNOUNCE("Our Queen set up an alliance with [faction]!"), 3, hivenumber) else - xeno_message(SPAN_XENOANNOUNCE("Your Queen broke the alliance with [faction]!"), 3, hivenumber) + xeno_message(SPAN_XENOANNOUNCE("Our Queen broke the alliance with [faction]!"), 3, hivenumber) for(var/number in GLOB.hive_datum) var/datum/hive_status/target_hive = GLOB.hive_datum[number] @@ -1291,14 +1292,14 @@ addtimer(CALLBACK(src, PROC_REF(handle_defectors), faction), 11 SECONDS) /datum/hive_status/corrupted/proc/give_defection_choice(mob/living/carbon/xenomorph/xeno, faction) - if(tgui_alert(xeno, "Your Queen has broken the alliance with the [faction]. The device inside your carapace begins to suppress your connection with the Hive. Do you remove it and stay loyal to her?", "Alliance broken!", list("Stay loyal", "Obey the talls"), 10 SECONDS) == "Obey the talls") + if(tgui_alert(xeno, "Our Queen has broken the alliance with the [faction]. The device inside our carapace begins to suppress our connection with the Hive. Do we remove it and stay loyal to her?", "Alliance broken!", list("Stay loyal", "Obey the talls"), 10 SECONDS) == "Obey the talls") if(!xeno.iff_tag) to_chat(xeno, SPAN_XENOWARNING("It's too late now. The device is gone and our service to the Queen continues.")) return defectors += xeno xeno.set_hive_and_update(XENO_HIVE_RENEGADE) to_chat(xeno, SPAN_XENOANNOUNCE("You lost the connection with your Hive. Now you have no Queen, only your masters.")) - to_chat(xeno, SPAN_NOTICE("Our instincts have changed, we seem compelled to protect [english_list(xeno.iff_tag.faction_groups, "no one")].")) + to_chat(xeno, SPAN_NOTICE("Your instincts have changed, you seem compelled to protect [english_list(xeno.iff_tag.faction_groups, "no one")].")) return xeno.visible_message(SPAN_XENOWARNING("[xeno] rips out [xeno.iff_tag]!"), SPAN_XENOWARNING("We rip out [xeno.iff_tag]! For the Hive!")) xeno.adjustBruteLoss(50) @@ -1313,20 +1314,58 @@ continue if(!(faction in xeno.iff_tag.faction_groups)) continue - xeno.visible_message(SPAN_XENOWARNING("[xeno] rips out [xeno.iff_tag]!"), SPAN_XENOWARNING("You rip out [xeno.iff_tag]! For the hive!")) + xeno.visible_message(SPAN_XENOWARNING("[xeno] rips out [xeno.iff_tag]!"), SPAN_XENOWARNING("We rip out [xeno.iff_tag]! For the hive!")) xeno.adjustBruteLoss(50) xeno.iff_tag.forceMove(get_turf(xeno)) xeno.iff_tag = null if(!length(defectors)) return - xeno_message(SPAN_XENOANNOUNCE("You sense that [english_list(defectors)] turned their backs against their sisters and the Queen in favor of their slavemasters!"), 3, hivenumber) + xeno_message(SPAN_XENOANNOUNCE("We sense that [english_list(defectors)] turned their backs against their sisters and the Queen in favor of their slavemasters!"), 3, hivenumber) defectors.Cut() +/datum/hive_status/corrupted/proc/add_personal_ally(mob/living/ally) + personal_allies += WEAKREF(ally) + ally.status_flags |= CORRUPTED_ALLY + ally.med_hud_set_status() + xeno_message(SPAN_XENOANNOUNCE("Our Queen proclaimed [ally] our ally! We must not harm them."), 3, hivenumber) + +/datum/hive_status/corrupted/proc/remove_personal_ally(datum/weakref/ally_ref) + personal_allies -= ally_ref + var/mob/living/ally = ally_ref.resolve() + if(ally) + ally.status_flags &= ~CORRUPTED_ALLY + ally.med_hud_set_status() + xeno_message(SPAN_XENOANNOUNCE("Our Queen has declared that [ally] is no longer our ally!"), 3, hivenumber) + +/datum/hive_status/corrupted/proc/clear_personal_allies(death = FALSE) + for(var/datum/weakref/ally_ref in personal_allies) + var/mob/living/ally = ally_ref.resolve() + if(!ally) + continue + ally.status_flags &= ~CORRUPTED_ALLY + ally.med_hud_set_status() + personal_allies.Cut() + if(!death) + xeno_message(SPAN_XENOANNOUNCE("Our Queen has broken all personal alliances with the talls! Favoritism is no more."), 3, hivenumber) + return + xeno_message(SPAN_XENOWARNING("With the death of the Queen, her friends no longer matter to us."), 3, hivenumber) + +/datum/hive_status/corrupted/is_ally(mob/living/living_mob) + if(living_mob.status_flags & CORRUPTED_ALLY) + return TRUE + return ..() + /datum/hive_status/proc/override_evilution(evil, override) if(SSxevolution) SSxevolution.override_power(hivenumber, evil, override) +/datum/hive_status/corrupted/on_queen_death() + ..() + if(!length(personal_allies)) + return + clear_personal_allies(TRUE) + //Xeno Resin Mark Shit, the very best place for it too :0) //Defines at the bottom of this list here will show up at the top in the mark menu /datum/xeno_mark_define diff --git a/code/modules/paperwork/desk_bell.dm b/code/modules/paperwork/desk_bell.dm index 6e7de1101ae7..ddd4a9dc5d58 100644 --- a/code/modules/paperwork/desk_bell.dm +++ b/code/modules/paperwork/desk_bell.dm @@ -93,3 +93,12 @@ flick("desk_bell_activate", src) times_rang++ return TRUE + +/obj/item/desk_bell/ares + name = "AI core reception bell" + +/obj/item/desk_bell/ares/ring_bell(mob/living/user) + if(broken_ringer) + return FALSE + ares_apollo_talk("Attendence requested at AI Core Reception.") + return ..() diff --git a/colonialmarines.dme b/colonialmarines.dme index 9392e74febea..cab62dffd2fc 100644 --- a/colonialmarines.dme +++ b/colonialmarines.dme @@ -822,6 +822,7 @@ #include "code\game\jobs\job\special\provost.dm" #include "code\game\jobs\job\special\uaac.dm" #include "code\game\jobs\job\special\uscm.dm" +#include "code\game\machinery\aicore_lockdown.dm" #include "code\game\machinery\air_alarm.dm" #include "code\game\machinery\air_sensor.dm" #include "code\game\machinery\autolathe.dm" diff --git a/html/changelogs/AutoChangeLog-pr-6094.yml b/html/changelogs/AutoChangeLog-pr-6094.yml new file mode 100644 index 000000000000..24ca7af1b3c4 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-6094.yml @@ -0,0 +1,5 @@ +author: "HumiliatedGoblin" +delete-after: True +changes: + - qol: "Now needs help intent to repair walls" + - qol: "Now needs disarm, grab and harm intent to deconstruct walls" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-6097.yml b/html/changelogs/AutoChangeLog-pr-6097.yml new file mode 100644 index 000000000000..e69ab191fbaf --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-6097.yml @@ -0,0 +1,5 @@ +author: "cuberound" +delete-after: True +changes: + - balance: "FM sound is 4 seconds before CAS open fire from 5" + - balance: "FM direction warning is 1 seconds before CAS open fire from 1.5" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-6155.yml b/html/changelogs/AutoChangeLog-pr-6155.yml new file mode 100644 index 000000000000..fddb8491f6d2 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-6155.yml @@ -0,0 +1,4 @@ +author: "ihatethisengine" +delete-after: True +changes: + - rscadd: "Corrupted Queen can set up personal alliances with humans" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-6173.yml b/html/changelogs/AutoChangeLog-pr-6173.yml new file mode 100644 index 000000000000..bec3e4ad190e --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-6173.yml @@ -0,0 +1,7 @@ +author: "realforest2001" +delete-after: True +changes: + - rscadd: "Changed the AI Core Lockdown to the same system as Research Lockdown." + - rscadd: "Added a subtype of desk bell for the AI Core reception desk that sends an alert over APOLLO Link." + - imageadd: "Added directional blast door sprites from Thwomper for blended black shutters." + - code_imp: "Renamed operator var in apollo console code to user." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-6192.yml b/html/changelogs/AutoChangeLog-pr-6192.yml new file mode 100644 index 000000000000..4e3fc164c00b --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-6192.yml @@ -0,0 +1,4 @@ +author: "Git-Nivrak" +delete-after: True +changes: + - rscadd: "Survivors can now receive command announcements with IFF and a marine headset." \ No newline at end of file diff --git a/html/changelogs/archive/2024-04.yml b/html/changelogs/archive/2024-04.yml index 9aab61922f48..bf3a3c8de208 100644 --- a/html/changelogs/archive/2024-04.yml +++ b/html/changelogs/archive/2024-04.yml @@ -349,3 +349,7 @@ hand labeler. realforest2001: - spellcheck: Fixes a typo for M4RA AP Ammo in the ASRS menu. +2024-04-27: + Lagomorphica: + - balance: The spotter laser designators, scout laser designators, and scout cloak + are now unmeltable and indestructible to explosions. diff --git a/icons/mob/hud/hud.dmi b/icons/mob/hud/hud.dmi index 507ec0dd485b..8d89fb781264 100644 Binary files a/icons/mob/hud/hud.dmi and b/icons/mob/hud/hud.dmi differ diff --git a/icons/obj/structures/doors/blastdoors_shutters.dmi b/icons/obj/structures/doors/blastdoors_shutters.dmi index 8c63d0580922..1fe1df44b23a 100644 Binary files a/icons/obj/structures/doors/blastdoors_shutters.dmi and b/icons/obj/structures/doors/blastdoors_shutters.dmi differ diff --git a/maps/map_files/USS_Almayer/USS_Almayer.dmm b/maps/map_files/USS_Almayer/USS_Almayer.dmm index 6bc6bfeb4a22..1c2e3e5b68b0 100644 --- a/maps/map_files/USS_Almayer/USS_Almayer.dmm +++ b/maps/map_files/USS_Almayer/USS_Almayer.dmm @@ -14160,6 +14160,15 @@ icon_state = "red" }, /area/almayer/shipboard/weapon_room) +"bFg" = ( +/obj/effect/decal/warning_stripes{ + icon_state = "W"; + layer = 3.3 + }, +/turf/open/floor/almayer/aicore/no_build{ + icon_state = "ai_floor2" + }, +/area/almayer/command/airoom) "bFj" = ( /obj/structure/pipes/standard/simple/hidden/supply{ dir = 4 @@ -14601,15 +14610,7 @@ name = "\improper ARES Mainframe Shutters"; plane = -7 }, -/obj/structure/machinery/door/poddoor/almayer/blended/aicore/open{ - closed_layer = 3.2; - id = "ARES Emergency"; - layer = 3.2; - name = "ARES Emergency Lockdown"; - needs_power = 0; - open_layer = 1.9; - plane = -7 - }, +/obj/structure/machinery/door/poddoor/almayer/blended/ai_lockdown/aicore, /turf/open/floor/almayer/no_build{ icon_state = "test_floor4" }, @@ -20167,15 +20168,15 @@ /obj/structure/disposalpipe/trunk{ dir = 1 }, -/obj/structure/disposaloutlet{ +/obj/structure/machinery/disposal/delivery{ density = 0; - desc = "An outlet for the pneumatic delivery system."; - icon_state = "delivery_outlet"; - name = "take-ins"; - pixel_x = -1; + desc = "A pneumatic delivery unit."; + icon_state = "delivery_engi"; + name = "Returns"; pixel_y = 28; - range = 0 + pixel_x = 25 }, +/obj/structure/surface/rack, /turf/open/floor/almayer/aicore/no_build, /area/almayer/command/airoom) "cJK" = ( @@ -22464,7 +22465,9 @@ autoname = 0; c_tag = "AI - Secondary Processors" }, -/turf/open/floor/almayer/aicore/glowing/no_build, +/turf/open/floor/almayer/aicore/no_build{ + icon_state = "ai_floor2" + }, /area/almayer/command/airoom) "dzG" = ( /obj/structure/reagent_dispensers/peppertank{ @@ -25241,6 +25244,19 @@ icon_state = "plate" }, /area/almayer/shipboard/starboard_point_defense) +"etM" = ( +/obj/effect/decal/warning_stripes{ + icon_state = "S"; + layer = 3.3 + }, +/obj/effect/decal/warning_stripes{ + icon_state = "NE-out"; + pixel_y = 1 + }, +/turf/open/floor/almayer/aicore/no_build{ + icon_state = "ai_floor2" + }, +/area/almayer/command/airoom) "etN" = ( /obj/effect/landmark/yautja_teleport, /turf/open/floor/plating/plating_catwalk, @@ -26358,7 +26374,7 @@ /obj/structure/machinery/door_control{ id = "ARES StairsUpper"; name = "ARES Core Access"; - pixel_x = -10; + pixel_x = -5; pixel_y = -24; req_one_access_txt = "91;92" }, @@ -26366,20 +26382,14 @@ id = "ARES StairsLock"; name = "ARES Exterior Lockdown"; pixel_y = -24; - req_one_access_txt = "91;92" + req_one_access_txt = "91;92"; + pixel_x = 6 }, /obj/structure/surface/table/reinforced/almayer_B{ indestructible = 1; unacidable = 1; unslashable = 1 }, -/obj/structure/machinery/door_control{ - id = "ARES Emergency"; - name = "ARES Emergency Lockdown"; - pixel_x = 10; - pixel_y = -24; - req_one_access_txt = "91;92" - }, /obj/structure/machinery/computer/cameras/almayer{ dir = 4; pixel_y = 12 @@ -26769,18 +26779,19 @@ /turf/open/floor/almayer, /area/almayer/living/offices) "eXy" = ( -/obj/effect/step_trigger/teleporter_vector{ +/obj/effect/projector{ name = "Almayer_AresDown"; vector_x = 96; vector_y = -65 }, -/obj/structure/machinery/light{ - dir = 1 - }, /obj/structure/stairs{ - dir = 1 + dir = 1; + icon_state = "ramptop" + }, +/turf/open/floor/almayer/aicore/glowing/no_build{ + icon_state = "ai_floor3"; + light_range = 3 }, -/turf/open/floor/almayer/aicore/no_build, /area/almayer/command/airoom) "eXD" = ( /obj/structure/prop/invuln/lattice_prop{ @@ -28784,7 +28795,9 @@ /obj/effect/decal/warning_stripes{ icon_state = "SW-out" }, -/turf/open/floor/almayer/aicore/glowing/no_build, +/turf/open/floor/almayer/aicore/no_build{ + icon_state = "ai_floor2" + }, /area/almayer/command/airoom) "fKh" = ( /obj/structure/window/framed/almayer, @@ -28951,15 +28964,6 @@ plane = -7 }, /obj/effect/step_trigger/ares_alert/core, -/obj/structure/machinery/door/poddoor/almayer/blended/aicore/open{ - closed_layer = 3.2; - id = "ARES Emergency"; - layer = 3.2; - name = "ARES Emergency Lockdown"; - needs_power = 0; - open_layer = 1.9; - plane = -7 - }, /obj/structure/sign/safety/laser{ pixel_x = 32; pixel_y = -8 @@ -28968,6 +28972,7 @@ pixel_x = 32; pixel_y = 6 }, +/obj/structure/machinery/door/poddoor/almayer/blended/ai_lockdown/aicore, /turf/open/floor/almayer/no_build{ icon_state = "test_floor4" }, @@ -31207,6 +31212,9 @@ req_one_access_txt = "91;92"; dir = 1 }, +/obj/structure/machinery/door/poddoor/almayer/blended/ai_lockdown/aicore{ + plane = -6 + }, /turf/open/floor/almayer/no_build{ icon_state = "test_floor4" }, @@ -35739,7 +35747,9 @@ /obj/effect/decal/warning_stripes{ icon_state = "SE-out" }, -/turf/open/floor/almayer/aicore/glowing/no_build, +/turf/open/floor/almayer/aicore/no_build{ + icon_state = "ai_floor2" + }, /area/almayer/command/airoom) "igs" = ( /obj/structure/surface/table/almayer, @@ -36051,17 +36061,12 @@ name = "\improper ARES Core Shutters"; plane = -7 }, -/obj/structure/machinery/door/poddoor/almayer/blended/open{ - id = "ARES Emergency"; - name = "ARES Emergency Lockdown"; - open_layer = 1.9; - plane = -7 - }, /obj/structure/disposalpipe/up/almayer{ id = "ares_vault_in"; name = "aicore"; dir = 2 }, +/obj/structure/machinery/door/poddoor/almayer/blended/ai_lockdown, /turf/open/floor/almayer/no_build{ icon_state = "test_floor4" }, @@ -36683,9 +36688,9 @@ }, /area/almayer/squads/delta) "izf" = ( -/obj/structure/disposalpipe/down/almayer{ +/obj/structure/disposalpipe/up/almayer{ dir = 4; - id = "ares_vault_in"; + id = "ares_vault_out"; name = "aicore" }, /turf/closed/wall/almayer/aicore/hull, @@ -38339,15 +38344,14 @@ pixel_x = -2; pixel_y = 26 }, -/obj/structure/machinery/door_control/brbutton{ - id = "ARES Emergency"; - name = "ARES Emergency Lockdown Override"; - pixel_x = 8; - pixel_y = 26 - }, /obj/structure/machinery/computer/cameras/almayer/ares{ dir = 4 }, +/obj/structure/machinery/aicore_lockdown{ + icon_state = "big_red_button_wallv"; + pixel_x = 8; + pixel_y = 26 + }, /turf/open/floor/wood/ship, /area/almayer/living/commandbunks) "jbX" = ( @@ -39300,15 +39304,7 @@ plane = -7 }, /obj/effect/step_trigger/ares_alert/core, -/obj/structure/machinery/door/poddoor/almayer/blended/aicore/open{ - closed_layer = 3.2; - id = "ARES Emergency"; - layer = 3.2; - name = "ARES Emergency Lockdown"; - needs_power = 0; - open_layer = 1.9; - plane = -7 - }, +/obj/structure/machinery/door/poddoor/almayer/blended/ai_lockdown/aicore, /turf/open/floor/almayer/no_build{ icon_state = "test_floor4" }, @@ -48270,6 +48266,10 @@ /area/almayer/living/port_emb) "mAe" = ( /obj/structure/window/framed/almayer/aicore/hull/black/hijack_bustable, +/obj/structure/machinery/door/poddoor/almayer/blended/ai_lockdown{ + plane = -6; + dir = 4 + }, /turf/open/floor/almayer/aicore/no_build, /area/almayer/command/airoom) "mAp" = ( @@ -48607,15 +48607,7 @@ name = "\improper ARES Mainframe Shutters"; plane = -7 }, -/obj/structure/machinery/door/poddoor/almayer/blended/aicore/open{ - closed_layer = 3.2; - id = "ARES Emergency"; - layer = 3.2; - name = "ARES Emergency Lockdown"; - needs_power = 0; - open_layer = 1.9; - plane = -7 - }, +/obj/structure/machinery/door/poddoor/almayer/blended/ai_lockdown/aicore, /turf/open/floor/almayer/no_build{ icon_state = "test_floor4" }, @@ -49291,15 +49283,6 @@ plane = -7 }, /obj/effect/step_trigger/ares_alert/core, -/obj/structure/machinery/door/poddoor/almayer/blended/aicore/open{ - closed_layer = 3.2; - id = "ARES Emergency"; - layer = 3.2; - name = "ARES Emergency Lockdown"; - needs_power = 0; - open_layer = 1.9; - plane = -7 - }, /obj/structure/sign/safety/terminal{ pixel_x = -18; pixel_y = -8 @@ -49308,6 +49291,7 @@ pixel_x = -18; pixel_y = 6 }, +/obj/structure/machinery/door/poddoor/almayer/blended/ai_lockdown/aicore, /turf/open/floor/almayer/no_build{ icon_state = "test_floor4" }, @@ -50866,9 +50850,9 @@ /turf/open/floor/plating, /area/almayer/engineering/starboard_atmos) "npq" = ( -/obj/structure/disposalpipe/up/almayer{ +/obj/structure/disposalpipe/down/almayer{ dir = 8; - id = "ares_vault_out"; + id = "ares_vault_in"; name = "aicore" }, /turf/closed/wall/almayer/aicore/hull, @@ -51959,16 +51943,18 @@ }, /area/almayer/command/lifeboat) "nKO" = ( -/obj/structure/machinery/disposal/delivery{ - density = 0; - desc = "A pneumatic delivery unit."; - icon_state = "delivery_engi"; - name = "Returns"; - pixel_y = 28 - }, /obj/structure/disposalpipe/trunk{ dir = 1 }, +/obj/structure/disposaloutlet{ + density = 0; + desc = "An outlet for the pneumatic delivery system."; + icon_state = "delivery_outlet"; + name = "take-ins"; + pixel_x = 7; + pixel_y = 28; + range = 0 + }, /turf/open/floor/almayer/aicore/no_build, /area/almayer/command/airoom) "nKP" = ( @@ -52089,6 +52075,19 @@ icon_state = "red" }, /area/almayer/hallways/upper/port) +"nNA" = ( +/obj/effect/decal/warning_stripes{ + icon_state = "N"; + pixel_y = 1 + }, +/obj/effect/decal/warning_stripes{ + icon_state = "S"; + layer = 3.3 + }, +/turf/open/floor/almayer/aicore/no_build{ + icon_state = "ai_floor2" + }, +/area/almayer/command/airoom) "nNH" = ( /turf/open/floor/almayer{ dir = 1; @@ -52718,6 +52717,19 @@ }, /turf/open/floor/wood/ship, /area/almayer/shipboard/brig/cells) +"nYg" = ( +/obj/effect/decal/warning_stripes{ + icon_state = "S"; + layer = 3.3 + }, +/obj/effect/decal/warning_stripes{ + icon_state = "NW-out"; + pixel_y = 1 + }, +/turf/open/floor/almayer/aicore/no_build{ + icon_state = "ai_floor2" + }, +/area/almayer/command/airoom) "nYi" = ( /obj/effect/decal/cleanable/dirt, /turf/open/floor/almayer{ @@ -55897,6 +55909,20 @@ icon_state = "silver" }, /area/almayer/hallways/lower/repair_bay) +"oYZ" = ( +/obj/effect/step_trigger/teleporter_vector{ + name = "Almayer_AresDown"; + vector_x = 96; + vector_y = -65 + }, +/obj/structure/stairs{ + dir = 1 + }, +/turf/open/floor/almayer/aicore/glowing/no_build{ + icon_state = "ai_floor3"; + light_range = 3 + }, +/area/almayer/command/airoom) "oZp" = ( /obj/structure/surface/table/almayer, /obj/structure/machinery/light, @@ -64093,6 +64119,15 @@ icon_state = "silver" }, /area/almayer/hallways/lower/repair_bay) +"rOz" = ( +/obj/effect/decal/warning_stripes{ + icon_state = "S"; + layer = 3.3 + }, +/turf/open/floor/almayer/aicore/no_build{ + icon_state = "ai_floor2" + }, +/area/almayer/command/airoom) "rOC" = ( /obj/structure/machinery/light{ dir = 1 @@ -69482,12 +69517,7 @@ name = "\improper ARES Core Shutters"; plane = -7 }, -/obj/structure/machinery/door/poddoor/almayer/blended/open{ - id = "ARES Emergency"; - name = "ARES Emergency Lockdown"; - open_layer = 1.9; - plane = -7 - }, +/obj/structure/machinery/door/poddoor/almayer/blended/ai_lockdown, /turf/open/floor/almayer/no_build{ icon_state = "test_floor4" }, @@ -71028,6 +71058,14 @@ icon_state = "test_floor4" }, /area/almayer/command/cichallway) +"ujn" = ( +/obj/effect/decal/warning_stripes{ + icon_state = "E" + }, +/turf/open/floor/almayer/aicore/no_build{ + icon_state = "ai_floor2" + }, +/area/almayer/command/airoom) "ujz" = ( /obj/structure/disposalpipe/segment, /obj/structure/pipes/standard/simple/hidden/supply, @@ -72977,9 +73015,16 @@ unslashable = 1 }, /obj/item/paper_bin/uscm{ - pixel_y = 6 + pixel_y = 6; + pixel_x = -12 + }, +/obj/item/tool/pen{ + pixel_x = -14 + }, +/obj/structure/machinery/aicore_lockdown{ + pixel_y = 4; + pixel_x = 3 }, -/obj/item/tool/pen, /turf/open/floor/almayer/aicore/no_build, /area/almayer/command/airoom) "uVc" = ( @@ -74300,15 +74345,15 @@ unacidable = 1; unslashable = 1 }, -/obj/item/desk_bell{ - pixel_y = 14; - pixel_x = -5; - anchored = 1 - }, /obj/structure/machinery/computer/working_joe{ layer = 3.3; dir = 8 }, +/obj/item/desk_bell/ares{ + pixel_y = 14; + pixel_x = -5; + anchored = 1 + }, /turf/open/floor/almayer/aicore/no_build, /area/almayer/command/airoom) "vpI" = ( @@ -75229,7 +75274,9 @@ c_tag = "AI - Primary Processors"; autoname = 0 }, -/turf/open/floor/almayer/aicore/glowing/no_build, +/turf/open/floor/almayer/aicore/no_build{ + icon_state = "ai_floor2" + }, /area/almayer/command/airoom) "vCO" = ( /obj/effect/landmark/start/bridge, @@ -77454,15 +77501,7 @@ alert_message = "Caution: Movement detected in ARES Core."; cooldown_duration = 1200 }, -/obj/structure/machinery/door/poddoor/almayer/blended/aicore/open{ - closed_layer = 3.2; - id = "ARES Emergency"; - layer = 3.2; - name = "ARES Emergency Lockdown"; - needs_power = 0; - open_layer = 1.9; - plane = -7 - }, +/obj/structure/machinery/door/poddoor/almayer/blended/ai_lockdown/aicore, /turf/open/floor/almayer/no_build{ icon_state = "test_floor4" }, @@ -78331,12 +78370,7 @@ /area/almayer/maint/hull/lower/l_m_s) "wyQ" = ( /obj/structure/surface/table/reinforced/almayer_B, -/obj/structure/machinery/door_control{ - id = "ARES Emergency"; - indestructible = 1; - name = "ARES Emergency Lockdown"; - req_one_access_txt = "91;92" - }, +/obj/structure/machinery/aicore_lockdown, /turf/open/floor/almayer/no_build{ icon_state = "plating" }, @@ -121669,10 +121703,10 @@ sgH qdJ xIj mOi -eXy vRA +oYZ ezq -ezq +eXy tFe xQV pax @@ -140207,7 +140241,7 @@ qQS bIp fKe dDp -dDp +bFg frM lcg daz @@ -140409,9 +140443,9 @@ dIn rby bIp euN +ujn sEK -sEK -mlb +etM lcg daz lmz @@ -140611,10 +140645,10 @@ lnS uVv flf ebN -cxc +rOz kBy kBy -gfu +nNA fPB daz lmz @@ -142033,9 +142067,9 @@ yaQ vLz mFN kSy +bFg dDp -dDp -frM +nYg lcg daz lmz @@ -142237,7 +142271,7 @@ qQS mFN igr sEK -sEK +ujn mlb lcg daz diff --git a/tgui/packages/tgui/interfaces/AresInterface.jsx b/tgui/packages/tgui/interfaces/AresInterface.jsx index e553e66e4191..5eae405a9166 100644 --- a/tgui/packages/tgui/interfaces/AresInterface.jsx +++ b/tgui/packages/tgui/interfaces/AresInterface.jsx @@ -387,6 +387,20 @@ const MainMenu = (props) => { onClick={() => act('page_core_sec')} /> + + act('security_lockdown')} + /> + )} diff --git a/tgui/packages/tgui/interfaces/WorkingJoe.jsx b/tgui/packages/tgui/interfaces/WorkingJoe.jsx index 9596a6942f63..d1fabe26b48a 100644 --- a/tgui/packages/tgui/interfaces/WorkingJoe.jsx +++ b/tgui/packages/tgui/interfaces/WorkingJoe.jsx @@ -260,6 +260,20 @@ const MainMenu = (props) => { onClick={() => act('page_core_gas')} /> + + act('security_lockdown')} + /> + )}