From a9520990f70bfd567c3e89a1d714941582b5d9ae Mon Sep 17 00:00:00 2001 From: SkyMarshal Date: Sun, 22 Jan 2012 22:41:17 -0700 Subject: [PATCH] More updates for the response team and stuff. The response team telecomm unit now works right, radios now have an autosay proc for automated announcements, the SpecOps shuttle now uses autosay, proper energy guns replace the bugged ones, Automated (non player AI) announcement of new players, another attempt at making the command frequency legible, HUD icon for secHUDs and ERT members. --- baystation12.dme | 1 + code/game/machinery/telecomms/broadcaster.dm | 4 +- .../objects/items/weapons/implants/implant.dm | 7 +- code/game/objects/radio/radio.dm | 115 +++++++++++++++++ code/game/response_team.dm | 120 ++++++++++++++---- code/game/specops_shuttle.dm | 47 ++++--- code/modules/admin/verbs/debug.dm | 2 +- code/modules/mob/new_player/new_player.dm | 12 +- code/modules/projectiles/gun.dm | 9 ++ code/stylesheet.dm | 3 +- icons/mob/hud.dmi | Bin 2489 -> 2551 bytes 11 files changed, 259 insertions(+), 61 deletions(-) diff --git a/baystation12.dme b/baystation12.dme index b694860cd8d..890997d4e92 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -577,6 +577,7 @@ #include "code\game\objects\kitchen.dm" #include "code\game\objects\lamarr.dm" #include "code\game\objects\mineral_doors.dm" +#include "code\game\objects\new_year.dm" #include "code\game\objects\noticeboard.dm" #include "code\game\objects\object_procs.dm" #include "code\game\objects\portals.dm" diff --git a/code/game/machinery/telecomms/broadcaster.dm b/code/game/machinery/telecomms/broadcaster.dm index fcfa830ebef..91ae88093ea 100644 --- a/code/game/machinery/telecomms/broadcaster.dm +++ b/code/game/machinery/telecomms/broadcaster.dm @@ -62,7 +62,7 @@ machinetype = 6 heatgen = 0 var/intercept = 0 // if nonzero, broadcasts all messages to syndicate channel - var/syndi = 1 //If 1, it goes to syndicate frequency. Else, goes to deathsquad + var/syndi = 1 //If 1, it goes to syndicate frequency. Else, goes to deathsquad/Response Team receive_signal(datum/signal/signal) @@ -210,7 +210,7 @@ // --- Broadcast to response team radio! --- - else if(data == 3) + else if(data == 4) var/datum/radio_frequency/syndicateconnection = radio_controller.return_frequency(1439) for (var/obj/item/device/radio/R in syndicateconnection.devices["[RADIO_CHAT]"]) diff --git a/code/game/objects/items/weapons/implants/implant.dm b/code/game/objects/items/weapons/implants/implant.dm index 8029addbfe3..9283f50e04c 100644 --- a/code/game/objects/items/weapons/implants/implant.dm +++ b/code/game/objects/items/weapons/implants/implant.dm @@ -283,13 +283,8 @@ the implant may become unstable and either pre-maturely inject the subject or si if(M.stat == 2) var/turf/t = get_turf(M) var/obj/item/device/radio/headset/a = new /obj/item/device/radio/headset(null) - var/mob/living/carbon/human/G = new /mob/living/carbon/human(null) - G.real_name = "[mobname]'s death alarm" - G.name = "[mobname]'s death alarm" - G.universal_speak = 1 - a.talk_into(G,"[mobname] has died in [t.loc.name]!") + a.autosay("[mobname] has died in [t.loc.name]!", "[mobname]'s Death Alarm") del(a) - del(G) processing_objects.Remove(src) diff --git a/code/game/objects/radio/radio.dm b/code/game/objects/radio/radio.dm index 1643c38ec3c..79faf801839 100644 --- a/code/game/objects/radio/radio.dm +++ b/code/game/objects/radio/radio.dm @@ -183,6 +183,121 @@ var/GLOBAL_RADIO_TYPE = 1 // radio type to use updateDialog() add_fingerprint(usr) +/obj/item/device/radio/proc/autosay(var/message, var/from, var/channel) + var/datum/radio_frequency/connection = null + if(channel && channels && channels.len > 0) + if (channel == "department") + //world << "DEBUG: channel=\"[channel]\" switching to \"[channels[1]]\"" + channel = channels[1] + connection = secure_radio_connections[channel] + else + connection = radio_connection + channel = null + if (!istype(connection)) + return + + if(subspace_transmission) + // First, we want to generate a new radio signal + var/datum/signal/signal = new + signal.transmission_method = 2 // 2 would be a subspace transmission. + // transmission_method could probably be enumerated through #define. Would be neater. + + // --- Finally, tag the actual signal with the appropriate values --- + signal.data = list( + // Identity-associated tags: + "mob" = new /mob/living/silicon/ai(src), // store a reference to the mob + "mobtype" = /mob/living/silicon/ai, // the mob's type + "realname" = from, // the mob's real name + "name" = from, // the mob's display name + "job" = "(Automated Announcement)", // the mob's job + "key" = "none", // the mob's key + "vmessage" = "*garbled automated announcement*", // the message to display if the voice wasn't understood + "vname" = "synthesized voice", // the name to display if the voice wasn't understood + "vmask" = 0, // 1 if the mob is using a voice gas mask + + // We store things that would otherwise be kept in the actual mob + // so that they can be logged even AFTER the mob is deleted or something + + // Other tags: + "compression" = rand(45,50), // compressed radio signal + "message" = message, // the actual sent message + "connection" = connection, // the radio connection to use + "radio" = src, // stores the radio used for transmission + "slow" = 0, // how much to sleep() before broadcasting - simulates net lag + "traffic" = 0 // dictates the total traffic sum that the signal went through + ) + signal.frequency = connection.frequency // Quick frequency set + + //#### Sending the signal to all subspace receivers ####// + for(var/obj/machinery/telecomms/receiver/R in world) + R.receive_signal(signal) + + // Allinone can act as receivers. + for(var/obj/machinery/telecomms/allinone/R in world) + R.receive_signal(signal) + + // Receiving code can be located in Telecommunications.dm + return + + + /* ###### Intercoms and station-bounced radios ###### */ + + var/filter_type = 2 + + /* --- Intercoms can only broadcast to other intercoms, but bounced radios can broadcast to bounced radios and intercoms --- */ + if(istype(src, /obj/item/device/radio/intercom)) + filter_type = 1 + + + var/datum/signal/signal = new + signal.transmission_method = 2 + + + /* --- Try to send a normal subspace broadcast first */ + + signal.data = list( + + "mob" = new /mob/living/silicon/ai(src), // store a reference to the mob + "mobtype" = /mob/living/silicon/ai, // the mob's type + "realname" = from, // the mob's real name + "name" = from, // the mob's display name + "job" = "(Automated Announcement)", // the mob's job + "key" = "none", // the mob's key + "vmessage" = "*garbled automated announcement*", // the message to display if the voice wasn't understood + "vname" = "synthesized voice", // the name to display if the voice wasn't understood + "vmask" = 0, // 1 if the mob is using a voice gas mask + + // We store things that would otherwise be kept in the actual mob + // so that they can be logged even AFTER the mob is deleted or something + + // Other tags: + "compression" = 0, // compressed radio signal + "message" = message, // the actual sent message + "connection" = connection, // the radio connection to use + "radio" = src, // stores the radio used for transmission + "slow" = 0, // how much to sleep() before broadcasting - simulates net lag + "traffic" = 0 // dictates the total traffic sum that the signal went through + ) + signal.frequency = connection.frequency // Quick frequency set + + for(var/obj/machinery/telecomms/receiver/R in world) + R.receive_signal(signal) + + + sleep(rand(10,25)) // wait a little... + + if(signal.data["done"]) + del(signal) // delete the signal - we're done here. + return + + // Oh my god; the comms are down or something because the signal hasn't been broadcasted yet. + // Send a mundane broadcast with limited targets: + + Broadcast_Message(connection, new /mob/living/silicon/ai(src), 0, "*garbled automated announcement*", + src, message, from, "(Automated Announcement)", from, "synthesized voice", + filter_type, signal.data["compression"]) + return + /obj/item/device/radio/talk_into(mob/M as mob, message, channel) if(GLOBAL_RADIO_TYPE == 1) // NEW RADIO SYSTEMS: By Doohl diff --git a/code/game/response_team.dm b/code/game/response_team.dm index 31316ec6d87..edb8811e955 100644 --- a/code/game/response_team.dm +++ b/code/game/response_team.dm @@ -22,14 +22,12 @@ client/verb/JoinResponseTeam() var/new_name = input(usr, "Pick a name","Name") as null|text if(!new_name) return - var/gender = alert(usr, "Pick a gender","Gender","Male","Female") - - var/mob/living/carbon/human/new_commando = create_response_team(L, leader_selected, new_name, gender) + var/mob/living/carbon/human/new_commando = create_response_team(L, leader_selected, new_name) new_commando.mind.key = usr.key new_commando.key = usr.key - new_commando << "\blue You are [!leader_selected?"member":"LEADER"] of an armed response team in CentComm's service. Something went down on [station_name()] and they're now on code red. Go in there and fix the problem." + new_commando << "\blue You are [!leader_selected?" a member":" the LEADER"] of an armed response team in CentComm's service. Something went down on [station_name()] and they're now on code red. Go in there and fix the problem." new_commando << "You should first gear up and discuss a plan with your team. More members may be joining, don't move out before you're ready." else @@ -75,30 +73,105 @@ proc/trigger_armed_response_team() send_emergency_team = 1 -/client/proc/create_response_team(obj/spawn_location, leader_selected = 0, commando_name, gender) +/client/proc/create_response_team(obj/spawn_location, leader_selected = 0, commando_name) - var/mob/living/carbon/human/new_commando = new(spawn_location.loc) - new_commando.gender = ((gender == "Male") ? MALE : FEMALE) + var/mob/living/carbon/human/M = new(spawn_location.loc) - var/datum/preferences/A = new()//Randomize appearance for the commando. - A.randomize_appearance_for(new_commando) + var/new_facial = input("Please select facial hair color.", "Character Generation") as color + if(new_facial) + M.r_facial = hex2num(copytext(new_facial, 2, 4)) + M.g_facial = hex2num(copytext(new_facial, 4, 6)) + M.b_facial = hex2num(copytext(new_facial, 6, 8)) - new_commando.real_name = commando_name - new_commando.age = !leader_selected ? rand(23,35) : rand(35,45) + var/new_hair = input("Please select hair color.", "Character Generation") as color + if(new_facial) + M.r_hair = hex2num(copytext(new_hair, 2, 4)) + M.g_hair = hex2num(copytext(new_hair, 4, 6)) + M.b_hair = hex2num(copytext(new_hair, 6, 8)) - new_commando.dna.ready_dna(new_commando)//Creates DNA. + var/new_eyes = input("Please select eye color.", "Character Generation") as color + if(new_eyes) + M.r_eyes = hex2num(copytext(new_eyes, 2, 4)) + M.g_eyes = hex2num(copytext(new_eyes, 4, 6)) + M.b_eyes = hex2num(copytext(new_eyes, 6, 8)) + + var/new_tone = input("Please select skin tone level: 1-220 (1=albino, 35=caucasian, 150=black, 220='very' black)", "Character Generation") as text + + if (new_tone) + M.s_tone = max(min(round(text2num(new_tone)), 220), 1) + M.s_tone = -M.s_tone + 35 + + // hair + var/list/all_hairs = typesof(/datum/sprite_accessory/hair) - /datum/sprite_accessory/hair + var/list/hairs = list() + + // loop through potential hairs + for(var/x in all_hairs) + var/datum/sprite_accessory/hair/H = new x // create new hair datum based on type x + hairs.Add(H.name) // add hair name to hairs + del(H) // delete the hair after it's all done + + var/new_style = input("Please select hair style", "Character Generation") as null|anything in hairs + + // if new style selected (not cancel) + if (new_style) + M.h_style = new_style + + for(var/x in all_hairs) // loop through all_hairs again. Might be slightly CPU expensive, but not significantly. + var/datum/sprite_accessory/hair/H = new x // create new hair datum + if(H.name == new_style) + M.hair_style = H // assign the hair_style variable a new hair datum + break + else + del(H) // if hair H not used, delete. BYOND can garbage collect, but better safe than sorry + + // facial hair + var/list/all_fhairs = typesof(/datum/sprite_accessory/facial_hair) - /datum/sprite_accessory/facial_hair + var/list/fhairs = list() + + for(var/x in all_fhairs) + var/datum/sprite_accessory/facial_hair/H = new x + fhairs.Add(H.name) + del(H) + + new_style = input("Please select facial style", "Character Generation") as null|anything in fhairs + + if(new_style) + M.f_style = new_style + for(var/x in all_fhairs) + var/datum/sprite_accessory/facial_hair/H = new x + if(H.name == new_style) + M.facial_hair_style = H + break + else + del(H) + + var/new_gender = alert(usr, "Please select gender.", "Character Generation", "Male", "Female") + if (new_gender) + if(new_gender == "Male") + M.gender = MALE + else + M.gender = FEMALE + M.update_body() + M.update_face() + M.update_clothing() + + M.real_name = commando_name + M.age = !leader_selected ? rand(23,35) : rand(35,45) + + M.dna.ready_dna(M)//Creates DNA. //Creates mind stuff. - new_commando.mind = new - new_commando.mind.current = new_commando - new_commando.mind.original = new_commando - new_commando.mind.assigned_role = "MODE" - new_commando.mind.special_role = "Response Team" - if(!(new_commando.mind in ticker.minds)) - ticker.minds += new_commando.mind//Adds them to regular mind list. - new_commando.equip_strike_team(leader_selected) + M.mind = new + M.mind.current = M + M.mind.original = M + M.mind.assigned_role = "MODE" + M.mind.special_role = "Response Team" + if(!(M.mind in ticker.minds)) + ticker.minds += M.mind//Adds them to regular mind list. + M.equip_strike_team(leader_selected) del(spawn_location) - return new_commando + return M /mob/living/carbon/human/proc/equip_strike_team(leader_selected = 0) @@ -144,7 +217,10 @@ proc/trigger_armed_response_team() var/obj/item/weapon/card/id/W = new(src) W.name = "[real_name]'s ID Card" W.icon_state = "centcom" - W.access = get_access("Head of Personnel") + if(leader_selected) + W.access = get_access("Captain") + else + W.access = get_access("Head of Personnel") W.access += list(access_cent_general, access_cent_specops, access_cent_living, access_cent_storage)//Let's add their alloted CentCom access. W.assignment = "Emergency Response Team" W.registered = real_name diff --git a/code/game/specops_shuttle.dm b/code/game/specops_shuttle.dm index 906ea0b5455..f05c6326cab 100644 --- a/code/game/specops_shuttle.dm +++ b/code/game/specops_shuttle.dm @@ -10,7 +10,6 @@ var/specops_shuttle_at_station = 0 var/specops_shuttle_can_send = 1 var/specops_shuttle_time = 0 var/specops_shuttle_timeleft = 0 -var/specops_shuttle_timereset = 0 /obj/machinery/computer/specops_shuttle name = "Spec. Ops. Shuttle Console" @@ -20,15 +19,16 @@ var/specops_shuttle_timereset = 0 var/temp = null var/hacked = 0 var/allowedtocall = 0 + var/specops_shuttle_timereset = 0 /proc/specops_return() - var/area/centcom/control/cent_com = locate()//To find announcer. This area should exist for this proc to work. - var/mob/living/silicon/decoy/announcer = locate() in cent_com//We need a fake AI to announce some stuff below. Otherwise it will be wonky. + var/obj/item/device/radio/intercom/announcer = new /obj/item/device/radio/intercom(null)//We need a fake AI to announce some stuff below. Otherwise it will be wonky. + announcer.config(list("Response Team" = 0)) var/message_tracker[] = list(0,1,2,3,5,10,30,45)//Create a a list with potential time values. - var/message = "THE SPECIAL OPERATIONS SHUTTLE IS PREPARING FOR LAUNCH"//Initial message shown. + var/message = "THE SPECIAL OPERATIONS SHUTTLE IS PREPARING TO RETURN"//Initial message shown. if(announcer) - announcer.say(message) + announcer.autosay(message, "A.L.I.C.E.", "Response Team") while(specops_shuttle_time - world.timeofday > 0) var/ticksleft = specops_shuttle_time - world.timeofday @@ -44,7 +44,7 @@ var/specops_shuttle_timereset = 0 message = "ALERT: [rounded_time_left] SECOND[(rounded_time_left!=1)?"S":""] REMAIN" if(rounded_time_left==0) message = "ALERT: TAKEOFF" - announcer.say(message) + announcer.autosay(message, "A.L.I.C.E.", "Response Team") message_tracker -= rounded_time_left//Remove the number from the list so it won't be called again next cycle. //Should call all the numbers but lag could mean some issues. Oh well. Not much I can do about that. @@ -82,17 +82,22 @@ var/specops_shuttle_timereset = 0 var/mob/M = locate(/mob) in T M << "\red You have arrived at Central Command. Operation has ended!" + for(var/obj/machinery/computer/specops_shuttle/S in world) + S.specops_shuttle_timereset = world.time + SPECOPS_RETURN_DELAY + + del(announcer) + /proc/specops_process() - var/area/centcom/control/cent_com = locate()//To find announcer. This area should exist for this proc to work. var/area/centcom/specops/special_ops = locate()//Where is the specops area located? - var/mob/living/silicon/decoy/announcer = locate() in cent_com//We need a fake AI to announce some stuff below. Otherwise it will be wonky. + var/obj/item/device/radio/intercom/announcer = new /obj/item/device/radio/intercom(null)//We need a fake AI to announce some stuff below. Otherwise it will be wonky. + announcer.config(list("Response Team" = 0)) var/message_tracker[] = list(0,1,2,3,5,10,30,45)//Create a a list with potential time values. var/message = "THE SPECIAL OPERATIONS SHUTTLE IS PREPARING FOR LAUNCH"//Initial message shown. if(announcer) - announcer.say(message) + announcer.autosay(message, "A.L.I.C.E.", "Response Team") message = "ARMORED SQUAD TAKE YOUR POSITION ON GRAVITY LAUNCH PAD" - announcer.say(message) + announcer.autosay(message, "A.L.I.C.E.", "Response Team") while(specops_shuttle_time - world.timeofday > 0) var/ticksleft = specops_shuttle_time - world.timeofday @@ -108,7 +113,7 @@ var/specops_shuttle_timereset = 0 message = "ALERT: [rounded_time_left] SECOND[(rounded_time_left!=1)?"S":""] REMAIN" if(rounded_time_left==0) message = "ALERT: TAKEOFF" - announcer.say(message) + announcer.autosay(message, "A.L.I.C.E.", "Response Team") message_tracker -= rounded_time_left//Remove the number from the list so it won't be called again next cycle. //Should call all the numbers but lag could mean some issues. Oh well. Not much I can do about that. @@ -218,17 +223,19 @@ var/specops_shuttle_timereset = 0 var/mob/M = locate(/mob) in T M << "\red You have arrived to [station_name]. Commence operation!" + for(var/obj/machinery/computer/specops_shuttle/S in world) + S.specops_shuttle_timereset = world.time + SPECOPS_RETURN_DELAY + + del(announcer) + /proc/specops_can_move() if(specops_shuttle_moving_to_station || specops_shuttle_moving_to_centcom) return 0 - else if(world.time <= specops_shuttle_timereset) - return 0 + for(var/obj/machinery/computer/specops_shuttle/S in world) + if(world.time <= S.specops_shuttle_timereset) + return 0 return 1 -/obj/machinery/computer/specops_shuttle/proc/make_move() - specops_shuttle_timereset = world.time - return - /obj/machinery/computer/specops_shuttle/attack_ai(var/mob/user as mob) return attack_hand(user) @@ -280,7 +287,9 @@ var/specops_shuttle_timereset = 0 if (!specops_can_move()) usr << "\blue Central Command will not allow the Special Operations shuttle to return yet." if(world.time <= specops_shuttle_timereset) - usr << "\blue [(world.time - specops_shuttle_timereset)/10] seconds remain!" + if (((world.time - specops_shuttle_timereset)/10) > 60) + usr << "\blue [-((world.time - specops_shuttle_timereset)/10)/60] minutes remain!" + usr << "\blue [-(world.time - specops_shuttle_timereset)/10] seconds remain!" return usr << "\blue The Special Operations shuttle will arrive at Central Command in [(SPECOPS_MOVETIME/10)] seconds." @@ -290,7 +299,6 @@ var/specops_shuttle_timereset = 0 specops_shuttle_moving_to_centcom = 1 specops_shuttle_time = world.timeofday + SPECOPS_MOVETIME - specops_shuttle_timereset = world.time + SPECOPS_RETURN_DELAY spawn(0) specops_return() @@ -312,7 +320,6 @@ var/specops_shuttle_timereset = 0 specops_shuttle_moving_to_station = 1 specops_shuttle_time = world.timeofday + SPECOPS_MOVETIME - specops_shuttle_timereset = world.time + SPECOPS_RETURN_DELAY spawn(0) specops_process() diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index 99357250ce6..2c3aa31f76e 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -690,7 +690,7 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that var/obj/item/clothing/glasses/sunglasses/V = new(M) V.loc = K M.equip_if_possible(K, M.slot_wear_suit) - M.equip_if_possible(new /obj/item/weapon/gun/energy(M), M.slot_s_store) + M.equip_if_possible(new /obj/item/weapon/gun/energy/gun(M), M.slot_s_store) var/obj/item/device/pda/heads/pda = new(M) pda.owner = M.real_name diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm index af2c6097c03..6d3ac0648ee 100644 --- a/code/modules/mob/new_player/new_player.dm +++ b/code/modules/mob/new_player/new_player.dm @@ -270,15 +270,9 @@ proc/AnnounceArrival(var/mob/living/carbon/human/character, var/rank) if (ticker.current_state == GAME_STATE_PLAYING) - var/ailist[] = list() - for (var/mob/living/silicon/ai/A in world) - if (!A.stat) - ailist += A - if (ailist.len) - var/mob/living/silicon/ai/announcer = pick(ailist) - if(character.mind) - if((character.mind.assigned_role != "Cyborg") && (character.mind.special_role != "MODE")) - announcer.say("[character.real_name] has signed up as [rank].") + var/obj/item/device/radio/intercom/a = new /obj/item/device/radio/intercom(null) + a.autosay("[character.real_name] has arrived on the station.", "Arrivals Announcement Computer") + del(a) proc/ManifestLateSpawn(var/mob/living/carbon/human/H, icon/H_icon) // Attempted fix to add late joiners to various databases -- TLE diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 92ba2cb0c05..4b66e30ca74 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -50,6 +50,15 @@ M.drop_item() del(src) return + if (target == user && user.zone_sel.selecting == "mouth") + M.visible_message("\red [user] sticks their gun in their mouth, ready to pull the trigger...") + if(!do_after(user, 20)) + M.visible_message("\blue [user] decided life was worth living") + return + M.visible_message("\red [user] pulls the trigger.") + M.apply_damage(60, BRUTE, "head") + M.apply_damage(90, BRUTE, "chest") + return if (!user.IsAdvancedToolUser()) user << "\red You don't have the dexterity to do this!" diff --git a/code/stylesheet.dm b/code/stylesheet.dm index 0cc4bfb71e9..120caff798a 100644 --- a/code/stylesheet.dm +++ b/code/stylesheet.dm @@ -94,7 +94,8 @@ h1, h2, h3, h4, h5, h6 .comradio { - color: #ACA82D; + color:#0028FF; + background: #FFD700; } .syndradio diff --git a/icons/mob/hud.dmi b/icons/mob/hud.dmi index 8fe609fbb676e295e0a988b2c33f827d6142a06f..92a4a81987a83f8b85c46992c5b95d320ebffef7 100644 GIT binary patch delta 2208 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 E0W*B{y8r+H