Skip to content

Commit

Permalink
fix(light): fix light's update_icon causing negative power consumption
Browse files Browse the repository at this point in the history
  • Loading branch information
intercepti0n authored Feb 28, 2024
1 parent 4e9ca13 commit 320483e
Showing 1 changed file with 115 additions and 105 deletions.
220 changes: 115 additions & 105 deletions code/modules/power/lighting.dm
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,10 @@
active_power_usage = 20 WATTS
power_channel = STATIC_LIGHT //Lights are calc'd via area so they dont need to be in the machine list

var/on = 0 // 1 if on, 0 if off
var/flickering = 0
/// Whether light is currently turned on.
var/on = TRUE
/// Whether bulb is currently asynchronously flickering.
var/flickering = FALSE
var/light_type = /obj/item/light/tube // the type of light item
var/construct_type = /obj/machinery/light_construct
var/pixel_shift = 0
Expand Down Expand Up @@ -191,7 +193,6 @@
desc = "A small lighting fixture."
light_type = /obj/item/light/bulb
construct_type = /obj/machinery/light_construct/small
pixel_shift = 3

/obj/machinery/light/small/he
name = "high efficiency light fixture"
Expand Down Expand Up @@ -224,8 +225,7 @@
/obj/machinery/light/Initialize(mapload, obj/machinery/light_construct/construct = null)
. = ..(mapload)

if(!light_eas)
light_eas = list()
LAZYINITLIST(light_eas)

s.set_up(1, 1, src)

Expand All @@ -238,90 +238,70 @@
if(prob(lightbulb.broken_chance))
broken(1)

on = powered()
update_icon()
on = has_power()
update(FALSE)

/obj/machinery/light/Destroy()
QDEL_NULL(lightbulb)
QDEL_NULL(s)
. = ..()

/obj/machinery/light/on_update_icon(trigger = 1)
/obj/machinery/light/proc/update_glow()
if(!on)
set_light(0)
return FALSE

if(!isnull(current_mode) && (current_mode in lightbulb.lighting_modes))
set_light(arglist(lightbulb.lighting_modes[current_mode]))
else
set_light(lightbulb.b_max_bright, lightbulb.b_inner_range, lightbulb.b_outer_range, lightbulb.b_curve, lightbulb.b_color)

return TRUE

/obj/machinery/light/on_update_icon()
ClearOverlays()
if(pixel_shift)
switch(dir)
if(NORTH)
pixel_y = pixel_shift
if(SOUTH)
pixel_y = -pixel_shift
if(EAST)
pixel_x = pixel_shift
if(WEST)
pixel_x = -pixel_shift

switch(get_status()) // set icon_states

switch(get_status())
if(LIGHT_OK)
icon_state = "[base_state][on]"
if(LIGHT_EMPTY)
icon_state = "[base_state]-empty"
on = 0
update_use_power(POWER_USE_OFF)
set_light(0)
return
if(LIGHT_BURNED)
icon_state = "[base_state]-burned"
on = 0
if(LIGHT_BROKEN)
icon_state = "[base_state]-broken"
on = 0

var/image/TO
var/TO_alpha = between(128, (lightbulb.b_max_bright * 1.25 * 255), 255)
var/TO_color = lightbulb.b_color
var/should_glow = update_glow()

if(on)
update_use_power(POWER_USE_ACTIVE)
if(!lightbulb?.tone_overlay)
return

var/changed = 0
if(current_mode && (current_mode in lightbulb.lighting_modes))
changed = set_light(arglist(lightbulb.lighting_modes[current_mode]))
if(lightbulb?.tone_overlay)
TO_color = lightbulb.lighting_modes[current_mode]["l_color"]
TO_alpha = between(128, (lightbulb.lighting_modes[current_mode]["l_max_bright"] * 1.5 * 255), 255) // Some fine tuning here
else
changed = set_light(lightbulb.b_max_bright, lightbulb.b_inner_range, lightbulb.b_outer_range, lightbulb.b_curve, lightbulb.b_color)
var/image/tone_overlay
var/tone_color = lightbulb.b_color
var/tone_alpha = between(128, (lightbulb.b_max_bright * 1.25 * 255), 255)

