From 3cb739527974693f5a3e9f7ead217546e66567db Mon Sep 17 00:00:00 2001 From: Arokha Sieyes Date: Sat, 11 Jun 2016 21:52:52 -0400 Subject: [PATCH 1/6] Rearranges get_mobs_and_objs_in_view_fast Also adds the ability to select between ghost eyes and ears. --- code/_helpers/game.dm | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/code/_helpers/game.dm b/code/_helpers/game.dm index 57ff4b7013..b10463b458 100644 --- a/code/_helpers/game.dm +++ b/code/_helpers/game.dm @@ -248,8 +248,11 @@ . |= M // Since we're already looping through mobs, why bother using |= ? This only slows things down. return . -/proc/get_mobs_and_objs_in_view_fast(var/turf/T, var/range, var/checkghosts = 1) - +//Uses dview to quickly return mobs and objects in view, +// then adds additional mobs or objects if they are in range 'smartly', +// based on their presence in lists of players or registered objects +// Type: 1-audio, 2-visual, 0-neither +/proc/get_mobs_and_objs_in_view_fast(var/turf/T, var/range, var/type = 1) var/list/mobs = list() var/list/objs = list() @@ -261,21 +264,30 @@ mobs += AM hearturfs += AM.locs[1] else if(isobj(AM)) - objs += AM + objs += AM hearturfs += AM.locs[1] - + //A list of every mob with a client for(var/mob/M in player_list) - if(checkghosts && M.stat == DEAD && M.is_preference_enabled(/datum/client_preference/ghost_ears)) - mobs |= M - continue if(M.loc && M.locs[1] in hearturfs) mobs |= M + else if(M.stat == DEAD) + switch(type) + if(1) //Audio messages use ghost_ears + if(M.is_preference_enabled(/datum/client_preference/ghost_ears)) + mobs |= M + if(2) //Visual messages use ghost_sight + if(M.is_preference_enabled(/datum/client_preference/ghost_sight)) + mobs |= M + + //For objects below the top level who still want to hear + for(var/obj/O in listening_objects) + if(O.loc && O.locs[1] in hearturfs) + objs |= O + return list("mobs" = mobs, "objs" = objs) - - #define SIGN(X) ((X<0)?-1:1) proc From 1e9e55d73d0df9f08eabd4e010a5e71ae9d47ae4 Mon Sep 17 00:00:00 2001 From: Arokha Sieyes Date: Sat, 11 Jun 2016 21:53:30 -0400 Subject: [PATCH 2/6] Moves static overlay to be a global HUD option --- code/_onclick/hud/hud.dm | 13 ++++++++++++- code/modules/mob/living/voice/voice.dm | 9 +++------ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm index 66d453ac36..7b9cf82cc5 100644 --- a/code/_onclick/hud/hud.dm +++ b/code/_onclick/hud/hud.dm @@ -6,12 +6,14 @@ var/datum/global_hud/global_hud = new() var/list/global_huds = list( global_hud.druggy, global_hud.blurry, + global_hud.whitense, global_hud.vimpaired, global_hud.darkMask, global_hud.nvg, global_hud.thermal, global_hud.meson, - global_hud.science) + global_hud.science + ) /datum/hud/var/obj/screen/grab_intent /datum/hud/var/obj/screen/hurt_intent @@ -21,6 +23,7 @@ var/list/global_huds = list( /datum/global_hud var/obj/screen/druggy var/obj/screen/blurry + var/obj/screen/whitense var/list/vimpaired var/list/darkMask var/obj/screen/nvg @@ -53,6 +56,14 @@ var/list/global_huds = list( blurry.layer = 17 blurry.mouse_opacity = 0 + //static overlay effect for cameras and the like + whitense = new /obj/screen() + whitense.screen_loc = ui_entire_screen + whitense.icon = 'icons/effects/static.dmi' + whitense.icon_state = "1 light" + whitense.layer = 17 + whitense.mouse_opacity = 0 + nvg = setup_overlay("nvg_hud") thermal = setup_overlay("thermal_hud") meson = setup_overlay("meson_hud") diff --git a/code/modules/mob/living/voice/voice.dm b/code/modules/mob/living/voice/voice.dm index e4eac0f439..a9f5dbd60a 100644 --- a/code/modules/mob/living/voice/voice.dm +++ b/code/modules/mob/living/voice/voice.dm @@ -42,12 +42,9 @@ // Parameters: None // Description: Adds a static overlay to the client's screen. /mob/living/voice/Login() - var/obj/screen/static_effect = new() //Since what the player sees is essentially a video feed, from a vast distance away, the view isn't going to be perfect. - static_effect.screen_loc = ui_entire_screen - static_effect.icon = 'icons/effects/static.dmi' - static_effect.icon_state = "1 light" - static_effect.mouse_opacity = 0 //So the static doesn't get in the way of clicking. - client.screen.Add(static_effect) + ..() + client.screen |= global_hud.whitense + client.screen |= global_hud.darkMask // Proc: Destroy() // Parameters: None From 40d0d75804763855419a744b17c7da918f780fbb Mon Sep 17 00:00:00 2001 From: Arokha Sieyes Date: Sat, 11 Jun 2016 21:53:56 -0400 Subject: [PATCH 3/6] Rewrites LOOC and emote to use new proc And to be more simple and sane --- code/game/verbs/ooc.dm | 61 ++++++++++++++++++++++++++++++++------- code/modules/mob/emote.dm | 49 ++++++++++--------------------- 2 files changed, 66 insertions(+), 44 deletions(-) diff --git a/code/game/verbs/ooc.dm b/code/game/verbs/ooc.dm index 3e6ed27302..7891951f20 100644 --- a/code/game/verbs/ooc.dm +++ b/code/game/verbs/ooc.dm @@ -106,7 +106,13 @@ log_ooc("(LOCAL) [mob.name]/[key] : [msg]") var/mob/source = mob.get_looc_source() - var/list/heard = get_mobs_or_objects_in_view(7, get_turf(source), 1, 0) + var/turf/T = get_turf(source) + if(!T) return + var/list/in_range = get_mobs_and_objs_in_view_fast(T,world.view,0) + var/list/m_viewers = in_range["mobs"] + + var/list/receivers = list() // Clients, not mobs. + var/list/r_receivers = list() var/display_name = key if(holder && holder.fakekey) @@ -114,34 +120,69 @@ if(mob.stat != DEAD) display_name = mob.name + // Everyone in normal viewing range of the LOOC + for(var/mob/viewer in m_viewers) + if(viewer.client && viewer.client.is_preference_enabled(/datum/client_preference/show_looc)) + receivers |= viewer.client + else if(istype(viewer,/mob/observer/eye)) // For AI eyes and the like + var/mob/observer/eye/E = viewer + if(E.owner && E.owner.client) + receivers |= E.owner.client + + // Admins with RLOOC displayed who weren't already in + for(var/client/admin in admins) + if(!(admin in receivers) && admin.is_preference_enabled(/datum/client_preference/holder/show_rlooc)) + r_receivers |= admin + + // Send a message + for(var/client/target in receivers) + var/admin_stuff = "" + + if(target in admins) + admin_stuff += "/([key])" + + target << "" + create_text_tag("looc", "LOOC:", target) + " [display_name][admin_stuff]: [msg]" + + for(var/client/target in r_receivers) + var/admin_stuff = "/([key])([admin_jump_link(mob, target.holder)])" + + target << "" + create_text_tag("looc", "LOOC:", target) + " (R)[display_name][admin_stuff]: [msg]" +/* for(var/client/target in clients) if(target.is_preference_enabled(/datum/client_preference/show_looc)) var/prefix = "" var/admin_stuff = "" var/send = 0 + // Admins get extra data. if(target in admins) admin_stuff += "/([key])" if(target != src) admin_stuff += "([admin_jump_link(mob, target.holder)])" - if(target.mob in heard) - send = 1 - if(isAI(target.mob)) + // For AIs, needs work done to see if the eye is in range as we're going over clients not mobs. + if(isAI(target.mob)) + var/mob/living/silicon/ai/A = target.mob + if(A.eyeobj in m_viewers) + send = 1 + prefix = "(Eye) " // Prefer the (Eye) prefix if they are in range of core and eye. + else if (A in m_viewers) + send = 1 prefix = "(Core) " - else if(isAI(target.mob)) // Special case - var/mob/living/silicon/ai/A = target.mob - if(A.eyeobj in hearers(7, source)) - send = 1 - prefix = "(Eye) " - + // If you're in range, you get the LOOC. + else if(target.mob in m_viewers) + send = 1 + + // If you weren't going to otherwise get it, but can see (R)LOOC. if(!send && (target in admins) && target.is_preference_enabled(/datum/client_preference/holder/show_rlooc)) send = 1 prefix = "(R)" + // Deliver message directly to the client with stream operator, not another proc. LOOC is important. if(send) target << "" + create_text_tag("looc", "LOOC:", target) + " [prefix][display_name][admin_stuff]: [msg]" +*/ /mob/proc/get_looc_source() return src diff --git a/code/modules/mob/emote.dm b/code/modules/mob/emote.dm index 7fb8052909..15b9992375 100644 --- a/code/modules/mob/emote.dm +++ b/code/modules/mob/emote.dm @@ -1,7 +1,7 @@ // All mobs should have custom emote, really.. //m_type == 1 --> visual. //m_type == 2 --> audible -/mob/proc/custom_emote(var/m_type=1,var/message = null) +/mob/proc/custom_emote(var/m_type=1,var/message = null,var/range=world.view) if(stat || !use_me && usr == src) src << "You are unable to emote." return @@ -23,42 +23,23 @@ if (message) log_emote("[name]/[key] : [message]") - //Hearing gasp and such every five seconds is not good emotes were not global for a reason. + // Hearing gasp and such every five seconds is not good emotes were not global for a reason. // Maybe some people are okay with that. - for(var/mob/M in player_list) - if (!M.client) - continue //skip monkeys and leavers - if (istype(M, /mob/new_player)) - continue - if(findtext(message," snores.")) //Because we have so many sleeping people. - break - if(M.stat == DEAD && M.is_preference_enabled(/datum/client_preference/ghost_sight) && !(M in viewers(src,null))) - M.show_message(message, m_type) + var/turf/T = get_turf(src) + if(!T) return + var/list/in_range = get_mobs_and_objs_in_view_fast(T,range,2) + var/list/m_viewers = in_range["mobs"] + var/list/o_viewers = in_range["objs"] - if (m_type & 1) - var/list/see = get_mobs_or_objects_in_view(world.view,src) | viewers(get_turf(src), null) - for(var/I in see) - if(isobj(I)) - spawn(0) - if(I) //It's possible that it could be deleted in the meantime. - var/obj/O = I - O.see_emote(src, message, 1) - else if(ismob(I)) - var/mob/M = I - M.show_message(message, 1) - - else if (m_type & 2) - var/list/hear = get_mobs_or_objects_in_view(world.view,src) - for(var/I in hear) - if(isobj(I)) - spawn(0) - if(I) //It's possible that it could be deleted in the meantime. - var/obj/O = I - O.see_emote(src, message, 2) - else if(ismob(I)) - var/mob/M = I - M.show_message(message, 2) + for(var/mob/M in m_viewers) + spawn(0) // It's possible that it could be deleted in the meantime, or that it runtimes. + if(M) + M.show_message(message, m_type) + for(var/obj/O in o_viewers) + spawn(0) + if(O) + O.see_emote(src, message, m_type) /mob/proc/emote_dead(var/message) From 288954087587b946f7e1e31b6654cc6a10737ff6 Mon Sep 17 00:00:00 2001 From: Arokha Sieyes Date: Sat, 11 Jun 2016 21:54:08 -0400 Subject: [PATCH 4/6] Fixes a random typo in limb_reattach --- code/modules/surgery/limb_reattach.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/surgery/limb_reattach.dm b/code/modules/surgery/limb_reattach.dm index ee0dfecb4f..8e6e8da21f 100644 --- a/code/modules/surgery/limb_reattach.dm +++ b/code/modules/surgery/limb_reattach.dm @@ -40,7 +40,7 @@ end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) var/obj/item/organ/external/E = tool - user.visible_message("[user] has attached [target]'s [E.name] to the [E.amputation_point].>", \ + user.visible_message("[user] has attached [target]'s [E.name] to the [E.amputation_point].", \ "You have attached [target]'s [E.name] to the [E.amputation_point].") user.drop_from_inventory(E) E.replaced(target) From 7b4d5718892abca92dec4827b6715e5dc5eeb692 Mon Sep 17 00:00:00 2001 From: Arokha Sieyes Date: Sat, 11 Jun 2016 22:05:01 -0400 Subject: [PATCH 5/6] Makes communicators great again --- code/_helpers/global_lists.dm | 1 + .../devices/communicator/communicator.dm | 67 +++++++++++++++---- code/modules/mob/living/voice/voice.dm | 8 ++- 3 files changed, 61 insertions(+), 15 deletions(-) diff --git a/code/_helpers/global_lists.dm b/code/_helpers/global_lists.dm index 1a1eced63a..9a90a3676b 100644 --- a/code/_helpers/global_lists.dm +++ b/code/_helpers/global_lists.dm @@ -11,6 +11,7 @@ var/global/list/human_mob_list = list() //List of all human mobs and sub-type var/global/list/silicon_mob_list = list() //List of all silicon mobs, including clientless var/global/list/living_mob_list = list() //List of all alive mobs, including clientless. Excludes /mob/new_player var/global/list/dead_mob_list = list() //List of all dead mobs, including clientless. Excludes /mob/new_player +var/global/list/listening_objects = list() //List of all objects which care about receiving messages (communicators, radios, etc) var/global/list/cable_list = list() //Index for all cables, so that powernets don't have to look through the entire world all the time var/global/list/chemical_reactions_list //list of all /datum/chemical_reaction datums. Used during chemical reactions diff --git a/code/game/objects/items/devices/communicator/communicator.dm b/code/game/objects/items/devices/communicator/communicator.dm index bc80bc9db3..e783139136 100644 --- a/code/game/objects/items/devices/communicator/communicator.dm +++ b/code/game/objects/items/devices/communicator/communicator.dm @@ -17,6 +17,8 @@ var/global/list/obj/item/device/communicator/all_communicators = list() origin_tech = list(TECH_ENGINEERING = 2, TECH_MAGNET = 2, TECH_BLUESPACE = 2, TECH_DATA = 2) matter = list(DEFAULT_WALL_MATERIAL = 30,"glass" = 10) + var/video_range = 4 + var/list/voice_mobs = list() var/list/voice_requests = list() var/list/voice_invites = list() @@ -474,6 +476,24 @@ var/global/list/obj/item/device/communicator/all_communicators = list() name = "[owner]'s [initial(name)]" + +// Proc: add_communicating() +// Parameters: 1 (comm - the communicator to add to communicating) +// Description: Used when this communicator gets a new communicator to relay say/me messages to +/obj/item/device/communicator/proc/add_communicating(obj/item/device/communicator/comm) + if(!comm || !istype(comm)) return + + communicating |= comm + listening_objects |= src + +// Proc: del_communicating() +// Parameters: 1 (comm - the communicator to remove from communicating) +// Description: Used when this communicator is being asked to stop relaying say/me messages to another +/obj/item/device/communicator/proc/del_communicating(obj/item/device/communicator/comm) + if(!comm || !istype(comm)) return + + communicating.Remove(comm) + // Proc: open_connection() // Parameters: 2 (user - the person who initiated the connecting being opened, candidate - the communicator or observer that will connect to the device) // Description: Typechecks the candidate, then calls the correct proc for further connecting. @@ -507,8 +527,8 @@ var/global/list/obj/item/device/communicator/all_communicators = list() comm.visible_message("\icon[src] Connection to [src] at [exonet.address] established.") sleep(20) - communicating |= comm - comm.communicating |= src + src.add_communicating(comm) + comm.add_communicating(src) // Proc: open_connection_to_ghost() // Parameters: 2 (user - the person who initiated this, candidate - the ghost that will be turned into a voice mob) @@ -530,6 +550,7 @@ var/global/list/obj/item/device/communicator/all_communicators = list() new_voice.mind = candidate.mind //Transfer the mind, if any. new_voice.ckey = candidate.ckey //Finally, bring the client over. voice_mobs.Add(new_voice) + listening_objects |= src var/obj/screen/blackness = new() //Makes a black screen, so the candidate can't see what's going on before actually 'connecting' to the communicator. blackness.screen_loc = ui_entire_screen @@ -586,10 +607,13 @@ var/global/list/obj/item/device/communicator/all_communicators = list() continue comm.visible_message("\icon[src] [reason].") visible_message("\icon[src] [reason].") - comm.communicating.Remove(src) - communicating.Remove(comm) + src.del_communicating(comm) + comm.del_communicating(src) update_icon() + if(voice_mobs.len == 0 && communicating.len == 0) + listening_objects.Remove(src) + // Proc: request() // Parameters: 1 (candidate - the ghost or communicator wanting to call the device) // Description: Response to a communicator or observer trying to call the device. Adds them to the list of requesters @@ -675,6 +699,7 @@ var/global/list/obj/item/device/communicator/all_communicators = list() voice_invites.Cut() all_communicators -= src processing_objects -= src + listening_objects.Remove(src) if(exonet) exonet.remove_address() exonet = null @@ -700,10 +725,18 @@ var/global/list/obj/item/device/communicator/all_communicators = list() /obj/item/device/communicator/see_emote(mob/living/M, text) var/rendered = "\icon[src] [text]" for(var/obj/item/device/communicator/comm in communicating) - for(var/mob/mob in viewers(get_turf(comm))) //We can't use visible_message(), or else we will get an infinite loop if two communicators hear each other. - mob.show_message(rendered) - for(var/mob/living/voice/V in comm.contents) - V.show_message(rendered) + var/turf/T = get_turf(comm) + if(!T) return + var/list/in_range = get_mobs_and_objs_in_view_fast(T,world.view,0) //Range of 3 since it's a tiny video display + var/list/mobs_to_relay = in_range["mobs"] + + for(var/mob/mob in mobs_to_relay) //We can't use visible_message(), or else we will get an infinite loop if two communicators hear each other. + var/dst = get_dist(get_turf(mob),get_turf(comm)) + if(dst <= video_range) + mob.show_message(rendered) + else + mob << "You can barely see some movement on \the [src]'s display." + ..() // Proc: hear_talk() @@ -712,9 +745,12 @@ var/global/list/obj/item/device/communicator/all_communicators = list() // Description: Relays the speech to all linked communicators. /obj/item/device/communicator/hear_talk(mob/living/M, text, verb, datum/language/speaking) for(var/obj/item/device/communicator/comm in communicating) - var/list/mobs_to_relay = list() - mobs_to_relay |= viewers(get_turf(comm)) - mobs_to_relay |= comm.contents //Needed so ghost-callers can see speech. + + var/turf/T = get_turf(comm) + if(!T) return + var/list/in_range = get_mobs_and_objs_in_view_fast(T,world.view,0) + var/list/mobs_to_relay = in_range["mobs"] + for(var/mob/mob in mobs_to_relay) //Can whoever is hearing us understand? if(!mob.say_understands(M, speaking)) @@ -736,7 +772,12 @@ var/global/list/obj/item/device/communicator/all_communicators = list() /obj/item/device/communicator/show_message(msg, type, alt, alt_type) var/rendered = "\icon[src] [msg]" for(var/obj/item/device/communicator/comm in communicating) - for(var/mob/mob in hearers(get_turf(comm))) //Ditto for audible messages. + var/turf/T = get_turf(comm) + if(!T) return + var/list/in_range = get_mobs_and_objs_in_view_fast(T,world.view,0) + var/list/mobs_to_relay = in_range["mobs"] + + for(var/mob/mob in mobs_to_relay) mob.show_message(rendered) ..() @@ -822,4 +863,4 @@ var/global/list/obj/item/device/communicator/all_communicators = list() usr << "You can't do that because you are dead!" return - src.attack_self(usr) \ No newline at end of file + src.attack_self(usr) diff --git a/code/modules/mob/living/voice/voice.dm b/code/modules/mob/living/voice/voice.dm index a9f5dbd60a..a27b0ffc94 100644 --- a/code/modules/mob/living/voice/voice.dm +++ b/code/modules/mob/living/voice/voice.dm @@ -107,7 +107,7 @@ // Proc: say() // Parameters: 4 (generic say() arguments) // Description: Adds a speech bubble to the communicator device, then calls ..() to do the real work. -/mob/living/voice/say(var/message, var/datum/language/speaking = null, var/verb="says", var/alt_name="") +/mob/living/voice/say(var/message, var/datum/language/speaking = null, var/verb="says", var/alt_name="", var/whispering=0) //Speech bubbles. if(comm) var/speech_bubble_test = say_test(message) @@ -119,4 +119,8 @@ M << speech_bubble src << speech_bubble - ..(message, speaking, verb, alt_name) //mob/living/say() can do the actual talking. \ No newline at end of file + ..(message, speaking, verb, alt_name, whispering) //mob/living/say() can do the actual talking. + +/mob/living/voice/custom_emote(var/m_type=1,var/message = null,var/range=world.view) + if(!comm) return + ..(m_type,message,comm.video_range) From 3ad30aebc5c8c6097a6d95d97737d459d152988d Mon Sep 17 00:00:00 2001 From: Arokha Sieyes Date: Sat, 11 Jun 2016 22:08:31 -0400 Subject: [PATCH 6/6] Removes old code comment block --- code/game/verbs/ooc.dm | 36 ------------------------------------ 1 file changed, 36 deletions(-) diff --git a/code/game/verbs/ooc.dm b/code/game/verbs/ooc.dm index 7891951f20..2a0f3b6607 100644 --- a/code/game/verbs/ooc.dm +++ b/code/game/verbs/ooc.dm @@ -147,42 +147,6 @@ var/admin_stuff = "/([key])([admin_jump_link(mob, target.holder)])" target << "" + create_text_tag("looc", "LOOC:", target) + " (R)[display_name][admin_stuff]: [msg]" -/* - for(var/client/target in clients) - if(target.is_preference_enabled(/datum/client_preference/show_looc)) - var/prefix = "" - var/admin_stuff = "" - var/send = 0 - - // Admins get extra data. - if(target in admins) - admin_stuff += "/([key])" - if(target != src) - admin_stuff += "([admin_jump_link(mob, target.holder)])" - - // For AIs, needs work done to see if the eye is in range as we're going over clients not mobs. - if(isAI(target.mob)) - var/mob/living/silicon/ai/A = target.mob - if(A.eyeobj in m_viewers) - send = 1 - prefix = "(Eye) " // Prefer the (Eye) prefix if they are in range of core and eye. - else if (A in m_viewers) - send = 1 - prefix = "(Core) " - - // If you're in range, you get the LOOC. - else if(target.mob in m_viewers) - send = 1 - - // If you weren't going to otherwise get it, but can see (R)LOOC. - if(!send && (target in admins) && target.is_preference_enabled(/datum/client_preference/holder/show_rlooc)) - send = 1 - prefix = "(R)" - - // Deliver message directly to the client with stream operator, not another proc. LOOC is important. - if(send) - target << "" + create_text_tag("looc", "LOOC:", target) + " [prefix][display_name][admin_stuff]: [msg]" -*/ /mob/proc/get_looc_source() return src