Browse Source

Overlay lighting component (#52413)

Sparks no longer lag, projectile beams move super smoothly, same with mobs and whatnot. This also allows for easy expansion into directional lights, field-of-view, wee-woo rotating lights or whatever.

It does have a downside: things right-clicked or checked through the alt+click tab will show the light overlay:


This is a BYOND limitation, very well worth it IMO.

๐Ÿ†‘
add: Smooth movable lighting system implemented. Projectiles, sparks, thrown flashlights or moving mobs with lights should be much smoother and less laggy.
balance: Light sources no longer stack in range, though they still do in intensity.
/๐Ÿ†‘
pull/2/head
Rohesie 7 months ago
committed by GitHub
parent
commit
eda7c6ca55
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
85 changed files with 1085 additions and 398 deletions
  1. +10
    -0
      code/__DEFINES/dcs/signals.dm
  2. +6
    -2
      code/__DEFINES/layers.dm
  3. +10
    -0
      code/__DEFINES/lighting.dm
  4. +3
    -0
      code/__DEFINES/mobs.dm
  5. +11
    -3
      code/_onclick/hud/plane_master.dm
  6. +362
    -0
      code/datums/components/overlay_lighting.dm
  7. +2
    -1
      code/datums/mutations/body.dm
  8. +5
    -1
      code/game/atoms.dm
  9. +7
    -0
      code/game/atoms_movable.dm
  10. +76
    -89
      code/game/machinery/dance_machine.dm
  11. +11
    -1
      code/game/machinery/flasher.dm
  12. +26
    -16
      code/game/mecha/combat/durand.dm
  13. +2
    -0
      code/game/mecha/mecha.dm
  14. +1
    -2
      code/game/mecha/mecha_actions.dm
  15. +19
    -0
      code/game/movable_luminosity.dm
  16. +3
    -2
      code/game/objects/effects/effect_system/effects_sparks.dm
  17. +8
    -2
      code/game/objects/effects/misc.dm
  18. +11
    -0
      code/game/objects/effects/overlays.dm
  19. +7
    -2
      code/game/objects/items/cigs_lighters.dm
  20. +11
    -13
      code/game/objects/items/devices/PDA/PDA.dm
  21. +1
    -1
      code/game/objects/items/devices/PDA/PDA_types.dm
  22. +60
    -31
      code/game/objects/items/devices/flashlight.dm
  23. +7
    -3
      code/game/objects/items/dualsaber.dm
  24. +3
    -2
      code/game/objects/items/flamethrower.dm
  25. +2
    -2
      code/game/objects/items/grenades/flashbang.dm
  26. +1
    -1
      code/game/objects/items/grenades/hypno.dm
  27. +6
    -5
      code/game/objects/items/melee/energy.dm
  28. +4
    -3
      code/game/objects/items/pitchfork.dm
  29. +24
    -11
      code/game/objects/items/tools/weldingtool.dm
  30. +1
    -1
      code/game/turfs/open/space/space.dm
  31. +3
    -0
      code/game/turfs/turf.dm
  32. +2
    -2
      code/modules/antagonists/cult/blood_magic.dm
  33. +6
    -3
      code/modules/antagonists/cult/cult_items.dm
  34. +11
    -1
      code/modules/assembly/flash.dm
  35. +5
    -4
      code/modules/atmospherics/environmental/LINDA_fire.dm
  36. +15
    -9
      code/modules/clothing/head/hardhat.dm
  37. +32
    -16
      code/modules/clothing/head/helmet.dm
  38. +4
    -4
      code/modules/clothing/head/misc_special.dm
  39. +12
    -6
      code/modules/clothing/shoes/miscellaneous.dm
  40. +9
    -8
      code/modules/clothing/spacesuits/hardsuit.dm
  41. +3
    -2
      code/modules/clothing/spacesuits/miscellaneous.dm
  42. +12
    -10
      code/modules/clothing/spacesuits/plasmamen.dm
  43. +1
    -0
      code/modules/hydroponics/grown/ambrosia.dm
  44. +3
    -2
      code/modules/hydroponics/plant_genes.dm
  45. +41
    -23
      code/modules/lighting/lighting_atom.dm
  46. +2
    -0
      code/modules/lighting/lighting_turf.dm
  47. +2
    -7
      code/modules/mining/equipment/kinetic_crusher.dm
  48. +2
    -0
      code/modules/mining/lavaland/necropolis_chests.dm
  49. +6
    -6
      code/modules/mining/minebot.dm
  50. +8
    -4
      code/modules/mob/dead/observer/observer.dm
  51. +29
    -15
      code/modules/mob/living/carbon/human/species_types/ethereal.dm
  52. +3
    -0
      code/modules/mob/living/carbon/human/species_types/jellypeople.dm
  53. +2
    -2
      code/modules/mob/living/carbon/human/species_types/shadowpeople.dm
  54. +20
    -11
      code/modules/mob/living/silicon/robot/robot.dm
  55. +5
    -3
      code/modules/mob/living/simple_animal/bot/bot.dm
  56. +6
    -7
      code/modules/mob/living/simple_animal/bot/vibebot.dm
  57. +8
    -3
      code/modules/mob/living/simple_animal/guardian/guardian.dm
  58. +8
    -8
      code/modules/mob/living/simple_animal/hostile/hivebot.dm
  59. +1
    -0
      code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
  60. +1
    -0
      code/modules/mob/living/simple_animal/hostile/mining_mobs/basilisk.dm
  61. +3
    -1
      code/modules/mob/living/simple_animal/hostile/retaliate/ghost.dm
  62. +11
    -1
      code/modules/photography/camera/camera.dm
  63. +21
    -11
      code/modules/projectiles/gun.dm
  64. +1
    -1
      code/modules/projectiles/guns/energy/energy_gun.dm
  65. +4
    -1
      code/modules/projectiles/projectile/beams.dm
  66. +22
    -2
      code/modules/reagents/chemistry/reagents/food_reagents.dm
  67. +2
    -2
      code/modules/reagents/chemistry/recipes/pyrotechnics.dm
  68. +2
    -2
      code/modules/spells/spell_types/lichdom.dm
  69. +24
    -9
      code/modules/surgery/organs/eyes.dm
  70. +6
    -8
      code/modules/surgery/tools.dm
  71. +21
    -10
      code/modules/swarmers/swarmer.dm
  72. BIN
      icons/effects/light_overlays/light_128.dmi
  73. BIN
      icons/effects/light_overlays/light_160.dmi
  74. BIN
      icons/effects/light_overlays/light_192.dmi
  75. BIN
      icons/effects/light_overlays/light_224.dmi
  76. BIN
      icons/effects/light_overlays/light_256.dmi
  77. BIN
      icons/effects/light_overlays/light_288.dmi
  78. BIN
      icons/effects/light_overlays/light_32.dmi
  79. BIN
      icons/effects/light_overlays/light_320.dmi
  80. BIN
      icons/effects/light_overlays/light_352.dmi
  81. BIN
      icons/effects/light_overlays/light_64.dmi
  82. BIN
      icons/effects/light_overlays/light_96.dmi
  83. +2
    -0
      tgstation.dme
  84. +4
    -0
      tools/CreditsTool/obj/Debug/.NETFramework,Version=v4.6.1.AssemblyAttributes.cs
  85. BIN
      tools/CreditsTool/obj/Debug/CreditsTool.csprojAssemblyReference.cache

+ 10
- 0
code/__DEFINES/dcs/signals.dm View File

@ -173,6 +173,8 @@
#define COMSIG_ATOM_SET_LIGHT_COLOR "atom_set_light_color"
///Called right before the atom changes the value of light_on to a different one, from base atom/set_light_on(): (new_value)
#define COMSIG_ATOM_SET_LIGHT_ON "atom_set_light_on"
///Called right before the atom changes the value of light_flags to a different one, from base atom/set_light_flags(): (new_value)
#define COMSIG_ATOM_SET_LIGHT_FLAGS "atom_set_light_flags"
///called for each movable in a turf contents on /turf/zImpact(): (atom/movable/A, levels)
#define COMSIG_ATOM_INTERCEPT_Z_FALL "movable_intercept_z_impact"
///called on a movable (NOT living) when someone starts pulling it (atom/movable/puller, state, force)
@ -274,6 +276,14 @@
#define COMSIG_MOVABLE_SET_ANCHORED "movable_set_anchored"
///from base of atom/movable/setGrabState(): (newstate)
#define COMSIG_MOVABLE_SET_GRAB_STATE "living_set_grab_state"
///Called when the movable tries to change its dynamic light color setting, from base atom/movable/lighting_overlay_set_color(): (color)
#define COMSIG_MOVABLE_LIGHT_OVERLAY_SET_RANGE "movable_light_overlay_set_color"
///Called when the movable tries to change its dynamic light power setting, from base atom/movable/lighting_overlay_set_power(): (power)
#define COMSIG_MOVABLE_LIGHT_OVERLAY_SET_POWER "movable_light_overlay_set_power"
///Called when the movable tries to change its dynamic light range setting, from base atom/movable/lighting_overlay_set_range(): (range)
#define COMSIG_MOVABLE_LIGHT_OVERLAY_SET_COLOR "movable_light_overlay_set_range"
///Called when the movable tries to toggle its dynamic light LIGHTING_ON status, from base atom/movable/lighting_overlay_toggle_on(): (new_state)
#define COMSIG_MOVABLE_LIGHT_OVERLAY_TOGGLE_ON "movable_light_overlay_toggle_on"
// /mob signals


+ 6
- 2
code/__DEFINES/layers.dm View File

@ -110,8 +110,12 @@
#define RAD_TEXT_LAYER 15.1
#define ABOVE_LIGHTING_PLANE 16
#define ABOVE_LIGHTING_LAYER 16
#define O_LIGHTING_VISUAL_PLANE 16
#define O_LIGHTING_VISUAL_LAYER 16
#define O_LIGHTING_VISUAL_RENDER_TARGET "O_LIGHT_VISUAL_PLANE"
#define ABOVE_LIGHTING_PLANE 17
#define ABOVE_LIGHTING_LAYER 17
#define ABOVE_LIGHTING_RENDER_TARGET "ABOVE_LIGHTING_PLANE"
#define BYOND_LIGHTING_PLANE 18


+ 10
- 0
code/__DEFINES/lighting.dm View File

@ -1,3 +1,13 @@
///Object doesn't use any of the light systems. Should be changed to add a light source to the object.
#define NO_LIGHT_SUPPORT 0
///Light made with the lighting datums, applying a matrix.
#define STATIC_LIGHT 1
///Light made by masking the lighting darkness plane.
#define MOVABLE_LIGHT 2
///Is a movable light source attached to another movable (its loc), meaning that the lighting component should go one level deeper.
#define LIGHT_ATTACHED (1<<0)
//Bay lighting engine shit, not in /code/modules/lighting because BYOND is being shit about it
/// frequency, in 1/10ths of a second, of the lighting process
#define LIGHTING_INTERVAL 5


+ 3
- 0
code/__DEFINES/mobs.dm View File

@ -373,3 +373,6 @@
#define EYE_CONTACT_RANGE 5
#define SILENCE_RANGED_MESSAGE (1<<0)
///Swarmer flags
#define SWARMER_LIGHT_ON (1<<0)

+ 11
- 3
code/_onclick/hud/plane_master.dm View File

@ -79,8 +79,9 @@
/obj/screen/plane_master/lighting/Initialize()
. = ..()
filters += filter(type="alpha", render_source=EMISSIVE_RENDER_TARGET, flags=MASK_INVERSE)
filters += filter(type="alpha", render_source=EMISSIVE_UNBLOCKABLE_RENDER_TARGET, flags=MASK_INVERSE)
filters += filter(type="alpha", render_source = EMISSIVE_RENDER_TARGET, flags = MASK_INVERSE)
filters += filter(type="alpha", render_source = EMISSIVE_UNBLOCKABLE_RENDER_TARGET, flags = MASK_INVERSE)
filters += filter(type="alpha", render_source = O_LIGHTING_VISUAL_RENDER_TARGET, flags = MASK_INVERSE)
/**
* Things placed on this mask the lighting plane. Doesn't render directly.
@ -104,7 +105,6 @@
* Always masks the light plane, isn't blocked by anything. Use for on mob glows,
* magic stuff, etc.
*/
/obj/screen/plane_master/emissive_unblockable
name = "unblockable emissive plane master"
plane = EMISSIVE_UNBLOCKABLE_PLANE
@ -145,3 +145,11 @@
appearance_flags = PLANE_MASTER
blend_mode = BLEND_OVERLAY
alpha = 0
/obj/screen/plane_master/o_light_visual
name = "overlight light visual plane master"
layer = O_LIGHTING_VISUAL_LAYER
plane = O_LIGHTING_VISUAL_PLANE
render_target = O_LIGHTING_VISUAL_RENDER_TARGET
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
blend_mode = BLEND_MULTIPLY

+ 362
- 0
code/datums/components/overlay_lighting.dm View File

@ -0,0 +1,362 @@
///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)
/**
* 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/obj/effect/overlay/light_visible/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
/datum/component/overlay_lighting/Initialize(_range, _power, _color, starts_on)
if(!ismovable(parent))
return COMPONENT_INCOMPATIBLE
var/atom/movable/movable_parent = parent
if(movable_parent.light_system != MOVABLE_LIGHT)
stack_trace("[type] added to [parent], with [movable_parent.light_system] value for the light_system var. Use [MOVABLE_LIGHT] instead.")
return COMPONENT_INCOMPATIBLE
. = ..()
visible_mask = new()
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()
. = ..()
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, .proc/on_parent_moved)
RegisterSignal(parent, COMSIG_ATOM_SET_LIGHT_RANGE, .proc/set_range)
RegisterSignal(parent, COMSIG_ATOM_SET_LIGHT_POWER, .proc/set_power)
RegisterSignal(parent, COMSIG_ATOM_SET_LIGHT_COLOR, .proc/set_color)
RegisterSignal(parent, COMSIG_ATOM_SET_LIGHT_ON, .proc/on_toggle)
RegisterSignal(parent, COMSIG_ATOM_SET_LIGHT_FLAGS, .proc/on_light_flags_change)
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_ATOM_SET_LIGHT_RANGE,
COMSIG_ATOM_SET_LIGHT_POWER,
COMSIG_ATOM_SET_LIGHT_COLOR,
COMSIG_ATOM_SET_LIGHT_ON,
COMSIG_ATOM_SET_LIGHT_FLAGS,
))
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()
QDEL_NULL(visible_mask)
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/t in affected_turfs)
var/turf/lit_turf = t
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
for(var/turf/lit_turf in view(lumcount_range, get_turf(current_holder)))
lit_turf.dynamic_lumcount += lum_power
LAZYADD(affected_turfs, lit_turf)
///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
get_new_turfs()
///Adds the luminosity and source for the afected movable atoms to keep track of their visibility.
/datum/component/overlay_lighting/proc/add_dynamic_lumi(atom/movable/affected_movable)
LAZYSET(affected_movable.affected_dynamic_lights, src, lumcount_range + 1)
affected_movable.vis_contents += visible_mask
affected_movable.update_dynamic_luminosity()
///Removes the luminosity and source for the afected movable atoms to keep track of their visibility.
/datum/component/overlay_lighting/proc/remove_dynamic_lumi(atom/movable/affected_movable)
LAZYREMOVE(affected_movable.affected_dynamic_lights, src)
affected_movable.vis_contents -= visible_mask
affected_movable.update_dynamic_luminosity()
///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_PARENT_QDELETING, COMSIG_MOVABLE_MOVED))
if(old_parent_attached_to == current_holder)
RegisterSignal(old_parent_attached_to, COMSIG_PARENT_QDELETING, .proc/on_holder_qdel)
RegisterSignal(old_parent_attached_to, COMSIG_MOVABLE_MOVED, .proc/on_holder_moved)
if(parent_attached_to)
if(parent_attached_to == current_holder)
UnregisterSignal(current_holder, list(COMSIG_PARENT_QDELETING, COMSIG_MOVABLE_MOVED))
RegisterSignal(parent_attached_to, COMSIG_PARENT_QDELETING, .proc/on_parent_attached_to_qdel)
RegisterSignal(parent_attached_to, COMSIG_MOVABLE_MOVED, .proc/on_parent_attached_to_moved)
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_PARENT_QDELETING, COMSIG_MOVABLE_MOVED))
if(overlay_lighting_flags & LIGHTING_ON)
remove_dynamic_lumi(current_holder)
current_holder = new_holder
if(new_holder == null)
clean_old_turfs()
return
if(overlay_lighting_flags & LIGHTING_ON)
add_dynamic_lumi(new_holder)
if(new_holder != parent && new_holder != parent_attached_to)
RegisterSignal(new_holder, COMSIG_PARENT_QDELETING, .proc/on_holder_qdel)
RegisterSignal(new_holder, COMSIG_MOVABLE_MOVED, .proc/on_holder_moved)
///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(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))
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
UnregisterSignal(current_holder, list(COMSIG_PARENT_QDELETING, COMSIG_MOVABLE_MOVED))
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()
///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_PARENT_QDELETING, COMSIG_MOVABLE_MOVED))
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, new_range)
SIGNAL_HANDLER
if(range == new_range)
return
if(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)
visible_mask.icon = light_overlays["[pixel_bounds]"]
if(pixel_bounds == 32)
visible_mask.transform = null
return
var/offset = (pixel_bounds - 32) * 0.5
var/matrix/transform = new
transform.Translate(-offset, -offset)
visible_mask.transform = transform
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, new_power)
SIGNAL_HANDLER
set_lum_power(new_power >= 0 ? 0.5 : -0.5)
set_alpha = min(230, (abs(new_power) * 120) + 30)
visible_mask.alpha = set_alpha
///Changes the light's color, pretty straightforward.
/datum/component/overlay_lighting/proc/set_color(atom/source, new_color)
SIGNAL_HANDLER
visible_mask.color = new_color
///Toggles the light on and off.
/datum/component/overlay_lighting/proc/on_toggle(atom/source, new_value)
SIGNAL_HANDLER
if(new_value) //Truthy value input, turn on.
turn_on()
return
turn_off() //Falsey value, turn off.
///Triggered right before the parent light flags change.
/datum/component/overlay_lighting/proc/on_light_flags_change(atom/source, new_value)
SIGNAL_HANDLER
var/atom/movable/movable_parent = parent
if(new_value & LIGHT_ATTACHED)
if(!(movable_parent.light_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 if(movable_parent.light_flags & LIGHT_ATTACHED) //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
if(current_holder)
add_dynamic_lumi(current_holder)
overlay_lighting_flags |= LIGHTING_ON
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(current_holder)
overlay_lighting_flags &= ~LIGHTING_ON
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/t in affected_turfs)
var/turf/lit_turf = t
lit_turf.dynamic_lumcount -= difference
#undef LIGHTING_ON
#undef LIGHTING_ATTACHED
#undef GET_PARENT

+ 2
- 1
code/datums/mutations/body.dm View File

@ -209,7 +209,8 @@
return
var/power = GET_MUTATION_POWER(src)
glowth.set_light(range * power, glow, glow_color)
glowth.set_light_range_power_color(range * power, glow, glow_color)
/// Returns the color for the glow effect
/datum/mutation/human/glow/proc/glow_color()


+ 5
- 1
code/game/atoms.dm View File

@ -92,6 +92,8 @@
/// Last appearance of the atom for demo saving purposes
var/image/demo_last_appearance
///Light systems, both shouldn't be active at the same time.
var/light_system = STATIC_LIGHT
///Range of the light in tiles. Zero means no light.
var/light_range = 0
///Intensity of the light. The stronger, the less shadows you will see on the lit area.
@ -100,6 +102,8 @@
var/light_color = COLOR_WHITE
///Boolean variable for toggleable lights. Has no effect without the proper light_system, light_range and light_power values.
var/light_on = TRUE
///Bitflags to determine lighting-related atom properties.
var/light_flags = NONE
///Our light source. Don't fuck with this directly unless you have a good reason!
var/tmp/datum/light_source/light
///Any light sources that are "inside" of us, for example, if src here was a mob that's carrying a flashlight, that flashlight's light source would be part of this list.
@ -204,7 +208,7 @@
if(color)
add_atom_colour(color, FIXED_COLOUR_PRIORITY)
if (light_power && light_range)
if (light_system == STATIC_LIGHT && light_power && light_range)
update_light()
if (length(smoothing_groups))


+ 7
- 0
code/game/atoms_movable.dm View File

@ -54,6 +54,11 @@
///Used for the calculate_adjacencies proc for icon smoothing.
var/can_be_unanchored = FALSE
///Lazylist to keep track on the sources of illumination.
var/list/affected_dynamic_lights
///Highest-intensity light affecting us, which determines our visibility.
var/affecting_dynamic_lumi = 0
/atom/movable/Initialize(mapload)
. = ..()
@ -66,6 +71,8 @@
vis_contents += em_block
if(opacity)
AddElement(/datum/element/light_blocking)
if(light_system == MOVABLE_LIGHT)
AddComponent(/datum/component/overlay_lighting)
/atom/movable/Destroy(force)


+ 76
- 89
code/game/machinery/dance_machine.dm View File

@ -185,60 +185,28 @@
var/turf/cen = get_turf(src)
FOR_DVIEW(var/turf/t, 3, get_turf(src),INVISIBILITY_LIGHTING)
if(t.x == cen.x && t.y > cen.y)
var/obj/item/flashlight/spotlight/L = new /obj/item/flashlight/spotlight(t)
L.set_light_color(COLOR_SOFT_RED)
L.set_light_power(30-(get_dist(src,L)*8))
L.range = 1+get_dist(src, L)
spotlights+=L
spotlights += new /obj/item/flashlight/spotlight(t, 1 + get_dist(src, t), 30 - (get_dist(src, t) * 8), COLOR_SOFT_RED)
continue
if(t.x == cen.x && t.y < cen.y)
var/obj/item/flashlight/spotlight/L = new /obj/item/flashlight/spotlight(t)
L.set_light_color(LIGHT_COLOR_PURPLE)
L.set_light_power(30-(get_dist(src,L)*8))
L.range = 1+get_dist(src, L)
spotlights+=L
spotlights += new /obj/item/flashlight/spotlight(t, 1 + get_dist(src, t), 30 - (get_dist(src, t) * 8), LIGHT_COLOR_PURPLE)
continue
if(t.x > cen.x && t.y == cen.y)
var/obj/item/flashlight/spotlight/L = new /obj/item/flashlight/spotlight(t)
L.set_light_color(LIGHT_COLOR_YELLOW)
L.set_light_power(30-(get_dist(src,L)*8))
L.range = 1+get_dist(src, L)
spotlights+=L
spotlights += new /obj/item/flashlight/spotlight(t, 1 + get_dist(src, t), 30 - (get_dist(src, t) * 8), LIGHT_COLOR_YELLOW)
continue
if(t.x < cen.x && t.y == cen.y)
var/obj/item/flashlight/spotlight/L = new /obj/item/flashlight/spotlight(t)
L.set_light_color(LIGHT_COLOR_GREEN)
L.set_light_power(30-(get_dist(src,L)*8))
L.range = 1+get_dist(src, L)
spotlights+=L
spotlights += new /obj/item/flashlight/spotlight(t, 1 + get_dist(src, t), 30 - (get_dist(src, t) * 8), LIGHT_COLOR_GREEN)
continue
if((t.x+1 == cen.x && t.y+1 == cen.y) || (t.x+2==cen.x && t.y+2 == cen.y))
var/obj/item/flashlight/spotlight/L = new /obj/item/flashlight/spotlight(t)
L.set_light_color(LIGHT_COLOR_ORANGE)
L.set_light_power(30-(get_dist(src,L)*8))
L.range = 1.4+get_dist(src, L)
spotlights+=L
spotlights += new /obj/item/flashlight/spotlight(t, 1.4 + get_dist(src, t), 30 - (get_dist(src, t) * 8), LIGHT_COLOR_ORANGE)
continue
if((t.x-1 == cen.x && t.y-1 == cen.y) || (t.x-2==cen.x && t.y-2 == cen.y))
var/obj/item/flashlight/spotlight/L = new /obj/item/flashlight/spotlight(t)
L.set_light_color(LIGHT_COLOR_CYAN)
L.set_light_power(30-(get_dist(src,L)*8))
L.range = 1.4+get_dist(src, L)
spotlights+=L
spotlights += new /obj/item/flashlight/spotlight(t, 1.4 + get_dist(src, t), 30 - (get_dist(src, t) * 8), LIGHT_COLOR_CYAN)
continue
if((t.x-1 == cen.x && t.y+1 == cen.y) || (t.x-2==cen.x && t.y+2 == cen.y))
var/obj/item/flashlight/spotlight/L = new /obj/item/flashlight/spotlight(t)
L.set_light_color(LIGHT_COLOR_BLUEGREEN)
L.set_light_power(30-(get_dist(src,L)*8))
L.range = 1.4+get_dist(src, L)
spotlights+=L
spotlights += new /obj/item/flashlight/spotlight(t, 1.4 + get_dist(src, t), 30 - (get_dist(src, t) * 8), LIGHT_COLOR_BLUEGREEN)
continue
if((t.x+1 == cen.x && t.y-1 == cen.y) || (t.x+2==cen.x && t.y-2 == cen.y))
var/obj/item/flashlight/spotlight/L = new /obj/item/flashlight/spotlight(t)
L.set_light_color(LIGHT_COLOR_BLUE)
L.set_light_power(30-(get_dist(src,L)*8))
L.range = 1.4+get_dist(src, L)
spotlights+=L
spotlights += new /obj/item/flashlight/spotlight(t, 1.4 + get_dist(src, t), 30 - (get_dist(src, t) * 8), LIGHT_COLOR_BLUE)
continue
continue
FOR_DVIEW_END
@ -270,61 +238,80 @@
sleep(7)
if(selection.song_name == "Engineering's Ultimate High-Energy Hustle")
sleep(280)
for(var/obj/reveal in sparkles)
for(var/s in sparkles)
var/obj/effect/overlay/sparkles/reveal = s
reveal.alpha = 255
while(active)
for(var/obj/item/flashlight/spotlight/glow in spotlights) // The multiples reflects custom adjustments to each colors after dozens of tests
if(QDELETED(src) || !active || QDELETED(glow))
for(var/g in spotlights) // The multiples reflects custom adjustments to each colors after dozens of tests
var/obj/item/flashlight/spotlight/glow = g
if(QDELETED(glow))
stack_trace("[glow?.gc_destroyed ? "Qdeleting glow" : "null entry"] found in [src].[gc_destroyed ? " Source qdeleting at the time." : ""]")
return
if(glow.light_color == COLOR_SOFT_RED)
glow.set_light_color(LIGHT_COLOR_BLUE)
glow.set_light_power(glow.light_power * 1.48)
glow.set_light_range(0)
glow.update_light()
continue
if(glow.light_color == LIGHT_COLOR_BLUE)
glow.set_light_color(LIGHT_COLOR_GREEN)
glow.set_light_range(glow.range * DISCO_INFENO_RANGE)
glow.set_light_power(glow.light_power * 2) // Any changes to power must come in pairs to neutralize it for other colors
glow.update_light()
continue
if(glow.light_color == LIGHT_COLOR_GREEN)
glow.set_light_color(LIGHT_COLOR_ORANGE)
glow.set_light_power(glow.light_power * 0.5)
glow.set_light_range(0)
glow.update_light()
continue
if(glow.light_color == LIGHT_COLOR_ORANGE)
glow.set_light_color(LIGHT_COLOR_PURPLE)
glow.set_light_power(glow.light_power * 2.27)
glow.set_light_range(glow.range * DISCO_INFENO_RANGE)
glow.update_light()
continue
if(glow.light_color == LIGHT_COLOR_PURPLE)
glow.set_light_color(LIGHT_COLOR_BLUEGREEN)
glow.set_light_power(glow.light_power * 0.44)
glow.set_light_range(0)
glow.update_light()
continue
if(glow.light_color == LIGHT_COLOR_BLUEGREEN)
glow.set_light_color(LIGHT_COLOR_YELLOW)
glow.set_light_range(glow.range * DISCO_INFENO_RANGE)
glow.update_light()
continue
if(glow.light_color == LIGHT_COLOR_YELLOW)
glow.set_light_color(LIGHT_COLOR_CYAN)
glow.set_light_range(0)
glow.update_light()
continue
if(glow.light_color == LIGHT_COLOR_CYAN)
glow.set_light_color(COLOR_SOFT_RED)
glow.set_light_power(glow.light_power * 0.68)
glow.set_light_range(glow.range * DISCO_INFENO_RANGE)
glow.update_light()
continue
switch(glow.light_color)
if(COLOR_SOFT_RED)
if(glow.even_cycle)
glow.set_light_on(FALSE)
glow.set_light_color(LIGHT_COLOR_BLUE)
else
glow.set_light_range_power_color(glow.base_light_range * DISCO_INFENO_RANGE, glow.light_power * 1.48, LIGHT_COLOR_BLUE)
glow.set_light_on(TRUE)
if(LIGHT_COLOR_BLUE)
if(glow.even_cycle)
glow.set_light_range_power_color(glow.base_light_range * DISCO_INFENO_RANGE, glow.light_power * 2, LIGHT_COLOR_GREEN)
glow.set_light_on(TRUE)
else
glow.set_light_on(FALSE)
glow.set_light_color(LIGHT_COLOR_GREEN)
if(LIGHT_COLOR_GREEN)
if(glow.even_cycle)
glow.set_light_on(FALSE)
glow.set_light_color(LIGHT_COLOR_ORANGE)
else
glow.set_light_range_power_color(glow.base_light_range * DISCO_INFENO_RANGE, glow.light_power * 0.5, LIGHT_COLOR_ORANGE)
glow.set_light_on(TRUE)
if(LIGHT_COLOR_ORANGE)
if(glow.even_cycle)
glow.set_light_range_power_color(glow.base_light_range * DISCO_INFENO_RANGE, glow.light_power * 2.27, LIGHT_COLOR_PURPLE)
glow.set_light_on(TRUE)
else
glow.set_light_on(FALSE)
glow.set_light_color(LIGHT_COLOR_PURPLE)
if(LIGHT_COLOR_PURPLE)
if(glow.even_cycle)
glow.set_light_on(FALSE)
glow.set_light_color(LIGHT_COLOR_BLUEGREEN)
else
glow.set_light_range_power_color(glow.base_light_range * DISCO_INFENO_RANGE, glow.light_power * 0.44, LIGHT_COLOR_BLUEGREEN)
glow.set_light_on(TRUE)
if(LIGHT_COLOR_BLUEGREEN)
if(glow.even_cycle)
glow.set_light_range(glow.base_light_range * DISCO_INFENO_RANGE)
glow.set_light_color(LIGHT_COLOR_YELLOW)
glow.set_light_on(TRUE)
else
glow.set_light_on(FALSE)
glow.set_light_color(LIGHT_COLOR_YELLOW)
if(LIGHT_COLOR_YELLOW)
if(glow.even_cycle)
glow.set_light_on(FALSE)
glow.set_light_color(LIGHT_COLOR_CYAN)
else
glow.set_light_range(glow.base_light_range * DISCO_INFENO_RANGE)
glow.set_light_color(LIGHT_COLOR_CYAN)
glow.set_light_on(TRUE)
if(LIGHT_COLOR_CYAN)
if(glow.even_cycle)
glow.set_light_range_power_color(glow.base_light_range * DISCO_INFENO_RANGE, glow.light_power * 0.68, COLOR_SOFT_RED)
glow.set_light_on(TRUE)
else
glow.set_light_on(FALSE)
glow.set_light_color(COLOR_SOFT_RED)
glow.even_cycle = !glow.even_cycle
if(prob(2)) // Unique effects for the dance floor that show up randomly to mix things up
INVOKE_ASYNC(src, .proc/hierofunk)
sleep(selection.song_beat)
if(QDELETED(src))
return
#undef DISCO_INFENO_RANGE


+ 11
- 1
code/game/machinery/flasher.dm View File

@ -25,6 +25,9 @@
anchored = FALSE
base_state = "pflash"
density = TRUE
light_system = MOVABLE_LIGHT //Used as a flash here.
light_range = FLASH_LIGHT_RANGE
light_on = FALSE
/obj/machinery/flasher/Initialize(mapload, ndir = 0, built = 0)
. = ..() // ..() is EXTREMELY IMPORTANT, never forget to add it
@ -35,6 +38,7 @@
else
bulb = new(src)
/obj/machinery/flasher/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override=FALSE)
id = "[idnum][id]"
@ -107,7 +111,9 @@
playsound(src.loc, 'sound/weapons/flash.ogg', 100, TRUE)
flick("[base_state]_flash", src)
flash_lighting_fx(FLASH_LIGHT_RANGE, light_power, light_color)
set_light_on(TRUE)
addtimer(CALLBACK(src, .proc/flash_end), FLASH_LIGHT_DURATION, TIMER_OVERRIDE|TIMER_UNIQUE)
last_flash = world.time
use_power(1000)
@ -126,6 +132,10 @@
return 1
/obj/machinery/flasher/proc/flash_end()
set_light_on(FALSE)
/obj/machinery/flasher/emp_act(severity)
. = ..()
if(!(machine_stat & (BROKEN|NOPOWER)) && !(. & EMP_PROTECT_SELF))


+ 26
- 16
code/game/mecha/combat/durand.dm View File

@ -13,18 +13,19 @@
wreckage = /obj/structure/mecha_wreckage/durand
var/obj/durand_shield/shield
/obj/mecha/combat/durand/Initialize()
shield = new/obj/durand_shield
shield.chassis = src
shield.layer = layer
. = ..()
shield = new /obj/durand_shield(loc, src, layer, dir)
RegisterSignal(src, COMSIG_MECHA_ACTION_ACTIVATE, .proc/relay)
RegisterSignal(src, COMSIG_PROJECTILE_PREHIT, .proc/prehit)
. = ..()
/obj/mecha/combat/durand/Destroy()
if(shield)
qdel(shield)
. = ..()
QDEL_NULL(shield)
return ..()
/obj/mecha/combat/durand/GrantActions(mob/living/user, human_occupant = 0)
..()
@ -43,7 +44,7 @@
. = ..()
if(shield)
shield.forceMove(loc)
shield.dir = dir
shield.setDir(dir)
/obj/mecha/combat/durand/forceMove(turf/T)
. = ..()
@ -59,11 +60,9 @@
SIGNAL_HANDLER
if(!shield) //if the shield somehow got deleted
shield = new/obj/durand_shield
shield.chassis = src
shield.layer = layer
shield.forceMove(loc)
shield.dir = dir
stack_trace("Durand triggered relay without a shield")
shield = new /obj/durand_shield(loc, src, layer)
shield.setDir(dir)
SEND_SIGNAL(shield, COMSIG_MECHA_ACTION_ACTIVATE, source, signal_args)
//Redirects projectiles to the shield if defense_check decides they should be blocked and returns true.
@ -143,17 +142,28 @@ own integrity back to max. Shield is automatically dropped if we run out of powe
max_integrity = 10000
obj_integrity = 10000
anchored = TRUE
light_system = MOVABLE_LIGHT
light_range = MINIMUM_USEFUL_LIGHT_RANGE
light_power = 5
light_color = LIGHT_COLOR_ELECTRIC_CYAN
light_on = FALSE
var/obj/mecha/combat/durand/chassis ///Our link back to the durand
var/switching = FALSE ///To keep track of things during the animation
/obj/durand_shield/Initialize()
/obj/durand_shield/Initialize(mapload, _chassis, _layer, _dir)
. = ..()
chassis = _chassis
layer = _layer
setDir(_dir)
RegisterSignal(src, COMSIG_MECHA_ACTION_ACTIVATE, .proc/activate)
/obj/durand_shield/Destroy()
if(chassis)
chassis.shield = null
. = ..()
chassis = null
return ..()
/**Handles activating and deactivating the shield. This proc is called by a signal sent from the mech's action button
and relayed by the mech itself. The "forced" variabe, signal_args[1], will skip the to-pilot text and is meant for when
@ -179,11 +189,12 @@ the shield is disabled by means other than the action button (like running out o
chassis.log_message("defense mode state changed -- now [chassis.defense_mode?"enabled":"disabled"].", LOG_MECHA)
chassis.defense_action.UpdateButtonIcon()
set_light_on(chassis.defense_mode)
if(chassis.defense_mode)
invisibility = 0
flick("shield_raise", src)
playsound(src, 'sound/mecha/mech_shield_raise.ogg', 50, FALSE)
set_light(l_range = MINIMUM_USEFUL_LIGHT_RANGE , l_power = 5, l_color = "#00FFFF")
addtimer(CALLBACK(src, .proc/shield_icon_enable), 3)
else
flick("shield_drop", src)
@ -195,7 +206,6 @@ the shield is disabled by means other than the action button (like running out o
icon_state = "shield"
/obj/durand_shield/proc/shield_icon_reset()
set_light(0)
icon_state = "shield_null"
invisibility = INVISIBILITY_MAXIMUM //no showing on right-click


+ 2
- 0
code/game/mecha/mecha.dm View File

@ -10,6 +10,8 @@
infra_luminosity = 15 //byond implementation is bugged.
force = 5
flags_1 = HEAR_1
light_system = MOVABLE_LIGHT
light_on = FALSE
var/ruin_mecha = FALSE //if the mecha starts on a ruin, don't automatically give it a tracking beacon to prevent metagaming.
var/can_move = 0 //time of next allowed movement
var/mob/living/carbon/occupant = null


+ 1
- 2
code/game/mecha/mecha_actions.dm View File

@ -112,11 +112,10 @@
return
chassis.lights = !chassis.lights
if(chassis.lights)
chassis.set_light(chassis.lights_power)
button_icon_state = "mech_lights_on"
else
chassis.set_light(-chassis.lights_power)
button_icon_state = "mech_lights_off"
chassis.set_light_on(chassis.lights)
chassis.occupant_message("<span class='notice'>Toggled lights [chassis.lights?"on":"off"].</span>")
chassis.log_message("Toggled lights [chassis.lights?"on":"off"].", LOG_MECHA)
UpdateButtonIcon()


+ 19
- 0
code/game/movable_luminosity.dm View File

@ -0,0 +1,19 @@
///Keeps track of the sources of dynamic luminosity and updates our visibility with the highest.
/atom/movable/proc/update_dynamic_luminosity()
var/highest = 0
for(var/i in affected_dynamic_lights)
if(affected_dynamic_lights[i] <= highest)
continue
highest = affected_dynamic_lights[i]
if(highest == affecting_dynamic_lumi)
return
luminosity -= affecting_dynamic_lumi
affecting_dynamic_lumi = highest
luminosity += affecting_dynamic_lumi
///Helper to change several lighting overlay settings.
/atom/movable/proc/set_light_range_power_color(range, power, color)
set_light_range(range)
set_light_power(power)
set_light_color(color)

+ 3
- 2
code/game/objects/effects/effect_system/effects_sparks.dm View File

@ -20,8 +20,9 @@
name = "sparks"
icon_state = "sparks"
anchored = TRUE
light_power = 1.3
light_range = MINIMUM_USEFUL_LIGHT_RANGE
light_system = MOVABLE_LIGHT
light_range = 2
light_power = 0.5
light_color = LIGHT_COLOR_FIRE
/obj/effect/particle_effect/sparks/Initialize()


+ 8
- 2
code/game/objects/effects/misc.dm View File

@ -75,13 +75,19 @@
name = "lighting fx obj"
desc = "Tell a coder if you're seeing this."
icon_state = "nothing"
light_system = MOVABLE_LIGHT
light_range = MINIMUM_USEFUL_LIGHT_RANGE
light_color = COLOR_WHITE
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
/obj/effect/dummy/lighting_obj/Initialize(mapload, _color, _range, _power, _duration)
/obj/effect/dummy/lighting_obj/Initialize(mapload, _range, _power, _color, _duration)
. = ..()
set_light(_range ? _range : light_range, _power ? _power : light_power, _color ? _color : light_color)
if(!isnull(_range))
set_light_range(_range)
if(!isnull(_power))
set_light_power(_power)
if(!isnull(_color))
set_light_color(_color)
if(_duration)
QDEL_IN(src, _duration)


+ 11
- 0
code/game/objects/effects/overlays.dm View File

@ -64,3 +64,14 @@
layer = ATMOS_GROUP_LAYER
plane = ATMOS_GROUP_PLANE
/obj/effect/overlay/light_visible
name = ""
icon = 'icons/effects/light_overlays/light_32.dmi'
icon_state = "light"
layer = O_LIGHTING_VISUAL_LAYER
plane = O_LIGHTING_VISUAL_PLANE
appearance_flags = RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
alpha = 0
vis_flags = NONE

+ 7
- 2
code/game/objects/items/cigs_lighters.dm View File

@ -621,7 +621,11 @@ CIGARETTE PACKETS ARE IN FANCY.DM
resistance_flags = FIRE_PROOF
grind_results = list(/datum/reagent/iron = 1, /datum/reagent/fuel = 5, /datum/reagent/fuel/oil = 5)
custom_price = 55
light_system = MOVABLE_LIGHT
light_range = 2
light_power = 0.6
light_color = LIGHT_COLOR_FIRE
light_on = FALSE
var/lit = 0
var/fancy = TRUE
var/overlay_state
@ -667,6 +671,8 @@ CIGARETTE PACKETS ARE IN FANCY.DM
. = "<span class='rose'>With a single flick of [user.p_their()] wrist, [user] smoothly lights [A] with [src]. Damn [user.p_theyre()] cool.</span>"
/obj/item/lighter/proc/set_lit(new_lit)
if(lit == new_lit)
return
lit = new_lit
if(lit)
force = 5
@ -674,15 +680,14 @@ CIGARETTE PACKETS ARE IN FANCY.DM
hitsound = 'sound/items/welder.ogg'
attack_verb_continuous = list("burns", "sings")
attack_verb_simple = list("burn", "sing")
set_light(1)
START_PROCESSING(SSobj, src)
else
hitsound = "swing_hit"
force = 0
attack_verb_continuous = null //human_defense.dm takes care of it
attack_verb_simple = null
set_light(0)
STOP_PROCESSING(SSobj, src)
set_light_on(lit)
update_icon()
/obj/item/lighter/extinguish()


+ 11
- 13
code/game/objects/items/devices/PDA/PDA.dm View File

@ -26,7 +26,11 @@ GLOBAL_LIST_EMPTY(PDAs)
actions_types = list(/datum/action/item_action/toggle_light)
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100)
resistance_flags = FIRE_PROOF | ACID_PROOF
light_system = MOVABLE_LIGHT
light_range = 2.3
light_power = 0.6
light_color = "#FFCC66"
light_on = FALSE
//Main variables
var/owner = null // String name of owner
@ -49,8 +53,6 @@ GLOBAL_LIST_EMPTY(PDAs)
//Secondary variables
var/scanmode = PDA_SCANNER_NONE
var/fon = FALSE //Is the flashlight function on?
var/f_lum = 2.3 //Luminosity for the flashlight function
var/silent = FALSE //To beep or not to beep, that is the question
var/toff = FALSE //If TRUE, messenger disabled
var/tnote = null //Current Texts
@ -106,8 +108,6 @@ GLOBAL_LIST_EMPTY(PDAs)
/obj/item/pda/Initialize()
. = ..()
if(fon)
set_light(f_lum)
GLOB.PDAs += src
if(default_cartridge)
@ -175,7 +175,7 @@ GLOBAL_LIST_EMPTY(PDAs)
if(inserted_item)
overlay.icon_state = "insert_overlay"
. += new /mutable_appearance(overlay)
if(fon)
if(light_on)
overlay.icon_state = "light_overlay"
. += new /mutable_appearance(overlay)
if(pai)
@ -311,7 +311,7 @@ GLOBAL_LIST_EMPTY(PDAs)
if (cartridge.access & CART_DRONEPHONE)
dat += "<li><a href='byond://?src=[REF(src)];choice=Drone Phone'>[PDAIMG(dronephone)]Drone Phone</a></li>"
dat += "<li><a href='byond://?src=[REF(src)];choice=3'>[PDAIMG(atmos)]Atmospheric Scan</a></li>"
dat += "<li><a href='byond://?src=[REF(src)];choice=Light'>[PDAIMG(flashlight)][fon ? "Disable" : "Enable"] Flashlight</a></li>"
dat += "<li><a href='byond://?src=[REF(src)];choice=Light'>[PDAIMG(flashlight)][light_on ? "Disable" : "Enable"] Flashlight</a></li>"
if (pai)
if(pai.loc != src)
pai = null
@ -835,12 +835,10 @@ GLOBAL_LIST_EMPTY(PDAs)
/obj/item/pda/proc/toggle_light(mob/user)
if(issilicon(user) || !user.canUseTopic(src, BE_CLOSE))
return
if(fon)
fon = FALSE
set_light(0)
else if(f_lum)
fon = TRUE
set_light(f_lum)
if(light_on)
set_light_on(FALSE)
else if(light_range)
set_light_on(TRUE)
update_icon()
for(var/X in actions)
var/datum/action/A = X


+ 1
- 1
code/game/objects/items/devices/PDA/PDA_types.dm View File

@ -43,7 +43,7 @@
/obj/item/pda/ai
icon = null
ttone = "data"
fon = FALSE
/obj/item/pda/ai/attack_self(mob/user)
if ((honkamt > 0) && (prob(60)))//For clown virus.


+ 60
- 31
code/game/objects/items/devices/flashlight.dm View File

@ -13,9 +13,12 @@
slot_flags = ITEM_SLOT_BELT
custom_materials = list(/datum/material/iron=50, /datum/material/glass=20)
actions_types = list(/datum/action/item_action/toggle_light)
light_system = MOVABLE_LIGHT
light_range = 4
light_power = 1
light_on = FALSE
var/on = FALSE
var/brightness_on = 4 //range of light when on
var/flashlight_power = 1 //strength of the light when on
/obj/item/flashlight/Initialize()
. = ..()
@ -23,16 +26,13 @@
on = TRUE
update_brightness()
/obj/item/flashlight/proc/update_brightness(mob/user = null)
/obj/item/flashlight/proc/update_brightness(mob/user)
if(on)
icon_state = "[initial(icon_state)]-on"
if(flashlight_power)
set_light(l_range = brightness_on, l_power = flashlight_power)
else
set_light(brightness_on)
else
icon_state = initial(icon_state)
set_light(0)
set_light_on(on)
/obj/item/flashlight/attack_self(mob/user)
on = !on
@ -64,7 +64,7 @@
to_chat(user, "<span class='warning'>[M] doesn't have a head!</span>")
return
if(flashlight_power < 1)
if(light_power < 1)
to_chat(user, "<span class='warning'>\The [src] isn't bright enough to see anything!</span> ")
return
@ -169,7 +169,7 @@
inhand_icon_state = ""
worn_icon_state = "pen"
flags_1 = CONDUCT_1
brightness_on = 2
light_range = 2
var/holo_cooldown = 0
/obj/item/flashlight/pen/afterattack(atom/target, mob/user, proximity_flag)
@ -217,7 +217,7 @@
lefthand_file = 'icons/mob/inhands/equipment/security_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/security_righthand.dmi'
force = 9 // Not as good as a stun baton.
brightness_on = 5 // A little better than the standard flashlight.
light_range = 5 // A little better than the standard flashlight.
hitsound = 'sound/weapons/genhit1.ogg'
// the desk lamps are a bit special
@ -229,7 +229,7 @@
lefthand_file = 'icons/mob/inhands/items_lefthand.dmi'
righthand_file = 'icons/mob/inhands/items_righthand.dmi'
force = 10
brightness_on = 5
light_range = 5
w_class = WEIGHT_CLASS_BULKY
flags_1 = CONDUCT_1
custom_materials = null
@ -265,7 +265,7 @@
name = "flare"
desc = "A red Nanotrasen issued flare. There are instructions on the side, it reads 'pull cord, make light'."
w_class = WEIGHT_CLASS_SMALL
brightness_on = 7 // Pretty bright.
light_range = 7 // Pretty bright.
icon_state = "flare"
inhand_icon_state = "flare"
worn_icon_state = "flare"
@ -335,7 +335,7 @@
name = "torch"
desc = "A torch fashioned from some leaves and a log."
w_class = WEIGHT_CLASS_BULKY
brightness_on = 4
light_range = 4
icon_state = "torch"
inhand_icon_state = "torch"
lefthand_file = 'icons/mob/inhands/items_lefthand.dmi'
@ -351,19 +351,19 @@
lefthand_file = 'icons/mob/inhands/equipment/mining_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/mining_righthand.dmi'
desc = "A mining lantern."
brightness_on = 6 // luminosity when on
light_range = 6 // luminosity when on
/obj/item/flashlight/lantern/heirloom_moth
name = "old lantern"
desc = "An old lantern that has seen plenty of use."
brightness_on = 4
light_range = 4
/obj/item/flashlight/lantern/syndicate
name = "suspicious lantern"
desc = "A suspicious looking lantern."
icon_state = "syndilantern"
inhand_icon_state = "syndilantern"
brightness_on = 10
light_range = 10
/obj/item/flashlight/lantern/jade
name = "jade lantern"
@ -381,7 +381,7 @@
w_class = WEIGHT_CLASS_SMALL
slot_flags = ITEM_SLOT_BELT
custom_materials = null
brightness_on = 6 //luminosity when on
light_range = 6 //luminosity when on
/obj/item/flashlight/emp
var/emp_max_charges = 4
@ -442,7 +442,7 @@
desc = "A military-grade glowstick."
custom_price = 50
w_class = WEIGHT_CLASS_SMALL
brightness_on = 4
light_range = 4
color = LIGHT_COLOR_GREEN
icon_state = "glowstick"
inhand_icon_state = "glowstick"
@ -450,14 +450,17 @@
grind_results = list(/datum/reagent/phenol = 15, /datum/reagent/hydrogen = 10, /datum/reagent/oxygen = 5) //Meth-in-a-stick
var/fuel = 0
/obj/item/flashlight/glowstick/Initialize()
fuel = rand(1600, 2000)
set_light_color(color)
. = ..()
return ..()
/obj/item/flashlight/glowstick/Destroy()
STOP_PROCESSING(SSobj, src)
. = ..()
return ..()
/obj/item/flashlight/glowstick/process()
fuel = max(fuel - 1, 0)
@ -476,13 +479,13 @@
if(!fuel)
icon_state = "glowstick-empty"
cut_overlays()
set_light(0)
set_light_on(FALSE)
else if(on)
var/mutable_appearance/glowstick_overlay = mutable_appearance(icon, "glowstick-glow")
glowstick_overlay.color = color
add_overlay(glowstick_overlay)
inhand_icon_state = "glowstick-on"
set_light(brightness_on)
set_light_on(TRUE)
else
icon_state = "glowstick"
cut_overlays()
@ -549,30 +552,56 @@
name = "disco light"
desc = "Groovy..."
icon_state = null
light_color = COLOR_WHITE
brightness_on = 0
light_range = 0
light_range = 4
light_power = 10
alpha = 0
layer = 0
on = TRUE
anchored = TRUE
var/range = null
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
///Boolean that switches when a full color flip ends, so the light can appear in all colors.
var/even_cycle = FALSE
///Base light_range that can be set on Initialize to use in smooth light range expansions and contractions.
var/base_light_range = 4
/obj/item/flashlight/spotlight/Initialize(mapload, _light_range, _light_power, _light_color)
. = ..()
if(!isnull(_light_range))
base_light_range = _light_range
set_light_range(_light_range)
if(!isnull(_light_power))
set_light_power(_light_power)
if(!isnull(_light_color))
set_light_color(_light_color)
/obj/item/flashlight/flashdark
name = "flashdark"
desc = "A strange device manufactured with mysterious elements that somehow emits darkness. Or maybe it just sucks in light? Nobody knows for sure."
icon_state = "flashdark"
inhand_icon_state = "flashdark"
brightness_on = 2.5
flashlight_power = -3
light_system = STATIC_LIGHT //The overlay light component is not yet ready to produce darkness.
light_range = 0
///Variable to preserve old lighting behavior in flashlights, to handle darkness.
var/dark_light_range = 2.5
///Variable to preserve old lighting behavior in flashlights, to handle darkness.
var/dark_light_power = -3
/obj/item/flashlight/flashdark/update_brightness(mob/user)
. = ..()
if(on)
set_light(dark_light_range, dark_light_power)
else
set_light(0)
/obj/item/flashlight/eyelight
name = "eyelight"
desc = "This shouldn't exist outside of someone's head, how are you seeing this?"
brightness_on = 15
flashlight_power = 1
light_range = 15
light_power = 1
flags_1 = CONDUCT_1
item_flags = DROPDEL
actions_types = list()

+ 7
- 3
code/game/objects/items/dualsaber.dm View File

@ -16,7 +16,10 @@
w_class = WEIGHT_CLASS_SMALL
hitsound = "swing_hit"
armour_penetration = 35
light_system = MOVABLE_LIGHT
light_range = 6 //TWICE AS BRIGHT AS A REGULAR ESWORD
light_color = LIGHT_COLOR_ELECTRIC_GREEN
light_on = FALSE
attack_verb_continuous = list("attacks", "slashes", "stabs", "slices", "tears", "lacerates", "rips", "dices", "cuts")
attack_verb_simple = list("attack", "slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "cut")
block_chance = 75
@ -29,7 +32,6 @@
var/saber_color = "green"
var/two_hand_force = 34
var/hacked = FALSE
var/brightness_on = 6 //TWICE AS BRIGHT AS A REGULAR ESWORD
var/list/possible_colors = list("red", "blue", "green", "purple")
var/wielded = FALSE // track wielded status on item
@ -50,7 +52,8 @@
w_class = w_class_on
hitsound = 'sound/weapons/blade1.ogg'
START_PROCESSING(SSobj, src)
set_light(brightness_on)
set_light_on(TRUE)
/// Triggered on unwield of two handed item
/// switch hitsounds
@ -61,7 +64,8 @@
w_class = initial(w_class)
hitsound = "swing_hit"
STOP_PROCESSING(SSobj, src)
set_light(0)
set_light_on(FALSE)
/obj/item/dualsaber/get_sharpness()
return wielded * sharpness


+ 3
- 2
code/game/objects/items/flamethrower.dm View File

@ -15,6 +15,8 @@
custom_materials = list(/datum/material/iron=500)
resistance_flags = FIRE_PROOF
trigger_guard = TRIGGER_GUARD_NORMAL
light_system = MOVABLE_LIGHT
light_on = FALSE
var/status = FALSE
var/lit = FALSE //on or off
var/operating = FALSE//cooldown
@ -165,16 +167,15 @@
to_chat(user, "<span class='notice'>You [lit ? "extinguish" : "ignite"] [src]!</span>")
lit = !lit
if(lit)
set_light(1)
playsound(loc, acti_sound, 50, TRUE)
START_PROCESSING(SSobj, src)
if(!warned_admins)
message_admins("[ADMIN_LOOKUPFLW(user)] has lit a flamethrower.")
warned_admins = TRUE
else
set_light(0)
playsound(loc, deac_sound, 50, TRUE)
STOP_PROCESSING(SSobj,src)
set_light_on(lit)
update_icon()
/obj/item/flamethrower/CheckParts(list/parts_list)


+ 2
- 2
code/game/objects/items/grenades/flashbang.dm View File

@ -14,7 +14,7 @@
return
do_sparks(rand(5, 9), FALSE, src)
playsound(flashbang_turf, 'sound/weapons/flashbang.ogg', 100, TRUE, 8, 0.9)
new /obj/effect/dummy/lighting_obj (flashbang_turf, COLOR_WHITE, (flashbang_range + 2), 4, 2)
new /obj/effect/dummy/lighting_obj (flashbang_turf, flashbang_range + 2, 4, COLOR_WHITE, 2)
for(var/mob/living/M in get_hearers_in_view(flashbang_range, flashbang_turf))
bang(get_turf(M), M)
qdel(src)
@ -82,7 +82,7 @@
return
do_sparks(rand(5, 9), FALSE, src)
playsound(flashbang_turf, 'sound/weapons/flashbang.ogg', 50, TRUE, 8, 0.9)
new /obj/effect/dummy/lighting_obj (flashbang_turf, COLOR_WHITE, (flashbang_range + 2), 2, 1)
new /obj/effect/dummy/lighting_obj (flashbang_turf, flashbang_range + 2, 2, COLOR_WHITE, 1)
for(var/mob/living/M in get_hearers_in_view(flashbang_range, flashbang_turf))
pop(get_turf(M), M)
qdel(src)


+ 1
- 1
code/game/objects/items/grenades/hypno.dm View File

@ -15,7 +15,7 @@
return
do_sparks(rand(5, 9), FALSE, src)
playsound(flashbang_turf, 'sound/effects/screech.ogg', 100, TRUE, 8, 0.9)
new /obj/effect/dummy/lighting_obj (flashbang_turf, LIGHT_COLOR_PURPLE, (flashbang_range + 2), 4, 2)
new /obj/effect/dummy/lighting_obj (flashbang_turf, flashbang_range + 2, 4, LIGHT_COLOR_PURPLE, 2)
for(var/mob/living/M in get_hearers_in_view(flashbang_range, flashbang_turf))
bang(get_turf(M), M)
qdel(src)


+ 6
- 5
code/game/objects/items/melee/energy.dm View File

@ -5,13 +5,15 @@
max_integrity = 200
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 30)
resistance_flags = FIRE_PROOF
var/brightness_on = 3
light_system = MOVABLE_LIGHT
light_range = 3
light_power = 1
light_on = FALSE
var/sword_color
/obj/item/melee/transforming/energy/Initialize()
. = ..()
if(active)
set_light(brightness_on)
START_PROCESSING(SSobj, src)
/obj/item/melee/transforming/energy/Destroy()
@ -40,10 +42,10 @@
if(sword_color)
icon_state = "sword[sword_color]"
START_PROCESSING(SSobj, src)
set_light(brightness_on)
else
STOP_PROCESSING(SSobj, src)
set_light(0)
set_light_on(active)
/obj/item/melee/transforming/energy/get_temperature()
return active * heat
@ -167,7 +169,6 @@
if(hacked)
var/set_color = pick(possible_colors)
set_light_color(possible_colors[set_color])
update_light()
/obj/item/melee/transforming/energy/sword/saber/red
possible_colors = list("red" = COLOR_SOFT_RED)


+ 4
- 3
code/game/objects/items/pitchfork.dm View File

@ -45,10 +45,11 @@
desc = "A red pitchfork, it looks like the work of the devil."
force = 19
throwforce = 24
light_system = MOVABLE_LIGHT
light_range = 3
light_power = 6
light_color = COLOR_SOFT_RED
/obj/item/pitchfork/demonic/Initialize()
. = ..()
set_light(3,6,COLOR_SOFT_RED)
/obj/item/pitchfork/demonic/ComponentInitialize()
. = ..()


+ 24
- 11
code/game/objects/items/tools/weldingtool.dm View File

@ -16,7 +16,11 @@
usesound = list('sound/items/welder.ogg', 'sound/items/welder2.ogg')
drop_sound = 'sound/items/handling/weldingtool_drop.ogg'
pickup_sound = 'sound/items/handling/weldingtool_pickup.ogg'
light_system = MOVABLE_LIGHT
light_range = 2
light_power = 0.75
light_color = LIGHT_COLOR_FIRE
light_on = FALSE
throw_speed = 3
throw_range = 5
w_class = WEIGHT_CLASS_SMALL
@ -28,12 +32,12 @@
wound_bonus = 10
bare_wound_bonus = 15
custom_materials = list(/datum/material/iron=70, /datum/material/glass=30)
var/welding = 0 //Whether or not the welding tool is off(0), on(1) or currently welding(2)
///Whether the welding tool is on or off.
var/welding = FALSE
var/status = TRUE //Whether the welder is secured or unsecured (able to attach rods to it to make a flamethrower)
var/max_fuel = 20 //The max amount of fuel the welder can hold
var/change_icons = 1
var/can_off_process = 0
var/light_intensity = 2 //how powerful the emitted light is when used.
var/burned_fuel_for = 0 //when fuel was last removed
var/acti_sound = 'sound/items/welderactivate.ogg'
var/deac_sound = 'sound/items/welderdeactivate.ogg'
@ -47,7 +51,7 @@
/obj/item/weldingtool/ComponentInitialize()
. = ..()
AddElement(/datum/element/update_icon_updates_onmob)
AddElement(/datum/element/tool_flash, light_intensity)
AddElement(/datum/element/tool_flash, light_range)
/obj/item/weldingtool/update_icon_state()
if(welding)
@ -158,16 +162,16 @@
message_admins("[ADMIN_LOOKUPFLW(user)] set [key_name_admin(L)] on fire with [src] at [AREACOORD(user)]")
log_game("[key_name(user)] set [key_name(L)] on fire with [src] at [AREACOORD(user)]")
/obj/item/weldingtool/attack_self(mob/user)
if(src.reagents.has_reagent(/datum/reagent/toxin/plasma))
message_admins("[ADMIN_LOOKUPFLW(user)] activated a rigged welder at [AREACOORD(user)].")
explode()
switched_on(user)
if(welding)
set_light(light_intensity)
update_icon()
// Ah fuck, I can't believe you've done this
/obj/item/weldingtool/proc/handle_fuel_and_temps(used = 0, mob/living/user)
use(used)
@ -194,10 +198,19 @@
return FALSE
//Toggles the welding value.
/obj/item/weldingtool/proc/set_welding(new_value)
if(welding == new_value)
return
. = welding
welding = new_value
set_light_on(welding)
//Turns off the welder if there is no more fuel (does this really need to be its own proc?)
/obj/item/weldingtool/proc/check_fuel(mob/user)
if(get_fuel() <= 0 && welding)
set_light(0)
set_light_on(FALSE)
switched_on(user)
update_icon()
return 0
@ -208,7 +221,7 @@
if(!status)
to_chat(user, "<span class='warning'>[src] can't be turned on while unsecured!</span>")
return
welding = !welding
set_welding(!welding)
if(welding)
if(get_fuel() >= 1)
to_chat(user, "<span class='notice'>You switch [src] on.</span>")
@ -228,8 +241,7 @@
//Switches the welder off
/obj/item/weldingtool/proc/switched_off(mob/user)
welding = 0
set_light(0)
set_welding(FALSE)
force = 3
damtype = "brute"
@ -335,7 +347,8 @@
icon = 'icons/obj/abductor.dmi'
icon_state = "welder"
toolspeed = 0.1
light_intensity = 0
light_system = NO_LIGHT_SUPPORT
light_range = 0
change_icons = 0
/obj/item/weldingtool/abductor/process()
@ -360,7 +373,7 @@
custom_materials = list(/datum/material/iron=70, /datum/material/glass=120)
change_icons = 0
can_off_process = 1
light_intensity = 1
light_range = 1
toolspeed = 0.5
var/last_gen = 0
var/nextrefueltick = 0


+ 1
- 1
code/game/turfs/open/space/space.dm View File

@ -57,7 +57,7 @@
if(requires_activation)
SSair.add_to_active(src)
if (light_power && light_range)
if (light_system == STATIC_LIGHT && light_power && light_range)
update_light()
if (opacity)


+ 3
- 0
code/game/turfs/turf.dm View File

@ -38,6 +38,9 @@ GLOBAL_LIST_EMPTY(station_turfs)
///Icon-smoothing variable to map a diagonal wall corner with a fixed underlay.
var/list/fixed_underlay = null
///Lumcount added by sources other than lighting datum objects, such as the overlay lighting component.
var/dynamic_lumcount = 0
var/dynamic_lighting = TRUE
var/tmp/lighting_corners_initialised = FALSE


+ 2
- 2
code/modules/antagonists/cult/blood_magic.dm View File

@ -421,12 +421,12 @@
user.visible_message("<span class='warning'>[user] holds up [user.p_their()] hand, which explodes in a flash of red light!</span>", \
"<span class='cultitalic'>You attempt to stun [L] with the spell!</span>")
user.mob_light(_color = LIGHT_COLOR_BLOOD_MAGIC, _range = 3, _duration = 2)
user.mob_light(_range = 3, _color = LIGHT_COLOR_BLOOD_MAGIC, _duration = 0.2 SECONDS)
var/anti_magic_source = L.anti_magic_check()
if(anti_magic_source)