diff --git a/aurorastation.dme b/aurorastation.dme index e4956a6e02d..f13e009a9b7 100644 --- a/aurorastation.dme +++ b/aurorastation.dme @@ -901,6 +901,7 @@ #include "code\game\objects\items\weapons\syndie.dm" #include "code\game\objects\items\weapons\tape.dm" #include "code\game\objects\items\weapons\teleportation.dm" +#include "code\game\objects\items\weapons\tether.dm" #include "code\game\objects\items\weapons\tools.dm" #include "code\game\objects\items\weapons\towel.dm" #include "code\game\objects\items\weapons\traps.dm" diff --git a/code/datums/beam.dm b/code/datums/beam.dm index b96cfe6c0b8..5e02d924655 100644 --- a/code/datums/beam.dm +++ b/code/datums/beam.dm @@ -7,10 +7,11 @@ var/icon var/icon_state = "" //icon state of the main segments of the beam var/max_distance = 0 + var/curr_distance = 0 var/sleep_time = 3 var/finished = 0 - var/target_oldloc = null - var/origin_oldloc = null + var/turf/target_oldloc = null + var/turf/origin_oldloc = null var/static_beam = 0 var/beam_type = /obj/effect/ebeam //must be subtype var/timing_id = null @@ -18,18 +19,20 @@ /datum/beam/New(beam_origin,beam_target,beam_icon='icons/effects/beam.dmi',beam_icon_state="b_beam",time=50,maxdistance=10,btype = /obj/effect/ebeam,beam_sleep_time=3) origin = beam_origin - origin_oldloc = get_turf(origin) + origin_oldloc = get_turf(origin) target = beam_target target_oldloc = get_turf(target) sleep_time = beam_sleep_time if(origin_oldloc == origin && target_oldloc == target) - static_beam = 1 + static_beam = TRUE max_distance = maxdistance + curr_distance = get_dist(origin_oldloc, target_oldloc) base_icon = new(beam_icon,beam_icon_state) icon = beam_icon icon_state = beam_icon_state beam_type = btype - addtimer(CALLBACK(src,.proc/End), time) + if(time != -1) + addtimer(CALLBACK(src,.proc/End), time) /datum/beam/proc/Start() Draw() @@ -41,9 +44,10 @@ return recalculating = TRUE timing_id = null - if(origin && target && get_dist(origin,target)length) + if(N+world.icon_size>length) var/icon/II = new(icon, icon_state) - II.DrawBox(null,1,(length-N),32,32) + II.DrawBox(null,1,(length-N),world.icon_size,world.icon_size) X.icon = II else X.icon = base_icon @@ -115,28 +119,61 @@ if(DX == 0) Pixel_x = 0 else - Pixel_x = round(sin(Angle)+32*sin(Angle)*(N+16)/32) + Pixel_x = round(sin(Angle)+world.icon_size*sin(Angle)*(N+16)/world.icon_size) if(DY == 0) Pixel_y = 0 else - Pixel_y = round(cos(Angle)+32*cos(Angle)*(N+16)/32) + Pixel_y = round(cos(Angle)+world.icon_size*cos(Angle)*(N+16)/world.icon_size) //Position the effect so the beam is one continous line var/a - if(abs(Pixel_x)>32) - a = Pixel_x > 0 ? round(Pixel_x/32) : Ceiling(Pixel_x/32) + if(abs(Pixel_x)>world.icon_size) + a = Pixel_x > 0 ? round(Pixel_x/world.icon_size) : Ceiling(Pixel_x/world.icon_size) X.x += a - Pixel_x %= 32 - if(abs(Pixel_y)>32) - a = Pixel_y > 0 ? round(Pixel_y/32) : Ceiling(Pixel_y/32) + Pixel_x %= world.icon_size + if(abs(Pixel_y)>world.icon_size) + a = Pixel_y > 0 ? round(Pixel_y/world.icon_size) : Ceiling(Pixel_y/world.icon_size) X.y += a - Pixel_y %= 32 + Pixel_y %= world.icon_size X.pixel_x = Pixel_x X.pixel_y = Pixel_y CHECK_TICK afterDraw() +/datum/beam/proc/get_x_translation_vector() + return (world.icon_size*target.x+target.pixel_x)-(world.icon_size*origin.x+origin.pixel_x) + +/datum/beam/proc/get_y_translation_vector() + return (world.icon_size*target.y+target.pixel_y)-(world.icon_size*origin.y+origin.pixel_y) + +/datum/beam/exploration + var/obj/item/tethering_device/owner + +/datum/beam/exploration/End() + owner.active_beams -= target + owner.untether(target, FALSE) + return ..() + +/datum/beam/exploration/get_x_translation_vector() + return (world.icon_size * target_oldloc.x) - (world.icon_size * origin_oldloc.x) + +/datum/beam/exploration/get_y_translation_vector() + return (world.icon_size * target_oldloc.y) - (world.icon_size * origin_oldloc.y) + +/datum/beam/exploration/afterDraw() + var/distance = curr_distance / max_distance + var/set_color = COLOR_GREEN + if(distance >= 0.8) + set_color = COLOR_MAROON + else if(distance >= 0.3) + set_color = COLOR_BLUE + else + set_color = COLOR_GREEN + for(var/beam in elements) + var/obj/effect/ebeam/B = beam + B.color = set_color + /obj/effect/ebeam mouse_opacity = 0 anchored = 1 diff --git a/code/game/objects/items/weapons/storage/boxes.dm b/code/game/objects/items/weapons/storage/boxes.dm index bbc3026ade5..ba143d0cc8e 100644 --- a/code/game/objects/items/weapons/storage/boxes.dm +++ b/code/game/objects/items/weapons/storage/boxes.dm @@ -316,6 +316,15 @@ desc = "A box of varied assortment of firing pins. Appears to have R&D stickers on all sides of the box. Also seems to have a smiley face sticker on the top of it." starts_with = list(/obj/item/device/firing_pin = 2, /obj/item/device/firing_pin/access = 2, /obj/item/device/firing_pin/implant/loyalty = 2, /obj/item/device/firing_pin/clown = 1, /obj/item/device/firing_pin/dna = 1) +/obj/item/storage/box/tethers + name = "box of tethering devices" + desc = "A box containing eight electro-tethers, used primarily to keep track of partners during expeditions." + starts_with = list(/obj/item/tethering_device = 8) + +/obj/item/storage/box/tethers/fill() + ..() + make_exact_fit() + /obj/item/storage/box/teargas name = "box of pepperspray grenades" desc = "A box containing 7 tear gas grenades. A gas mask is printed on the label.
WARNING: Exposure carries risk of serious injury or death. Keep away from persons with lung conditions." diff --git a/code/game/objects/items/weapons/tether.dm b/code/game/objects/items/weapons/tether.dm new file mode 100644 index 00000000000..67c1cf1a999 --- /dev/null +++ b/code/game/objects/items/weapons/tether.dm @@ -0,0 +1,86 @@ +var/list/global/all_tethers = list() + +/obj/item/tethering_device + name = "tethering device" + desc = "A device used by explorers to keep track of partners by way of electro-tether." + desc_info = "Use in-hand to activate, must be on the same level and within fifteen tiles of another device to latch. Tethers are colour coded by distance." + icon = 'icons/obj/device.dmi' + icon_state = "locator" + w_class = ITEMSIZE_SMALL + slot_flags = SLOT_BELT + force = 1 + var/active = FALSE + var/list/linked_tethers = list() + var/tether_range = 15 + var/list/active_beams = list() + +/obj/item/tethering_device/Initialize(mapload, ...) + . = ..() + all_tethers += src + +/obj/item/tethering_device/Destroy() + STOP_PROCESSING(SSprocessing, src) + deactivate() + all_tethers -= src + return ..() + +/obj/item/tethering_device/attack_self(mob/user) + active = !active + var/msg = "You [active ? "activate" : "deactivate"] \the [src]." + to_chat(user, SPAN_NOTICE(msg)) + if(active) + activate() + else + deactivate() + +/obj/item/tethering_device/process() + var/turf/our_turf = get_turf(src) + for(var/tether in all_tethers) + var/obj/item/tethering_device/TD = tether + if(TD == src) + continue + if(!TD.active) + continue + var/turf/target_turf = get_turf(TD) + if(our_turf == target_turf) + continue + if(target_turf.z != our_turf.z) + continue + if(get_dist(target_turf, our_turf) > tether_range) + continue + if(TD in linked_tethers) + continue + if(src in TD.linked_tethers) + continue + tether(TD) + +/obj/item/tethering_device/emp_act() + deactivate() + +/obj/item/tethering_device/proc/activate() + START_PROCESSING(SSprocessing, src) + +/obj/item/tethering_device/proc/deactivate() + STOP_PROCESSING(SSprocessing, src) + for(var/beam in active_beams) + var/datum/beam/exploration/B = active_beams[beam] + B.End() + for(var/tether in all_tethers) + var/obj/item/tethering_device/TD = tether + TD.untether(src) + +/obj/item/tethering_device/proc/tether(var/obj/item/tethering_device/TD) + linked_tethers |= TD + var/datum/beam/exploration/B = new /datum/beam/exploration(src, TD, beam_icon_state = "explore_beam", time = -1, maxdistance = tether_range) + B.owner = src + B.Start() + active_beams[TD] = B + +// untethering logic is primarily dictated by the beam itself, who will end if the max distance is reached, and call this proc +/obj/item/tethering_device/proc/untether(var/obj/item/tethering_device/TD, var/destroy_beam = TRUE) + linked_tethers -= TD + if(!destroy_beam) + return + var/datum/beam/exploration/B = active_beams[TD] + if(B) + B.End() \ No newline at end of file diff --git a/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm b/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm index 4cdb8bb7281..a3d76b6ebcf 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm @@ -47,6 +47,7 @@ new /obj/item/storage/box/firingpinsRD(src) new /obj/item/device/pin_extractor(src) new /obj/item/storage/box/fancy/keypouch/sci(src) + new /obj/item/storage/box/tethers(src) /obj/structure/closet/secure_closet/RD2 name = "research director's attire" diff --git a/html/changelogs/geeves-tethers.yml b/html/changelogs/geeves-tethers.yml new file mode 100644 index 00000000000..d371ec1d484 --- /dev/null +++ b/html/changelogs/geeves-tethers.yml @@ -0,0 +1,6 @@ +author: Geeves + +delete-after: True + +changes: + - rscadd: "Added a box of eight electro-tethers to the RD's secure locker." \ No newline at end of file diff --git a/icons/effects/beam.dmi b/icons/effects/beam.dmi index 924bc156104..3ab304ae67e 100644 Binary files a/icons/effects/beam.dmi and b/icons/effects/beam.dmi differ