mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-10 09:42:29 +00:00
## About The Pull Request All usages of world.icon_size in code have been replaced with new `ICONSIZE_X`, `ICONSIZE_Y` and `ICONSIZE_ALL` defines depending on context Replaces some "32" magic numbers with the defines A few bits of code have been modified to split up x/y math as well ## Why It's Good For The Game Magic number bad, code more readable, code more flexible and I'm told there's an access cost to doing world.icon_size so minor performance gains ## Changelog 🆑 tonty code: made some code relating to the world's icon size more readable /🆑 --------- Co-authored-by: Ghom <42542238+Ghommie@users.noreply.github.com>
311 lines
9.1 KiB
Plaintext
311 lines
9.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"
|
|
base_icon_state = "infrared"
|
|
custom_materials = list(
|
|
/datum/material/iron = HALF_SHEET_MATERIAL_AMOUNT,
|
|
/datum/material/glass = SMALL_MATERIAL_AMOUNT * 5,
|
|
)
|
|
is_position_sensitive = TRUE
|
|
drop_sound = 'sound/items/handling/component_drop.ogg'
|
|
pickup_sound = 'sound/items/handling/component_pickup.ogg'
|
|
set_dir_on_move = FALSE
|
|
/// Whether the beam is beaming
|
|
var/on = FALSE
|
|
/// Whether the beam is visible
|
|
var/visible = FALSE
|
|
/// The length the beam can go
|
|
var/max_beam_length = 8
|
|
/// The radius of which people can hear triggers
|
|
var/hearing_range = 3
|
|
/// Pass flags the beam uses to determine what it can pass through
|
|
var/beam_pass_flags = PASSTABLE|PASSGLASS|PASSGRILLE
|
|
/// The current active beam datum
|
|
VAR_FINAL/datum/beam/active_beam
|
|
/// A reference to the turf at the END of our active beam
|
|
VAR_FINAL/turf/buffer_turf
|
|
|
|
/obj/item/assembly/infra/Initialize(mapload)
|
|
. = ..()
|
|
AddComponent(/datum/component/simple_rotation)
|
|
|
|
/obj/item/assembly/infra/Destroy()
|
|
QDEL_NULL(active_beam)
|
|
buffer_turf = null
|
|
return ..()
|
|
|
|
|
|
/obj/item/assembly/infra/examine(mob/user)
|
|
. = ..()
|
|
. += span_notice("The infrared trigger is [on ? "on" : "off"].")
|
|
|
|
/// Checks if the passed movable can block the beam.
|
|
/obj/item/assembly/infra/proc/atom_blocks_beam(atom/movable/beam_atom)
|
|
if(isnull(beam_atom))
|
|
return FALSE
|
|
if(beam_atom == src || beam_atom == holder)
|
|
return FALSE
|
|
// Blocks beams from triggering themselves, important to avoid infinite loops
|
|
if(istype(beam_atom, /obj/effect/ebeam))
|
|
return FALSE
|
|
// Anti-revenant / anti-ghost guard
|
|
if(beam_atom.invisibility)
|
|
return FALSE
|
|
// In general non-dense items should not block beams, but make special cases for things being thrown
|
|
if(!beam_atom.density && !beam_atom.throwing)
|
|
return FALSE
|
|
// The actually important check. Ensures stuff like mobs trip it but stuff like laser projectiles don't
|
|
if(beam_atom.pass_flags_self & beam_pass_flags)
|
|
return FALSE
|
|
if(isitem(beam_atom))
|
|
var/obj/item/beam_item = beam_atom
|
|
if(beam_item.item_flags & ABSTRACT)
|
|
return FALSE
|
|
|
|
return TRUE
|
|
|
|
/// Checks if the passed turf (or something on it) can block the beam.
|
|
/obj/item/assembly/infra/proc/turf_blocks_beam(turf/beam_turf)
|
|
if(beam_turf.density)
|
|
return TRUE
|
|
for(var/atom/movable/blocker as anything in beam_turf)
|
|
if(atom_blocks_beam(blocker))
|
|
return TRUE
|
|
return FALSE
|
|
|
|
/// Used to refresh the beam in whatever context.
|
|
/obj/item/assembly/infra/proc/make_beam()
|
|
SHOULD_NOT_SLEEP(TRUE)
|
|
|
|
if(!isnull(buffer_turf))
|
|
UnregisterSignal(buffer_turf, list(COMSIG_ATOM_EXITED, COMSIG_TURF_CHANGE))
|
|
buffer_turf = null
|
|
|
|
QDEL_NULL(active_beam)
|
|
if(!on || !secured)
|
|
return
|
|
|
|
var/atom/start_loc = holder || src
|
|
var/turf/start_turf = start_loc.loc
|
|
if(!istype(start_turf))
|
|
return
|
|
// One extra turf is added to max length to get an extra buffer
|
|
var/list/turf/potential_turfs = get_line(start_turf, get_ranged_target_turf(start_turf, dir, max_beam_length + 1))
|
|
if(!length(potential_turfs))
|
|
return
|
|
|
|
var/list/turf/final_turfs = list()
|
|
for(var/turf/target_turf as anything in potential_turfs)
|
|
if(target_turf != start_turf && turf_blocks_beam(target_turf))
|
|
break
|
|
final_turfs += target_turf
|
|
|
|
if(!length(final_turfs))
|
|
return
|
|
|
|
var/turf/last_turf = final_turfs[length(final_turfs)]
|
|
buffer_turf = get_step(last_turf, dir)
|
|
|
|
active_beam = start_loc.Beam(
|
|
BeamTarget = last_turf,
|
|
beam_type = /obj/effect/ebeam/reacting/infrared,
|
|
icon = 'icons/effects/beam.dmi',
|
|
icon_state = "infrared",
|
|
emissive = TRUE,
|
|
override_target_pixel_x = pixel_x,
|
|
override_target_pixel_y = pixel_y,
|
|
)
|
|
RegisterSignal(active_beam, COMSIG_BEAM_ENTERED, PROC_REF(beam_entered))
|
|
RegisterSignal(active_beam, COMSIG_BEAM_TURFS_CHANGED, PROC_REF(beam_turfs_changed))
|
|
update_visible()
|
|
// Buffer can be null (if we're at map edge for an example) but this fine
|
|
if(!isnull(buffer_turf))
|
|
// We need to check the state of the turf at the end of the beam, to determine when we need to re-grow (if blocked)
|
|
RegisterSignal(buffer_turf, COMSIG_ATOM_EXITED, PROC_REF(buffer_exited))
|
|
RegisterSignal(buffer_turf, COMSIG_TURF_CHANGE, PROC_REF(buffer_changed))
|
|
|
|
/obj/item/assembly/infra/proc/beam_entered(datum/beam/source, obj/effect/ebeam/hit, atom/movable/entered)
|
|
SIGNAL_HANDLER
|
|
|
|
// First doesn't count
|
|
if(hit == active_beam.elements[1])
|
|
return
|
|
if(!atom_blocks_beam(entered))
|
|
return
|
|
|
|
beam_trigger(hit, entered)
|
|
|
|
/obj/item/assembly/infra/proc/beam_turfs_changed(datum/beam/source, list/datum/callback/post_change_callbacks)
|
|
SIGNAL_HANDLER
|
|
// If the turfs changed it's possible something is now blocking it, remake when done
|
|
post_change_callbacks += CALLBACK(src, PROC_REF(make_beam))
|
|
|
|
/obj/item/assembly/infra/proc/buffer_exited(turf/source, atom/movable/exited, ...)
|
|
SIGNAL_HANDLER
|
|
|
|
if(!atom_blocks_beam(exited))
|
|
return
|
|
|
|
make_beam()
|
|
|
|
/obj/item/assembly/infra/proc/buffer_changed(turf/source, path, list/new_baseturfs, flags, list/datum/callback/post_change_callbacks)
|
|
SIGNAL_HANDLER
|
|
|
|
post_change_callbacks += CALLBACK(src, PROC_REF(make_beam))
|
|
|
|
/obj/item/assembly/infra/proc/beam_trigger(obj/effect/ebeam/hit, atom/movable/entered)
|
|
make_beam()
|
|
if(!COOLDOWN_FINISHED(src, next_activate))
|
|
return
|
|
|
|
pulse()
|
|
audible_message(
|
|
message = span_infoplain("[icon2html(src, hearers(holder || src))] *beep* *beep* *beep*"),
|
|
hearing_distance = hearing_range,
|
|
)
|
|
playsound(src, 'sound/machines/beep/triple_beep.ogg', ASSEMBLY_BEEP_VOLUME, TRUE, extrarange = hearing_range - SOUND_RANGE + 1, falloff_distance = hearing_range)
|
|
COOLDOWN_START(src, next_activate, 3 SECONDS)
|
|
|
|
/obj/item/assembly/infra/activate()
|
|
. = ..()
|
|
if(!.)
|
|
return
|
|
|
|
toggle_on()
|
|
|
|
/obj/item/assembly/infra/toggle_secure()
|
|
. = ..()
|
|
make_beam()
|
|
|
|
/// Toggles the beam on or off.
|
|
/obj/item/assembly/infra/proc/toggle_on()
|
|
on = !on
|
|
make_beam()
|
|
update_appearance()
|
|
|
|
/// Toggles the visibility of the beam.
|
|
/obj/item/assembly/infra/proc/toggle_visible()
|
|
visible = !visible
|
|
update_visible()
|
|
update_appearance()
|
|
|
|
/// Updates the visibility of the beam (if active).
|
|
/obj/item/assembly/infra/proc/update_visible()
|
|
if(visible)
|
|
for(var/obj/effect/ebeam/beam as anything in active_beam?.elements)
|
|
beam.RemoveInvisibility(REF(src))
|
|
else
|
|
for(var/obj/effect/ebeam/beam as anything in active_beam?.elements)
|
|
beam.SetInvisibility(INVISIBILITY_ABSTRACT, REF(src))
|
|
|
|
/obj/item/assembly/infra/vv_edit_var(var_name, var_value)
|
|
. = ..()
|
|
if(!.)
|
|
return
|
|
switch(var_name)
|
|
if(NAMEOF(src, visible))
|
|
update_visible()
|
|
update_appearance()
|
|
|
|
if(NAMEOF(src, on), NAMEOF(src, max_beam_length), NAMEOF(src, beam_pass_flags))
|
|
make_beam()
|
|
update_appearance()
|
|
|
|
/obj/item/assembly/infra/update_appearance(updates)
|
|
. = ..()
|
|
holder?.update_appearance(updates)
|
|
|
|
/obj/item/assembly/infra/update_overlays()
|
|
. = ..()
|
|
attached_overlays = list()
|
|
if(on)
|
|
attached_overlays += "[base_icon_state]_on"
|
|
|
|
. += attached_overlays
|
|
|
|
/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
|
|
make_beam()
|
|
|
|
/obj/item/assembly/infra/on_attach()
|
|
. = ..()
|
|
make_beam()
|
|
holder.set_dir_on_move = set_dir_on_move
|
|
|
|
/obj/item/assembly/infra/on_detach()
|
|
holder.set_dir_on_move = initial(holder.set_dir_on_move)
|
|
. = ..()
|
|
if(!.)
|
|
return
|
|
make_beam()
|
|
|
|
/obj/item/assembly/infra/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change)
|
|
. = ..()
|
|
if(loc == old_loc)
|
|
return
|
|
make_beam()
|
|
if(!visible || forced || !movement_dir || !Adjacent(old_loc))
|
|
return
|
|
// Because the new beam is made in the new loc, it "jumps" from one turf to another
|
|
// We can do an animate to pretend we're gliding between turfs rather than making a whole new beam
|
|
var/x_move = 0
|
|
var/y_move = 0
|
|
if(movement_dir & NORTH)
|
|
y_move = -ICON_SIZE_Y
|
|
else if(movement_dir & SOUTH)
|
|
y_move = ICON_SIZE_Y
|
|
if(movement_dir & WEST)
|
|
x_move = ICON_SIZE_X
|
|
else if(movement_dir & EAST)
|
|
x_move = -ICON_SIZE_X
|
|
|
|
var/fake_glide_time = round(ICON_SIZE_ALL / glide_size * world.tick_lag, world.tick_lag)
|
|
for(var/obj/effect/ebeam/beam as anything in active_beam?.elements)
|
|
var/matrix/base_transform = matrix(beam.transform)
|
|
beam.transform = beam.transform.Translate(x_move, y_move)
|
|
animate(beam, transform = base_transform, time = fake_glide_time)
|
|
|
|
/obj/item/assembly/infra/setDir(newdir)
|
|
var/prev_dir = dir
|
|
. = ..()
|
|
if(dir == prev_dir)
|
|
return
|
|
make_beam()
|
|
|
|
/obj/item/assembly/infra/ui_status(mob/user, datum/ui_state/state)
|
|
return is_secured(user) ? ..() : 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, list/params, datum/tgui/ui, datum/ui_state/state)
|
|
. = ..()
|
|
if(.)
|
|
return .
|
|
|
|
switch(action)
|
|
if("power")
|
|
toggle_on()
|
|
return TRUE
|
|
if("visibility")
|
|
toggle_visible()
|
|
return TRUE
|
|
|
|
// Beam subtype for the infrared emitter
|
|
/obj/effect/ebeam/reacting/infrared
|
|
name = "infrared beam"
|
|
alpha = 175
|