From ddbe7073eb2d2bc195c8cadf5cd06d8eaca3a782 Mon Sep 17 00:00:00 2001 From: RustingWithYou <63625389+RustingWithYou@users.noreply.github.com> Date: Mon, 10 Jun 2024 00:09:08 +1200 Subject: [PATCH] Ve'katak Hivenet Receiver (#18771) Adds a new augment, available in loadout to non-Vaurca members of the Ve'katak Phalanx, which can receive Hivenet broadcasts and transmit from a selection of preset messages. Sprites done by @GMR25 --------- Signed-off-by: RustingWithYou <63625389+RustingWithYou@users.noreply.github.com> Co-authored-by: GMR25 Co-authored-by: Cody Brittain --- .../loadout/items/augments.dm | 9 + code/modules/mob/language/station.dm | 14 ++ .../mob/living/carbon/human/human_powers.dm | 211 ++++++++++++++---- .../augment/augments/language_processor.dm | 37 +++ html/changelogs/RustingWithYou - phalanx.yml | 41 ++++ icons/mob/human_races/augments_external.dmi | Bin 505 -> 633 bytes icons/obj/organs/augments.dmi | Bin 27048 -> 27249 bytes 7 files changed, 274 insertions(+), 38 deletions(-) create mode 100644 html/changelogs/RustingWithYou - phalanx.yml diff --git a/code/modules/client/preference_setup/loadout/items/augments.dm b/code/modules/client/preference_setup/loadout/items/augments.dm index 0f6214b91b4..4f8f073e776 100644 --- a/code/modules/client/preference_setup/loadout/items/augments.dm +++ b/code/modules/client/preference_setup/loadout/items/augments.dm @@ -262,3 +262,12 @@ allowed_roles = list("Physician", "Surgeon", "Pharmacist", "First Responder", "Psychiatrist", "Medical Intern", "Medical Personnel", "Security Officer", "Warden", "Security Cadet", "Investigator", "Security Personnel", "Corporate Liaison", "Assistant", "Off-Duty Crew Member") faction = "Private Military Contracting Group" cost = 1 + +/datum/gear/augment/vekatak_hivenet + display_name = "Ve'katak Phalanx Hivenet receiver" + description = "An experimental augment developed for the non-Vaurca of the Ve'katak Phalanx, allowing them to recieve Hivenet transmissions and send preset messages." + path = /obj/item/organ/internal/augment/language/vekatak + whitelisted = list(SPECIES_HUMAN, SPECIES_HUMAN_OFFWORLD, SPECIES_TAJARA, SPECIES_TAJARA_ZHAN, SPECIES_TAJARA_MSAI, SPECIES_SKRELL, SPECIES_SKRELL_AXIORI, SPECIES_IPC, SPECIES_IPC_G1, SPECIES_IPC_G2, SPECIES_IPC_XION, SPECIES_IPC_ZENGHU, SPECIES_IPC_BISHOP, SPECIES_IPC_SHELL, SPECIES_UNATHI) + faction = "Private Military Contracting Group" + cost = 4 + allowed_roles = list("Physician", "Surgeon", "Pharmacist", "First Responder", "Psychiatrist", "Medical Intern", "Medical Personnel", "Security Officer", "Warden", "Security Cadet", "Investigator", "Security Personnel", "Corporate Liaison", "Assistant", "Off-Duty Crew Member") diff --git a/code/modules/mob/language/station.dm b/code/modules/mob/language/station.dm index c29b329fecb..ef1ae0567b5 100644 --- a/code/modules/mob/language/station.dm +++ b/code/modules/mob/language/station.dm @@ -265,9 +265,13 @@ to_chat(player, encrypted_msg) continue var/obj/item/organ/internal/vaurca/neuralsocket/listener_socket = listener_human.internal_organs_by_name[BP_NEURAL_SOCKET] + var/obj/item/organ/internal/augment/language/vekatak/receiver = listener_human.internal_organs_by_name[BP_AUG_LANGUAGE] if(!listener_socket || listener_socket.decryption_key != speaker_encryption_key) to_chat(player, encrypted_msg) continue + if (!receiver || receiver.decryption_key != speaker_encryption_key) + to_chat(player, encrypted_msg) + continue to_chat(player, msg) /datum/language/bug/format_message(message, verb, speaker_mask) @@ -301,6 +305,10 @@ return 0 if(M.internal_organs_by_name[BP_NEURAL_SOCKET] && (GLOB.all_languages[LANGUAGE_VAURCA] in M.languages)) return 1 + if(M.internal_organs_by_name[BP_AUG_LANGUAGE]) + var/obj/item/organ/internal/augment/language/vekatak/V = M.internal_organs_by_name[BP_AUG_LANGUAGE] + if(istype(V) && (GLOB.all_languages[LANGUAGE_VAURCA] in M.languages)) + return 1 if(M.internal_organs_by_name["blackkois"]) return 1 @@ -321,11 +329,17 @@ /datum/language/bug/check_speech_restrict(var/mob/speaker) var/mob/living/carbon/human/H = speaker var/obj/item/organ/internal/vaurca/neuralsocket/S = H.internal_organs_by_name[BP_NEURAL_SOCKET] + var/obj/item/organ/internal/augment/language/vekatak/V = H.internal_organs_by_name[BP_AUG_LANGUAGE] //Black k'ois zombies don't have neural sockets but need to talk, hence check if the socket exists, or it will runtime for them if(S && (S.muted || S.disrupted)) to_chat(speaker, SPAN_WARNING("You have been muted over the Hivenet!")) return FALSE + + if(istype(V)) + if(!V.transmitting || V.disrupted || V.muted) + to_chat(speaker, SPAN_WARNING("Your implant cannot transmit over the Hivenet!")) + return FALSE else return TRUE diff --git a/code/modules/mob/living/carbon/human/human_powers.dm b/code/modules/mob/living/carbon/human/human_powers.dm index 67207f5def3..16f4d61657c 100644 --- a/code/modules/mob/living/carbon/human/human_powers.dm +++ b/code/modules/mob/living/carbon/human/human_powers.dm @@ -1415,13 +1415,32 @@ var/player_surname = player_fullname[2] if(player_surname == surname || HAS_TRAIT(src, TRAIT_ORIGIN_ELECTRONIC_WARFARE)) LAZYADD(available_vaurca, player) - var/mob/living/carbon/human/target = input(src, "Select a Vaurca to ban.", "Hivenet Ban") as null|anything in available_vaurca - if(!target || !isvaurca(target)) + if(player.internal_organs_by_name[BP_AUG_LANGUAGE]) + var/obj/item/organ/internal/augment/language/vekatak/V = player.internal_organs_by_name[BP_AUG_LANGUAGE] + if(istype(V)) + LAZYADD(available_vaurca, player) + var/mob/living/carbon/human/target = tgui_input_list(src, "Select a target to ban", "Hivenet Ban", available_vaurca) + if(!target) return var/obj/item/organ/internal/vaurca/neuralsocket/S = target.internal_organs_by_name[BP_NEURAL_SOCKET] + var/obj/item/organ/internal/augment/language/vekatak/V = target.internal_organs_by_name[BP_AUG_LANGUAGE] var/list/target_fullname = splittext(target.name, " ") - var/target_surname = target_fullname[2] - to_chat(src, target.real_name) + var/target_surname = target_fullname[target_fullname.len] + if(istype(V)) + if(!(GLOB.all_languages[LANGUAGE_VAURCA] in target.languages) && V.banned) + target.add_language(LANGUAGE_VAURCA) + V.banned = FALSE + to_chat(src, SPAN_NOTICE("You extend your will, restoring [target]'s connection to the Hivenet. Hopefully they will be better-behaved in future.")) + to_chat(target, SPAN_NOTICE("You feel your implant reactivate, as your limited connection to the Hivenet is restored.")) + return + else if((GLOB.all_languages[LANGUAGE_VAURCA] in target.languages) && !V.banned) + to_chat(src, SPAN_NOTICE("You extend your will, severing [target]'s connection to the Hivenet. Perhaps now they will learn their lesson.")) + to_chat(target, SPAN_WARNING("You feel your implant's connection to the Hivenet shut off, as [src]'s will severs it.")) + target.remove_language(LANGUAGE_VAURCA) + V.banned = TRUE + host.last_action = world.time + 1 MINUTES + return + if(!(GLOB.all_languages[LANGUAGE_VAURCA] in target.languages) && S.banned) target.add_language(LANGUAGE_VAURCA) S.banned = FALSE @@ -1505,16 +1524,16 @@ var/player_surname = player_fullname[2] if(player_surname == surname || HAS_TRAIT(src, TRAIT_ORIGIN_ELECTRONIC_WARFARE)) LAZYADD(available_vaurca, player) - var/mob/living/carbon/human/target = input(src, "Select a Vaurca to void.", "Hivenet Void") as null|anything in available_vaurca + var/mob/living/carbon/human/target = tgui_input_list(src, "Select a target to void", "Hivenet Void", available_vaurca) if(!target || !isvaurca(target)) return - var/choice = alert(src, "Are you sure you want to void [target]? This cannot be undone!", "Void User?", "Proceed", "Cancel") + var/choice = tgui_alert(src, "Are you sure you want to void [target]? This cannot be undone!", "Void User?", list("Proceed", "Cancel")) if(choice == "Cancel") return msg_admin_attack("[key_name_admin(src)] attempted to void [key_name_admin(target)]'s neural socket! (JMP)",ckey=key_name(src),ckey_target=key_name(target)) var/obj/item/organ/internal/vaurca/neuralsocket/S = target.internal_organs_by_name[BP_NEURAL_SOCKET] var/list/target_fullname = splittext(target.name, " ") - var/target_surname = target_fullname[2] + var/target_surname = target_fullname[target_fullname.len] if(target_surname == surname) if(S.shielded) to_chat(src, SPAN_WARNING("You feel a sudden pain in your neural socket as you are repelled by [target]'s countermeasures!")) @@ -1573,15 +1592,35 @@ for(var/mob/living/carbon/human/player in (GLOB.human_mob_list - src)) if(isvaurca(player) && player.internal_organs_by_name[BP_NEURAL_SOCKET]) var/list/player_fullname = splittext(player.name, " ") - var/player_surname = player_fullname[2] + var/player_surname = player_fullname[player_fullname.len] if(player_surname == surname || HAS_TRAIT(src, TRAIT_ORIGIN_ELECTRONIC_WARFARE)) LAZYADD(available_vaurca, player) - var/mob/living/carbon/human/target = input(src, "Select a Vaurca to mute.", "Hivenet Mute") as null|anything in available_vaurca - if(!target || !isvaurca(target)) + if(player.internal_organs_by_name[BP_AUG_LANGUAGE]) + var/obj/item/organ/internal/augment/language/vekatak/V = player.internal_organs_by_name[BP_AUG_LANGUAGE] + if(istype(V)) + LAZYADD(available_vaurca, player) + + var/mob/living/carbon/human/target = tgui_input_list(src, "Select a target to mute", "Hivenet Mute", available_vaurca) + if(!target) return var/obj/item/organ/internal/vaurca/neuralsocket/S = target.internal_organs_by_name[BP_NEURAL_SOCKET] + var/obj/item/organ/internal/augment/language/vekatak/V = target.internal_organs_by_name[BP_AUG_LANGUAGE] var/list/target_fullname = splittext(target.name, " ") - var/target_surname = target_fullname[2] + var/target_surname = target_fullname[target_fullname.len] + if(istype(V)) + if(V.banned) + to_chat(src, SPAN_NOTICE("[target] is already banned from the Hivenet. Muting them would be pointless.")) + return + if(V.muted) + V.muted = FALSE + to_chat(src, SPAN_NOTICE("You extend your will, restoring [target]'s ability to speak over the Hivenet. Hopefully it will be better-behaved in future.")) + to_chat(target, SPAN_NOTICE("You feel [src]'s restriction on your implant lifted, allowing you to transmit over the Hivenet once more.")) + return + to_chat(src, SPAN_NOTICE("You extend your will, disabling [target]'s Hivenet implant.")) + to_chat(target, SPAN_WARNING("You feel [src]'s will enter your mind, disabling your implant's transmission function. Though you can still receive Hivenet broadcasts, you are incapable of transmitting.")) + V.muted = TRUE + host.last_action = world.time + 5 MINUTES + return if(S.banned) to_chat(src, SPAN_NOTICE("[target] is already banned from the Hivenet. Muting them would be pointless.")) return @@ -1649,14 +1688,34 @@ set category = "Hivenet" var/obj/item/organ/internal/vaurca/neuralsocket/S = src.internal_organs_by_name[BP_NEURAL_SOCKET] - if(!src.can_hivenet()) + var/obj/item/organ/internal/augment/language/vekatak/V = src.internal_organs_by_name[BP_AUG_LANGUAGE] + if(src.stat != CONSCIOUS) + to_chat(src, SPAN_WARNING("You must be conscious to use this ability!")) return - if(S.decryption_key) - S.decryption_key = null - to_chat(src, SPAN_NOTICE("Your Hivenet decryption key has been reset.")) + + if(!(GLOB.all_languages[LANGUAGE_VAURCA] in src.languages)) + to_chat(src, SPAN_DANGER("Your mind is dark, unable to communicate with the Hive.")) return - S.decryption_key = input(src, "Enter a new decryption key for Hivenet messages.", "Hivenet Decryption") as text - to_chat(src, SPAN_NOTICE("Your Hivenet decryption key has been set to [S.decryption_key].")) + + if(!istype(S) && !istype(V)) + to_chat(src, SPAN_WARNING("You do not have a functional connection to the Hivenet!")) + return + + if(istype(S)) + if(S.decryption_key) + S.decryption_key = null + to_chat(src, SPAN_NOTICE("Your Hivenet decryption key has been reset.")) + return + S.decryption_key = tgui_input_text(src, "Enter a new decryption key for Hivenet messages", "Hivenet Decryption") + to_chat(src, SPAN_NOTICE("Your Hivenet decryption key has been set to [S.decryption_key].")) + + else if(istype(V)) + if(V.decryption_key) + V.decryption_key = null + to_chat(src, SPAN_NOTICE("Your Hivenet decryption key has been reset.")) + return + V.decryption_key = tgui_input_text(src, "Enter a new decryption key for Hivenet messages", "Hivenet Decryption") + to_chat(src, SPAN_NOTICE("Your Hivenet decryption key has been set to [V.decryption_key].")) /mob/living/carbon/human/proc/hivenet_encrypt() set name = "Set Hivenet Encryption" @@ -1669,7 +1728,7 @@ S.encryption_key = null to_chat(src, SPAN_NOTICE("Your Hivenet encryption key has been reset.")) return - S.encryption_key = input(src, "Enter a new encryption key for Hivenet messages.", "Hivenet Decryption") as text + S.encryption_key = tgui_input_text(src, "Enter a new encryption key for Hivenet messages", "Hivenet Encryption") to_chat(src, SPAN_NOTICE("Your Hivenet encryption key has been set to [S.encryption_key].")) /mob/living/carbon/human/proc/hivenet_decrypt() @@ -1716,25 +1775,35 @@ reset_view(0) return for(var/mob/living/carbon/human/player in (GLOB.human_mob_list - src)) + if(player.stat != CONSCIOUS) + continue if(isvaurca(player) && player.internal_organs_by_name[BP_NEURAL_SOCKET]) - if(player.stat != CONSCIOUS) - continue LAZYADD(available_vaurca, player) - var/mob/living/carbon/human/target = input(src, "Select a Vaurca to observe.", "Hivenet Remote Observation") as null|anything in available_vaurca - if(!target || !isvaurca(target)) + if(player.internal_organs_by_name[BP_AUG_LANGUAGE]) + var/obj/item/organ/internal/augment/language/vekatak/V = player.internal_organs_by_name[BP_AUG_LANGUAGE] + if(istype(V)) + LAZYADD(available_vaurca, player) + var/mob/living/carbon/human/target = tgui_input_list(src, "Select a Vaurca to observe.", "Hivenet Remote Observation", available_vaurca) + if(!target) remoteview_target = null reset_view(0) return + var/obj/item/organ/internal/augment/language/vekatak/V = target.internal_organs_by_name[BP_AUG_LANGUAGE] + if(istype(V)) + to_chat(src, SPAN_NOTICE("You extend your mind into the Hivenet, accessing [target]'s senses. Use this verb again to cancel.")) + remoteview_target = target + reset_view(target) + return var/obj/item/organ/internal/vaurca/neuralsocket/S = target.internal_organs_by_name[BP_NEURAL_SOCKET] var/list/target_fullname = splittext(target.name, " ") - var/target_surname = target_fullname[2] + var/target_surname = target_fullname[target_fullname.len] if(target_surname == surname && !S.shielded) to_chat(src, SPAN_NOTICE("You extend your mind into the Hivenet, accessing [target]'s senses. Use this verb again to cancel.")) remoteview_target = target reset_view(target) else host.last_action = world.time + 5 MINUTES - var/choice = alert(target, "[src] is attempting to access your senses. Do you wish to allow this?", "Hivenet Remote Observation", "Deny", "Allow") + var/choice = tgui_alert(target, "[src] is attempting to access your senses. Do you wish to allow this?", "Hivenet Remote Observation", list("Deny", "Allow")) if(choice == "Allow") to_chat(src, SPAN_NOTICE("You extend your mind into the Hivenet, accessing [target]'s senses. Use this verb again to cancel.")) remoteview_target = target @@ -1742,7 +1811,7 @@ if(choice == "Deny") if(HAS_TRAIT(src, TRAIT_ORIGIN_ELECTRONIC_WARFARE)) - var/hijack = alert(src, "[target] has denied your access request. Attempt a hijack?", "Hijack Hivenet Senses", "No", "Yes") + var/hijack = tgui_alert(src, "[target] has denied your access request. Attempt a hijack?", "Hijack Hivenet Senses", list("No", "Yes")) if(hijack == "Yes") if(prob(40) && !S.shielded) to_chat(src, SPAN_NOTICE("You extend your mind into the Hivenet, accessing [target]'s senses. Use this verb again to cancel.")) @@ -1777,15 +1846,28 @@ for(var/mob/living/carbon/human/player in (GLOB.human_mob_list - src)) if(isvaurca(player) && player.internal_organs_by_name[BP_NEURAL_SOCKET]) var/list/player_fullname = splittext(player.name, " ") - var/player_surname = player_fullname[2] + var/player_surname = player_fullname[player_fullname.len] if(player_surname == surname || HAS_TRAIT(src, TRAIT_ORIGIN_ELECTRONIC_WARFARE)) LAZYADD(available_vaurca, player) - var/mob/living/carbon/human/target = input(src, "Select a Vaurca to shock.", "Neural Shock") as null|anything in available_vaurca - if(!target || !isvaurca(target)) + if(player.internal_organs_by_name[BP_AUG_LANGUAGE]) + var/obj/item/organ/internal/augment/language/vekatak/V = player.internal_organs_by_name[BP_AUG_LANGUAGE] + if(istype(V)) + LAZYADD(available_vaurca, player) + var/mob/living/carbon/human/target = tgui_input_list(src, "Select a target to shock", "Neural Shock", available_vaurca) + if(!target) + return + var/obj/item/organ/internal/augment/language/vekatak/V = target.internal_organs_by_name[BP_AUG_LANGUAGE] + if(istype(V)) + to_chat(src, SPAN_WARNING("You lash out over the Hivenet, delivering a neural shock to [target]!")) + to_chat(target, SPAN_DANGER("You feel [src]'s will strike out at you, pain burning inside your head!")) + target.adjustHalLoss(15) + target.flash_pain(15) + target.adjustBrainLoss(10) + host.last_action = world.time + 5 MINUTES return var/obj/item/organ/internal/vaurca/neuralsocket/S = target.internal_organs_by_name[BP_NEURAL_SOCKET] var/list/target_fullname = splittext(target.name, " ") - var/target_surname = target_fullname[2] + var/target_surname = target_fullname[target_fullname.len] if(!istype(S) || S.is_broken()) to_chat(src, SPAN_WARNING("The target must have a functional neural socket!")) return @@ -1832,10 +1914,9 @@ if(HAS_TRAIT(src, TRAIT_ORIGIN_ELECTRONIC_WARFARE)) max = 5 if(length(host.shielded_sockets)) - var/choice = alert(src, "Do you wish to remove your protection from a Vaurca?", "Hivenet Defensive Lattice", "No", "Yes") - to_chat(src, SPAN_NOTICE("You chose [choice]")) + var/choice = tgui_alert(src, "Do you wish to remove your protection from a Vaurca?", "Hivenet Defensive Lattice", list("No", "Yes")) if(choice == "Yes") - var/mob/living/carbon/human/H = input(src, "Select a Vaurca to remove your defenses from.", "Hivenet Defensive Lattice", null) as anything in host.shielded_mobs + var/mob/living/carbon/human/H = tgui_input_list(src, "Select a Vaurca to remove your defenses from.", "Hivenet Defensive Lattice", host.shielded_mobs) var/obj/item/organ/internal/vaurca/neuralsocket/S = H.internal_organs_by_name[BP_NEURAL_SOCKET] to_chat(src, SPAN_NOTICE("You remove your protection from [H]'s neural socket.")) to_chat(H, SPAN_WARNING("You feel [src]'s protection vanish from you, leaving your neural socket exposed.")) @@ -1882,14 +1963,30 @@ continue if(isvaurca(player) && player.internal_organs_by_name[BP_NEURAL_SOCKET]) LAZYADD(available_vaurca, player) + if(player.internal_organs_by_name[BP_AUG_LANGUAGE]) + var/obj/item/organ/internal/augment/language/vekatak/V = player.internal_organs_by_name[BP_AUG_LANGUAGE] + if(istype(V)) + LAZYADD(available_vaurca, player) LAZYADD(available_vaurca, "Cancel") - var/mob/living/carbon/human/target = input(src, "Select a target to disrupt", "Disrupt Hivenet User", null) as anything in available_vaurca + var/mob/living/carbon/human/target = tgui_input_list(src, "Select a target to disrupt", "Hivenet Disrupt", available_vaurca) if(!istype(target)) return + var/obj/item/organ/internal/augment/language/vekatak/V = target.internal_organs_by_name[BP_AUG_LANGUAGE] + if(istype(V)) + if(prob(35)) + to_chat(src, SPAN_DANGER("Your disruption attempt fails, [target]'s countermeasures repelling your assault! You can feel their defenses spring to life, tracing your location!")) + to_chat(target, SPAN_DANGER("You feel a presence attempting to block your neural socket, but your countermeasures repel it! Analysing the attack, you sense that it came from [get_area(src)]!")) + return + to_chat(target, SPAN_DANGER("Suddenly, you feel an attack on your systems, blocking your neural socket's ability to transmit to the Hivenet!")) + V.disrupted = TRUE + V.disrupttime = world.time + 10 MINUTES + host.last_action = world.time + 5 MINUTES + return var/obj/item/organ/internal/vaurca/neuralsocket/S = target.internal_organs_by_name[BP_NEURAL_SOCKET] - if(prob(70) || S.shielded) + if(prob(60) || S.shielded) to_chat(src, SPAN_DANGER("Your disruption attempt fails, [target]'s countermeasures repelling your assault! You can feel their defenses spring to life, tracing your location!")) to_chat(target, SPAN_DANGER("You feel a presence attempting to block your neural socket, but your countermeasures repel it! Analysing the attack, you sense that it came from [get_area(src)]!")) + return to_chat(target, SPAN_DANGER("Suddenly, you feel an attack on your systems, blocking your neural socket's ability to transmit to the Hivenet!")) S.disrupted = TRUE S.disrupttime = world.time + 10 MINUTES @@ -1909,7 +2006,7 @@ continue if(isvaurca(player) && player.internal_organs_by_name[BP_NEURAL_SOCKET]) LAZYADD(available_vaurca, player) - var/mob/living/carbon/human/target = input(src, "Select a target to shock", "Neural Shock User", null) as anything in available_vaurca + var/mob/living/carbon/human/target = tgui_input_list(src, "Select a target to shock", "Neural Shock", available_vaurca) if(!istype(target)) to_chat(src, SPAN_WARNING("Invalid target!")) return @@ -1954,15 +2051,15 @@ if(player.stat != CONSCIOUS) continue LAZYADD(available_vaurca, player) - var/mob/living/carbon/human/target = input(src, "Select a Vaurca to observe.", "Hivenet Sensory Hijack") as null|anything in available_vaurca + var/mob/living/carbon/human/target = tgui_input_list(src, "Select a target to observe", "Hivenet Sensory Hijack", available_vaurca) if(!target || !isvaurca(target)) remoteview_target = null reset_view(0) return var/obj/item/organ/internal/vaurca/neuralsocket/S = target.internal_organs_by_name[BP_NEURAL_SOCKET] - var/stealth = alert(src, "Do you wish to ask your target's permission?", "Hivenet Sensory Hijack", "No", "Yes") + var/stealth = tgui_alert(src, "Do you wish to ask your target's permission?", "Hivenet Sensory Hijack", list("No", "Yes")) if(stealth == "Yes") - var/allowed = alert(target, "Someone is attempting to access your senses through the Hivenet. Do you wish to allow them?", "Hivenet Sensory Access", "Deny", "Allow") + var/allowed = tgui_alert(target, "Someone is attempting to access your senses through the Hivenet. Do you wish to allow them?", "Hivenet Sensory Access", list("Allow", "Deny")) if(allowed == "Allow") to_chat(src, SPAN_NOTICE("You extend your mind into the Hivenet, accessing [target]'s senses. Use this verb again to cancel.")) remoteview_target = target @@ -2095,6 +2192,44 @@ msg_admin_attack("[key_name_admin(src)] infected [key_name_admin(H)] with black k'ois! (JMP)",ckey=key_name(src),ckey_target=key_name(H)) +/mob/living/carbon/human/proc/phalanx_transmit() + set name = "Phalanx Hivenet Transmission" + set desc = "Make a preset transmission over the Hivenet." + set category = "Hivenet" + + var/obj/item/organ/internal/augment/language/vekatak/V = src.internal_organs_by_name[BP_AUG_LANGUAGE] + var/list/messages = list( + "I remain operational.", + "Message received.", + "Order completed.", + "Cannot complete order.", + "I am on standby.", + "Minor damage registered.", + "Damage registered", + "Critical damage registered", + "Assistance required at my location.", + "Hostiles sighted at my location.", + "Location clear of threats." + ) + if(src.stat != CONSCIOUS) + to_chat(src, SPAN_WARNING("You are in no state to do that!")) + return + + if(!(GLOB.all_languages[LANGUAGE_VAURCA] in src.languages) || !(istype(V))) + to_chat(src, SPAN_WARNING("You are not connected to the Hivenet!")) + return + + if(within_jamming_range(src)) + to_chat(src, SPAN_WARNING("You attempt to reach the Hivenet, but find nothing!")) + return + + var/message = input("What message do you wish to transmit?","Choose a message") as null|anything in messages + if(!message) + return + V.transmitting = TRUE + say(",9[message]") + V.transmitting = FALSE + /mob/living/carbon/human/proc/hivenet_manifest() set name = "Hivenet Manifest" set desc = "Get a list of all vaurca currently on the Hivenet." diff --git a/code/modules/organs/subtypes/augment/augments/language_processor.dm b/code/modules/organs/subtypes/augment/augments/language_processor.dm index 33833dfffa3..9c1bcd29927 100644 --- a/code/modules/organs/subtypes/augment/augments/language_processor.dm +++ b/code/modules/organs/subtypes/augment/augments/language_processor.dm @@ -8,6 +8,8 @@ var/list/augment_languages = list() /// A list of languages that get added when it's installed. used to remove languages later. don't touch this. var/list/added_languages = list() + /// A list of language-related verbs granted by the augment. + var/list/granted_verbs = list() /obj/item/organ/internal/augment/language/replaced(var/mob/living/carbon/human/target, obj/item/organ/external/affected) . = ..() @@ -15,11 +17,13 @@ if(!(language in target.languages)) target.add_language(language) added_languages += language + add_verb(target, granted_verbs) /obj/item/organ/internal/augment/language/removed(var/mob/living/carbon/human/target, mob/living/user) for(var/language in added_languages) target.remove_language(language) added_languages = list() + remove_verb(target, granted_verbs) ..() /obj/item/organ/internal/augment/language/emp_act() @@ -99,3 +103,36 @@ SPECIES_VAURCA_WARRIOR, SPECIES_VAURCA_WORKER, ) + +/obj/item/organ/internal/augment/language/vekatak + name = "Ve'katak Phalanx Hivenet receiver" + icon_state = "phalanx_hivenet" + dead_icon = "phalanx_hivenet_broken" + on_mob_icon = 'icons/mob/human_races/augments_external.dmi' + augment_languages = list(LANGUAGE_VAURCA) + granted_verbs = list(/mob/living/carbon/human/proc/hivenet_recieve, /mob/living/carbon/human/proc/phalanx_transmit) + var/decryption_key + var/banned = FALSE + var/muted = FALSE + var/transmitting = FALSE + var/disrupted = FALSE + var/disrupttime = 0 + +/obj/item/organ/internal/augment/language/vekatak/process() + . = ..() + if(disrupted) + if(disrupttime > world.time) + disrupttime-- + else + disrupted = FALSE + +/obj/item/organ/internal/augment/language/vekatak/emp_act() + . = ..() + for(var/language in added_languages) + if(prob(25)) + owner.remove_language(language) + owner.set_default_language(pick(owner.languages)) + to_chat(owner, SPAN_DANGER("You feel thousands of voices, all clamoring inside your mind!")) + owner.adjustHalLoss(15) + owner.flash_pain(15) + owner.adjustBrainLoss(5) diff --git a/html/changelogs/RustingWithYou - phalanx.yml b/html/changelogs/RustingWithYou - phalanx.yml new file mode 100644 index 00000000000..d7759eecb45 --- /dev/null +++ b/html/changelogs/RustingWithYou - phalanx.yml @@ -0,0 +1,41 @@ +################################ +# Example Changelog File +# +# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. +# +# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) +# When it is, any changes listed below will disappear. +# +# Valid Prefixes: +# bugfix +# wip (For works in progress) +# tweak +# soundadd +# sounddel +# rscadd (general adding of nice things) +# rscdel (general deleting of nice things) +# imageadd +# imagedel +# maptweak +# spellcheck (typo fixes) +# experiment +# balance +# admin +# backend +# security +# refactor +################################# + +# Your name. +author: RustingWithYou + +# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. +delete-after: True + +# Any changes you've made. See valid prefix list above. +# INDENT WITH TWO SPACES. NOT TABS. SPACES. +# SCREW THIS UP AND IT WON'T WORK. +# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries. +# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog. +changes: + - rscadd: "Adds a Ve'katak Phalanx Hivenet receiver augment." diff --git a/icons/mob/human_races/augments_external.dmi b/icons/mob/human_races/augments_external.dmi index 90f9dcdb82273f74154881f8f245c3df7cde1211..a33b26af06f528a95697e537a80b3dc2bcdc9149 100644 GIT binary patch literal 633 zcmV-<0*3vGP)004jp0{{R3ySGM`GrNX(!KR!9Vy0BQWu3h=_q@tK_ZDdV4FKSp#n~8n@x&S;aC46dMYFbZCK{+id zC^a!I3qa&A00001bW%=J06^y0W&i*HpL$eSbVOxyV{&P5bZKvH004NLm5@6Q!Y~j8 zYx@*d(j$H?4N8PkkSkaVSz-&bvFwdOoE`@XDg<jZH|%|N8n6hBMNqtWPi%Jp)*ROk@Ed0003%Nklc>aL=S&JTKL%?Crb6LGqJGD;{4xRn0Kf`iK&F_Tg;2KU zzldWlLs)u=Q|&@w#;6%T#>;dq-t>p}*%@P6@TuRdf_b9gYZs?Paemr$&JlB4TWlSeFXaf!34*&oF0KgVsH=G65 TK?BTQ00000NkvXXu0mjf|3wv5 literal 505 zcmVi4iI43c_xF9nxRf&r;C9|j) zq?L;^ttc@!6~s0~sI5xPOV22cFUSG%2`Vm2EG}&vd=r`oI#oSE* z008AlL_t(&f$h}M4uc>Jg<%IeL`2{JZHHcX<0>@`G0XmMmu zy^|9Rx-rVOZvp(^1}_HawR6;sC-1U>w^()BG3v&XeFI{Z4X^?A=VkZ~O91mTUH%7w->psm;s5{uz>oR>hPMR(oy@FS00000NkvXXu0mjfE2P+h diff --git a/icons/obj/organs/augments.dmi b/icons/obj/organs/augments.dmi index 74c17efff6d41b1d7b4a7a795ecf749e951ec6df..9288db8f4c66e0f730e3e6137b6dc5a20bb1d5e6 100644 GIT binary patch delta 9356 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 G9{4{%_D!+? delta 9173 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