mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-17 21:24:01 +00:00
* Fixes a hard del in overlay lighting, fixes inconsistent light overlays (#79939)
## About The Pull Request
Fixes https://github.com/tgstation/tgstation/issues/79418
Fixes https://github.com/tgstation/tgstation/issues/79345
Fixes https://github.com/Skyrat-SS13/Skyrat-tg/issues/25220

The root of the issue though was an early return in `on_holder_qdeleted`
that resulted in not setting the `current_holder` to null.
I'm assuming this can also happen because `check_holder()` can
potentially set the `current_holder` back to the original parent's `loc`
(in this case, the mechanical toolbox) in the code below, after the
parent has been qdeleted.
8c0becb4f0/code/datums/components/overlay_lighting.dm (L276-L278)
Adds checks to ensure that this cannot happen.
Edit:
On top of this, stored light sources were behaving inconsistently where
if you placed a storage item (like a backpack for instance) on the floor
and then put the flashlight inside of that, it would allow the light to
shine through. However as soon as you picked the storage item up, the
light would mysteriously vanish.
<details><summary>For simplicity's sake, the light will always get
blocked if placed inside of a storage item now.</summary>

</details>
## Why It's Good For The Game
Bugfix
## Changelog
🆑
fix: fixes an overlay lighting hard del
fix: flashlights placed inside of backpacks and other storage items that
were on the floor will no longer allow light to shine through
/🆑
* Fixes a hard del in overlay lighting, fixes inconsistent light overlays
---------
Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com>
576 lines
21 KiB
Plaintext
576 lines
21 KiB
Plaintext
///For switchable lights, is it on and currently emitting light?
|
|
#define LIGHTING_ON (1<<0)
|
|
///Is the parent attached to something else, its loc? Then we need to keep an eye of this.
|
|
#define LIGHTING_ATTACHED (1<<1)
|
|
|
|
#define GET_PARENT (parent_attached_to || parent)
|
|
|
|
#define SHORT_CAST 2
|
|
|
|
/**
|
|
* Movable atom overlay-based lighting component.
|
|
*
|
|
* * Component works by applying a visual object to the parent target.
|
|
*
|
|
* * The component tracks the parent's loc to determine the current_holder.
|
|
* * The current_holder is either the parent or its loc, whichever is on a turf. If none, then the current_holder is null and the light is not visible.
|
|
*
|
|
* * Lighting works at its base by applying a dark overlay and "cutting" said darkness with light, adding (possibly colored) transparency.
|
|
* * This component uses the visible_mask visual object to apply said light mask on the darkness.
|
|
*
|
|
* * The main limitation of this system is that it uses a limited number of pre-baked geometrical shapes, but for most uses it does the job.
|
|
*
|
|
* * Another limitation is for big lights: you only see the light if you see the object emiting it.
|
|
* * For small objects this is good (you can't see them behind a wall), but for big ones this quickly becomes prety clumsy.
|
|
*/
|
|
/datum/component/overlay_lighting
|
|
///How far the light reaches, float.
|
|
var/range = 1
|
|
///Ceiling of range, integer without decimal entries.
|
|
var/lumcount_range = 0
|
|
///How much this light affects the dynamic_lumcount of turfs.
|
|
var/lum_power = 0.5
|
|
///Transparency value.
|
|
var/set_alpha = 0
|
|
///For light sources that can be turned on and off.
|
|
var/overlay_lighting_flags = NONE
|
|
|
|
///Cache of the possible light overlays, according to size.
|
|
var/static/list/light_overlays = list(
|
|
"32" = 'icons/effects/light_overlays/light_32.dmi',
|
|
"64" = 'icons/effects/light_overlays/light_64.dmi',
|
|
"96" = 'icons/effects/light_overlays/light_96.dmi',
|
|
"128" = 'icons/effects/light_overlays/light_128.dmi',
|
|
"160" = 'icons/effects/light_overlays/light_160.dmi',
|
|
"192" = 'icons/effects/light_overlays/light_192.dmi',
|
|
"224" = 'icons/effects/light_overlays/light_224.dmi',
|
|
"256" = 'icons/effects/light_overlays/light_256.dmi',
|
|
"288" = 'icons/effects/light_overlays/light_288.dmi',
|
|
"320" = 'icons/effects/light_overlays/light_320.dmi',
|
|
"352" = 'icons/effects/light_overlays/light_352.dmi',
|
|
)
|
|
|
|
///Overlay effect to cut into the darkness and provide light.
|
|
var/image/visible_mask
|
|
///Lazy list to track the turfs being affected by our light, to determine their visibility.
|
|
var/list/turf/affected_turfs
|
|
///Movable atom currently holding the light. Parent might be a flashlight, for example, but that might be held by a mob or something else.
|
|
var/atom/movable/current_holder
|
|
///Movable atom the parent is attached to. For example, a flashlight into a helmet or gun. We'll need to track the thing the parent is attached to as if it were the parent itself.
|
|
var/atom/movable/parent_attached_to
|
|
///Whether we're a directional light
|
|
var/directional = FALSE
|
|
///Whether we're a beam light
|
|
var/beam = FALSE
|
|
///A cone overlay for directional light, it's alpha and color are dependant on the light
|
|
var/image/cone
|
|
///Current tracked direction for the directional cast behaviour
|
|
var/current_direction
|
|
///Tracks current directional x offset so we dont update unecessarily
|
|
var/directional_offset_x
|
|
///Tracks current directional y offset so we dont update unecessarily
|
|
var/directional_offset_y
|
|
///Cast range for the directional cast (how far away the atom is moved)
|
|
var/cast_range = 2
|
|
|
|
/datum/component/overlay_lighting/Initialize(_range, _power, _color, starts_on, is_directional, is_beam)
|
|
if(!ismovable(parent))
|
|
return COMPONENT_INCOMPATIBLE
|
|
|
|
var/atom/movable/movable_parent = parent
|
|
if(movable_parent.light_system != MOVABLE_LIGHT && movable_parent.light_system != MOVABLE_LIGHT_DIRECTIONAL && movable_parent.light_system != MOVABLE_LIGHT_BEAM)
|
|
stack_trace("[type] added to [parent], with [movable_parent.light_system] value for the light_system var. Use [MOVABLE_LIGHT], [MOVABLE_LIGHT_DIRECTIONAL] or [MOVABLE_LIGHT_BEAM] instead.")
|
|
return COMPONENT_INCOMPATIBLE
|
|
|
|
. = ..()
|
|
|
|
visible_mask = image('icons/effects/light_overlays/light_32.dmi', icon_state = "light")
|
|
SET_PLANE_EXPLICIT(visible_mask, O_LIGHTING_VISUAL_PLANE, movable_parent)
|
|
visible_mask.appearance_flags = RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM
|
|
visible_mask.alpha = 0
|
|
if(is_directional)
|
|
directional = TRUE
|
|
cone = image('icons/effects/light_overlays/light_cone.dmi', icon_state = "light")
|
|
SET_PLANE_EXPLICIT(cone, O_LIGHTING_VISUAL_PLANE, movable_parent)
|
|
cone.appearance_flags = RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM
|
|
cone.alpha = 110
|
|
cone.transform = cone.transform.Translate(-32, -32)
|
|
set_direction(movable_parent.dir)
|
|
if(is_beam)
|
|
beam = TRUE
|
|
if(!isnull(_range))
|
|
movable_parent.set_light_range(_range)
|
|
set_range(parent, movable_parent.light_range)
|
|
if(!isnull(_power))
|
|
movable_parent.set_light_power(_power)
|
|
set_power(parent, movable_parent.light_power)
|
|
if(!isnull(_color))
|
|
movable_parent.set_light_color(_color)
|
|
set_color(parent, movable_parent.light_color)
|
|
if(!isnull(starts_on))
|
|
movable_parent.set_light_on(starts_on)
|
|
|
|
|
|
/datum/component/overlay_lighting/RegisterWithParent()
|
|
. = ..()
|
|
if(directional)
|
|
RegisterSignal(parent, COMSIG_ATOM_DIR_CHANGE, PROC_REF(on_parent_dir_change))
|
|
RegisterSignal(parent, COMSIG_ATOM_UPDATE_LIGHT_RANGE, PROC_REF(set_range))
|
|
RegisterSignal(parent, COMSIG_ATOM_UPDATE_LIGHT_POWER, PROC_REF(set_power))
|
|
RegisterSignal(parent, COMSIG_ATOM_UPDATE_LIGHT_COLOR, PROC_REF(set_color))
|
|
RegisterSignal(parent, COMSIG_ATOM_UPDATE_LIGHT_ON, PROC_REF(on_toggle))
|
|
RegisterSignal(parent, COMSIG_ATOM_UPDATE_LIGHT_FLAGS, PROC_REF(on_light_flags_change))
|
|
RegisterSignal(parent, COMSIG_ATOM_USED_IN_CRAFT, PROC_REF(on_parent_crafted))
|
|
RegisterSignal(parent, COMSIG_LIGHT_EATER_QUEUE, PROC_REF(on_light_eater))
|
|
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, PROC_REF(on_parent_moved))
|
|
RegisterSignal(parent, COMSIG_MOVABLE_Z_CHANGED, PROC_REF(on_z_move))
|
|
var/atom/movable/movable_parent = parent
|
|
if(movable_parent.light_flags & LIGHT_ATTACHED)
|
|
overlay_lighting_flags |= LIGHTING_ATTACHED
|
|
set_parent_attached_to(ismovable(movable_parent.loc) ? movable_parent.loc : null)
|
|
check_holder()
|
|
if(movable_parent.light_on)
|
|
turn_on()
|
|
|
|
|
|
/datum/component/overlay_lighting/UnregisterFromParent()
|
|
overlay_lighting_flags &= ~LIGHTING_ATTACHED
|
|
set_parent_attached_to(null)
|
|
set_holder(null)
|
|
clean_old_turfs()
|
|
UnregisterSignal(parent, list(
|
|
COMSIG_MOVABLE_MOVED,
|
|
COMSIG_MOVABLE_Z_CHANGED,
|
|
COMSIG_ATOM_UPDATE_LIGHT_RANGE,
|
|
COMSIG_ATOM_UPDATE_LIGHT_POWER,
|
|
COMSIG_ATOM_UPDATE_LIGHT_COLOR,
|
|
COMSIG_ATOM_UPDATE_LIGHT_ON,
|
|
COMSIG_ATOM_UPDATE_LIGHT_FLAGS,
|
|
COMSIG_ATOM_USED_IN_CRAFT,
|
|
COMSIG_LIGHT_EATER_QUEUE,
|
|
))
|
|
if(directional)
|
|
UnregisterSignal(parent, COMSIG_ATOM_DIR_CHANGE)
|
|
if(overlay_lighting_flags & LIGHTING_ON)
|
|
turn_off()
|
|
return ..()
|
|
|
|
|
|
/datum/component/overlay_lighting/Destroy()
|
|
set_parent_attached_to(null)
|
|
set_holder(null)
|
|
clean_old_turfs()
|
|
visible_mask = null
|
|
cone = null
|
|
parent_attached_to = null
|
|
return ..()
|
|
|
|
|
|
///Clears the affected_turfs lazylist, removing from its contents the effects of being near the light.
|
|
/datum/component/overlay_lighting/proc/clean_old_turfs()
|
|
for(var/turf/lit_turf as anything in affected_turfs)
|
|
lit_turf.dynamic_lumcount -= lum_power
|
|
affected_turfs = null
|
|
|
|
|
|
///Populates the affected_turfs lazylist, adding to its contents the effects of being near the light.
|
|
/datum/component/overlay_lighting/proc/get_new_turfs()
|
|
if(!current_holder)
|
|
return
|
|
. = list()
|
|
for(var/turf/lit_turf in view(lumcount_range, get_turf(current_holder)))
|
|
lit_turf.dynamic_lumcount += lum_power
|
|
. += lit_turf
|
|
if(length(.))
|
|
affected_turfs = .
|
|
|
|
|
|
///Clears the old affected turfs and populates the new ones.
|
|
/datum/component/overlay_lighting/proc/make_luminosity_update()
|
|
clean_old_turfs()
|
|
if(!isturf(current_holder?.loc))
|
|
return
|
|
if(directional)
|
|
cast_directional_light()
|
|
get_new_turfs()
|
|
|
|
|
|
///Adds the luminosity and source for the affected movable atoms to keep track of their visibility.
|
|
/datum/component/overlay_lighting/proc/add_dynamic_lumi()
|
|
LAZYSET(current_holder.affected_dynamic_lights, src, lumcount_range + 1)
|
|
current_holder.underlays += visible_mask
|
|
current_holder.update_dynamic_luminosity()
|
|
if(directional)
|
|
current_holder.underlays += cone
|
|
|
|
///Removes the luminosity and source for the affected movable atoms to keep track of their visibility.
|
|
/datum/component/overlay_lighting/proc/remove_dynamic_lumi()
|
|
LAZYREMOVE(current_holder.affected_dynamic_lights, src)
|
|
current_holder.underlays -= visible_mask
|
|
current_holder.update_dynamic_luminosity()
|
|
if(directional)
|
|
current_holder.underlays -= cone
|
|
|
|
///Called to change the value of parent_attached_to.
|
|
/datum/component/overlay_lighting/proc/set_parent_attached_to(atom/movable/new_parent_attached_to)
|
|
if(new_parent_attached_to == parent_attached_to)
|
|
return
|
|
|
|
. = parent_attached_to
|
|
parent_attached_to = new_parent_attached_to
|
|
if(.)
|
|
var/atom/movable/old_parent_attached_to = .
|
|
UnregisterSignal(old_parent_attached_to, list(COMSIG_QDELETING, COMSIG_MOVABLE_MOVED, COMSIG_LIGHT_EATER_QUEUE))
|
|
if(old_parent_attached_to == current_holder)
|
|
RegisterSignal(old_parent_attached_to, COMSIG_QDELETING, PROC_REF(on_holder_qdel))
|
|
RegisterSignal(old_parent_attached_to, COMSIG_MOVABLE_MOVED, PROC_REF(on_holder_moved))
|
|
RegisterSignal(old_parent_attached_to, COMSIG_LIGHT_EATER_QUEUE, PROC_REF(on_light_eater))
|
|
if(parent_attached_to)
|
|
if(parent_attached_to == current_holder)
|
|
UnregisterSignal(current_holder, list(COMSIG_QDELETING, COMSIG_MOVABLE_MOVED, COMSIG_LIGHT_EATER_QUEUE))
|
|
RegisterSignal(parent_attached_to, COMSIG_QDELETING, PROC_REF(on_parent_attached_to_qdel))
|
|
RegisterSignal(parent_attached_to, COMSIG_MOVABLE_MOVED, PROC_REF(on_parent_attached_to_moved))
|
|
RegisterSignal(parent_attached_to, COMSIG_LIGHT_EATER_QUEUE, PROC_REF(on_light_eater))
|
|
check_holder()
|
|
|
|
|
|
///Called to change the value of current_holder.
|
|
/datum/component/overlay_lighting/proc/set_holder(atom/movable/new_holder)
|
|
if(new_holder == current_holder)
|
|
return
|
|
if(current_holder)
|
|
if(current_holder != parent && current_holder != parent_attached_to)
|
|
UnregisterSignal(current_holder, list(COMSIG_QDELETING, COMSIG_MOVABLE_MOVED, COMSIG_LIGHT_EATER_QUEUE))
|
|
if(directional)
|
|
UnregisterSignal(current_holder, COMSIG_ATOM_DIR_CHANGE)
|
|
if(overlay_lighting_flags & LIGHTING_ON)
|
|
remove_dynamic_lumi()
|
|
current_holder = new_holder
|
|
if(new_holder == null)
|
|
clean_old_turfs()
|
|
return
|
|
if(new_holder != parent && new_holder != parent_attached_to)
|
|
RegisterSignal(new_holder, COMSIG_QDELETING, PROC_REF(on_holder_qdel))
|
|
RegisterSignal(new_holder, COMSIG_LIGHT_EATER_QUEUE, PROC_REF(on_light_eater))
|
|
if(overlay_lighting_flags & LIGHTING_ON)
|
|
RegisterSignal(new_holder, COMSIG_MOVABLE_MOVED, PROC_REF(on_holder_moved))
|
|
if(directional)
|
|
RegisterSignal(new_holder, COMSIG_ATOM_DIR_CHANGE, PROC_REF(on_holder_dir_change))
|
|
if(directional && current_direction != new_holder.dir)
|
|
current_direction = new_holder.dir
|
|
if(overlay_lighting_flags & LIGHTING_ON)
|
|
add_dynamic_lumi()
|
|
make_luminosity_update()
|
|
|
|
|
|
///Used to determine the new valid current_holder from the parent's loc.
|
|
/datum/component/overlay_lighting/proc/check_holder()
|
|
var/atom/movable/movable_parent = GET_PARENT
|
|
if(QDELETED(movable_parent))
|
|
set_holder(null)
|
|
return
|
|
if(isturf(movable_parent.loc))
|
|
set_holder(movable_parent)
|
|
return
|
|
var/atom/inside = movable_parent.loc //Parent's loc
|
|
if(isnull(inside))
|
|
set_holder(null)
|
|
return
|
|
if(isturf(inside.loc))
|
|
// storage items block light, also don't be moving into a qdeleted item
|
|
if(QDELETED(inside) || istype(inside, /obj/item/storage))
|
|
set_holder(null)
|
|
else
|
|
set_holder(inside)
|
|
return
|
|
set_holder(null)
|
|
|
|
|
|
///Called when the current_holder is qdeleted, to remove the light effect.
|
|
/datum/component/overlay_lighting/proc/on_holder_qdel(atom/movable/source, force)
|
|
SIGNAL_HANDLER
|
|
if(QDELETED(current_holder))
|
|
set_holder(null)
|
|
return
|
|
UnregisterSignal(current_holder, list(COMSIG_QDELETING, COMSIG_MOVABLE_MOVED))
|
|
if(directional)
|
|
UnregisterSignal(current_holder, COMSIG_ATOM_DIR_CHANGE)
|
|
set_holder(null)
|
|
|
|
|
|
///Called when current_holder changes loc.
|
|
/datum/component/overlay_lighting/proc/on_holder_moved(atom/movable/source, OldLoc, Dir, Forced)
|
|
SIGNAL_HANDLER
|
|
if(!(overlay_lighting_flags & LIGHTING_ON))
|
|
return
|
|
make_luminosity_update()
|
|
|
|
|
|
///Called when parent changes loc.
|
|
/datum/component/overlay_lighting/proc/on_parent_moved(atom/movable/source, OldLoc, Dir, Forced)
|
|
SIGNAL_HANDLER
|
|
var/atom/movable/movable_parent = parent
|
|
if(overlay_lighting_flags & LIGHTING_ATTACHED)
|
|
set_parent_attached_to(ismovable(movable_parent.loc) ? movable_parent.loc : null)
|
|
check_holder()
|
|
if(!(overlay_lighting_flags & LIGHTING_ON) || !current_holder)
|
|
return
|
|
make_luminosity_update()
|
|
|
|
/datum/component/overlay_lighting/proc/on_z_move(atom/source)
|
|
SIGNAL_HANDLER
|
|
if(current_holder && overlay_lighting_flags & LIGHTING_ON)
|
|
current_holder.underlays -= visible_mask
|
|
current_holder.underlays -= cone
|
|
SET_PLANE_EXPLICIT(visible_mask, O_LIGHTING_VISUAL_PLANE, source)
|
|
if(cone)
|
|
SET_PLANE_EXPLICIT(cone, O_LIGHTING_VISUAL_PLANE, source)
|
|
if(current_holder && overlay_lighting_flags & LIGHTING_ON)
|
|
current_holder.underlays += visible_mask
|
|
current_holder.underlays += cone
|
|
|
|
///Called when the current_holder is qdeleted, to remove the light effect.
|
|
/datum/component/overlay_lighting/proc/on_parent_attached_to_qdel(atom/movable/source, force)
|
|
SIGNAL_HANDLER
|
|
UnregisterSignal(parent_attached_to, list(COMSIG_QDELETING, COMSIG_MOVABLE_MOVED))
|
|
if(directional)
|
|
UnregisterSignal(parent_attached_to, COMSIG_ATOM_DIR_CHANGE)
|
|
if(parent_attached_to == current_holder)
|
|
set_holder(null)
|
|
set_parent_attached_to(null)
|
|
|
|
|
|
///Called when parent_attached_to changes loc.
|
|
/datum/component/overlay_lighting/proc/on_parent_attached_to_moved(atom/movable/source, OldLoc, Dir, Forced)
|
|
SIGNAL_HANDLER
|
|
check_holder()
|
|
if(!(overlay_lighting_flags & LIGHTING_ON) || !current_holder)
|
|
return
|
|
make_luminosity_update()
|
|
|
|
|
|
///Changes the range which the light reaches. 0 means no light, 6 is the maximum value.
|
|
/datum/component/overlay_lighting/proc/set_range(atom/source, old_range)
|
|
SIGNAL_HANDLER
|
|
var/new_range = source.light_range
|
|
if(range == new_range)
|
|
return
|
|
if(new_range == 0)
|
|
turn_off()
|
|
range = clamp(CEILING(new_range, 0.5), 1, 6)
|
|
var/pixel_bounds = ((range - 1) * 64) + 32
|
|
lumcount_range = CEILING(range, 1)
|
|
if(current_holder && overlay_lighting_flags & LIGHTING_ON)
|
|
current_holder.underlays -= visible_mask
|
|
visible_mask.icon = light_overlays["[pixel_bounds]"]
|
|
if(pixel_bounds == 32)
|
|
if(!directional) // it's important that we make it to the end of this function if we are a directional light
|
|
visible_mask.transform = null
|
|
return
|
|
else
|
|
var/offset = (pixel_bounds - 32) * 0.5
|
|
var/matrix/transform = new
|
|
transform.Translate(-offset, -offset)
|
|
visible_mask.transform = transform
|
|
if(current_holder && overlay_lighting_flags & LIGHTING_ON)
|
|
current_holder.underlays += visible_mask
|
|
if(directional)
|
|
if(beam)
|
|
cast_range = max(round(new_range * 0.5), 1)
|
|
else
|
|
cast_range = clamp(round(new_range * 0.5), 1, 3)
|
|
if(overlay_lighting_flags & LIGHTING_ON)
|
|
make_luminosity_update()
|
|
|
|
|
|
///Changes the intensity/brightness of the light by altering the visual object's alpha.
|
|
/datum/component/overlay_lighting/proc/set_power(atom/source, old_power)
|
|
SIGNAL_HANDLER
|
|
var/new_power = source.light_power
|
|
set_lum_power(new_power >= 0 ? 0.5 : -0.5)
|
|
set_alpha = min(230, (abs(new_power) * 120) + 30)
|
|
if(current_holder && overlay_lighting_flags & LIGHTING_ON)
|
|
current_holder.underlays -= visible_mask
|
|
visible_mask.alpha = set_alpha
|
|
if(current_holder && overlay_lighting_flags & LIGHTING_ON)
|
|
current_holder.underlays += visible_mask
|
|
if(!directional)
|
|
return
|
|
if(current_holder && overlay_lighting_flags & LIGHTING_ON)
|
|
current_holder.underlays -= cone
|
|
cone.alpha = min(200, (abs(new_power) * 90)+20)
|
|
if(current_holder && overlay_lighting_flags & LIGHTING_ON)
|
|
current_holder.underlays += cone
|
|
|
|
|
|
///Changes the light's color, pretty straightforward.
|
|
/datum/component/overlay_lighting/proc/set_color(atom/source, old_color)
|
|
SIGNAL_HANDLER
|
|
var/new_color = source.light_color
|
|
if(current_holder && overlay_lighting_flags & LIGHTING_ON)
|
|
current_holder.underlays -= visible_mask
|
|
visible_mask.color = new_color
|
|
if(current_holder && overlay_lighting_flags & LIGHTING_ON)
|
|
current_holder.underlays += visible_mask
|
|
if(!directional)
|
|
return
|
|
if(current_holder && overlay_lighting_flags & LIGHTING_ON)
|
|
current_holder.underlays -= cone
|
|
cone.color = new_color
|
|
if(current_holder && overlay_lighting_flags & LIGHTING_ON)
|
|
current_holder.underlays += cone
|
|
|
|
|
|
///Toggles the light on and off.
|
|
/datum/component/overlay_lighting/proc/on_toggle(atom/source, old_value)
|
|
SIGNAL_HANDLER
|
|
var/new_value = source.light_on
|
|
if(new_value) //Truthy value input, turn on.
|
|
turn_on()
|
|
return
|
|
turn_off() //Falsey value, turn off.
|
|
|
|
|
|
///Triggered right after the parent light flags change.
|
|
/datum/component/overlay_lighting/proc/on_light_flags_change(atom/source, old_flags)
|
|
SIGNAL_HANDLER
|
|
var/new_flags = source.light_flags
|
|
var/atom/movable/movable_parent = parent
|
|
if(!((new_flags ^ old_flags) & LIGHT_ATTACHED))
|
|
return
|
|
|
|
if(new_flags & LIGHT_ATTACHED) // Gained the [LIGHT_ATTACHED] property
|
|
overlay_lighting_flags |= LIGHTING_ATTACHED
|
|
if(ismovable(movable_parent.loc))
|
|
set_parent_attached_to(movable_parent.loc)
|
|
else // Lost the [LIGHT_ATTACHED] property
|
|
overlay_lighting_flags &= ~LIGHTING_ATTACHED
|
|
set_parent_attached_to(null)
|
|
|
|
|
|
///Toggles the light on.
|
|
/datum/component/overlay_lighting/proc/turn_on()
|
|
if(overlay_lighting_flags & LIGHTING_ON)
|
|
return
|
|
overlay_lighting_flags |= LIGHTING_ON
|
|
if(current_holder)
|
|
add_dynamic_lumi()
|
|
if(directional)
|
|
cast_directional_light()
|
|
if(current_holder && current_holder != parent && current_holder != parent_attached_to)
|
|
RegisterSignal(current_holder, COMSIG_MOVABLE_MOVED, PROC_REF(on_holder_moved))
|
|
get_new_turfs()
|
|
|
|
|
|
///Toggles the light off.
|
|
/datum/component/overlay_lighting/proc/turn_off()
|
|
if(!(overlay_lighting_flags & LIGHTING_ON))
|
|
return
|
|
if(current_holder)
|
|
remove_dynamic_lumi()
|
|
overlay_lighting_flags &= ~LIGHTING_ON
|
|
if(current_holder && current_holder != parent && current_holder != parent_attached_to)
|
|
UnregisterSignal(current_holder, COMSIG_MOVABLE_MOVED)
|
|
clean_old_turfs()
|
|
|
|
|
|
///Here we append the behavior associated to changing lum_power.
|
|
/datum/component/overlay_lighting/proc/set_lum_power(new_lum_power)
|
|
if(lum_power == new_lum_power)
|
|
return
|
|
. = lum_power
|
|
lum_power = new_lum_power
|
|
var/difference = . - lum_power
|
|
for(var/turf/lit_turf as anything in affected_turfs)
|
|
lit_turf.dynamic_lumcount -= difference
|
|
|
|
///Here we append the behavior associated to changing lum_power.
|
|
/datum/component/overlay_lighting/proc/cast_directional_light()
|
|
var/final_distance = cast_range
|
|
//Lower the distance by 1 if we're not looking at a cardinal direction, and we're not a short cast
|
|
if(final_distance > SHORT_CAST && !(ALL_CARDINALS & current_direction))
|
|
final_distance -= 1
|
|
var/turf/scanning = get_turf(current_holder)
|
|
for(var/i in 1 to final_distance)
|
|
var/turf/next_turf = get_step(scanning, current_direction)
|
|
if(isnull(next_turf) || IS_OPAQUE_TURF(next_turf))
|
|
final_distance = i
|
|
break
|
|
scanning = next_turf
|
|
|
|
current_holder.underlays -= visible_mask
|
|
|
|
var/translate_x = -((range - 1) * 32)
|
|
var/translate_y = translate_x
|
|
var/scale_x = 1
|
|
var/scale_y = 1
|
|
switch(current_direction)
|
|
if(NORTH)
|
|
translate_y += 32 * final_distance
|
|
if(beam && range > 1)
|
|
scale_x = 1 / (range - (range/5))
|
|
if(SOUTH)
|
|
translate_y += -32 * final_distance
|
|
if(beam && range > 1)
|
|
scale_x = 1 / (range - (range/5))
|
|
if(EAST)
|
|
translate_x += 32 * final_distance
|
|
if(beam && range > 1)
|
|
scale_y = 1 / (range - (range/5))
|
|
if(WEST)
|
|
translate_x += -32 * final_distance
|
|
if(beam && range > 1)
|
|
scale_y = 1 / (range - (range/5))
|
|
|
|
if((directional_offset_x != translate_x) || (directional_offset_y != translate_y))
|
|
directional_offset_x = translate_x
|
|
directional_offset_y = translate_y
|
|
var/matrix/transform = matrix()
|
|
if(beam && range > 1)
|
|
transform.Scale(scale_x, scale_y)
|
|
transform.Translate(translate_x, translate_y)
|
|
visible_mask.transform = transform
|
|
if(overlay_lighting_flags & LIGHTING_ON)
|
|
current_holder.underlays += visible_mask
|
|
|
|
///Called when current_holder changes loc.
|
|
/datum/component/overlay_lighting/proc/on_holder_dir_change(atom/movable/source, olddir, newdir)
|
|
SIGNAL_HANDLER
|
|
set_direction(newdir)
|
|
|
|
///Called when parent changes loc.
|
|
/datum/component/overlay_lighting/proc/on_parent_dir_change(atom/movable/source, olddir, newdir)
|
|
SIGNAL_HANDLER
|
|
set_direction(newdir)
|
|
|
|
///Sets a new direction for the directional cast, then updates luminosity
|
|
/datum/component/overlay_lighting/proc/set_direction(newdir)
|
|
if(!newdir)
|
|
return
|
|
if(current_direction == newdir)
|
|
return
|
|
current_direction = newdir
|
|
if(overlay_lighting_flags & LIGHTING_ON)
|
|
make_luminosity_update()
|
|
|
|
/datum/component/overlay_lighting/proc/on_parent_crafted(datum/source, atom/movable/new_craft)
|
|
SIGNAL_HANDLER
|
|
|
|
if(!istype(new_craft))
|
|
return
|
|
|
|
UnregisterSignal(parent, COMSIG_ATOM_USED_IN_CRAFT)
|
|
RegisterSignal(new_craft, COMSIG_ATOM_USED_IN_CRAFT, PROC_REF(on_parent_crafted))
|
|
set_parent_attached_to(new_craft)
|
|
|
|
/// Handles putting the source for overlay lights into the light eater queue since we aren't tracked by [/atom/var/light_sources]
|
|
/datum/component/overlay_lighting/proc/on_light_eater(datum/source, list/light_queue, datum/light_eater)
|
|
SIGNAL_HANDLER
|
|
light_queue[parent] = TRUE
|
|
return NONE
|
|
|
|
#undef LIGHTING_ON
|
|
#undef LIGHTING_ATTACHED
|
|
#undef GET_PARENT
|
|
#undef SHORT_CAST
|