mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-18 13:43:27 +00:00
* Enforce preserving parent proc return values across ui_act call stacks (#53964) All ui_act procs should call parent by default. All procs should preserve the value of the parent proc when it's TRUTHY and pass it down the call stack. No UI should be interactible when its flags or state indicate it should not be, except when explicity overriden by child procs intentionally disregarding parent return values to achieve a specific goal. * Enforce preserving parent proc return values across ui_act call stacks Co-authored-by: Timberpoes <silent_insomnia_pp@hotmail.co.uk>
239 lines
6.1 KiB
Plaintext
239 lines
6.1 KiB
Plaintext
/obj/item/assembly/infra
|
|
name = "infrared emitter"
|
|
desc = "Emits a visible or invisible beam and is triggered when the beam is interrupted."
|
|
icon_state = "infrared"
|
|
custom_materials = list(/datum/material/iron=1000, /datum/material/glass=500)
|
|
is_position_sensitive = TRUE
|
|
drop_sound = 'sound/items/handling/component_drop.ogg'
|
|
pickup_sound = 'sound/items/handling/component_pickup.ogg'
|
|
var/on = FALSE
|
|
var/visible = FALSE
|
|
var/maxlength = 8
|
|
var/list/obj/effect/beam/i_beam/beams
|
|
var/olddir = 0
|
|
var/turf/listeningTo
|
|
var/hearing_range = 3
|
|
|
|
/obj/item/assembly/infra/Initialize()
|
|
. = ..()
|
|
beams = list()
|
|
START_PROCESSING(SSobj, src)
|
|
|
|
/obj/item/assembly/infra/ComponentInitialize()
|
|
. = ..()
|
|
var/static/rotation_flags = ROTATION_ALTCLICK | ROTATION_CLOCKWISE | ROTATION_COUNTERCLOCKWISE | ROTATION_FLIP | ROTATION_VERBS
|
|
AddComponent(/datum/component/simple_rotation, rotation_flags, after_rotation=CALLBACK(src,.proc/after_rotation))
|
|
|
|
/obj/item/assembly/infra/proc/after_rotation()
|
|
refreshBeam()
|
|
|
|
/obj/item/assembly/infra/Destroy()
|
|
STOP_PROCESSING(SSobj, src)
|
|
listeningTo = null
|
|
QDEL_LIST(beams)
|
|
. = ..()
|
|
|
|
/obj/item/assembly/infra/examine(mob/user)
|
|
. = ..()
|
|
. += "<span class='notice'>The infrared trigger is [on?"on":"off"].</span>"
|
|
|
|
/obj/item/assembly/infra/activate()
|
|
if(!..())
|
|
return FALSE //Cooldown check
|
|
on = !on
|
|
refreshBeam()
|
|
update_icon()
|
|
return TRUE
|
|
|
|
/obj/item/assembly/infra/toggle_secure()
|
|
secured = !secured
|
|
if(secured)
|
|
START_PROCESSING(SSobj, src)
|
|
refreshBeam()
|
|
else
|
|
QDEL_LIST(beams)
|
|
STOP_PROCESSING(SSobj, src)
|
|
update_icon()
|
|
return secured
|
|
|
|
/obj/item/assembly/infra/update_icon()
|
|
cut_overlays()
|
|
attached_overlays = list()
|
|
if(on)
|
|
add_overlay("infrared_on")
|
|
attached_overlays += "infrared_on"
|
|
if(visible && secured)
|
|
add_overlay("infrared_visible")
|
|
attached_overlays += "infrared_visible"
|
|
|
|
if(holder)
|
|
holder.update_icon()
|
|
return
|
|
|
|
/obj/item/assembly/infra/dropped()
|
|
. = ..()
|
|
if(holder)
|
|
holder_movement() //sync the dir of the device as well if it's contained in a TTV or an assembly holder
|
|
else
|
|
refreshBeam()
|
|
|
|
/obj/item/assembly/infra/process()
|
|
if(!on || !secured)
|
|
refreshBeam()
|
|
return
|
|
|
|
/obj/item/assembly/infra/proc/refreshBeam()
|
|
QDEL_LIST(beams)
|
|
if(throwing || !on || !secured)
|
|
return
|
|
if(holder)
|
|
if(holder.master) //incase the sensor is part of an assembly that's contained in another item, such as a single tank bomb
|
|
if(!holder.master.IsSpecialAssembly() || !isturf(holder.master.loc))
|
|
return
|
|
else if(!isturf(holder.loc)) //else just check where the holder is
|
|
return
|
|
else if(!isturf(loc)) //or just where the fuck we are in general
|
|
return
|
|
var/turf/T = get_turf(src)
|
|
var/_dir = dir
|
|
var/turf/_T = get_step(T, _dir)
|
|
if(_T)
|
|
for(var/i in 1 to maxlength)
|
|
var/obj/effect/beam/i_beam/I = new(T)
|
|
if(istype(holder, /obj/item/assembly_holder))
|
|
var/obj/item/assembly_holder/assembly_holder = holder
|
|
I.icon_state = "[initial(I.icon_state)]_[(assembly_holder.a_left == src) ? "l":"r"]" //Sync the offset of the beam with the position of the sensor.
|
|
else if(istype(holder, /obj/item/transfer_valve))
|
|
I.icon_state = "[initial(I.icon_state)]_ttv"
|
|
I.density = TRUE
|
|
if(!I.Move(_T))
|
|
qdel(I)
|
|
switchListener(_T)
|
|
break
|
|
I.density = FALSE
|
|
beams += I
|
|
I.master = src
|
|
I.setDir(_dir)
|
|
I.invisibility = visible? 0 : INVISIBILITY_ABSTRACT
|
|
T = _T
|
|
_T = get_step(_T, _dir)
|
|
CHECK_TICK
|
|
|
|
/obj/item/assembly/infra/on_detach()
|
|
. = ..()
|
|
if(!.)
|
|
return
|
|
refreshBeam()
|
|
|
|
/obj/item/assembly/infra/attack_hand()
|
|
. = ..()
|
|
refreshBeam()
|
|
|
|
/obj/item/assembly/infra/Moved()
|
|
var/t = dir
|
|
. = ..()
|
|
setDir(t)
|
|
|
|
/obj/item/assembly/infra/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, force, gentle = FALSE, quickstart = TRUE)
|
|
. = ..()
|
|
olddir = dir
|
|
|
|
/obj/item/assembly/infra/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
|
|
. = ..()
|
|
if(!olddir)
|
|
return
|
|
setDir(olddir)
|
|
olddir = null
|
|
|
|
/obj/item/assembly/infra/proc/trigger_beam(atom/movable/AM, turf/location)
|
|
refreshBeam()
|
|
switchListener(location)
|
|
if(!secured || !on || next_activate > world.time)
|
|
return FALSE
|
|
pulse(FALSE)
|
|
audible_message("[icon2html(src, hearers(src))] *beep* *beep* *beep*", null, hearing_range)
|
|
for(var/CHM in get_hearers_in_view(hearing_range, src))
|
|
if(ismob(CHM))
|
|
var/mob/LM = CHM
|
|
LM.playsound_local(get_turf(src), 'sound/machines/triple_beep.ogg', ASSEMBLY_BEEP_VOLUME, TRUE)
|
|
next_activate = world.time + 30
|
|
|
|
/obj/item/assembly/infra/proc/switchListener(turf/newloc)
|
|
if(listeningTo == newloc)
|
|
return
|
|
if(listeningTo)
|
|
UnregisterSignal(listeningTo, COMSIG_ATOM_EXITED)
|
|
RegisterSignal(newloc, COMSIG_ATOM_EXITED, .proc/check_exit)
|
|
listeningTo = newloc
|
|
|
|
/obj/item/assembly/infra/proc/check_exit(datum/source, atom/movable/offender)
|
|
SIGNAL_HANDLER_DOES_SLEEP
|
|
|
|
if(QDELETED(src))
|
|
return
|
|
if(offender == src || istype(offender,/obj/effect/beam/i_beam))
|
|
return
|
|
if (offender && isitem(offender))
|
|
var/obj/item/I = offender
|
|
if (I.item_flags & ABSTRACT)
|
|
return
|
|
return refreshBeam()
|
|
|
|
/obj/item/assembly/infra/setDir()
|
|
. = ..()
|
|
refreshBeam()
|
|
|
|
/obj/item/assembly/infra/ui_status(mob/user)
|
|
if(is_secured(user))
|
|
return ..()
|
|
return UI_CLOSE
|
|
|
|
/obj/item/assembly/infra/ui_interact(mob/user, datum/tgui/ui)
|
|
ui = SStgui.try_update_ui(user, src, ui)
|
|
if(!ui)
|
|
ui = new(user, src, "InfraredEmitter", name)
|
|
ui.open()
|
|
|
|
/obj/item/assembly/infra/ui_data(mob/user)
|
|
var/list/data = list()
|
|
data["on"] = on
|
|
data["visible"] = visible
|
|
return data
|
|
|
|
/obj/item/assembly/infra/ui_act(action, params)
|
|
. = ..()
|
|
if(.)
|
|
return
|
|
|
|
switch(action)
|
|
if("power")
|
|
on = !on
|
|
. = TRUE
|
|
if("visibility")
|
|
visible = !visible
|
|
. = TRUE
|
|
|
|
update_icon()
|
|
refreshBeam()
|
|
|
|
/***************************IBeam*********************************/
|
|
|
|
/obj/effect/beam/i_beam
|
|
name = "infrared beam"
|
|
icon = 'icons/obj/projectiles.dmi'
|
|
icon_state = "ibeam"
|
|
anchored = TRUE
|
|
density = FALSE
|
|
pass_flags = PASSTABLE|PASSGLASS|PASSGRILLE|LETPASSTHROW
|
|
var/obj/item/assembly/infra/master
|
|
|
|
/obj/effect/beam/i_beam/Crossed(atom/movable/AM as mob|obj)
|
|
. = ..()
|
|
if(istype(AM, /obj/effect/beam))
|
|
return
|
|
if (isitem(AM))
|
|
var/obj/item/I = AM
|
|
if (I.item_flags & ABSTRACT)
|
|
return
|
|
master.trigger_beam(AM, get_turf(src))
|