mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-23 20:16:55 +01:00
Boo! Rework (#14543)
* Boo Refactor * Boo-Refactor Review Items Co-authored-by: SteelSlayer <42044220+SteelSlayer@users.noreply.github.com> * Vending Machines Flicker * Dave's Fire PR Review Mixtape Ft. SteelSlayer Co-authored-by: SteelSlayer <42044220+SteelSlayer@users.noreply.github.com> Co-authored-by: SteelSlayer <42044220+SteelSlayer@users.noreply.github.com>
This commit is contained in:
+12
-9
@@ -5,7 +5,7 @@
|
||||
var/panel = "Debug"//What panel the proc holder needs to go on.
|
||||
var/active = FALSE //Used by toggle based abilities.
|
||||
var/ranged_mousepointer
|
||||
var/mob/living/ranged_ability_user
|
||||
var/mob/ranged_ability_user
|
||||
|
||||
/obj/effect/proc_holder/singularity_act()
|
||||
return
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell))
|
||||
|
||||
/obj/effect/proc_holder/proc/InterceptClickOn(mob/living/user, params, atom/A)
|
||||
/obj/effect/proc_holder/proc/InterceptClickOn(mob/user, params, atom/A)
|
||||
if(user.ranged_ability != src)
|
||||
to_chat(user, "<span class='warning'><b>[user.ranged_ability.name]</b> has been disabled.")
|
||||
user.ranged_ability.remove_ranged_ability(user)
|
||||
@@ -38,7 +38,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell))
|
||||
spell.remove_ranged_ability(spell.ranged_ability_user)
|
||||
return ..()
|
||||
|
||||
/obj/effect/proc_holder/proc/add_ranged_ability(mob/living/user, var/msg)
|
||||
/obj/effect/proc_holder/proc/add_ranged_ability(mob/user, var/msg)
|
||||
if(!user || !user.client)
|
||||
return
|
||||
if(user.ranged_ability && user.ranged_ability != src)
|
||||
@@ -61,7 +61,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell))
|
||||
if(C && ranged_mousepointer && C.mouse_pointer_icon == ranged_mousepointer)
|
||||
C.mouse_pointer_icon = initial(C.mouse_pointer_icon)
|
||||
|
||||
/obj/effect/proc_holder/proc/remove_ranged_ability(mob/living/user, var/msg)
|
||||
/obj/effect/proc_holder/proc/remove_ranged_ability(mob/user, var/msg)
|
||||
if(!user || (user.ranged_ability && user.ranged_ability != src)) //To avoid removing the wrong ability
|
||||
return
|
||||
user.ranged_ability = null
|
||||
@@ -135,7 +135,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell))
|
||||
* @param start_recharge If the proc should set the cooldown
|
||||
* @param user The caster of the spell
|
||||
*/
|
||||
/obj/effect/proc_holder/spell/proc/cast_check(charge_check = TRUE, start_recharge = TRUE, mob/living/user = usr) //checks if the spell can be cast based on its settings; skipcharge is used when an additional cast_check is called inside the spell
|
||||
/obj/effect/proc_holder/spell/proc/cast_check(charge_check = TRUE, start_recharge = TRUE, mob/user = usr) //checks if the spell can be cast based on its settings; skipcharge is used when an additional cast_check is called inside the spell
|
||||
if(!can_cast(user, charge_check, TRUE))
|
||||
return FALSE
|
||||
|
||||
@@ -428,9 +428,12 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell))
|
||||
var/selection_deactivated_message = "<span class='notice'>You choose to not cast this spell.</span>"
|
||||
var/allowed_type = /mob/living // Which type the targets have to be
|
||||
var/auto_target_single = TRUE // If the spell should auto select a target if only one is found
|
||||
/// does this spell generate attack logs?
|
||||
var/create_logs = TRUE
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/click/Click()
|
||||
var/mob/living/user = usr
|
||||
// biased goddamn variable types assuming that we're alive. eat shit.
|
||||
var/mob/user = usr
|
||||
if(!istype(user))
|
||||
return
|
||||
|
||||
@@ -455,7 +458,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell))
|
||||
|
||||
if(target && cast_check(TRUE, TRUE, user)) // Singular target found. Cast it instantly
|
||||
to_chat(user, "<span class='warning'>Only one target found. Casting [src] on [target]!</span>")
|
||||
perform(list(target), user = user)
|
||||
perform(list(target), user = user, make_attack_logs = create_logs)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
@@ -500,7 +503,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell))
|
||||
revert_cast(user)
|
||||
return FALSE
|
||||
|
||||
perform(targets, user = user)
|
||||
perform(targets, user = user, make_attack_logs = create_logs)
|
||||
remove_ranged_ability(user)
|
||||
return TRUE
|
||||
|
||||
@@ -513,7 +516,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell))
|
||||
return istype(target, allowed_type) && (include_user || target != user) && \
|
||||
(target in view_or_range(range, user, selection_type))
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/click/choose_targets(mob/living/user, atom/A) // Not used
|
||||
/obj/effect/proc_holder/spell/targeted/click/choose_targets(mob/user, atom/A) // Not used
|
||||
return
|
||||
|
||||
/obj/effect/proc_holder/spell/aoe_turf/choose_targets(mob/user = usr)
|
||||
|
||||
@@ -68,6 +68,8 @@
|
||||
|
||||
var/parallax_movedir = 0
|
||||
var/moving = FALSE
|
||||
/// "Haunted" areas such as the morgue and chapel are easier to boo. Because flavor.
|
||||
var/is_haunted = FALSE
|
||||
|
||||
/area/Initialize(mapload)
|
||||
GLOB.all_areas += src
|
||||
|
||||
@@ -929,6 +929,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
|
||||
/area/chapel
|
||||
icon_state = "chapel"
|
||||
ambientsounds = HOLY_SOUNDS
|
||||
is_haunted = TRUE
|
||||
|
||||
/area/chapel/main
|
||||
name = "\improper Chapel"
|
||||
@@ -1299,6 +1300,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
|
||||
name = "\improper Morgue"
|
||||
icon_state = "morgue"
|
||||
ambientsounds = SPOOKY_SOUNDS
|
||||
is_haunted = TRUE
|
||||
|
||||
/area/medical/chemistry
|
||||
name = "\improper Chemistry"
|
||||
@@ -1777,10 +1779,12 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
|
||||
/area/derelict/medical/morgue
|
||||
name = "\improper Derelict Morgue"
|
||||
icon_state = "morgue"
|
||||
is_haunted = TRUE
|
||||
|
||||
/area/derelict/medical/chapel
|
||||
name = "\improper Derelict Chapel"
|
||||
icon_state = "chapel"
|
||||
is_haunted = TRUE
|
||||
|
||||
/area/derelict/teleporter
|
||||
name = "\improper Derelict Teleporter"
|
||||
|
||||
+8
-1
@@ -420,8 +420,15 @@
|
||||
if(AM && isturf(AM.loc))
|
||||
step(AM, turn(AM.dir, 180))
|
||||
|
||||
/*
|
||||
* Base proc, terribly named but it's all over the code so who cares I guess right?
|
||||
*
|
||||
* Returns FALSE by default, if a child returns TRUE it is implied that the atom has in
|
||||
* some way done a spooky thing. Current usage is so that Boo knows if it needs to cool
|
||||
* down or not, but this could be expanded upon if you were a bad enough dude.
|
||||
*/
|
||||
/atom/proc/get_spooked()
|
||||
return
|
||||
return FALSE
|
||||
|
||||
/**
|
||||
Base proc, intended to be overriden.
|
||||
|
||||
@@ -17,6 +17,10 @@
|
||||
var/light_range_on = 2
|
||||
var/light_power_on = 1
|
||||
var/overlay_layer
|
||||
/// Are we in the middle of a flicker event?
|
||||
var/flickering = FALSE
|
||||
/// Are we forcing the icon to be represented in a no-power state?
|
||||
var/force_no_power_icon_state = FALSE
|
||||
|
||||
/obj/machinery/computer/New()
|
||||
overlay_layer = layer
|
||||
@@ -36,9 +40,41 @@
|
||||
set_light(0)
|
||||
visible_message("<span class='danger'>[src] grows dim, its screen barely readable.</span>")
|
||||
|
||||
/*
|
||||
* Reimp, flash the screen on and off repeatedly.
|
||||
*/
|
||||
/obj/machinery/computer/flicker()
|
||||
if(flickering)
|
||||
return FALSE
|
||||
|
||||
if(stat & (BROKEN|NOPOWER))
|
||||
return FALSE
|
||||
|
||||
flickering = TRUE
|
||||
INVOKE_ASYNC(src, /obj/machinery/computer/.proc/flicker_event)
|
||||
|
||||
return TRUE
|
||||
|
||||
/*
|
||||
* Proc to be called by invoke_async in the above flicker() proc.
|
||||
*/
|
||||
/obj/machinery/computer/proc/flicker_event()
|
||||
var/amount = rand(5, 15)
|
||||
|
||||
for(var/i in 1 to amount)
|
||||
force_no_power_icon_state = TRUE
|
||||
update_icon()
|
||||
sleep(rand(1, 3))
|
||||
|
||||
force_no_power_icon_state = FALSE
|
||||
update_icon()
|
||||
sleep(rand(1, 10))
|
||||
update_icon()
|
||||
flickering = FALSE
|
||||
|
||||
/obj/machinery/computer/update_icon()
|
||||
overlays.Cut()
|
||||
if(stat & NOPOWER)
|
||||
if((stat & NOPOWER) || force_no_power_icon_state)
|
||||
if(icon_keyboard)
|
||||
overlays += image(icon,"[icon_keyboard]_off",overlay_layer)
|
||||
return
|
||||
|
||||
@@ -123,6 +123,15 @@ About the new airlock wires panel:
|
||||
..()
|
||||
wires = new(src)
|
||||
|
||||
/*
|
||||
* reimp, imitate an access denied event.
|
||||
*/
|
||||
/obj/machinery/door/airlock/flicker()
|
||||
if(arePowerSystemsOn())
|
||||
do_animate("deny")
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/door/airlock/Initialize()
|
||||
. = ..()
|
||||
if(closeOtherId != null)
|
||||
|
||||
@@ -93,6 +93,8 @@ Class Procs:
|
||||
Compiled by Aygar
|
||||
*/
|
||||
|
||||
#define MACHINE_FLICKER_CHANCE 0.05 // roughly 1/2000 chance of a machine flickering on any given tick. That means in a two hour round each machine will flicker on average a little less than two times.
|
||||
|
||||
/obj/machinery
|
||||
name = "machinery"
|
||||
icon = 'icons/obj/stationobjs.dmi'
|
||||
@@ -125,6 +127,19 @@ Class Procs:
|
||||
/// A reference to a `datum/radio_frequency`. Gives the machine the ability to interact with things using radio signals.
|
||||
var/datum/radio_frequency/radio_connection
|
||||
|
||||
/*
|
||||
* reimp, attempts to flicker this machinery if the behavior is supported.
|
||||
*/
|
||||
/obj/machinery/get_spooked()
|
||||
return flicker()
|
||||
|
||||
/*
|
||||
* Base class, attempt to flicker. Returns TRUE if we complete our 'flicker
|
||||
* behavior', false otherwise.
|
||||
*/
|
||||
/obj/machinery/proc/flicker()
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/Initialize(mapload)
|
||||
if(!armor)
|
||||
armor = list(melee = 25, bullet = 10, laser = 10, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 50, acid = 70)
|
||||
@@ -199,6 +214,8 @@ Class Procs:
|
||||
use_power(idle_power_usage,power_channel, 1)
|
||||
else if(use_power >= ACTIVE_POWER_USE)
|
||||
use_power(active_power_usage,power_channel, 1)
|
||||
if(prob(MACHINE_FLICKER_CHANCE))
|
||||
flicker()
|
||||
return 1
|
||||
|
||||
/obj/machinery/proc/multitool_topic(mob/user, list/href_list, obj/O)
|
||||
|
||||
@@ -78,8 +78,12 @@
|
||||
set_picture("ai_bsod")
|
||||
..(severity)
|
||||
|
||||
/obj/machinery/status_display/get_spooked()
|
||||
/obj/machinery/status_display/flicker()
|
||||
if(stat & (NOPOWER | BROKEN))
|
||||
return FALSE
|
||||
|
||||
spookymode = TRUE
|
||||
return TRUE
|
||||
|
||||
// set what is displayed
|
||||
/obj/machinery/status_display/proc/update()
|
||||
@@ -230,8 +234,12 @@
|
||||
set_picture("ai_bsod")
|
||||
..(severity)
|
||||
|
||||
/obj/machinery/ai_status_display/get_spooked()
|
||||
/obj/machinery/ai_status_display/flicker()
|
||||
if(stat & (NOPOWER | BROKEN))
|
||||
return FALSE
|
||||
|
||||
spookymode = TRUE
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/ai_status_display/proc/update()
|
||||
if(mode==0) //Blank
|
||||
|
||||
@@ -95,6 +95,11 @@
|
||||
/// the actual item inserted
|
||||
var/obj/item/inserted_item = null
|
||||
|
||||
/// blocks further flickering while true
|
||||
var/flickering = FALSE
|
||||
/// do I look unpowered, even when powered?
|
||||
var/force_no_power_icon_state = FALSE
|
||||
|
||||
/obj/machinery/vending/Initialize(mapload)
|
||||
var/build_inv = FALSE
|
||||
if(!refill_canister)
|
||||
@@ -138,6 +143,49 @@
|
||||
for(var/obj/item/vending_refill/VR in component_parts)
|
||||
restock(VR)
|
||||
|
||||
/obj/machinery/vending/update_icon()
|
||||
cut_overlays()
|
||||
if(panel_open)
|
||||
add_overlay(image(icon, "[initial(icon_state)]-panel"))
|
||||
|
||||
if(stat & BROKEN)
|
||||
icon_state = "[initial(icon_state)]-broken"
|
||||
else if (stat & NOPOWER || force_no_power_icon_state)
|
||||
icon_state = "[initial(icon_state)]-off"
|
||||
else
|
||||
icon_state = initial(icon_state)
|
||||
|
||||
/*
|
||||
* Reimp, flash the screen on and off repeatedly.
|
||||
*/
|
||||
/obj/machinery/vending/flicker()
|
||||
if(flickering)
|
||||
return FALSE
|
||||
|
||||
if(stat & (BROKEN|NOPOWER))
|
||||
return FALSE
|
||||
|
||||
flickering = TRUE
|
||||
INVOKE_ASYNC(src, /obj/machinery/vending/.proc/flicker_event)
|
||||
|
||||
return TRUE
|
||||
|
||||
/*
|
||||
* Proc to be called by invoke_async in the above flicker() proc.
|
||||
*/
|
||||
/obj/machinery/vending/proc/flicker_event()
|
||||
var/amount = rand(5, 15)
|
||||
|
||||
for(var/i in 1 to amount)
|
||||
force_no_power_icon_state = TRUE
|
||||
update_icon()
|
||||
sleep(rand(1, 3))
|
||||
|
||||
force_no_power_icon_state = FALSE
|
||||
update_icon()
|
||||
sleep(rand(1, 10))
|
||||
update_icon()
|
||||
flickering = FALSE
|
||||
|
||||
/**
|
||||
* Build src.produdct_records from the products lists
|
||||
@@ -285,12 +333,8 @@
|
||||
return
|
||||
if(anchored)
|
||||
panel_open = !panel_open
|
||||
if(panel_open)
|
||||
SCREWDRIVER_OPEN_PANEL_MESSAGE
|
||||
overlays += image(icon, "[initial(icon_state)]-panel")
|
||||
else
|
||||
SCREWDRIVER_CLOSE_PANEL_MESSAGE
|
||||
overlays.Cut()
|
||||
panel_open ? SCREWDRIVER_OPEN_PANEL_MESSAGE : SCREWDRIVER_CLOSE_PANEL_MESSAGE
|
||||
update_icon()
|
||||
SStgui.update_uis(src)
|
||||
|
||||
/obj/machinery/vending/wirecutter_act(mob/user, obj/item/I)
|
||||
@@ -753,21 +797,18 @@
|
||||
atom_say(message)
|
||||
|
||||
/obj/machinery/vending/power_change()
|
||||
if(stat & BROKEN)
|
||||
icon_state = "[initial(icon_state)]-broken"
|
||||
if(powered())
|
||||
stat &= ~NOPOWER
|
||||
update_icon()
|
||||
else
|
||||
if( powered() )
|
||||
icon_state = initial(icon_state)
|
||||
stat &= ~NOPOWER
|
||||
else
|
||||
spawn(rand(0, 15))
|
||||
icon_state = "[initial(icon_state)]-off"
|
||||
stat |= NOPOWER
|
||||
spawn(rand(0, 15))
|
||||
stat |= NOPOWER
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/vending/obj_break(damage_flag)
|
||||
if(!(stat & BROKEN))
|
||||
stat |= BROKEN
|
||||
icon_state = "[initial(icon_state)]-broken"
|
||||
update_icon()
|
||||
|
||||
var/dump_amount = 0
|
||||
var/found_anything = TRUE
|
||||
|
||||
@@ -330,10 +330,6 @@
|
||||
/turf/proc/Bless()
|
||||
flags |= NOJAUNT
|
||||
|
||||
/turf/get_spooked()
|
||||
for(var/atom/movable/AM in contents)
|
||||
AM.get_spooked()
|
||||
|
||||
// Defined here to avoid runtimes
|
||||
/turf/proc/MakeDry(wet_setting = TURF_WET_WATER)
|
||||
return
|
||||
|
||||
@@ -41,7 +41,7 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
|
||||
/mob/dead/observer/proc/open_spawners_menu)
|
||||
|
||||
// Our new boo spell.
|
||||
AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/boo(null))
|
||||
AddSpell(new /obj/effect/proc_holder/spell/targeted/click/boo(null))
|
||||
|
||||
can_reenter_corpse = flags & GHOST_CAN_REENTER
|
||||
started_as_observer = flags & GHOST_IS_OBSERVER
|
||||
|
||||
@@ -9,22 +9,38 @@ GLOBAL_LIST_INIT(boo_phrases, list(
|
||||
"It feels like someone's standing behind you.",
|
||||
))
|
||||
|
||||
/obj/effect/proc_holder/spell/aoe_turf/boo
|
||||
/obj/effect/proc_holder/spell/targeted/click/boo
|
||||
name = "Boo!"
|
||||
desc = "Fuck with the living."
|
||||
selection_deactivated_message = "<span class='shadowling'>Your presence will not be known. For now.</span>"
|
||||
selection_activated_message = "<span class='shadowling'>You prepare to reach across the veil. <b>Left-click to influence a target!</b></span>"
|
||||
auto_target_single = FALSE
|
||||
allowed_type = /atom // No subtypes are safe from spookage.
|
||||
|
||||
ghost = TRUE
|
||||
|
||||
action_icon_state = "boo"
|
||||
school = "transmutation"
|
||||
charge_max = 600
|
||||
charge_max = 2 MINUTES
|
||||
starts_charged = FALSE
|
||||
clothes_req = 0
|
||||
stat_allowed = 1
|
||||
invocation = ""
|
||||
invocation_type = "none"
|
||||
range = 1 // Or maybe 3?
|
||||
range = 20
|
||||
// no need to spam admins regarding boo casts
|
||||
create_logs = FALSE
|
||||
|
||||
/obj/effect/proc_holder/spell/aoe_turf/boo/cast(list/targets, mob/user = usr)
|
||||
for(var/turf/T in targets)
|
||||
T.get_spooked()
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/click/boo/cast(list/targets, mob/user = usr)
|
||||
var/atom/target = targets[1]
|
||||
ASSERT(istype(target))
|
||||
|
||||
if(target.get_spooked())
|
||||
var/area/spook_zone = get_area(target)
|
||||
if (spook_zone.is_haunted == TRUE)
|
||||
to_chat(usr, "<span class='shadowling'>The veil is weak in [spook_zone], it took less effort to influence [target].</span>")
|
||||
charge_counter = charge_max / 2
|
||||
return
|
||||
|
||||
charge_counter = charge_max * 0.9 // We've targetted a non-spookable object! Try again fast!
|
||||
|
||||
@@ -1962,6 +1962,7 @@ Eyes need to have significantly high darksight to shine unless the mob has the X
|
||||
|
||||
/mob/living/carbon/human/get_spooked()
|
||||
to_chat(src, "<span class='whisper'>[pick(GLOB.boo_phrases)]</span>")
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/human/extinguish_light()
|
||||
// Parent function handles stuff the human may be holding
|
||||
|
||||
@@ -57,7 +57,6 @@
|
||||
var/gene_stability = DEFAULT_GENE_STABILITY
|
||||
var/ignore_gene_stability = 0
|
||||
|
||||
var/obj/effect/proc_holder/ranged_ability //Any ranged ability the mob has, as a click override
|
||||
|
||||
var/tesla_ignore = FALSE
|
||||
|
||||
|
||||
@@ -199,3 +199,5 @@
|
||||
|
||||
var/forced_look = null // This can either be a numerical direction or a soft object reference (UID). It makes the mob always face towards the selected thing.
|
||||
var/registered_z
|
||||
|
||||
var/obj/effect/proc_holder/ranged_ability //Any ranged ability the mob has, as a click override
|
||||
|
||||
@@ -419,18 +419,27 @@
|
||||
update_icon()
|
||||
updating_icon = 0
|
||||
|
||||
/obj/machinery/power/apc/get_spooked(second_pass = FALSE)
|
||||
/obj/machinery/power/apc/flicker(second_pass = FALSE)
|
||||
if(opened || panel_open)
|
||||
return
|
||||
return FALSE
|
||||
if(stat & (NOPOWER | BROKEN))
|
||||
return
|
||||
return FALSE
|
||||
if(!second_pass) //The first time, we just cut overlays
|
||||
addtimer(CALLBACK(src, /obj/machinery/power/apc/proc.get_spooked, TRUE), 1)
|
||||
addtimer(CALLBACK(src, /obj/machinery/power/apc/proc.flicker, TRUE), 1)
|
||||
cut_overlays()
|
||||
// APC power distruptions have a chance to propogate to other machines on its network
|
||||
for(var/obj/machinery/M in area)
|
||||
// Please don't cascade, thanks
|
||||
if(M == src)
|
||||
continue
|
||||
if(prob(10))
|
||||
M.flicker()
|
||||
else
|
||||
flick("apcemag", src) //Second time we cause the APC to update its icon, then add a timer to update icon later
|
||||
addtimer(CALLBACK(src, /obj/machinery/power/apc/proc.update_icon, TRUE), 10)
|
||||
|
||||
return TRUE
|
||||
|
||||
//attack with an item - open/close cover, insert cell, or (un)lock interface
|
||||
/obj/machinery/power/apc/attackby(obj/item/W, mob/living/user, params)
|
||||
|
||||
@@ -1231,6 +1240,21 @@
|
||||
else if(last_ch != charging)
|
||||
queue_icon_update()
|
||||
|
||||
if(prob(MACHINE_FLICKER_CHANCE))
|
||||
flicker()
|
||||
|
||||
// lights don't have their own processing loop, so APCs will be the father they never had. 3x as likely to cause a light flicker in a particular area, pick a light to flicker at random
|
||||
if(prob(MACHINE_FLICKER_CHANCE) * 3)
|
||||
var/list/lights = list()
|
||||
for(var/obj/machinery/light/L in area)
|
||||
lights += L
|
||||
|
||||
if(lights.len > 0)
|
||||
var/obj/machinery/light/picked_light = pick(lights)
|
||||
ASSERT(istype(picked_light))
|
||||
picked_light.flicker()
|
||||
|
||||
|
||||
/obj/machinery/power/apc/proc/autoset(var/val, var/on)
|
||||
if(on==0)
|
||||
if(val==2) // if on, return off
|
||||
|
||||
@@ -289,9 +289,6 @@
|
||||
on = FALSE
|
||||
return
|
||||
|
||||
/obj/machinery/light/get_spooked()
|
||||
flicker()
|
||||
|
||||
/**
|
||||
* Updates the light's properties
|
||||
*
|
||||
@@ -519,32 +516,38 @@
|
||||
var/area/A = get_area(src)
|
||||
return A.lightswitch && A.power_light
|
||||
|
||||
/obj/machinery/light/proc/flicker(amount = rand(10, 20))
|
||||
/obj/machinery/light/flicker(amount = rand(20, 30))
|
||||
if(flickering)
|
||||
return
|
||||
return FALSE
|
||||
|
||||
if(!on)
|
||||
return
|
||||
if(!on || status != LIGHT_OK)
|
||||
return FALSE
|
||||
|
||||
flickering = TRUE
|
||||
INVOKE_ASYNC(src, /obj/machinery/light/.proc/flicker_event, amount)
|
||||
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Flicker routine for the light.
|
||||
* Called by invoke_async so the parent proc can return immediately.
|
||||
*/
|
||||
/obj/machinery/light/proc/flicker_event(amount)
|
||||
for(var/i in 1 to amount)
|
||||
if(status != LIGHT_OK)
|
||||
break
|
||||
on = !on
|
||||
update() // No param means that ghosts can burn out lights
|
||||
sleep(rand(5, 15))
|
||||
if(status == LIGHT_OK)
|
||||
on = TRUE
|
||||
/obj/machinery/light/proc/flicker_event(var/amount)
|
||||
if(on && status == LIGHT_OK)
|
||||
for(var/i = 0; i < amount; i++)
|
||||
if(status != LIGHT_OK)
|
||||
break
|
||||
on = FALSE
|
||||
update(FALSE)
|
||||
sleep(rand(1, 3))
|
||||
on = (status == LIGHT_OK)
|
||||
update(FALSE)
|
||||
sleep(rand(1, 10))
|
||||
on = (status == LIGHT_OK)
|
||||
update(FALSE)
|
||||
flickering = FALSE
|
||||
|
||||
|
||||
// ai attack - make lights flicker, because why not
|
||||
/obj/machinery/light/attack_ai(mob/user)
|
||||
flicker(1)
|
||||
|
||||
Reference in New Issue
Block a user