mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-12 02:32:10 +00:00
## About The Pull Request I was looking at screenshots of the game and realized we had a lot of light sources that were really... flat. Medium intensity, not colored at all, cringe. So I went over all the uses of overlay styled lighting (since I've done matrix lighting already) and gave them more unique features. Colors that match the sprite they're used with, intensity to produce vibes, that sort of thing. It's kinda impossible to go one by one cause there's a LOT. I may have gone a bit overboard with a few, I'm messing around with some things like giving bots colors based off their department, etc. We'll see how this all turns out. Oh also I tweaked how the cone of overlay lighting is drawn. It seemed a bit too present to me so I dropped the alpha down from like 200 to 120 at max (so it's roughly half of the mask's alpha so it's less overwhelming ## Why It's Good For The Game Lighting should be impactful, subtle and colorful <details> <summary> Old Lights </summary>           </details> <details> <summary> New Lights </summary>           </details> ## Changelog 🆑 add: Tweaked the saturation, color and intensity of a bunch of lights /🆑
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 != OVERLAY_LIGHT && movable_parent.light_system != OVERLAY_LIGHT_DIRECTIONAL && movable_parent.light_system != OVERLAY_LIGHT_BEAM)
|
|
stack_trace("[type] added to [parent], with [movable_parent.light_system] value for the light_system var. Use [OVERLAY_LIGHT], [OVERLAY_LIGHT_DIRECTIONAL] or [OVERLAY_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(120, (abs(new_power) * 60) + 15)
|
|
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
|