Refactors beams. Adds tethering. IV drips/bags are now tethered. (#29570)

* refactor

* tether

* tetherrrs

* logic fix (i hope)

* ci fix

* ok please work
This commit is contained in:
Contrabang
2025-07-09 07:49:40 -07:00
committed by GitHub
parent 6c2aa06eb3
commit 1f124ac835
15 changed files with 404 additions and 106 deletions
@@ -292,7 +292,7 @@
/obj/item/projectile/tentacle/fire(setAngle)
if(firer)
chain = firer.Beam(src, icon_state = "tentacle", time = INFINITY, maxdistance = INFINITY, beam_sleep_time = 1)
chain = firer.Beam(src, icon_state = "tentacle", time = INFINITY, maxdistance = INFINITY)
..()
/mob/proc/tentacle_stab(mob/living/carbon/C)
@@ -22,8 +22,7 @@
anchors += locate(x + 2, y - 2, z)
for(var/turf/T in anchors)
var/datum/beam/B = Beam(T, "vine", time=INFINITY, maxdistance=5, beam_type=/obj/effect/ebeam/vine)
B.sleep_time = 10 //these shouldn't move, so let's slow down updates to 1 second (any slower and the deletion of the vines would be too slow)
Beam(T, "vine", time = INFINITY, maxdistance = 5, beam_type = /obj/effect/ebeam/vine)
addtimer(CALLBACK(src, PROC_REF(bear_fruit)), growth_time)
/obj/structure/alien/resin/flower_bud_enemy/proc/bear_fruit()
@@ -76,8 +75,7 @@
for(var/mob/living/L in grasping)
if(L.stat == DEAD)
var/datum/beam/B = grasping[L]
if(B)
B.End()
qdel(B)
grasping -= L
//Can attack+pull multiple times per cycle
+3 -5
View File
@@ -82,7 +82,7 @@
grabbed_atom.add_overlay(kinesis_icon)
pre_pixel_x = grabbed_atom.pixel_x
pre_pixel_y = grabbed_atom.pixel_y
beam.chain = beam.Beam(grabbed_atom, icon_state = "kinesis", icon='icons/effects/beam.dmi', time = 100 SECONDS, maxdistance = 15, beam_type = /obj/effect/ebeam, beam_sleep_time = 3)
beam.chain = beam.Beam(grabbed_atom, icon_state = "kinesis", icon='icons/effects/beam.dmi', time = 100 SECONDS, maxdistance = 15, beam_type = /obj/effect/ebeam)
kinesis_catcher = mod.wearer.overlay_fullscreen("kinesis", /atom/movable/screen/fullscreen/stretch/cursor_catcher/kinesis, 0)
kinesis_catcher.assign_to_mob(mod.wearer)
soundloop.start()
@@ -113,8 +113,7 @@
if(grabbed_atom.pixel_x == kinesis_catcher.given_x - world.icon_size/2 && grabbed_atom.pixel_y == kinesis_catcher.given_y - world.icon_size/2)
return //spare us redrawing if we are standing still
animate(grabbed_atom, 0.2 SECONDS, pixel_x = pre_pixel_x + kinesis_catcher.given_x - world.icon_size/2, pixel_y = pre_pixel_y + kinesis_catcher.given_y - world.icon_size/2)
beam.chain.Reset()
beam.chain.Draw()
beam.chain.redrawing()
return
animate(grabbed_atom, 0.2 SECONDS, pixel_x = pre_pixel_x + kinesis_catcher.given_x - world.icon_size/2, pixel_y = pre_pixel_y + kinesis_catcher.given_y - world.icon_size/2)
var/turf/next_turf = get_step_towards(grabbed_atom, kinesis_catcher.given_turf)
@@ -137,8 +136,7 @@
else if(direction & WEST)
pixel_x_change = -world.icon_size / 2
animate(grabbed_atom, 0.2 SECONDS, pixel_x = pre_pixel_x + pixel_x_change, pixel_y = pre_pixel_y + pixel_y_change) //Not as smooth as I would like, will look into this in the future
beam.chain.Reset()
beam.chain.Draw()
beam.chain.redrawing()
if(!isitem(grabbed_atom) || !COOLDOWN_FINISHED(src, hit_cooldown))
return
var/atom/hitting_atom
+4 -3
View File
@@ -54,9 +54,8 @@
current_target = target
active = TRUE
var/datum/beam/current_beam = new(user,current_target,time=6000,beam_icon_state="medbeam",btype=/obj/effect/ebeam/medical)
var/datum/beam/current_beam = user.Beam(current_target, "medbeam", time = 10 MINUTES, beam_type = /obj/effect/ebeam/medical)
beam_UID = current_beam.UID()
INVOKE_ASYNC(current_beam, TYPE_PROC_REF(/datum/beam, Start))
SSblackbox.record_feedback("tally", "gun_fired", 1, type)
@@ -87,6 +86,8 @@
/obj/item/gun/medbeam/proc/los_check(atom/movable/user, mob/target)
var/turf/user_turf = user.loc
var/datum/beam/current_beam = locateUID(beam_UID)
if(QDELETED(current_beam))
return FALSE
if(mounted)
user_turf = get_turf(user)
else if(!istype(user_turf))
@@ -104,7 +105,7 @@
qdel(dummy)
return FALSE
for(var/obj/effect/ebeam/medical/B in turf)// Don't cross the str-beams!
if(B.owner != current_beam)
if(B.owner && B.owner != current_beam && !QDELETED(B)) // only blow up if it has a CONFIRMED different owner than us. Don't want it blowing up on creation/deletion of beams.
turf.visible_message("<span class='userdanger'>The medbeams cross and EXPLODE!</span>")
explosion(B.loc,0,3,5,8, cause = "Crossed beams")
qdel(dummy)
@@ -18,6 +18,10 @@
var/mob/living/carbon/human/injection_target
var/injection_action_delay = 3 SECONDS
/obj/item/reagent_containers/iv_bag/Initialize(mapload)
. = ..()
RegisterSignal(src, COMSIG_TETHER_DESTROYED, PROC_REF(tether_snapped))
/obj/item/reagent_containers/iv_bag/Destroy()
end_processing()
return ..()
@@ -52,12 +56,34 @@
injection_target = target
RegisterSignal(injection_target, COMSIG_PARENT_EXAMINE, PROC_REF(on_examine))
START_PROCESSING(SSobj, src)
update_iv_type()
/obj/item/reagent_containers/iv_bag/proc/end_processing()
/obj/item/reagent_containers/iv_bag/proc/update_iv_type()
var/target = injection_target
injection_target = null
SEND_SIGNAL(src, COMSIG_TETHER_STOP)
injection_target = target
if(!injection_target)
return
if(istype(loc, /obj/machinery/iv_drip))
injection_target.AddComponent(/datum/component/tether, src, 2, 50, "iv_tether", "tubing")
else
injection_target.AddComponent(/datum/component/tether, src, 1, 5, "iv_tether", "tubing")
/obj/item/reagent_containers/iv_bag/proc/end_processing(send_signal = TRUE)
if(injection_target)
UnregisterSignal(injection_target, COMSIG_PARENT_EXAMINE)
injection_target = null
STOP_PROCESSING(SSobj, src)
if(send_signal)
SEND_SIGNAL(src, COMSIG_TETHER_STOP)
/obj/item/reagent_containers/iv_bag/proc/tether_snapped()
if(!injection_target)
return
to_chat(injection_target, "<span class='userdanger'>[src]'s needle is ripped out of you!</span>")
injection_target.apply_damage(3, BRUTE, pick("r_arm", "l_arm"))
end_processing(FALSE)
/obj/item/reagent_containers/iv_bag/process()
if(QDELETED(injection_target))
@@ -69,12 +95,6 @@
end_processing()
return
if(get_dist(get_turf(src), get_turf(injection_target)) > 1)
to_chat(injection_target, "<span class='userdanger'>[src]'s needle is ripped out of you!</span>")
injection_target.apply_damage(3, BRUTE, pick("r_arm", "l_arm"))
end_processing()
return
if(mode) // Injecting
if(reagents.total_volume)
var/fraction = min(amount_per_transfer_from_this/reagents.total_volume, 1) //The amount of reagents we'll transfer to the person