From 6a7fc1600c7eb31cdf7ae5019ad2acf3dd79f06d Mon Sep 17 00:00:00 2001 From: Doubleumc Date: Tue, 16 Jul 2024 09:37:56 -0400 Subject: [PATCH] Quadtrees shapes (#6681) # About the pull request Additional shapes available for testing against quadtrees or elsewhere: square, ellipse, circle. Square is a simplified version of the rectangle, circle is a simplified version of the ellipse. Cleaned up existing code for shapes (rectangles), should be better documented and easier to read. Where possible converted existing RECT usage to SQUARE (everything was squares anyway). Where possible loosened defined types to the base `/datum/shape` so shape types can be swapped as desired. # Explain why it's good for the game Should (currently) have no effect on the game, but paves the way for more interesting uses for quadtrees. Circular areas of effect, for instance. # Testing Photographs and Procedure Boots. Sentries, flamer sentries, bell towers, flags, sentry laptop, motion detector, and egg morpher all appear to work as intended. # Changelog No player facing changes. --- code/_macros.dm | 3 + code/controllers/subsystem/sound.dm | 3 +- code/datums/quadtree.dm | 145 ++++++++++++++---- code/game/camera_manager/camera_manager.dm | 20 +-- .../machinery/computer/dropship_weapons.dm | 3 +- .../objects/items/devices/motion_detector.dm | 11 +- .../structures/special/egg_morpher.dm | 6 +- code/modules/defenses/bell_tower.dm | 2 +- code/modules/defenses/planted_flag.dm | 10 +- code/modules/defenses/sentry.dm | 30 ++-- code/modules/defenses/sentry_computer.dm | 3 +- code/modules/defenses/sentry_flamer.dm | 8 +- 12 files changed, 160 insertions(+), 84 deletions(-) diff --git a/code/_macros.dm b/code/_macros.dm index abfa83df7d36..9b92dc8730c3 100644 --- a/code/_macros.dm +++ b/code/_macros.dm @@ -95,6 +95,9 @@ #define GENERATE_DEBUG_ID "[rand(0, 9)][rand(0, 9)][rand(0, 9)][rand(0, 9)][pick(alphabet_lowercase)][pick(alphabet_lowercase)][pick(alphabet_lowercase)][pick(alphabet_lowercase)]" #define RECT new /datum/shape/rectangle +#define SQUARE new /datum/shape/rectangle/square +#define ELLIPSE new /datum/shape/ellipse +#define CIRCLE new /datum/shape/ellipse/circle #define QTREE new /datum/quadtree #define SEARCH_QTREE(qtree, shape_range, flags) qtree.query_range(shape_range, null, flags) diff --git a/code/controllers/subsystem/sound.dm b/code/controllers/subsystem/sound.dm index 024df7cc45ad..13dd6a0dddf1 100644 --- a/code/controllers/subsystem/sound.dm +++ b/code/controllers/subsystem/sound.dm @@ -19,8 +19,7 @@ SUBSYSTEM_DEF(sound) if(!run_hearers) // Initialize for handling next template run_hearers = run_queue[run_template] // get base hearers if(run_template.range) // ranging - var/datum/shape/rectangle/zone = RECT(run_template.x, run_template.y, run_template.range * 2, run_template.range * 2) - run_hearers |= SSquadtree.players_in_range(zone, run_template.z) + run_hearers |= SSquadtree.players_in_range(SQUARE(run_template.x, run_template.y, run_template.range), run_template.z) if(MC_TICK_CHECK) return while(length(run_hearers)) // Output sound to hearers diff --git a/code/datums/quadtree.dm b/code/datums/quadtree.dm index 5e5b27d57330..200a51b358a0 100644 --- a/code/datums/quadtree.dm +++ b/code/datums/quadtree.dm @@ -49,43 +49,124 @@ ..() return QDEL_HINT_IWILLGC -/datum/shape //Leaving rectangles as a subtype if anyone decides to add circles later +/// A simple geometric shape for testing collisions and intersections. This one is a single point. +/datum/shape + /// Horizontal position of the shape's center point. var/center_x = 0 + /// Vertical position of the shape's center point. var/center_y = 0 + /// Distance from the shape's leftmost to rightmost extent. + var/bounds_x = 0 + /// Distance from the shape's topmost to bottommost extent. + var/bounds_y = 0 -/datum/shape/proc/intersects() - return -/datum/shape/proc/contains() - return +/datum/shape/New(center_x, center_y) + set_shape(center_x, center_y) +/// Assign shape variables. +/datum/shape/proc/set_shape(center_x, center_y) + src.center_x = center_x + src.center_y = center_y + +/// Returns TRUE if the coordinates x, y are in or on the shape, otherwise FALSE. +/datum/shape/proc/contains_xy(x, y) + return center_x == x && center_y == y + +/// Returns TRUE if the coord datum is in or on the shape, otherwise FALSE. +/datum/shape/proc/contains_coords(datum/coords/coords) + return contains_xy(coords.x_pos, coords.y_pos) + +/// Returns TRUE if the atom is in or on the shape, otherwise FALSE. +/datum/shape/proc/contains_atom(atom/atom) + return contains_xy(atom.x, atom.y) + +/// Returns TRUE if this shape's bounding box intersects the provided shape's bounding box, otherwise FALSE. Generally faster than a full intersection test. +/datum/shape/proc/intersects_aabb(datum/shape/aabb) + return (abs(src.center_x - aabb.center_x) <= (src.bounds_x + aabb.bounds_x) * 0.5) && (abs(src.center_y - aabb.center_y) <= (src.bounds_x + aabb.bounds_x) * 0.5) + +/// Returns TRUE if this shape intersects the provided rectangle shape, otherwise FALSE. +/datum/shape/proc/intersects_rect(datum/shape/rectangle/rect) + return rect.contains_xy(src.center_x, src.center_y) + +/// A simple geometric shape for testing collisions and intersections. This one is an axis-aligned rectangle. /datum/shape/rectangle + /// Distance from the shape's leftmost to rightmost extent. + var/width = 0 + /// Distance from the shape's topmost to bottommost extent. + var/height = 0 + +/datum/shape/rectangle/New(center_x, center_y, width, height) + set_shape(center_x, center_y, width, height) + +/datum/shape/rectangle/set_shape(center_x, center_y, width, height) + ..() + src.bounds_x = width + src.bounds_y = height + src.width = width + src.height = height + +/datum/shape/rectangle/contains_xy(x, y) + return (abs(center_x - x) <= width * 0.5) && (abs(center_y - y) <= height * 0.5) + +/datum/shape/rectangle/intersects_rect(datum/shape/rectangle/rect) + return intersects_aabb(rect) + +/// A simple geometric shape for testing collisions and intersections. This one is an axis-aligned square. +/datum/shape/rectangle/square + /// Distance between the shape's opposing extents. + var/length = 0 + +/datum/shape/rectangle/square/New(center_x, center_y, length) + set_shape(center_x, center_y, length) + +/datum/shape/rectangle/square/set_shape(center_x, center_y, length) + ..(center_x, center_y, length, length) + src.length = length + +/// A simple geometric shape for testing collisions and intersections. This one is an axis-aligned ellipse. +/datum/shape/ellipse + /// Distance from the shape's leftmost to rightmost extent. var/width = 0 + /// Distance from the shape's topmost to bottommost extent. var/height = 0 + VAR_PROTECTED/_axis_x_sq = 0 + VAR_PROTECTED/_axis_y_sq = 0 + +/datum/shape/ellipse/New(center_x, center_y, width, height) + set_shape(center_x, center_y, width, height) -/datum/shape/rectangle/New(x, y, w, h) +/datum/shape/ellipse/set_shape(center_x, center_y, width, height) ..() - center_x = x - center_y = y - width = w - height = h - -/datum/shape/rectangle/intersects(datum/shape/rectangle/range) - return !(range.center_x + range.width/2 < center_x - width / 2|| \ - range.center_x - range.width/2 > center_x + width / 2|| \ - range.center_y + range.height/2 < center_y - height / 2|| \ - range.center_y - range.height/2 > center_y + height / 2) - -/datum/shape/rectangle/contains(datum/coords/coords) - return (coords.x_pos >= center_x - width / 2 \ - && coords.x_pos <= center_x + width / 2 \ - && coords.y_pos >= center_y - height /2 \ - && coords.y_pos <= center_y + height / 2) - -/datum/shape/rectangle/proc/contains_atom(atom/A) - return (A.x >= center_x - width / 2 \ - && A.x <= center_x + width / 2 \ - && A.y >= center_y - height /2 \ - && A.y <= center_y + height / 2) + src.bounds_x = width + src.bounds_y = height + src.width = width + src.height = height + src._axis_x_sq = (width * 0.5)**2 + src._axis_y_sq = (height * 0.5)**2 + +/datum/shape/ellipse/contains_xy(x, y) + return ((center_x - x)**2 / _axis_x_sq + (center_y - y)**2 / _axis_y_sq <= 1) + +/datum/shape/ellipse/intersects_rect(datum/shape/rectangle/rect) + if(..()) + return TRUE + + var/nearest_x = clamp(src.center_x, rect.center_x - rect.width * 0.5, rect.center_x + rect.width * 0.5) + var/nearest_y = clamp(src.center_y, rect.center_y - rect.height * 0.5, rect.center_y + rect.height * 0.5) + + return src.contains_xy(nearest_x, nearest_y) + +/// A simple geometric shape for testing collisions and intersections. This one is a circle. +/datum/shape/ellipse/circle + /// Distance from the shape's center to edge. + var/radius = 0 + +/datum/shape/ellipse/circle/New(center_x, center_y, radius) + set_shape(center_x, center_y, radius) + +/datum/shape/ellipse/circle/set_shape(center_x, center_y, radius) + ..(center_x, center_y, radius * 2, radius * 2) + src.radius = radius /datum/quadtree/proc/subdivide() //Warning: this might give you eye cancer @@ -96,7 +177,7 @@ is_divided = TRUE /datum/quadtree/proc/insert_player(datum/coords/qtplayer/p_coords) - if(!boundary.contains(p_coords)) + if(!boundary.contains_coords(p_coords)) return FALSE if(!player_coords) @@ -118,11 +199,11 @@ player_coords.Add(p_coords) return TRUE -/datum/quadtree/proc/query_range(datum/shape/rectangle/range, list/found_players, flags = 0) +/datum/quadtree/proc/query_range(datum/shape/range, list/found_players, flags = 0) if(!found_players) found_players = list() . = found_players - if(!range?.intersects(boundary)) + if(!range?.intersects_rect(boundary)) return if(is_divided) nw_branch.query_range(range, found_players, flags) @@ -136,7 +217,7 @@ continue if((flags & QTREE_EXCLUDE_OBSERVER) && P.is_observer) continue - if(range.contains(P)) + if(range.contains_coords(P)) if(flags & QTREE_SCAN_MOBS) found_players.Add(P.player.mob) else diff --git a/code/game/camera_manager/camera_manager.dm b/code/game/camera_manager/camera_manager.dm index 9f111b0f8ec6..90e80ec7037e 100644 --- a/code/game/camera_manager/camera_manager.dm +++ b/code/game/camera_manager/camera_manager.dm @@ -6,7 +6,7 @@ /datum/component/camera_manager var/map_name var/obj/structure/machinery/camera/current - var/datum/shape/rectangle/current_area + var/datum/shape/current_area var/atom/movable/screen/map_view/cam_screen var/atom/movable/screen/background/cam_background var/list/range_turfs = list() @@ -86,7 +86,7 @@ RegisterSignal(parent, COMSIG_CAMERA_UNREGISTER_UI, PROC_REF(unregister)) RegisterSignal(parent, COMSIG_CAMERA_SET_NVG, PROC_REF(enable_nvg)) RegisterSignal(parent, COMSIG_CAMERA_CLEAR_NVG, PROC_REF(disable_nvg)) - RegisterSignal(parent, COMSIG_CAMERA_SET_AREA, PROC_REF(set_camera_rect)) + RegisterSignal(parent, COMSIG_CAMERA_SET_AREA, PROC_REF(set_camera_area)) RegisterSignal(parent, COMSIG_CAMERA_SET_TARGET, PROC_REF(set_camera)) RegisterSignal(parent, COMSIG_CAMERA_CLEAR, PROC_REF(clear_camera)) RegisterSignal(parent, COMSIG_CAMERA_REFRESH, PROC_REF(refresh_camera)) @@ -133,18 +133,18 @@ RegisterSignal(current, COMSIG_PARENT_QDELETING, PROC_REF(show_camera_static)) update_target_camera() -/datum/component/camera_manager/proc/set_camera_rect(source, x, y, z, w, h) +/datum/component/camera_manager/proc/set_camera_area(source, datum/shape/new_area, z) SIGNAL_HANDLER render_mode = RENDER_MODE_AREA if(current) UnregisterSignal(current, COMSIG_PARENT_QDELETING) current = null - current_area = RECT(x, y, w, h) - target_x = x - target_y = y + current_area = new_area + target_x = current_area.center_x + target_y = current_area.center_y target_z = z - target_width = w - target_height = h + target_width = current_area.bounds_x + target_height = current_area.bounds_y update_area_camera() /datum/component/camera_manager/proc/enable_nvg(source, power, matrixcol) @@ -221,8 +221,8 @@ // Cameras that get here are moving, and are likely attached to some moving atom such as cyborgs. last_camera_turf = new_location - var/x_size = current_area.width - var/y_size = current_area.height + var/x_size = current_area.bounds_x + var/y_size = current_area.bounds_y var/turf/target = locate(current_area.center_x, current_area.center_y, target_z) var/list/visible_things = isXRay ? range("[x_size]x[y_size]", target) : view("[x_size]x[y_size]", target) diff --git a/code/game/machinery/computer/dropship_weapons.dm b/code/game/machinery/computer/dropship_weapons.dm index e07b415ed233..7f8f4f2b3850 100644 --- a/code/game/machinery/computer/dropship_weapons.dm +++ b/code/game/machinery/computer/dropship_weapons.dm @@ -313,9 +313,8 @@ var/obj/structure/machinery/defenses/sentry/defense = sentry.deployed_turret if(defense.has_camera) defense.set_range() - var/datum/shape/rectangle/current_bb = defense.range_bounds camera_area_equipment = sentry - SEND_SIGNAL(src, COMSIG_CAMERA_SET_AREA, current_bb.center_x, current_bb.center_y, defense.loc.z, current_bb.width, current_bb.height) + SEND_SIGNAL(src, COMSIG_CAMERA_SET_AREA, defense.range_bounds, defense.loc.z) return TRUE if("clear-camera") diff --git a/code/game/objects/items/devices/motion_detector.dm b/code/game/objects/items/devices/motion_detector.dm index 3551e3a02bef..dcbcc0dd8bc7 100644 --- a/code/game/objects/items/devices/motion_detector.dm +++ b/code/game/objects/items/devices/motion_detector.dm @@ -35,7 +35,7 @@ var/iff_signal = FACTION_MARINE actions_types = list(/datum/action/item_action) var/scanning = FALSE // controls if MD is in process of scan - var/datum/shape/rectangle/range_bounds + var/datum/shape/rectangle/square/range_bounds var/long_range_locked = FALSE //only long-range MD var/ping_overlay @@ -48,7 +48,7 @@ /obj/item/device/motiondetector/Initialize() . = ..() - range_bounds = new //Just creating a rectangle datum + range_bounds = new //Just creating a square datum update_icon() /obj/item/device/motiondetector/Destroy() @@ -215,12 +215,7 @@ if(!istype(cur_turf)) return - if(!range_bounds) - range_bounds = new/datum/shape/rectangle - range_bounds.center_x = cur_turf.x - range_bounds.center_y = cur_turf.y - range_bounds.width = detector_range * 2 - range_bounds.height = detector_range * 2 + range_bounds.set_shape(cur_turf.x, cur_turf.y, detector_range * 2) var/list/ping_candidates = SSquadtree.players_in_range(range_bounds, cur_turf.z, QTREE_EXCLUDE_OBSERVER | QTREE_SCAN_MOBS) diff --git a/code/modules/cm_aliens/structures/special/egg_morpher.dm b/code/modules/cm_aliens/structures/special/egg_morpher.dm index c4fb5c0a900c..ac501bb5c970 100644 --- a/code/modules/cm_aliens/structures/special/egg_morpher.dm +++ b/code/modules/cm_aliens/structures/special/egg_morpher.dm @@ -14,14 +14,14 @@ var/huggers_to_grow_max = 12 var/huggers_reserved = 0 var/mob/captured_mob - var/datum/shape/rectangle/range_bounds + var/datum/shape/range_bounds appearance_flags = KEEP_TOGETHER layer = FACEHUGGER_LAYER /obj/effect/alien/resin/special/eggmorph/Initialize(mapload, hive_ref) . = ..() - range_bounds = RECT(x, y, EGGMORPG_RANGE, EGGMORPG_RANGE) + range_bounds = SQUARE(x, y, EGGMORPG_RANGE) /obj/effect/alien/resin/special/eggmorph/Destroy() if (stored_huggers && linked_hive) @@ -158,7 +158,7 @@ /obj/effect/alien/resin/special/eggmorph/proc/check_facehugger_target() if(!range_bounds) - range_bounds = RECT(x, y, EGGMORPG_RANGE, EGGMORPG_RANGE) + range_bounds = SQUARE(x, y, EGGMORPG_RANGE) var/list/targets = SSquadtree.players_in_range(range_bounds, z, QTREE_SCAN_MOBS | QTREE_EXCLUDE_OBSERVER) if(isnull(targets) || !length(targets)) diff --git a/code/modules/defenses/bell_tower.dm b/code/modules/defenses/bell_tower.dm index 68d58f02b481..7ce252b3f4d7 100644 --- a/code/modules/defenses/bell_tower.dm +++ b/code/modules/defenses/bell_tower.dm @@ -257,7 +257,7 @@ STOP_PROCESSING(SSobj, src) return - var/list/targets = SSquadtree.players_in_range(RECT(M.x, M.y, area_range, area_range), M.z, QTREE_SCAN_MOBS | QTREE_EXCLUDE_OBSERVER) + var/list/targets = SSquadtree.players_in_range(SQUARE(M.x, M.y, area_range), M.z, QTREE_SCAN_MOBS | QTREE_EXCLUDE_OBSERVER) if(!targets) return diff --git a/code/modules/defenses/planted_flag.dm b/code/modules/defenses/planted_flag.dm index d2b9b23e8f3b..d44f22f38b68 100644 --- a/code/modules/defenses/planted_flag.dm +++ b/code/modules/defenses/planted_flag.dm @@ -7,7 +7,7 @@ desc = "A planted flag with the iconic USCM flag plastered all over it, you feel a burst of energy by its mere sight." handheld_type = /obj/item/defenses/handheld/planted_flag disassemble_time = 10 - var/datum/shape/rectangle/range_bounds + var/datum/shape/range_bounds var/area_range = PLANTED_FLAG_RANGE var/buff_intensity = PLANTED_FLAG_BUFF health = 200 @@ -33,7 +33,7 @@ apply_area_effect() start_processing() - range_bounds = RECT(x, y, PLANTED_FLAG_RANGE, PLANTED_FLAG_RANGE) + range_bounds = SQUARE(x, y, PLANTED_FLAG_RANGE) update_icon() /obj/structure/machinery/defenses/planted_flag/Destroy() @@ -70,9 +70,9 @@ /obj/structure/machinery/defenses/planted_flag/proc/apply_area_effect() if(!range_bounds) - range_bounds = RECT(x, y, area_range, area_range) + range_bounds = SQUARE(x, y, area_range) - var/list/targets = SSquadtree.players_in_range(RECT(x, y, area_range, area_range), z, QTREE_SCAN_MOBS | QTREE_EXCLUDE_OBSERVER) + var/list/targets = SSquadtree.players_in_range(SQUARE(x, y, area_range), z, QTREE_SCAN_MOBS | QTREE_EXCLUDE_OBSERVER) if(!targets) return @@ -180,7 +180,7 @@ if(!M.x && !M.y && !M.z) return - var/list/targets = SSquadtree.players_in_range(RECT(M.x, M.y, area_range, area_range), M.z, QTREE_SCAN_MOBS | QTREE_EXCLUDE_OBSERVER) + var/list/targets = SSquadtree.players_in_range(SQUARE(M.x, M.y, area_range), M.z, QTREE_SCAN_MOBS | QTREE_EXCLUDE_OBSERVER) targets |= M for(var/mob/living/carbon/human/H in targets) diff --git a/code/modules/defenses/sentry.dm b/code/modules/defenses/sentry.dm index 695b3387d909..8ad4cd407e75 100644 --- a/code/modules/defenses/sentry.dm +++ b/code/modules/defenses/sentry.dm @@ -12,7 +12,7 @@ var/list/targets = list() // Lists of current potential targets var/list/other_targets = list() //List of special target types to shoot at, if needed. var/atom/movable/target = null - var/datum/shape/rectangle/range_bounds + var/datum/shape/range_bounds var/datum/effect_system/spark_spread/spark_system //The spark system, used for generating... sparks? var/last_fired = 0 var/fire_delay = 4 @@ -93,17 +93,17 @@ /obj/structure/machinery/defenses/sentry/proc/set_range() if(omni_directional) - range_bounds = RECT(x, y, 8, 8) + range_bounds = SQUARE(x, y, 8) return switch(dir) if(EAST) - range_bounds = RECT(x + 4, y, 7, 7) + range_bounds = SQUARE(x + 4, y, 7) if(WEST) - range_bounds = RECT(x - 4, y, 7, 7) + range_bounds = SQUARE(x - 4, y, 7) if(NORTH) - range_bounds = RECT(x, y + 4, 7, 7) + range_bounds = SQUARE(x, y + 4, 7) if(SOUTH) - range_bounds = RECT(x, y - 4, 7, 7) + range_bounds = SQUARE(x, y - 4, 7) /obj/structure/machinery/defenses/sentry/proc/unset_range() SIGNAL_HANDLER @@ -614,17 +614,17 @@ var/dbl_range = range * 2 if(omni_directional) - range_bounds = RECT(x, y, dbl_range, dbl_range) + range_bounds = SQUARE(x, y, dbl_range) return switch(dir) if(EAST) - range_bounds = RECT(x+range, y, dbl_range, dbl_range) + range_bounds = SQUARE(x+range, y, dbl_range) if(WEST) - range_bounds = RECT(x-range, y, dbl_range, dbl_range) + range_bounds = SQUARE(x-range, y, dbl_range) if(NORTH) - range_bounds = RECT(x, y+range, dbl_range, dbl_range) + range_bounds = SQUARE(x, y+range, dbl_range) if(SOUTH) - range_bounds = RECT(x, y-range, dbl_range, dbl_range) + range_bounds = SQUARE(x, y-range, dbl_range) //the turret inside the shuttle sentry deployment system /obj/structure/machinery/defenses/sentry/premade/dropship @@ -672,13 +672,13 @@ /obj/structure/machinery/defenses/sentry/dmr/set_range() switch(dir) if(EAST) - range_bounds = RECT(x + (SENTRY_SNIPER_RANGE/2), y, SENTRY_SNIPER_RANGE, SENTRY_SNIPER_RANGE) + range_bounds = SQUARE(x + (SENTRY_SNIPER_RANGE/2), y, SENTRY_SNIPER_RANGE) if(WEST) - range_bounds = RECT(x - (SENTRY_SNIPER_RANGE/2), y, SENTRY_SNIPER_RANGE, SENTRY_SNIPER_RANGE) + range_bounds = SQUARE(x - (SENTRY_SNIPER_RANGE/2), y, SENTRY_SNIPER_RANGE) if(NORTH) - range_bounds = RECT(x, y + (SENTRY_SNIPER_RANGE/2), SENTRY_SNIPER_RANGE, SENTRY_SNIPER_RANGE) + range_bounds = SQUARE(x, y + (SENTRY_SNIPER_RANGE/2), SENTRY_SNIPER_RANGE) if(SOUTH) - range_bounds = RECT(x, y - (SENTRY_SNIPER_RANGE/2), SENTRY_SNIPER_RANGE, SENTRY_SNIPER_RANGE) + range_bounds = SQUARE(x, y - (SENTRY_SNIPER_RANGE/2), SENTRY_SNIPER_RANGE) #undef SENTRY_SNIPER_RANGE /obj/structure/machinery/defenses/sentry/shotgun diff --git a/code/modules/defenses/sentry_computer.dm b/code/modules/defenses/sentry_computer.dm index 59c6409d552c..639a74e6ba30 100644 --- a/code/modules/defenses/sentry_computer.dm +++ b/code/modules/defenses/sentry_computer.dm @@ -402,8 +402,7 @@ var/obj/structure/machinery/defenses/sentry/defense = sentry if (defense.has_camera) defense.set_range() - var/datum/shape/rectangle/current_bb = defense.range_bounds - SEND_SIGNAL(src, COMSIG_CAMERA_SET_AREA, current_bb.center_x, current_bb.center_y, defense.loc.z, current_bb.width, current_bb.height) + SEND_SIGNAL(src, COMSIG_CAMERA_SET_AREA, defense.range_bounds, defense.loc.z) return TRUE if("ping") diff --git a/code/modules/defenses/sentry_flamer.dm b/code/modules/defenses/sentry_flamer.dm index 979d18eb41d1..2c5e9ae62677 100644 --- a/code/modules/defenses/sentry_flamer.dm +++ b/code/modules/defenses/sentry_flamer.dm @@ -90,13 +90,13 @@ /obj/structure/machinery/defenses/sentry/flamer/plasma/set_range() switch(dir) if(EAST) - range_bounds = RECT(x + (FLAMER_SENTRY_SNIPER_RANGE/2), y, FLAMER_SENTRY_SNIPER_RANGE, FLAMER_SENTRY_SNIPER_RANGE) + range_bounds = SQUARE(x + (FLAMER_SENTRY_SNIPER_RANGE/2), y, FLAMER_SENTRY_SNIPER_RANGE) if(WEST) - range_bounds = RECT(x - (FLAMER_SENTRY_SNIPER_RANGE/2), y, FLAMER_SENTRY_SNIPER_RANGE, FLAMER_SENTRY_SNIPER_RANGE) + range_bounds = SQUARE(x - (FLAMER_SENTRY_SNIPER_RANGE/2), y, FLAMER_SENTRY_SNIPER_RANGE) if(NORTH) - range_bounds = RECT(x, y + (FLAMER_SENTRY_SNIPER_RANGE/2), FLAMER_SENTRY_SNIPER_RANGE, FLAMER_SENTRY_SNIPER_RANGE) + range_bounds = SQUARE(x, y + (FLAMER_SENTRY_SNIPER_RANGE/2), FLAMER_SENTRY_SNIPER_RANGE) if(SOUTH) - range_bounds = RECT(x, y - (FLAMER_SENTRY_SNIPER_RANGE/2), FLAMER_SENTRY_SNIPER_RANGE, FLAMER_SENTRY_SNIPER_RANGE) + range_bounds = SQUARE(x, y - (FLAMER_SENTRY_SNIPER_RANGE/2), FLAMER_SENTRY_SNIPER_RANGE) #undef FLAMER_SENTRY_SNIPER_RANGE