diff --git a/code/game/machinery/computer/camera.dm b/code/game/machinery/computer/camera.dm index 273ee679a9..2067bd43a0 100644 --- a/code/game/machinery/computer/camera.dm +++ b/code/game/machinery/computer/camera.dm @@ -127,6 +127,10 @@ //don't need to check if the camera works for AI because the AI jumps to the camera location and doesn't actually look through cameras. if(isAI(user)) var/mob/living/silicon/ai/A = user + // Only allow non-carded AIs to view because the interaction with the eye gets all wonky otherwise. + if(!A.is_in_chassis()) + return 0 + A.eyeobj.setLoc(get_turf(C)) A.client.eye = A.eyeobj return 1 diff --git a/code/game/machinery/machinery.dm b/code/game/machinery/machinery.dm index 2b577a469a..c5eaf35497 100644 --- a/code/game/machinery/machinery.dm +++ b/code/game/machinery/machinery.dm @@ -187,63 +187,9 @@ Class Procs: /obj/machinery/Topic(href, href_list, var/nowindow = 0, var/checkrange = 1) if(..()) return 1 - if(!can_be_used_by(usr, be_close = checkrange)) - return 1 - add_fingerprint(usr) - return 0 - -/obj/machinery/proc/can_be_used_by(mob/user, be_close = 1) if(!interact_offline && stat & (NOPOWER|BROKEN)) - return 0 - if(!user.canUseTopic(src, be_close)) - return 0 - return 1 - -//////////////////////////////////////////////////////////////////////////////////////////// - -/mob/proc/canUseTopic(atom/movable/M, be_close = 1) - return - -/mob/dead/observer/canUseTopic(atom/movable/M, be_close = 1) - if(check_rights(R_ADMIN, 0)) - return - -/mob/living/canUseTopic(atom/movable/M, be_close = 1, no_dextery = 0) - if(no_dextery) - src << "You don't have the dexterity to do this!" - return 0 - return be_close && !in_range(M, src) - -/mob/living/carbon/human/canUseTopic(atom/movable/M, be_close = 1) - if(restrained() || lying || stat || stunned || weakened) - return - if(be_close && !in_range(M, src)) - if(TK in mutations) - var/mob/living/carbon/human/H = M - if(istype(H.l_hand, /obj/item/tk_grab) || istype(H.r_hand, /obj/item/tk_grab)) - return 1 - return - if(!isturf(M.loc) && M.loc != src) - return - return 1 - -/mob/living/silicon/ai/canUseTopic(atom/movable/M) - if(stat) - return - // Prevents the AI from using Topic on admin levels (by for example viewing through the court/thunderdome cameras) - // unless it's on the same level as the object it's interacting with. - if(!(z == M.z || M.z in config.player_levels)) - return - //stop AIs from leaving windows open and using then after they lose vision - //apc_override is needed here because AIs use their own APC when powerless - if(cameranet && !cameranet.checkTurfVis(get_turf(M)) && !apc_override) - return - return 1 - -/mob/living/silicon/robot/canUseTopic(atom/movable/M) - if(stat || lockcharge || stunned || weakened) - return - return 1 + return 1 + return 0 //////////////////////////////////////////////////////////////////////////////////////////// diff --git a/code/game/objects/items/devices/uplinks.dm b/code/game/objects/items/devices/uplinks.dm index cd2ff9b5fb..53efa61f96 100644 --- a/code/game/objects/items/devices/uplinks.dm +++ b/code/game/objects/items/devices/uplinks.dm @@ -108,6 +108,9 @@ datum/nano_item_lists return pick(random_items) /obj/item/device/uplink/Topic(href, href_list) + if(..()) + return 1 + if(href_list["buy_item"] == "random") var/datum/uplink_item/UI = chooseRandomItem() href_list["buy_item"] = UI.reference @@ -208,10 +211,10 @@ datum/nano_item_lists // The purchasing code. /obj/item/device/uplink/hidden/Topic(href, href_list) if (usr.stat || usr.restrained()) - return + return 1 if (!( istype(usr, /mob/living/carbon/human))) - return 0 + return 1 var/mob/user = usr var/datum/nanoui/ui = nanomanager.get_open_ui(user, src, "main") if ((usr.contents.Find(src.loc) || (in_range(src.loc, usr) && istype(src.loc.loc, /turf)))) diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index 167794721b..bbcad347b5 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -16,11 +16,14 @@ var/damtype = "brute" var/force = 0 -/obj/Topic(href, href_list, var/nowindow = 0) +/obj/Topic(href, href_list, var/nowindow = 0, var/checkrange = 1) // Calling Topic without a corresponding window open causes runtime errors - if(nowindow) - return 0 - return ..() + if(!nowindow && ..()) + return 1 + if(usr.can_interact_with_interface(src, checkrange) != STATUS_INTERACTIVE) + return 1 + add_fingerprint(usr) + return 0 /obj/item/proc/is_used_on(obj/O, mob/user) diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index c25e833c08..5f7f79f1a0 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -766,5 +766,8 @@ var/list/ai_verbs_default = list( return 1 return 0 +/mob/living/silicon/ai/proc/is_in_chassis() + return istype(loc, /turf) + #undef AI_CHECK_WIRELESS #undef AI_CHECK_RADIO diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index bf4ac5164d..6829af21fa 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -1277,16 +1277,6 @@ var/list/robot_verbs_default = list( return 1 return 0 -/mob/living/silicon/robot/syndicate/canUseTopic(atom/movable/M) - if(stat || lockcharge || stunned || weakened) - return - if(z in config.admin_levels) - return 1 - if(istype(M, /obj/machinery)) - var/obj/machinery/Machine = M - return Machine.emagged - return 1 - /mob/living/silicon/robot/proc/notify_ai(var/notifytype, var/oldname, var/newname) if(!connected_ai) return diff --git a/code/modules/nano/nanoui.dm b/code/modules/nano/nanoui.dm index 8861d1fabc..a283066157 100644 --- a/code/modules/nano/nanoui.dm +++ b/code/modules/nano/nanoui.dm @@ -6,11 +6,6 @@ nanoui class (or whatever Byond calls classes) nanoui is used to open and update nano browser uis **********************************************************/ - -#define STATUS_INTERACTIVE 2 // GREEN Visability -#define STATUS_UPDATE 1 // ORANGE Visability -#define STATUS_DISABLED 0 // RED Visability - /datum/nanoui // the user who opened this ui var/mob/user @@ -59,9 +54,6 @@ nanoui is used to open and update nano browser uis var/cached_data = null - // Only allow users with a certain user.stat to get updates. Defaults to 0 (concious) - var/allowed_user_stat = 0 // -1 = ignore, 0 = alive, 1 = unconcious or alive, 2 = dead concious or alive - /** * Create a new nanoui instance. * @@ -140,37 +132,110 @@ nanoui is used to open and update nano browser uis * @return nothing */ /datum/nanoui/proc/update_status(var/push_update = 0) - if (istype(user, /mob/dead/observer)) - /* Ghosts see updates but can't interact */ - set_status(STATUS_UPDATE, push_update) - else if (istype(user, /mob/living/silicon/ai) || (get_dist(get_turf(user),get_turf(src_object)) <= 1)) - set_status(STATUS_INTERACTIVE, push_update) // interactive (green visibility) - else if (istype(user, /mob/living/silicon/robot)) - if (src_object in view(7, user)) // robots can see and interact with things they can see within 7 tiles - set_status(STATUS_INTERACTIVE, push_update) // interactive (green visibility) - else - set_status(STATUS_DISABLED, push_update) // no updates, completely disabled (red visibility) + var/status = user.can_interact_with_interface(src_object) + if(status == STATUS_CLOSE) + close() else - var/dist = get_dist(src_object, user) + set_status(status, push_update) - if (dist > 4) - close() - return +/* + Procs called by update_status() +*/ - if ((allowed_user_stat > -1) && (user.stat > allowed_user_stat)) - set_status(STATUS_DISABLED, push_update) // no updates, completely disabled (red visibility) - else if (user.restrained() || user.lying) - set_status(STATUS_UPDATE, push_update) // update only (orange visibility) - else if (istype(src_object, /obj/item/device/uplink/hidden)) // You know what if they have the uplink open let them use the UI - set_status(STATUS_INTERACTIVE, push_update) // Will build in distance checks on the topics for sanity. - else if (!(src_object in view(4, user))) // If the src object is not in visable, set status to 0 - set_status(STATUS_DISABLED, push_update) // interactive (green visibility) - else if (dist <= 1) - set_status(STATUS_INTERACTIVE, push_update) // interactive (green visibility) - else if (dist <= 2) - set_status(STATUS_UPDATE, push_update) // update only (orange visibility) - else if (dist <= 4) - set_status(STATUS_DISABLED, push_update) // no updates, completely disabled (red visibility) +/mob/proc/can_interact_with_interface(var/src_object) + return STATUS_CLOSE // By default no mob can do anything with NanoUI + +/mob/dead/observer/can_interact_with_interface() + if(check_rights(R_ADMIN, 0)) + return STATUS_INTERACTIVE // Admins are more equal + return STATUS_UPDATE // Ghosts can view updates + +/mob/living/silicon/robot/can_interact_with_interface(var/src_object) + if(stat || !client) + return STATUS_CLOSE + if(lockcharge || stunned || weakened) + return STATUS_DISABLED + if (src_object in view(client.view, src)) // robots can see and interact with things they can see within their view range + return STATUS_INTERACTIVE // interactive (green visibility) + return STATUS_DISABLED // no updates, completely disabled (red visibility) + +/mob/living/silicon/robot/syndicate/can_interact_with_interface(var/src_object) + . = ..() + if(. != STATUS_INTERACTIVE) + return + + if(z in config.admin_levels) // Syndicate borgs can interact with everything on the admin level + return STATUS_INTERACTIVE + if(istype(get_area(src), /area/syndicate_station)) // If elsewhere, they can interact with everything on the syndicate shuttle + return STATUS_INTERACTIVE + if(istype(src_object, /obj/machinery)) // Otherwise they can only interact with emagged machinery + var/obj/machinery/Machine = src_object + if(Machine.emagged) + return STATUS_INTERACTIVE + return STATUS_UPDATE + +/mob/living/silicon/ai/can_interact_with_interface(var/src_object) + if(stat || !client) + return STATUS_CLOSE + // Prevents the AI from using Topic on admin levels (by for example viewing through the court/thunderdome cameras) + // unless it's on the same level as the object it's interacting with. + var/turf/T = get_turf(src_object) + if(!T || !(z == T.z || (T.z in config.player_levels))) + return STATUS_CLOSE + + // If an object is in view then we can interact with it + if(src_object in view(client.view, src)) + return STATUS_INTERACTIVE + + // If we're installed in a chassi, rather than transfered to an inteliCard or other container, then check if we have camera view + if(is_in_chassis()) + //stop AIs from leaving windows open and using then after they lose vision + //apc_override is needed here because AIs use their own APC when powerless + if(cameranet && !cameranet.checkTurfVis(get_turf(src_object))) + return apc_override ? STATUS_INTERACTIVE : STATUS_CLOSE + return STATUS_INTERACTIVE + + return STATUS_CLOSE + +/mob/living/proc/shared_living_nano_interaction(var/src_object) + if (src.stat != CONSCIOUS) + return STATUS_CLOSE // no updates, close the interface + else if (restrained() || lying || stat || stunned || weakened) + return STATUS_UPDATE // update only (orange visibility) + return STATUS_INTERACTIVE + +/mob/living/proc/shared_living_nano_distance(var/atom/movable/src_object) + if(!isturf(src_object.loc)) + if(src_object.loc == src) // Item in the inventory + return STATUS_INTERACTIVE + if(src.contents.Find(src_object.loc)) // A hidden uplink inside an item + return STATUS_INTERACTIVE + + if (!(src_object in view(4, src))) // If the src object is not in visable, disable updates + return STATUS_CLOSE + + var/dist = get_dist(src_object, src) + if (dist <= 1) + return STATUS_INTERACTIVE // interactive (green visibility) + else if (dist <= 2) + return STATUS_UPDATE // update only (orange visibility) + else if (dist <= 4) + return STATUS_DISABLED // no updates, completely disabled (red visibility) + return STATUS_CLOSE + +/mob/living/can_interact_with_interface(var/src_object, var/be_close = 1) + . = shared_living_nano_interaction(src_object) + if(. == STATUS_INTERACTIVE && be_close) + . = shared_living_nano_distance(src_object) + if(STATUS_INTERACTIVE) + return STATUS_UPDATE + +/mob/living/carbon/human/can_interact_with_interface(var/src_object, var/be_close = 1) + . = shared_living_nano_interaction(src_object) + if(. == STATUS_INTERACTIVE && be_close) + . = shared_living_nano_distance(src_object) + if(. == STATUS_UPDATE && (TK in mutations)) // If we have telekinesis and remain close enough, allow interaction. + return STATUS_INTERACTIVE /** * Set the ui to auto update (every master_controller tick) diff --git a/code/setup.dm b/code/setup.dm index eae4565e48..e1b8b6695b 100644 --- a/code/setup.dm +++ b/code/setup.dm @@ -17,9 +17,9 @@ #define GAS_CRITICAL_TEMPERATURE 132.65 // K. The critical point temperature for air. /* - The pipe looks to be thin vertically and wide horizontally, so we'll assume that it's - three centimeters thick, one meter wide, and only explosed to the sun 3 degrees off of edge-on. - Since the radiatior is uniform along it's length, the ratio of surface area touched by sunlight + The pipe looks to be thin vertically and wide horizontally, so we'll assume that it's + three centimeters thick, one meter wide, and only explosed to the sun 3 degrees off of edge-on. + Since the radiatior is uniform along it's length, the ratio of surface area touched by sunlight to the total surface area is the same as the ratio of the perimeter of the cross-section. */ #define RADIATOR_EXPOSED_SURFACE_AREA_RATIO 0.04 // (3 cm + 100 cm * sin(3deg))/(2*(3+100 cm)). Unitless ratio. @@ -775,3 +775,10 @@ var/list/be_special_flags = list( #define SUIT_SENSOR_BINARY 1 #define SUIT_SENSOR_VITAL 2 #define SUIT_SENSOR_TRACKING 3 + +// NanoUI flags +#define STATUS_INTERACTIVE 2 // GREEN Visability +#define STATUS_UPDATE 1 // ORANGE Visability +#define STATUS_DISABLED 0 // RED Visability +#define STATUS_CLOSE -1 // Close the interface +