[MIRROR] Refactors Beams to use signals: Revived from 2019 edition! BONUS: Medbeams are also refactored to use signals (#2237)

* Refactors Beams to use signals: Revived from 2019 edition! BONUS: Medbeams are also refactored to use signals (#55193)

Huge removal of dead vars, bad timers, and other sloppy jitteriness from beams. They go from checking movement to waiting for a signal.
VARIABLE KILL LIST:

sleep_time: signals baby
finished: signals BAYBEEE
target_oldloc: not only not typecasted as a turf or named as a turf, it was unused. when are we going to use this? the beam starts from the origin!
origin_oldloc: bad name, not typecasted. renamed to originturf
static_beam: how are you an unused variable and still get replaced by signals like really
timing_id: signallllss bbbaaaabbyy
recalculating: you get the drill by now signals baby
base_icon: unused, seemingly replaced by visuals I think

* Refactors Beams to use signals: Revived from 2019 edition! BONUS: Medbeams are also refactored to use signals

Co-authored-by: tralezab <40974010+tralezab@users.noreply.github.com>
This commit is contained in:
SkyratBot
2020-12-19 04:42:09 +01:00
committed by GitHub
co-authored by tralezab
parent 21f164e8f4
commit 24743f2696
28 changed files with 131 additions and 131 deletions
+68 -72
View File
@@ -1,101 +1,86 @@
//Beam Datum and effect
/** # Beam Datum and Effect
* **IF YOU ARE LAZY AND DO NOT WANT TO READ, GO TO THE BOTTOM OF THE FILE AND USE THAT PROC!**
*
* This is the beam datum! It's a really neat effect for the game in drawing a line from one atom to another.
* It has two parts:
* The datum itself which manages redrawing the beam to constantly keep it pointing from the origin to the target.
* The effect which is what the beams are made out of. They're placed in a line from the origin to target, rotated towards the target and snipped off at the end.
* These effects are kept in a list and constantly created and destroyed (hence the proc names draw and reset, reset destroying all effects and draw creating more.)
*
* You can add more special effects to the beam itself by changing what the drawn beam effects do. For example you can make a vine that pricks people by making the beam_type
* include a crossed proc that damages the crosser. Examples in venus_human_trap.dm
*/
/datum/beam
///where the beam goes from
var/atom/origin = null
///where the beam goes to
var/atom/target = null
///list of beam objects. These have their visuals set by the visuals var which is created on starting
var/list/elements = list()
var/icon/base_icon = null
///icon used by the beam.
var/icon
var/icon_state = "" //icon state of the main segments of the beam
///icon state of the main segments of the beam
var/icon_state = ""
///The beam will qdel if it's longer than this many tiles.
var/max_distance = 0
var/sleep_time = 3
var/finished = 0
var/target_oldloc = null
var/origin_oldloc = null
var/static_beam = 0
var/beam_type = /obj/effect/ebeam //must be subtype
var/timing_id = null
var/recalculating = FALSE
///the objects placed in the elements list
var/beam_type = /obj/effect/ebeam
///This is used as the visual_contents of beams, so you can apply one effect to this and the whole beam will look like that. never gets deleted on redrawing.
var/obj/effect/ebeam/visuals
var/obj/effect/ebeam/visuals //what we add to the ebeam's visual contents. never gets deleted on redrawing.
/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)
/datum/beam/New(beam_origin,beam_target,beam_icon='icons/effects/beam.dmi',beam_icon_state="b_beam",time=INFINITY,maxdistance=INFINITY,btype = /obj/effect/ebeam)
origin = beam_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
max_distance = maxdistance
base_icon = new(beam_icon,beam_icon_state)
icon = beam_icon
icon_state = beam_icon_state
beam_type = btype
if(time < INFINITY)
addtimer(CALLBACK(src,.proc/End), time)
QDEL_IN(src, time)
/**
* Proc called by the atom Beam() proc. Sets up signals, and draws the beam for the first time.
*/
/datum/beam/proc/Start()
visuals = new beam_type()
visuals.icon = icon
visuals.icon_state = icon_state
Draw()
recalculate_in(sleep_time)
RegisterSignal(origin, COMSIG_MOVABLE_MOVED, .proc/redrawing)
RegisterSignal(target, COMSIG_MOVABLE_MOVED, .proc/redrawing)
/datum/beam/proc/recalculate()
if(recalculating)
recalculate_in(sleep_time)
return
recalculating = TRUE
timing_id = null
/**
* Triggered by signals set up when the beam is set up. If it's still sane to create a beam, it removes the old beam, creates a new one. Otherwise it kills the beam.
*
* Arguments:
* mover: either the origin of the beam or the target of the beam that moved.
* oldloc: from where mover moved.
* direction: in what direction mover moved from.
*/
/datum/beam/proc/redrawing(atom/movable/mover, atom/oldloc, direction)
if(origin && target && get_dist(origin,target)<max_distance && origin.z == target.z)
var/origin_turf = get_turf(origin)
var/target_turf = get_turf(target)
if(!static_beam && (origin_turf != origin_oldloc || target_turf != target_oldloc))
origin_oldloc = origin_turf //so we don't keep checking against their initial positions, leading to endless Reset()+Draw() calls
target_oldloc = target_turf
Reset()
Draw()
after_calculate()
recalculating = FALSE
QDEL_LIST(elements)
Draw()
else
End()
/datum/beam/proc/afterDraw()
return
/datum/beam/proc/recalculate_in(time)
if(timing_id)
deltimer(timing_id)
timing_id = addtimer(CALLBACK(src, .proc/recalculate), time, TIMER_STOPPABLE)
/datum/beam/proc/after_calculate()
if((sleep_time == null) || finished) //Does not automatically recalculate.
return
if(isnull(timing_id))
timing_id = addtimer(CALLBACK(src, .proc/recalculate), sleep_time, TIMER_STOPPABLE)
/datum/beam/proc/End(destroy_self = TRUE)
finished = TRUE
if(!isnull(timing_id))
deltimer(timing_id)
if(!QDELETED(src) && destroy_self)
qdel(src)
/datum/beam/proc/Reset()
for(var/obj/effect/ebeam/B in elements)
qdel(B)
elements.Cut()
/datum/beam/Destroy()
Reset()
QDEL_LIST(elements)
qdel(visuals)
UnregisterSignal(origin, COMSIG_MOVABLE_MOVED)
UnregisterSignal(target, COMSIG_MOVABLE_MOVED)
target = null
origin = null
return ..()
/**
* Creates the beam effects and places them in a line from the origin to the target. Sets their rotation to make the beams face the target, too.
*/
/datum/beam/proc/Draw()
var/Angle = round(Get_Angle(origin,target))
var/matrix/rot_matrix = matrix()
var/turf/origin_turf = get_turf(origin)
rot_matrix.Turn(Angle)
//Translation vector for origin and target
@@ -105,17 +90,17 @@
var/length = round(sqrt((DX)**2+(DY)**2)) //hypotenuse of the triangle formed by target and origin's displacement
for(N in 0 to length-1 step 32)//-1 as we want < not <=, but we want the speed of X in Y to Z and step X
if(QDELETED(src) || finished)
if(QDELETED(src))
break
var/obj/effect/ebeam/X = new beam_type(origin_oldloc)
var/obj/effect/ebeam/X = new beam_type(origin_turf)
X.owner = src
elements += X
//Assign our single visual ebeam to each ebeam's vis_contents
//ends are cropped by a transparent box icon of length-N pixel size laid over the visuals obj
if(N+32>length) //went past the target, needs to be cut short
var/icon/II = new(icon, icon_state) //the way to keep this the same as the vis_contents is unreasonable right now, maybe in the far future.
II.DrawBox(null,1,(length-N),32,32)//anyway we cut the icon on the ebeam to end at the target instead of overshooting
if(N+32>length) //went past the target, we draw a box of space to cut away from the beam sprite so the icon actually ends at the center of the target sprite
var/icon/II = new(icon, icon_state)//this means we exclude the overshooting object from the visual contents which does mean those visuals don't show up for the final bit of the beam...
II.DrawBox(null,1,(length-N),32,32)//in the future if you want to improve this, remove the drawbox and instead use a 513 filter to cut away at the final object's icon
X.icon = II
else
X.vis_contents += visuals
@@ -147,7 +132,6 @@
X.pixel_x = Pixel_x
X.pixel_y = Pixel_y
CHECK_TICK
afterDraw()
/obj/effect/ebeam
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
@@ -163,7 +147,19 @@
/obj/effect/ebeam/singularity_act()
return
/atom/proc/Beam(atom/BeamTarget,icon_state="b_beam",icon='icons/effects/beam.dmi',time=50, maxdistance=10,beam_type=/obj/effect/ebeam,beam_sleep_time = 3)
var/datum/beam/newbeam = new(src,BeamTarget,icon,icon_state,time,maxdistance,beam_type,beam_sleep_time)
/**
* This is what you use to start a beam. Example: origin.Beam(target, args). **Store the return of this proc if you don't set maxdist or time, you need it to delete the beam.**
*
* Unless you're making a custom beam effect (see the beam_type argument), you won't actually have to mess with any other procs. Make sure you store the return of this Proc, you'll need it
* to kill the beam.
* **Arguments:**
* BeamTarget: Where you're beaming from. Where do you get origin? You didn't read the docs, fuck you.
* icon_state: What the beam's icon_state is. The datum effect isn't the ebeam object, it doesn't hold any icon and isn't type dependent.
* icon: What the beam's icon file is. Don't change this, man. All beam icons should be in beam.dmi anyways.
* maxdistance: how far the beam will go before stopping itself. Used mainly for two things: preventing lag if the beam may go in that direction and setting a range to abilities that use beams.
* beam_type: The type of your custom beam. This is for adding other wacky stuff for your beam only. Most likely, you won't (and shouldn't) change it.
*/
/atom/proc/Beam(atom/BeamTarget,icon_state="b_beam",icon='icons/effects/beam.dmi',time=INFINITY,maxdistance=INFINITY,beam_type=/obj/effect/ebeam)
var/datum/beam/newbeam = new(src,BeamTarget,icon,icon_state,time,maxdistance,beam_type)
INVOKE_ASYNC(newbeam, /datum/beam/.proc/Start)
return newbeam
+1 -1
View File
@@ -37,7 +37,7 @@
user.forceMove(T)
playsound(T, dash_sound, 25, TRUE)
var/obj/spot2 = new phasein(get_turf(user), user.dir)
spot1.Beam(spot2,beam_effect,time=20)
spot1.Beam(spot2,beam_effect,time=2 SECONDS)
current_charges--
holder.update_action_buttons_icon()
addtimer(CALLBACK(src, .proc/charge), charge_rate)
+2 -2
View File
@@ -84,7 +84,7 @@
A.color = "#9C00FF"
flash_color(A, flash_color = "#9C00FF", flash_time = 3 SECONDS)
animate(A, color = oldcolor, time = 3 SECONDS)
/datum/martial_art/plasma_fist/proc/Apotheosis(mob/living/carbon/human/A, mob/living/carbon/human/D)
A.say("APOTHEOSIS!!", forced="plasma fist")
@@ -164,7 +164,7 @@
. = ..()
beam_target = _beam_target
if(beam_target)
var/datum/beam/beam = Beam(beam_target, "plasmabeam", time= 3 SECONDS, maxdistance=INFINITY, beam_type=/obj/effect/ebeam/plasma_fist)
var/datum/beam/beam = Beam(beam_target, "plasmabeam", beam_type=/obj/effect/ebeam/plasma_fist, time = 3 SECONDS)
animate(beam.visuals, alpha = 0, time = 3 SECONDS)
animate(src, alpha = 0, transform = matrix()*0.5, time = 3 SECONDS)