if(lightbulb?.tone_overlay)
TO = OVERLAY(icon, "[icon_state]-over", TO_alpha, RESET_COLOR, TO_color, dir, EFFECTS_ABOVE_LIGHTING_PLANE, ABOVE_LIGHTING_LAYER)
if(should_glow)
if(current_mode && (current_mode in lightbulb.lighting_modes))
tone_color = lightbulb.lighting_modes[current_mode]["l_color"]
tone_alpha = between(128, (lightbulb.lighting_modes[current_mode]["l_max_bright"] * 1.5 * 255), 255)

if(trigger && changed && get_status() == LIGHT_OK)
switch_check()
tone_overlay = OVERLAY(icon, "[icon_state]-over", tone_alpha, RESET_COLOR, tone_color, dir, EFFECTS_ABOVE_LIGHTING_PLANE, ABOVE_LIGHTING_LAYER)

if(!light_eas[icon_state])
if(isnull(light_eas[icon_state]))
light_eas[icon_state] = emissive_appearance(icon, "[icon_state]_ea")

AddOverlays(light_eas[icon_state])
else
if(lightbulb?.tone_overlay)
TO = OVERLAY(icon, "[icon_state]-over", TO_alpha, RESET_COLOR, TO_color, dir)
update_use_power(POWER_USE_OFF)
set_light(0)

if(TO)
AddOverlays(TO)
tone_overlay = OVERLAY(icon, "[icon_state]-over", tone_alpha, RESET_COLOR, tone_color, dir)

change_power_consumption((light_outer_range * light_max_bright) * LIGHTING_POWER_FACTOR, POWER_USE_ACTIVE)
AddOverlays(tone_overlay)

/obj/machinery/light/proc/get_status()
if(QDELETED(lightbulb))
return LIGHT_EMPTY
else
return lightbulb.status

/obj/machinery/light/proc/switch_check()
lightbulb.switch_on()
if(get_status() != LIGHT_OK)
set_light(0)

/obj/machinery/light/attack_generic(mob/user, damage)
if(!damage)
return
Expand All @@ -347,30 +327,26 @@
..()

/obj/machinery/light/proc/set_mode(new_mode)
if(current_mode == new_mode || !lightbulb)
if(current_mode == new_mode)
return

if(isnull(lightbulb))
return

if(new_mode in lightbulb.lighting_modes)
current_mode = new_mode

else if(new_mode == null)
else
current_mode = null

update_icon(0)

// attempt to set the light's on/off status
// will not switch on if broken/burned/empty
/obj/machinery/light/proc/seton(state)
on = (state && get_status() == LIGHT_OK)
queue_icon_update()
update(FALSE)

// examine verb
/obj/machinery/light/_examine_text(mob/user)
. = ..()
var/fitting = get_fitting_name()
switch(get_status())
if(LIGHT_OK)
. += "\nIt is turned [on? "on" : "off"]."
. += "\nIt is turned [on ? "on" : "off"]."
if(LIGHT_EMPTY)
. += "\nThe [fitting] has been removed."
if(LIGHT_BURNED)
Expand All @@ -392,16 +368,16 @@
if(A && (A.lighting_mode in lightbulb.lighting_modes))
current_mode = A.lighting_mode

on = powered()
update_icon()
on = has_power()
update(TRUE)

/obj/machinery/light/proc/remove_bulb()
. = lightbulb
lightbulb.dropInto(loc)
lightbulb.update_icon()
lightbulb = null
current_mode = null
update_icon()
update(FALSE)

/obj/machinery/light/attackby(obj/item/W, mob/user)

Expand Down Expand Up @@ -436,7 +412,7 @@
if(prob(1 + W.force * 5))

user.visible_message("<span class='warning'>[user.name] smashed the light!</span>", "<span class='warning'>You smash the light!</span>", "You hear a tinkle of breaking glass")
if(on && (W.obj_flags & OBJ_FLAG_CONDUCTIBLE))
if(has_power() && (W.obj_flags & OBJ_FLAG_CONDUCTIBLE))
if (prob(12))
electrocute_mob(user, get_area(src), src, 0.3)
broken()
Expand All @@ -448,7 +424,7 @@

