diff --git a/code/__defines/turfs.dm b/code/__defines/turfs.dm index cbcc45c1f5..679b83fa4a 100644 --- a/code/__defines/turfs.dm +++ b/code/__defines/turfs.dm @@ -20,4 +20,5 @@ #define isDiagonal(x) (x == NORTHEAST || x == SOUTHEAST || x == NORTHWEST || x == SOUTHWEST) #define IS_OPAQUE_TURF(turf) (turf.directional_opacity == ALL_CARDINALS) +#define IS_OPAQUE_TURF_DIR(turf, dir) (turf.directional_opacity & dir) #define FOOTSTEP_SPRITE_AMT 2 diff --git a/code/controllers/subsystems/planets.dm b/code/controllers/subsystems/planets.dm index c9a4a2db43..16fbe59d3a 100644 --- a/code/controllers/subsystems/planets.dm +++ b/code/controllers/subsystems/planets.dm @@ -104,7 +104,7 @@ SUBSYSTEM_DEF(planets) /datum/controller/subsystem/planets/proc/updateSunlight(var/datum/planet/P) var/new_brightness = P.sun["brightness"] - P.sun_holder.update_brightness(new_brightness) + P.sun_holder.update_brightness(new_brightness, P.planet_floors) var/new_color = P.sun["color"] P.sun_holder.update_color(new_color) diff --git a/code/datums/components/overlay_lighting.dm b/code/datums/components/overlay_lighting.dm index a037e7fab1..b6a812ce9a 100644 --- a/code/datums/components/overlay_lighting.dm +++ b/code/datums/components/overlay_lighting.dm @@ -94,7 +94,6 @@ cone = new() cone_hint_x = movable_parent.light_cone_x_offset cone_hint_y = movable_parent.light_cone_y_offset - cone.transform = cone.transform.Translate(-32, -32) set_direction(movable_parent.dir) if(!isnull(_range)) movable_parent.set_light_range(_range) @@ -436,19 +435,52 @@ var/turf/lit_turf = t lit_turf.dynamic_lumcount -= difference -///Here we append the behavior associated to changing lum_power. +///Moves the light directional_atom that emits our "light" based on our position and our direction /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) + + . = 0 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)) + if(isnull(next_turf) || IS_OPAQUE_TURF_DIR(next_turf, reverse_dir[current_direction])) break scanning = next_turf + .++ + directional_atom.forceMove(scanning) + directional_atom.face_light(GET_PARENT, dir2angle(current_direction), .) + +///Tries to place the directional light in a specific turf +/datum/component/overlay_lighting/proc/place_directional_light(turf/target) + var/final_distance = round(cast_range*2) + + //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 & get_dir(GET_PARENT, target))) + final_distance -= 1 + var/turf/scanning = get_turf(GET_PARENT) + + . = 0 + for(var/i in 1 to final_distance) + var/next_dir = get_dir(scanning, target) + var/turf/next_turf = get_step(scanning, next_dir) + if(isnull(next_turf) || IS_OPAQUE_TURF_DIR(next_turf, get_dir(scanning, next_turf))) + break + scanning = next_turf + .++ + + directional_atom.forceMove(scanning) + var/turf/Ts = get_turf(GET_PARENT) + var/turf/To = get_turf(GET_LIGHT_SOURCE) + + var/angle = Get_Angle(Ts, To) + + directional_atom.face_light(GET_PARENT, angle, .) + set_cone_direction(NORTH, angle) ///Called when current_holder changes loc. /datum/component/overlay_lighting/proc/on_holder_dir_change(atom/movable/source, olddir, newdir) @@ -460,14 +492,23 @@ SIGNAL_HANDLER set_direction(newdir) +///Sets the cone's direction for directional lighting +/datum/component/overlay_lighting/proc/set_cone_direction(dir, angle) + cone.reset_transform() + if(dir) + cone.set_dir(dir) + if(angle) + cone.transform = turn(cone.transform, angle) + cone.apply_standard_transform() + ///Sets a new direction for the directional cast, then updates luminosity -/datum/component/overlay_lighting/proc/set_direction(newdir) +/datum/component/overlay_lighting/proc/set_direction(newdir, skip_update) if(!newdir) return if(current_direction == newdir) return current_direction = newdir - cone.set_dir(newdir) + set_cone_direction(newdir) if(newdir & NORTH) cone.pixel_y = 16 @@ -476,8 +517,10 @@ else if(!isnull(cone_hint_y)) cone.pixel_y = cone_hint_y + directional_atom.pixel_y = cone_hint_y else cone.pixel_y = 0 + directional_atom.pixel_y = 0 if(newdir & EAST) cone.pixel_x = 16 @@ -487,12 +530,15 @@ if(!isnull(cone_hint_x)) if(newdir & NORTH) cone.pixel_x = -1*cone_hint_x + directional_atom.pixel_x = -1*cone_hint_x else cone.pixel_x = cone_hint_x + directional_atom.pixel_x = cone_hint_x else cone.pixel_x = 0 + directional_atom.pixel_x = 0 - if(overlay_lighting_flags & LIGHTING_ON) + if(!skip_update && (overlay_lighting_flags & LIGHTING_ON)) make_luminosity_update() /datum/component/overlay_lighting/proc/on_parent_crafted(datum/source, atom/movable/new_craft) diff --git a/code/game/objects/effects/misc.dm b/code/game/objects/effects/misc.dm index a251a4e3a7..d60664cd2e 100644 --- a/code/game/objects/effects/misc.dm +++ b/code/game/objects/effects/misc.dm @@ -1,3 +1,4 @@ +<<<<<<< HEAD //The effect when you wrap a dead body in gift wrap /obj/effect/spresent name = "strange present" @@ -106,3 +107,264 @@ stack_trace("Directional light atom deleted, but not by our component") return QDEL_HINT_LETMELIVE return ..() +||||||| parent of 33c73ce38f... Merge pull request #10752 from VOREStation/Arokha/flashpoint +//The effect when you wrap a dead body in gift wrap +/obj/effect/spresent + name = "strange present" + desc = "It's a ... present?" + icon = 'icons/obj/items.dmi' + icon_state = "strangepresent" + density = 1 + anchored = 0 + +/obj/effect/temporary_effect + name = "self deleting effect" + desc = "How are you examining what which cannot be seen?" + icon = 'icons/effects/effects.dmi' + invisibility = 0 + var/time_to_die = 10 SECONDS // Afer which, it will delete itself. + +/obj/effect/temporary_effect/Initialize() + . = ..() + if(time_to_die) + QDEL_IN(src, time_to_die) + +// Shown really briefly when attacking with axes. +/obj/effect/temporary_effect/cleave_attack + name = "cleaving attack" + desc = "Something swinging really wide." + icon = 'icons/effects/96x96.dmi' + icon_state = "cleave" + plane = MOB_PLANE + layer = ABOVE_MOB_LAYER + time_to_die = 6 + alpha = 140 + mouse_opacity = 0 + pixel_x = -32 + pixel_y = -32 + +/obj/effect/temporary_effect/cleave_attack/Initialize() // Makes the slash fade smoothly. When completely transparent it should qdel itself. + . = ..() + animate(src, alpha = 0, time = time_to_die - 1) + +/obj/effect/temporary_effect/shuttle_landing + name = "shuttle landing" + desc = "You better move if you don't want to go splat!" + //VOREStation Edit Start + icon = 'icons/goonstation/featherzone.dmi' + icon_state = "hazard-corners" + time_to_die = 5 SECONDS + //VOREStation Edit End + +// The manifestation of Zeus's might. Or just a really unlucky day. +// This is purely a visual effect, this isn't the part of the code that hurts things. +/obj/effect/temporary_effect/lightning_strike + name = "lightning" + desc = "How shocked you must be, to see this text. You must have lightning reflexes. \ + The humor in this description is just so electrifying." + icon = 'icons/effects/96x256.dmi' + icon_state = "lightning_strike" + plane = PLANE_LIGHTING_ABOVE + time_to_die = 1 SECOND + pixel_x = -32 + +/obj/effect/temporary_effect/lightning_strike/Initialize() + icon_state += "[rand(1,2)]" // To have two variants of lightning sprites. + animate(src, alpha = 0, time = time_to_die - 1) + . = ..() + +/obj/effect/dummy/lighting_obj + 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 + light_on = TRUE + blocks_emissive = FALSE + +/obj/effect/dummy/lighting_obj/Initialize(mapload, _range, _power, _color, _duration) + . = ..() + 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) + +/obj/effect/dummy/lighting_obj/moblight + name = "mob lighting fx" + +/obj/effect/dummy/lighting_obj/moblight/Initialize(mapload, _color, _range, _power, _duration) + . = ..() + if(!ismob(loc)) + return INITIALIZE_HINT_QDEL + +/obj/effect/dummy/lighting_obj/moblight/fire + name = "fire" + light_color = LIGHT_COLOR_FIRE + light_range = LIGHT_RANGE_FIRE + +/obj/effect/abstract/directional_lighting + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + +/obj/effect/abstract/directional_lighting/Destroy(force) + if(!force) + stack_trace("Directional light atom deleted, but not by our component") + return QDEL_HINT_LETMELIVE + return ..() +======= +//The effect when you wrap a dead body in gift wrap +/obj/effect/spresent + name = "strange present" + desc = "It's a ... present?" + icon = 'icons/obj/items.dmi' + icon_state = "strangepresent" + density = 1 + anchored = 0 + +/obj/effect/temporary_effect + name = "self deleting effect" + desc = "How are you examining what which cannot be seen?" + icon = 'icons/effects/effects.dmi' + invisibility = 0 + var/time_to_die = 10 SECONDS // Afer which, it will delete itself. + +/obj/effect/temporary_effect/Initialize() + . = ..() + if(time_to_die) + QDEL_IN(src, time_to_die) + +// Shown really briefly when attacking with axes. +/obj/effect/temporary_effect/cleave_attack + name = "cleaving attack" + desc = "Something swinging really wide." + icon = 'icons/effects/96x96.dmi' + icon_state = "cleave" + plane = MOB_PLANE + layer = ABOVE_MOB_LAYER + time_to_die = 6 + alpha = 140 + mouse_opacity = 0 + pixel_x = -32 + pixel_y = -32 + +/obj/effect/temporary_effect/cleave_attack/Initialize() // Makes the slash fade smoothly. When completely transparent it should qdel itself. + . = ..() + animate(src, alpha = 0, time = time_to_die - 1) + +/obj/effect/temporary_effect/shuttle_landing + name = "shuttle landing" + desc = "You better move if you don't want to go splat!" + //VOREStation Edit Start + icon = 'icons/goonstation/featherzone.dmi' + icon_state = "hazard-corners" + time_to_die = 5 SECONDS + //VOREStation Edit End + +// The manifestation of Zeus's might. Or just a really unlucky day. +// This is purely a visual effect, this isn't the part of the code that hurts things. +/obj/effect/temporary_effect/lightning_strike + name = "lightning" + desc = "How shocked you must be, to see this text. You must have lightning reflexes. \ + The humor in this description is just so electrifying." + icon = 'icons/effects/96x256.dmi' + icon_state = "lightning_strike" + plane = PLANE_LIGHTING_ABOVE + time_to_die = 1 SECOND + pixel_x = -32 + +/obj/effect/temporary_effect/lightning_strike/Initialize() + icon_state += "[rand(1,2)]" // To have two variants of lightning sprites. + animate(src, alpha = 0, time = time_to_die - 1) + . = ..() + +/obj/effect/dummy/lighting_obj + 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 + light_on = TRUE + blocks_emissive = FALSE + +/obj/effect/dummy/lighting_obj/Initialize(mapload, _range, _power, _color, _duration) + . = ..() + 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) + +/obj/effect/dummy/lighting_obj/moblight + name = "mob lighting fx" + +/obj/effect/dummy/lighting_obj/moblight/Initialize(mapload, _color, _range, _power, _duration) + . = ..() + if(!ismob(loc)) + return INITIALIZE_HINT_QDEL + +/obj/effect/dummy/lighting_obj/moblight/fire + name = "fire" + light_color = LIGHT_COLOR_FIRE + light_range = LIGHT_RANGE_FIRE + +/obj/effect/abstract + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + +/obj/effect/abstract/light_spot + icon = 'icons/effects/eris_flashlight.dmi' + icon_state = "medium" + pixel_x = -16 + pixel_y = -16 + +/obj/effect/abstract/directional_lighting + var/obj/effect/abstract/light_spot/light_spot = new + var/trans_angle + var/icon_dist + +/obj/effect/abstract/directional_lighting/Initialize() + . = ..() + vis_contents += light_spot + +/obj/effect/abstract/directional_lighting/proc/face_light(atom/movable/source, angle, distance) + if(!loc) // We're in nullspace + return + + // Save ourselves some matrix math + if(angle != trans_angle) + trans_angle = angle + // Doing this in one operation (tn = turn(initial(tn), angle)) has strange results... + light_spot.transform = initial(light_spot.transform) + light_spot.transform = turn(light_spot.transform, angle) + + if(icon_dist != distance) + icon_dist = distance + switch(distance) + if(0) + light_spot.icon_state = "vclose" + if(1) + light_spot.icon_state = "close" + if(2) + light_spot.icon_state = "medium" + if(3 to INFINITY) + light_spot.icon_state = "far" + +/obj/effect/abstract/directional_lighting/Destroy(force) + if(!force) + stack_trace("Directional light atom deleted, but not by our component") + return QDEL_HINT_LETMELIVE + + vis_contents.Cut() + qdel_null(light_spot) + + return ..() +>>>>>>> 33c73ce38f... Merge pull request #10752 from VOREStation/Arokha/flashpoint diff --git a/code/game/objects/effects/overlays.dm b/code/game/objects/effects/overlays.dm index 5a5f043ebd..3a62216be6 100644 --- a/code/game/objects/effects/overlays.dm +++ b/code/game/objects/effects/overlays.dm @@ -161,6 +161,20 @@ alpha = 110 blocks_emissive = FALSE + var/static/matrix/normal_transform + +/obj/effect/overlay/light_cone/Initialize() + . = ..() + apply_standard_transform() + +/obj/effect/overlay/light_cone/proc/reset_transform(apply_standard) + transform = initial(transform) + if(apply_standard) + apply_standard_transform() + +/obj/effect/overlay/light_cone/proc/apply_standard_transform() + transform = transform.Translate(-32, -32) + /obj/effect/overlay/light_cone/Destroy(force) if(!force) stack_trace("Directional light cone deleted, but not by our component") diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm index 62d1b4b934..57e1404b9c 100644 --- a/code/game/objects/items/devices/flashlight.dm +++ b/code/game/objects/items/devices/flashlight.dm @@ -210,6 +210,14 @@ else ..() +/obj/item/device/flashlight/afterattack(atom/target, mob/user, proximity_flag, click_parameters) + . = ..() + var/turf/T = get_turf(target) + var/datum/component/overlay_lighting/OL = GetComponent(/datum/component/overlay_lighting) + if(!OL) + return + OL.place_directional_light(T) + /obj/item/device/flashlight/pen name = "penlight" desc = "A pen-sized light, used by medical staff." diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index 76aa5985a2..143a3c76e8 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -41,7 +41,7 @@ Entered(AM) //Lighting related - luminosity = !(dynamic_lighting) + set_luminosity(!(dynamic_lighting)) if(opacity) directional_opacity = ALL_CARDINALS diff --git a/code/modules/lighting/lighting_overlay.dm b/code/modules/lighting/lighting_overlay.dm index abf3c39ba6..45d4004dd9 100644 --- a/code/modules/lighting/lighting_overlay.dm +++ b/code/modules/lighting/lighting_overlay.dm @@ -26,7 +26,7 @@ stack_trace("a lighting object was assigned to a turf that already had a lighting object!") affected_turf.lighting_object = src - affected_turf.luminosity = 0 + affected_turf.set_luminosity(0) for(var/turf/space/space_tile in RANGE_TURFS(1, affected_turf)) space_tile.update_starlight() @@ -40,7 +40,7 @@ SSlighting.objects_queue -= src if (isturf(affected_turf)) affected_turf.lighting_object = null - affected_turf.luminosity = 1 + affected_turf.set_luminosity(1) affected_turf.underlays -= current_underlay affected_turf = null return ..() @@ -112,7 +112,7 @@ affected_turf.underlays += current_underlay - affected_turf.luminosity = set_luminosity + affected_turf.set_luminosity(set_luminosity) /datum/lighting_object/proc/removefromturf() affected_turf.underlays -= current_underlay diff --git a/code/modules/lighting/lighting_turf.dm b/code/modules/lighting/lighting_turf.dm index 59732b5d60..d59a4d5315 100644 --- a/code/modules/lighting/lighting_turf.dm +++ b/code/modules/lighting/lighting_turf.dm @@ -93,6 +93,13 @@ return recalculate_directional_opacity() +///Setter for the byond luminosity var +/turf/proc/set_luminosity(new_luminosity, force) + // SSplanets handles outdoor turfs + if(outdoors && !force) + return + + luminosity = new_luminosity ///Calculate on which directions this turfs block view. /turf/proc/recalculate_directional_opacity() diff --git a/code/modules/planet/planet.dm b/code/modules/planet/planet.dm index 293a64c9fb..b7fd464c9d 100644 --- a/code/modules/planet/planet.dm +++ b/code/modules/planet/planet.dm @@ -13,7 +13,7 @@ var/datum/sun_holder/sun_holder var/sun_position = 0 // 0 means midnight, 1 means noon. - var/list/sun = list("range","brightness","color") + var/list/sun = list("brightness","color") var/list/expected_z_levels = list() var/turf/unsimulated/wall/planetary/planetary_wall_type = /turf/unsimulated/wall/planetary @@ -62,8 +62,7 @@ if(weather_holder) weather_holder.process() -/datum/planet/proc/update_sun_deferred(var/new_range, var/new_brightness, var/new_color) - sun["range"] = new_range +/datum/planet/proc/update_sun_deferred(var/new_brightness, var/new_color) sun["brightness"] = new_brightness sun["color"] = new_color needs_work |= PLANET_PROCESS_SUN diff --git a/code/modules/planet/sif.dm b/code/modules/planet/sif.dm index 96cfb548ac..af6f632bdc 100644 --- a/code/modules/planet/sif.dm +++ b/code/modules/planet/sif.dm @@ -95,7 +95,7 @@ var/datum/planet/sif/planet_sif = null new_color = rgb(new_r, new_g, new_b) spawn(1) - update_sun_deferred(2, new_brightness, new_color) + update_sun_deferred(new_brightness, new_color) // We're gonna pretend there are 32 hours in a Sif day instead of 32.64 for the purposes of not losing sanity. We lose 38m 24s but the alternative is a path to madness. /datum/time/sif diff --git a/code/modules/planet/sun.dm b/code/modules/planet/sun.dm index 55f739d217..52172d4d5a 100644 --- a/code/modules/planet/sun.dm +++ b/code/modules/planet/sun.dm @@ -2,26 +2,52 @@ var/atom/movable/sun_visuals/sun = new var/datum/planet/our_planet + var/our_color = "#FFFFFF" + var/our_brightness = 1.0 + /datum/sun_holder/New(var/source) our_planet = source /datum/sun_holder/proc/update_color(new_color) - sun.color = new_color - -/datum/sun_holder/proc/update_brightness(new_brightness) - sun.alpha = round(CLAMP01(new_brightness)*255,1) + // Doesn't save much work, but might save a smidge of client work + if(our_color == new_color) + return + + // Visible change + sun.color = our_color = new_color +/datum/sun_holder/proc/update_brightness(new_brightness, list/turfs) + // Doesn't save much work, but might save a smidge of client work + if(our_brightness == new_brightness) + return + + // Store the old for math + . = our_brightness + our_brightness = new_brightness + + // Visible change + sun.alpha = round(CLAMP01(our_brightness)*255,1) + + // Update dynamic lumcount so darksight and stuff works + var/difference = . - our_brightness + for(var/turf/T as anything in turfs) + T.dynamic_lumcount -= difference + /datum/sun_holder/proc/apply_to_turf(turf/T) if(sun in T.vis_contents) warning("Was asked to add fake sun to [T.x], [T.y], [T.z] despite already having us in it's vis contents") return T.vis_contents += sun + T.dynamic_lumcount += our_brightness + T.set_luminosity(1, TRUE) /datum/sun_holder/proc/remove_from_turf(turf/T) if(!(sun in T.vis_contents)) warning("Was asked to remove fake sun from [T.x], [T.y], [T.z] despite it not having us in it's vis contents") return T.vis_contents -= sun + T.dynamic_lumcount -= our_brightness + T.set_luminosity(!IS_DYNAMIC_LIGHTING(T), TRUE) /datum/sun_holder/proc/rainbow() var/end = world.time + 30 SECONDS diff --git a/code/modules/planet/virgo3b_vr.dm b/code/modules/planet/virgo3b_vr.dm index f9cc58ca0c..2700b69805 100644 --- a/code/modules/planet/virgo3b_vr.dm +++ b/code/modules/planet/virgo3b_vr.dm @@ -94,7 +94,7 @@ var/datum/planet/virgo3b/planet_virgo3b = null new_color = rgb(new_r, new_g, new_b) spawn(1) - update_sun_deferred(2, new_brightness, new_color) + update_sun_deferred(new_brightness, new_color) /datum/weather_holder/virgo3b diff --git a/code/modules/planet/virgo4_vr.dm b/code/modules/planet/virgo4_vr.dm index 3909b9e6cd..6ac748f421 100644 --- a/code/modules/planet/virgo4_vr.dm +++ b/code/modules/planet/virgo4_vr.dm @@ -92,7 +92,7 @@ var/datum/planet/virgo4/planet_virgo4 = null new_color = rgb(new_r, new_g, new_b) spawn(1) - update_sun_deferred(2, new_brightness, new_color) + update_sun_deferred(new_brightness, new_color) /datum/weather_holder/virgo4 diff --git a/icons/effects/eris_flashlight.dmi b/icons/effects/eris_flashlight.dmi new file mode 100644 index 0000000000..91167e9f41 Binary files /dev/null and b/icons/effects/eris_flashlight.dmi differ diff --git a/icons/effects/light_overlays/light_cone.dmi b/icons/effects/light_overlays/light_cone.dmi index 75f322a937..3a906a9f2a 100644 Binary files a/icons/effects/light_overlays/light_cone.dmi and b/icons/effects/light_overlays/light_cone.dmi differ