// attempt to remove the lightbulb out of the fixture with a crowbar
else if(isCrowbar(W) && lightbulb)
if(powered() && (W.obj_flags & OBJ_FLAG_CONDUCTIBLE))
if(has_power() && (W.obj_flags & OBJ_FLAG_CONDUCTIBLE))
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
s.set_up(3, 1, src)
s.start()
Expand Down Expand Up @@ -480,33 +456,71 @@
return

to_chat(user, "You stick \the [W] into the light socket!")
if(powered() && (W.obj_flags & OBJ_FLAG_CONDUCTIBLE))
if(has_power() && (W.obj_flags & OBJ_FLAG_CONDUCTIBLE))
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
s.set_up(3, 1, src)
s.start()
if (prob(75))
electrocute_mob(user, get_area(src), src, rand(0.7,1.0))

/obj/machinery/light/proc/has_power()
var/area/our_area = get_area(src)
return our_area.lightswitch && !(stat & NOPOWER)

// returns whether this light has power
// true if area has power and lightswitch is on
/obj/machinery/light/powered()
var/area/A = get_area(src)
return A && A.lightswitch && ..(power_channel)
/obj/machinery/light/power_change()
. = ..()

on = has_power()
update(TRUE)

/**
* Updates lighting, icon and optionally calls `switch_on` on the inserted lightbulb. This
* method is prefered over `update_icon` due to multiple edge-case handlers.
*
* Vars:
* * trigger - If set to `TRUE` calls `switch_on` on a lightbulb.
*
*/
/obj/machinery/light/proc/update(trigger = FALSE)
switch(get_status())
if(LIGHT_BROKEN, LIGHT_BURNED, LIGHT_EMPTY)
on = FALSE

if(on)
change_power_consumption((light_outer_range * light_max_bright) * LIGHTING_POWER_FACTOR, POWER_USE_ACTIVE)
update_use_power(POWER_USE_ACTIVE)
lightbulb.switch_on()
else
update_use_power(POWER_USE_IDLE)

update_icon()

/obj/machinery/light/proc/flicker(amount = rand(10, 20))
if(flickering) return
flickering = 1
spawn(0)
if(on && get_status() == LIGHT_OK)
for(var/i = 0; i < amount; i++)
if(get_status() != LIGHT_OK) break
on = !on
update_icon(0)
sleep(rand(5, 15))
on = (get_status() == LIGHT_OK)
update_icon(0)
flickering = 0
set waitfor = FALSE

if(flickering)
return

if(!powered()) // Allows to bypass ligthswitch check.
return

if(get_status() != LIGHT_OK)
return

flickering = TRUE

for(var/i = 0; i < amount; i++)
if(get_status() != LIGHT_OK || !powered())
break

on = !on
update(FALSE)
sleep(rand(5, 15))

on = get_status() == LIGHT_OK
update(FALSE)

flickering = FALSE

// ai attack - make lights flicker, because why not

Expand Down Expand Up @@ -587,25 +601,30 @@
else return ..()

// break the light and make sparks if was on
/obj/machinery/light/proc/broken(skip_sound_and_sparks = 0)
/obj/machinery/light/proc/broken(skip_sound_and_sparks = FALSE)
if(!lightbulb)
return

if(!skip_sound_and_sparks)
if(lightbulb && !(lightbulb.status == LIGHT_BROKEN))
playsound(src.loc, GET_SFX(SFX_GLASS_HIT), 75, 1)
if(on)

if(powered())
s.set_up(3, 1, src)
s.start()

lightbulb.status = LIGHT_BROKEN
update_icon()

update(!skip_sound_and_sparks)

/obj/machinery/light/proc/fix()
if(get_status() == LIGHT_OK)
return

lightbulb.status = LIGHT_OK
on = 1
update_icon()

on = has_power()
update(FALSE)

// explosion effect
// destroy the whole light fixture or just shatter it
Expand All @@ -622,15 +641,6 @@
if (prob(50))
broken()

// timed process
// use power

// called when area power state changes
/obj/machinery/light/power_change()
seton(powered())

// called when on fire

/obj/machinery/light/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
if(prob(max(0, exposed_temperature - 673))) //0% at <400C, 100% at >500C
broken()
Expand Down

0 comments on commit 320483e

Please sign in to comment.