mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-07-13 00:55:20 +01:00
6f0a9400f4
## About The Pull Request Updates Biodome to be gooder. ## Why It's Good For The Game Biodome is one of the more interesting maps thanks to the titular gimmick, but for one reason or another the playerbase loathes it. I'll be making changes to Biodome that I think will improve it, as well as changes to ## Proof Of Testing <details> <summary>Screenshots/Videos</summary> <img width="1861" height="1187" alt="17684994760802257449426043441716" src="https://github.com/user-attachments/assets/0617a32e-bee7-4cbf-a5d9-e9234046bde3" /> <img width="1952" height="1483" alt="17684995784481011964462438821388" src="https://github.com/user-attachments/assets/bf8ee6df-f3a6-4692-bff2-729be806b2b6" /> <img width="1610" height="1279" alt="17684995044717250940024567843557" src="https://github.com/user-attachments/assets/c33d9ba5-f20c-42a4-a985-b0dae3b47e66" /> </details> ## Changelog 🆑 map: various changes to Biodome /🆑 ## To-do - [x] Rework to science - [x] Divide upper biodome with firelocks so that vacuum cannot spread - [x] Plasmaglass to turbine - [x] Compress solars and make them stylistically identical: follow Boxstation example - [x] Expand bitrunning; chute to send crates straight to ore storage? Space heater. Make it look pretty and Gamer in there. - [x] Remove bitrunning window. (Gamers hate sunlight, and also voidwalker abductions) - [x] Make unique cryopods room - [x] Expand crystallizer room ( https://discord.com/channels/1059199070016655462/1460406585401544867/1461868917285982269 ) - [x] Reorganize service biodome departments: move janitorial to be built into the wall. Remove bathroom and rad shelter and build them into a building. Make more space so that the biodome can be more bio. - [x] Reorganize the bridge: move more stuff to lower floor (meeting room, HOP office). Make the blueshield office less of a shrek shack. - [x] Make the cargo waiting area bigger and friendlier to passerby. - [x] Expand blacksmith's workshop. Right now it's more like maints... - [x] Transport tube rebuild; make them less winding and more practical to get to square hallways around station - [x] Add more space windows for void walkers - [x] Wire APC research lab into the grid - [x] Warden's office windoors - [x] Wires/atmospipes south of sec to connect in - [x] Sec firing range and maints door near it need access change proper - [x] Look at courtrooms access - [x] Remove metal foam floors from maints above engi - [x] APC in R&D front office wire to grid - [x] APC in sec C-hallway wire to grid - [x] Correct airlocks direction near vacant office - [x] Vacant office mislabelled maints door - [x] SM cooling loop unconnected in plasma windows - [x] Fix dispopipes and atmospipes in wrestling arena - [x] Biodome lake tiles need planet atmos removed - [x] Doors in science need acess tweaks - [x] L-shaped genpop area - [x] Fix elevator engineering side to be OSHA compliant - [ ] Beer tap fix - [x] Sec locker room needs lights - [x] Wall-mounted extinguisher is on the table near arrivals secpoint - [ ] Check maints for holes - [x] Remove duplicated button in sec mechbay - [x] Fix access to the law office backdoor - [x] Change the west minibridge - [x] Check on the courthouse backroom access - [x] Replace the metal foam over the engineering areas - [x] The new sauna in the unisex restrooms has no APC and therefore has infinite power. - [x] The old dorm in maints (with neon carpet) has an non-functional bolting button. (Possibly intentional.) - [x] Robotics mechbay shutters have no access, for the inside buttons; hallway button does. (Possibly intentional.) - [x] Captains Quarters area extenders outside of the area. (Image attached below.) - [x] Science external solars are disconnected from maintenance and the walls do not attach properly (Image attached below.) - [ ] Gather more criticism of Biodome flaws - [ ] Testing
801 lines
28 KiB
Plaintext
801 lines
28 KiB
Plaintext
#define NIGHTSHIFT_COLOR_MODIFIER 0.15 // BUBBER EDIT ADDITION - LIGHTING
|
|
|
|
// the standard tube light fixture
|
|
/obj/machinery/light
|
|
name = "light fixture"
|
|
icon = 'icons/obj/lighting.dmi'
|
|
icon_state = "tube"
|
|
desc = "A lighting fixture."
|
|
layer = WALL_OBJ_LAYER
|
|
max_integrity = 100
|
|
use_power = ACTIVE_POWER_USE
|
|
idle_power_usage = BASE_MACHINE_IDLE_CONSUMPTION * 0.02
|
|
active_power_usage = BASE_MACHINE_ACTIVE_CONSUMPTION * 0.02
|
|
power_channel = AREA_USAGE_LIGHT //Lights are calc'd via area so they dont need to be in the machine list
|
|
always_area_sensitive = TRUE
|
|
light_angle = 170
|
|
///What overlay the light should use
|
|
var/overlay_icon = 'icons/obj/lighting_overlay.dmi'
|
|
///base description and icon_state
|
|
var/base_state = "tube"
|
|
///Is the light on?
|
|
var/on = FALSE
|
|
///Amount of power used
|
|
var/static_power_used = 0
|
|
///Luminosity when on, also used in power calculation
|
|
var/brightness = 8
|
|
///Basically the alpha of the emitted light source
|
|
var/bulb_power = 1
|
|
///Default colour of the light.
|
|
var/bulb_colour = LIGHT_COLOR_DEFAULT
|
|
///LIGHT_OK, _EMPTY, _BURNED or _BROKEN
|
|
var/status = LIGHT_OK
|
|
///Should we flicker?
|
|
var/flickering = FALSE
|
|
///The type of light item
|
|
var/light_type = /obj/item/light/tube
|
|
///String of the light type, used in descriptions and in examine
|
|
var/fitting = "tube"
|
|
///Count of number of times switched on/off, this is used to calculate the probability the light burns out
|
|
var/switchcount = 0
|
|
///Cell reference
|
|
var/obj/item/stock_parts/power_store/cell
|
|
/// If TRUE, then cell is null, but one is pretending to exist.
|
|
/// This is to defer emergency cell creation unless necessary, as it is very expensive.
|
|
var/has_mock_cell = TRUE
|
|
///If true, this fixture generates a very weak cell at roundstart
|
|
var/start_with_cell = TRUE
|
|
///Currently in night shift mode?
|
|
var/nightshift_enabled = FALSE
|
|
///Set to FALSE to never let this light get switched to night mode.
|
|
var/nightshift_allowed = TRUE
|
|
///Brightness of the nightshift light
|
|
var/nightshift_brightness = 8
|
|
///Alpha of the nightshift light
|
|
var/nightshift_light_power = 0.45
|
|
///Basecolor of the nightshift light
|
|
var/nightshift_light_color = "#FFDDCC"
|
|
//BUBBER NIGHT COLOR: 250ACC
|
|
///If true, the light is in low power mode
|
|
var/low_power_mode = FALSE
|
|
///If true, this light cannot ever be in low power mode
|
|
var/no_low_power = FALSE
|
|
///If true, overrides lights to use emergency lighting
|
|
var/major_emergency = FALSE
|
|
///Multiplier for this light's base brightness during a cascade
|
|
var/bulb_major_emergency_brightness_mul = 0.75
|
|
///Colour of the light when major emergency mode is on
|
|
var/bulb_emergency_colour = "#ff4e4e"
|
|
///Multiplier for this light's base brightness in low power power mode
|
|
var/bulb_low_power_brightness_mul = 0.25
|
|
///Determines the colour of the light while it's in low power mode
|
|
var/bulb_low_power_colour = COLOR_VIVID_RED
|
|
///The multiplier for determining the light's power in low power mode
|
|
var/bulb_low_power_pow_mul = 0.75
|
|
///The minimum value for the light's power in low power mode
|
|
var/bulb_low_power_pow_min = 0.5
|
|
///The Light range to use when working in fire alarm status
|
|
var/fire_brightness = 9
|
|
///The Light power to use when working in fire alarm status
|
|
var/fire_power = 0.5
|
|
///The Light colour to use when working in fire alarm status
|
|
var/fire_colour = COLOR_FIRE_LIGHT_RED
|
|
///Power usage - W per unit of luminosity
|
|
var/power_consumption_rate = 20
|
|
///break if moved, if false also makes it ignore if the wall its on breaks
|
|
var/break_if_moved = TRUE
|
|
|
|
// create a new lighting fixture
|
|
/obj/machinery/light/Initialize(mapload)
|
|
. = ..()
|
|
|
|
// Detect and scream about double stacked lights
|
|
if(PERFORM_ALL_TESTS(focus_only/stacked_lights))
|
|
var/turf/our_location = get_turf(src)
|
|
for(var/obj/machinery/light/on_turf in our_location)
|
|
if(on_turf == src)
|
|
continue
|
|
if(on_turf.dir != dir)
|
|
continue
|
|
stack_trace("Conflicting double stacked light [on_turf.type] found at [get_area(our_location)] ([our_location.x],[our_location.y],[our_location.z])")
|
|
qdel(on_turf)
|
|
|
|
if(!mapload) //sync up nightshift lighting for player made lights
|
|
var/area/our_area = get_room_area()
|
|
var/obj/machinery/power/apc/temp_apc = our_area.apc
|
|
nightshift_enabled = temp_apc?.nightshift_lights
|
|
|
|
if(!start_with_cell || no_low_power)
|
|
has_mock_cell = FALSE
|
|
|
|
if(is_station_level(z))
|
|
RegisterSignal(SSdcs, COMSIG_GLOB_GREY_TIDE_LIGHT, PROC_REF(grey_tide)) //Only put the signal on station lights
|
|
|
|
// Light projects out backwards from the dir of the light
|
|
set_light(l_dir = REVERSE_DIR(dir))
|
|
RegisterSignal(src, COMSIG_LIGHT_EATER_ACT, PROC_REF(on_light_eater))
|
|
AddElement(/datum/element/atmos_sensitive, mapload)
|
|
AddElement(/datum/element/contextual_screentip_bare_hands, rmb_text = "Remove bulb")
|
|
if(mapload)
|
|
find_and_mount_on_atom(mark_for_late_init = TRUE)
|
|
|
|
/obj/machinery/light/get_turfs_to_mount_on()
|
|
return list(get_step(src, dir))
|
|
|
|
/obj/machinery/light/find_and_mount_on_atom(mark_for_late_init, late_init)
|
|
if(break_if_moved)
|
|
return ..()
|
|
|
|
/obj/machinery/light/post_machine_initialize()
|
|
. = ..()
|
|
#ifndef MAP_TEST
|
|
switch(fitting)
|
|
if("tube")
|
|
if(prob(2))
|
|
break_light_tube(TRUE)
|
|
if("bulb")
|
|
if(prob(5))
|
|
break_light_tube(TRUE)
|
|
#endif
|
|
update(trigger = FALSE)
|
|
|
|
/obj/machinery/light/Destroy()
|
|
var/area/local_area = get_room_area()
|
|
if(local_area)
|
|
on = FALSE
|
|
QDEL_NULL(cell)
|
|
return ..()
|
|
|
|
/obj/machinery/light/Move()
|
|
if(status != LIGHT_BROKEN && break_if_moved)
|
|
break_light_tube(TRUE)
|
|
return ..()
|
|
|
|
/obj/machinery/light/Exited(atom/movable/gone, direction)
|
|
. = ..()
|
|
if(gone == cell)
|
|
cell = null
|
|
|
|
/obj/machinery/light/setDir(newdir)
|
|
. = ..()
|
|
set_light(l_dir = REVERSE_DIR(dir))
|
|
|
|
// If we're adjacent to the source, we make this sorta indentation for our light to ensure it stays lit (and to make distances look right)
|
|
// By shifting the light position we use forward a bit, towards something that isn't off by 0.5 from being in angle
|
|
// Because angle calculation is kinda harsh it's hard to find a happy point between fulldark and fullbright for the corners behind the light. this is good enough tho
|
|
/obj/machinery/light/get_light_offset()
|
|
var/list/hand_back = ..()
|
|
var/list/dir_offset = dir2offset(REVERSE_DIR(dir))
|
|
hand_back[1] += dir_offset[1] * 0.5
|
|
hand_back[2] += dir_offset[2] * 0.5
|
|
return hand_back
|
|
|
|
/obj/machinery/light/update_icon_state()
|
|
switch(status) // set icon_states
|
|
if(LIGHT_OK)
|
|
var/area/local_area = get_room_area()
|
|
if(low_power_mode || major_emergency || (local_area?.fire))
|
|
icon_state = "[base_state]_emergency"
|
|
else
|
|
icon_state = "[base_state]"
|
|
if(LIGHT_EMPTY)
|
|
icon_state = "[base_state]-empty"
|
|
if(LIGHT_BURNED)
|
|
icon_state = "[base_state]-burned"
|
|
if(LIGHT_BROKEN)
|
|
icon_state = "[base_state]-broken"
|
|
return ..()
|
|
|
|
/obj/machinery/light/update_overlays()
|
|
. = ..()
|
|
if(!on || status != LIGHT_OK)
|
|
return
|
|
|
|
. += emissive_appearance(overlay_icon, "[base_state]", src, alpha = src.alpha)
|
|
|
|
var/area/local_area = get_room_area()
|
|
|
|
if(flickering)
|
|
. += mutable_appearance(overlay_icon, "[base_state]_flickering")
|
|
return
|
|
if(low_power_mode || major_emergency || (local_area?.fire))
|
|
. += mutable_appearance(overlay_icon, "[base_state]_emergency")
|
|
return
|
|
if(nightshift_enabled)
|
|
. += mutable_appearance(overlay_icon, "[base_state]_nightshift")
|
|
return
|
|
. += mutable_appearance(overlay_icon, base_state)
|
|
|
|
// Area sensitivity is traditionally tied directly to power use, as an optimization
|
|
// But since we want it for fire reacting, we disregard that
|
|
/obj/machinery/light/setup_area_power_relationship()
|
|
. = ..()
|
|
if(!.)
|
|
return
|
|
var/area/our_area = get_room_area()
|
|
RegisterSignal(our_area, COMSIG_AREA_FIRE_CHANGED, PROC_REF(handle_fire))
|
|
|
|
/obj/machinery/light/on_enter_area(datum/source, area/area_to_register)
|
|
..()
|
|
RegisterSignal(area_to_register, COMSIG_AREA_FIRE_CHANGED, PROC_REF(handle_fire))
|
|
handle_fire(area_to_register, area_to_register.fire)
|
|
|
|
/obj/machinery/light/on_exit_area(datum/source, area/area_to_unregister)
|
|
..()
|
|
UnregisterSignal(area_to_unregister, COMSIG_AREA_FIRE_CHANGED)
|
|
|
|
/obj/machinery/light/proc/handle_fire(area/source, new_fire)
|
|
SIGNAL_HANDLER
|
|
update(play_sound = FALSE) // BUBBER EDIT CHANGE - LIGHTING - ORIGINAL: update()
|
|
|
|
// update the icon_state and luminosity of the light depending on its state
|
|
/obj/machinery/light/proc/update(trigger = TRUE, play_sound = TRUE) // BUBBER EDIT CHANGE - LIGHTING - add play_sound
|
|
switch(status)
|
|
if(LIGHT_BROKEN,LIGHT_BURNED,LIGHT_EMPTY)
|
|
on = FALSE
|
|
low_power_mode = FALSE
|
|
if(on)
|
|
var/brightness_set = brightness
|
|
var/power_set = bulb_power
|
|
var/color_set = bulb_colour
|
|
if(color)
|
|
color_set = color
|
|
if(reagents)
|
|
START_PROCESSING(SSmachines, src)
|
|
var/area/local_area = get_room_area()
|
|
if (flickering)
|
|
brightness_set = brightness * 0.25 // BUBBER EDIT CHANGE - LIGHTING - Original: brightness * bulb_low_power_brightness_mul
|
|
power_set = bulb_low_power_pow_mul
|
|
color_set = nightshift_light_color
|
|
else if (local_area?.fire)
|
|
color_set = fire_colour
|
|
power_set = fire_power
|
|
brightness_set = fire_brightness
|
|
else if (major_emergency)
|
|
color_set = bulb_emergency_colour
|
|
brightness_set = brightness * bulb_major_emergency_brightness_mul
|
|
else if (nightshift_enabled)
|
|
brightness_set = nightshift_brightness
|
|
power_set = nightshift_light_power
|
|
if(!color)
|
|
// BUBBER EDIT CHANGE START - Dynamic nightshift color
|
|
// color_set = nightshift_light_color
|
|
if(isnull(nightshift_light_color))
|
|
// Adjust light values to be warmer. I doubt caching would speed this up by any worthwhile amount, as it's all very fast number and string operations.
|
|
// Convert to numbers for easier manipulation.
|
|
var/list/color_parts = rgb2num(bulb_colour)
|
|
var/red = color_parts[1]
|
|
var/green = color_parts[2]
|
|
var/blue = color_parts[3]
|
|
|
|
red += round(red * NIGHTSHIFT_COLOR_MODIFIER)
|
|
green -= round(green * NIGHTSHIFT_COLOR_MODIFIER * 0.3)
|
|
red = clamp(red, 0, 255) // clamp to be safe, or you can end up with an invalid hex value
|
|
green = clamp(green, 0, 255)
|
|
blue = clamp(blue, 0, 255)
|
|
color_set = rgb(red, green, blue) // Splice the numbers together and turn them back to hex.
|
|
else
|
|
color_set = nightshift_light_color
|
|
// BUBBER EDIT ADDITION END
|
|
if (cached_color_filter)
|
|
color_set = apply_matrix_to_color(color_set, cached_color_filter["color"], cached_color_filter["space"] || COLORSPACE_RGB)
|
|
var/matching = light && brightness_set == light.light_range && power_set == light.light_power && color_set == light.light_color
|
|
if(!matching)
|
|
switchcount++
|
|
if( prob( min(60, (switchcount**2)*0.01) ) )
|
|
if(trigger)
|
|
burn_out()
|
|
else
|
|
use_power = ACTIVE_POWER_USE
|
|
set_light(
|
|
l_range = brightness_set,
|
|
l_power = power_set,
|
|
l_color = color_set
|
|
)
|
|
// BUBBER EDIT ADDITION BEGIN - LIGHTING
|
|
if(play_sound)
|
|
playsound(src.loc, 'modular_skyrat/modules/aesthetics/lights/sound/light_on.ogg', 65, 1)
|
|
// BUBBER EDIT ADDITION END
|
|
else if(has_emergency_power(LIGHT_EMERGENCY_POWER_USE) && !turned_off())
|
|
use_power = IDLE_POWER_USE
|
|
low_power_mode = TRUE
|
|
START_PROCESSING(SSmachines, src)
|
|
else
|
|
use_power = IDLE_POWER_USE
|
|
set_light(l_range = 0)
|
|
update_appearance()
|
|
update_current_power_usage()
|
|
broken_sparks(start_only=TRUE)
|
|
|
|
/obj/machinery/light/update_current_power_usage()
|
|
if(!on && static_power_used > 0) //Light is off but still powered
|
|
removeStaticPower(static_power_used, AREA_USAGE_STATIC_LIGHT)
|
|
static_power_used = 0
|
|
else if(on) //Light is on, just recalculate usage
|
|
var/static_power_used_new = 0
|
|
var/area/local_area = get_room_area()
|
|
if (nightshift_enabled && !local_area?.fire)
|
|
static_power_used_new = nightshift_brightness * nightshift_light_power * power_consumption_rate
|
|
else
|
|
static_power_used_new = brightness * bulb_power * power_consumption_rate
|
|
if(static_power_used != static_power_used_new) //Consumption changed - update
|
|
removeStaticPower(static_power_used, AREA_USAGE_STATIC_LIGHT)
|
|
static_power_used = static_power_used_new
|
|
addStaticPower(static_power_used, AREA_USAGE_STATIC_LIGHT)
|
|
|
|
/obj/machinery/light/update_atom_colour()
|
|
..()
|
|
update(play_sound = FALSE) // BUBBER EDIT CHANGE - LIGHTING - ORIGINAL: update()
|
|
|
|
/obj/machinery/light/proc/broken_sparks(start_only=FALSE)
|
|
if(!QDELETED(src) && status == LIGHT_BROKEN && has_power() && MC_RUNNING())
|
|
if(!start_only)
|
|
do_sparks(3, TRUE, src)
|
|
var/delay = rand(BROKEN_SPARKS_MIN, BROKEN_SPARKS_MAX)
|
|
addtimer(CALLBACK(src, PROC_REF(broken_sparks)), delay, TIMER_UNIQUE | TIMER_NO_HASH_WAIT)
|
|
|
|
/obj/machinery/light/proc/is_full_charge()
|
|
if(cell)
|
|
return cell.charge == cell.maxcharge
|
|
return TRUE
|
|
|
|
/obj/machinery/light/process(seconds_per_tick)
|
|
if(has_power())
|
|
// If the cell is done mooching station power, and reagents don't need processing, stop processing
|
|
if(is_full_charge() && !reagents)
|
|
return PROCESS_KILL
|
|
if(cell)
|
|
charge_cell(LIGHT_EMERGENCY_POWER_USE * seconds_per_tick, cell = cell) //Recharge emergency power automatically while not using it
|
|
if(reagents) //with most reagents coming out at 300, and with most meaningful reactions coming at 370+, this rate gives a few seconds of time to place it in and get out of dodge regardless of input.
|
|
reagents.adjust_thermal_energy(8 * reagents.total_volume * SPECIFIC_HEAT_DEFAULT * seconds_per_tick)
|
|
reagents.handle_reactions()
|
|
if(low_power_mode && !use_emergency_power(LIGHT_EMERGENCY_POWER_USE * seconds_per_tick))
|
|
update(trigger = FALSE, play_sound = FALSE) // BUBBER EDIT CHANGE - LIGHTING - Original: update(FALSE) //Disables emergency mode and sets the color to normal
|
|
|
|
/obj/machinery/light/proc/burn_out()
|
|
if(status == LIGHT_OK)
|
|
status = LIGHT_BURNED
|
|
icon_state = "[base_state]-burned"
|
|
on = FALSE
|
|
set_light(l_range = 0)
|
|
|
|
// attempt to set the light's on/off status
|
|
// will not switch on if broken/burned/empty
|
|
/obj/machinery/light/proc/set_on(turn_on)
|
|
on = (turn_on && status == LIGHT_OK)
|
|
update()
|
|
|
|
/obj/machinery/light/get_cell()
|
|
if (has_mock_cell)
|
|
cell = new /obj/item/stock_parts/power_store/cell/emergency_light(src)
|
|
has_mock_cell = FALSE
|
|
|
|
return cell
|
|
|
|
// examine verb
|
|
/obj/machinery/light/examine(mob/user)
|
|
. = ..()
|
|
switch(status)
|
|
if(LIGHT_OK)
|
|
. += span_notice("It is turned [on? "on" : "off"].")
|
|
if(LIGHT_EMPTY)
|
|
. += span_notice("The [fitting] has been removed.")
|
|
if(LIGHT_BURNED)
|
|
. += span_danger("The [fitting] is burnt out.")
|
|
if(LIGHT_BROKEN)
|
|
. += span_danger("The [fitting] has been smashed.")
|
|
if(cell || has_mock_cell)
|
|
. += span_notice("Its backup power charge meter reads [has_mock_cell ? 100 : round((cell.charge / cell.maxcharge) * 100, 0.1)]%.")
|
|
|
|
// attack with item - insert light (if right type), otherwise try to break the light
|
|
|
|
/obj/machinery/light/attackby(obj/item/tool, mob/living/user, list/modifiers, list/attack_modifiers)
|
|
// attempt to insert light
|
|
if(istype(tool, /obj/item/light))
|
|
if(status == LIGHT_OK)
|
|
to_chat(user, span_warning("There is a [fitting] already inserted!"))
|
|
return
|
|
add_fingerprint(user)
|
|
var/obj/item/light/light_object = tool
|
|
if(!istype(light_object, light_type))
|
|
to_chat(user, span_warning("This type of light requires a [fitting]!"))
|
|
return
|
|
if(!user.temporarilyRemoveItemFromInventory(light_object))
|
|
return
|
|
|
|
add_fingerprint(user)
|
|
if(status != LIGHT_EMPTY)
|
|
drop_light_tube(user)
|
|
to_chat(user, span_notice("You replace [light_object]."))
|
|
else
|
|
to_chat(user, span_notice("You insert [light_object]."))
|
|
if(length(light_object.reagents.reagent_list))
|
|
create_reagents(LIGHT_REAGENT_CAPACITY, SEALED_CONTAINER | TRANSPARENT)
|
|
light_object.reagents.trans_to(reagents, LIGHT_REAGENT_CAPACITY)
|
|
status = light_object.status
|
|
switchcount = light_object.switchcount
|
|
brightness = light_object.brightness
|
|
on = has_power()
|
|
update()
|
|
|
|
qdel(light_object)
|
|
|
|
return
|
|
|
|
// attempt to stick weapon into light socket
|
|
if(status != LIGHT_EMPTY || user.combat_mode)
|
|
return ..()
|
|
if(tool.tool_behaviour == TOOL_SCREWDRIVER) //If it's a screwdriver open it.
|
|
tool.play_tool_sound(src, 75)
|
|
user.visible_message(span_notice("[user.name] opens [src]'s casing."), \
|
|
span_notice("You open [src]'s casing."), span_hear("You hear a noise."))
|
|
deconstruct()
|
|
return
|
|
|
|
if(tool.item_flags & ABSTRACT)
|
|
return
|
|
|
|
to_chat(user, span_userdanger("You stick \the [tool] into the light socket!"))
|
|
if(has_power() && (tool.obj_flags & CONDUCTS_ELECTRICITY))
|
|
do_sparks(3, TRUE, src)
|
|
if (prob(75))
|
|
electrocute_mob(user, get_area(src), src, (rand(7,10) * 0.1), TRUE)
|
|
|
|
/obj/machinery/light/on_deconstruction(disassembled)
|
|
var/atom/drop_point = drop_location()
|
|
|
|
var/obj/item/wallframe/light_fixture/frame = null
|
|
switch(fitting)
|
|
if("tube")
|
|
frame = new /obj/item/wallframe/light_fixture(drop_point)
|
|
if("bulb")
|
|
frame = new /obj/item/wallframe/light_fixture/small(drop_point)
|
|
if("floor bulb")
|
|
frame = new /obj/item/wallframe/light_fixture/small(drop_point)
|
|
if(!disassembled)
|
|
frame.take_damage(frame.max_integrity * 0.5, sound_effect = FALSE)
|
|
if(status != LIGHT_BROKEN)
|
|
break_light_tube()
|
|
if(status != LIGHT_EMPTY)
|
|
drop_light_tube()
|
|
new /obj/item/stack/cable_coil(loc, 1, "red")
|
|
transfer_fingerprints_to(frame)
|
|
|
|
var/obj/item/stock_parts/power_store/real_cell = get_cell()
|
|
if(!QDELETED(real_cell))
|
|
real_cell.forceMove(drop_point)
|
|
|
|
/obj/machinery/light/attacked_by(obj/item/attacking_object, mob/living/user, list/modifiers, list/attack_modifiers)
|
|
. = ..()
|
|
if(. <= 0)
|
|
return
|
|
if(status != LIGHT_BROKEN && status != LIGHT_EMPTY)
|
|
return
|
|
if(!on || !(attacking_object.obj_flags & CONDUCTS_ELECTRICITY))
|
|
return
|
|
if(!prob(12))
|
|
return
|
|
electrocute_mob(user, get_area(src), src, 0.3, TRUE)
|
|
|
|
/obj/machinery/light/take_damage(damage_amount, damage_type = BRUTE, damage_flag = "", sound_effect = TRUE, attack_dir, armour_penetration = 0)
|
|
. = ..()
|
|
if(. && !QDELETED(src))
|
|
if(prob(damage_amount * 5))
|
|
break_light_tube()
|
|
|
|
/obj/machinery/light/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0)
|
|
switch(damage_type)
|
|
if(BRUTE)
|
|
switch(status)
|
|
if(LIGHT_EMPTY)
|
|
playsound(loc, 'sound/items/weapons/smash.ogg', 50, TRUE)
|
|
if(LIGHT_BROKEN)
|
|
playsound(loc, 'sound/effects/hit_on_shattered_glass.ogg', 90, TRUE)
|
|
else
|
|
playsound(loc, 'sound/effects/glass/glasshit.ogg', 90, TRUE)
|
|
if(BURN)
|
|
playsound(loc, 'sound/items/tools/welder.ogg', 100, TRUE)
|
|
|
|
// returns if the light has power /but/ is manually turned off
|
|
// if a light is turned off, it won't activate emergency power
|
|
/obj/machinery/light/proc/turned_off()
|
|
var/area/local_area = get_room_area()
|
|
return !local_area.lightswitch && local_area.power_light || flickering
|
|
|
|
// returns whether this light has power
|
|
// true if area has power and lightswitch is on
|
|
/obj/machinery/light/proc/has_power()
|
|
var/area/local_area = get_room_area()
|
|
return local_area.lightswitch && local_area.power_light
|
|
|
|
// returns whether this light has emergency power
|
|
// can also return if it has access to a certain amount of that power
|
|
/obj/machinery/light/proc/has_emergency_power(power_usage_amount)
|
|
if(no_low_power || (!cell && !has_mock_cell))
|
|
return FALSE
|
|
if (has_mock_cell)
|
|
return status == LIGHT_OK
|
|
if(power_usage_amount ? cell.charge >= power_usage_amount : cell.charge)
|
|
return status == LIGHT_OK
|
|
return FALSE
|
|
|
|
// attempts to use power from the installed emergency cell, returns true if it does and false if it doesn't
|
|
/obj/machinery/light/proc/use_emergency_power(power_usage_amount = LIGHT_EMERGENCY_POWER_USE)
|
|
if(!has_emergency_power(power_usage_amount))
|
|
return FALSE
|
|
var/obj/item/stock_parts/power_store/real_cell = get_cell()
|
|
if(real_cell.charge > 2.5 * /obj/item/stock_parts/power_store/cell/emergency_light::maxcharge) //it's meant to handle 120 W, ya doofus
|
|
visible_message(span_warning("[src] short-circuits from too powerful of a power cell!"))
|
|
burn_out()
|
|
return FALSE
|
|
real_cell.use(power_usage_amount)
|
|
set_light(
|
|
l_range = brightness * bulb_low_power_brightness_mul,
|
|
l_power = max(bulb_low_power_pow_min, bulb_low_power_pow_mul * (real_cell.charge / real_cell.maxcharge)),
|
|
l_color = bulb_low_power_colour
|
|
)
|
|
return TRUE
|
|
|
|
/obj/machinery/light/proc/flicker(amount = 1)
|
|
set waitfor = FALSE
|
|
if(flickering || !on || status != LIGHT_OK)
|
|
return
|
|
|
|
. = TRUE // did we actually flicker? Send this now because we expect immediate response, before sleeping.
|
|
set_light(
|
|
l_range = brightness * 0.25, // BUBBER EDIT CHANGE - LIGHTING - Original: brightness * bulb_low_power_brightness_mul,
|
|
l_power = bulb_low_power_pow_mul,
|
|
l_color = nightshift_light_color,
|
|
)
|
|
cut_overlays(src)
|
|
stoplag(0.7 SECONDS)
|
|
if(prob(30))
|
|
do_sparks(number = 2, cardinal_only = TRUE, source = src)
|
|
|
|
for(var/i in 1 to amount)
|
|
if(status != LIGHT_OK || !has_power())
|
|
break
|
|
flickering = !flickering
|
|
update(trigger = FALSE, play_sound = FALSE) // BUBBER EDIT CHANGE - LIGHTING - Original: update(FALSE)
|
|
stoplag(pick(list(2 SECONDS, 4 SECONDS, 6 SECONDS)))
|
|
|
|
if(has_power())
|
|
on = (status == LIGHT_OK)
|
|
else
|
|
on = FALSE
|
|
|
|
flickering = FALSE
|
|
update(trigger = FALSE, play_sound = FALSE) // BUBBER EDIT CHANGE - LIGHTING - Original: update(FALSE)
|
|
|
|
// ai attack - make lights flicker, because why not
|
|
|
|
/obj/machinery/light/attack_ai(mob/user)
|
|
no_low_power = !no_low_power
|
|
to_chat(user, span_notice("Emergency lights for this fixture have been [no_low_power ? "disabled" : "enabled"]."))
|
|
update(trigger = FALSE, play_sound = FALSE) // BUBBER EDIT CHANGE - LIGHTING - Original: update(FALSE)
|
|
return
|
|
|
|
// attack with hand - remove tube/bulb
|
|
// if hands aren't protected and the light is on, burn the player
|
|
|
|
/obj/machinery/light/attack_hand_secondary(mob/living/carbon/human/user, list/modifiers)
|
|
. = ..()
|
|
if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN)
|
|
return
|
|
user.changeNext_move(CLICK_CD_MELEE)
|
|
add_fingerprint(user)
|
|
|
|
if(status == LIGHT_EMPTY)
|
|
to_chat(user, span_warning("There is no [fitting] in this light!"))
|
|
return
|
|
|
|
// make it burn hands unless you're wearing heat insulated gloves or have the RESISTHEAT/RESISTHEATHANDS traits
|
|
if(!on)
|
|
to_chat(user, span_notice("You remove the light [fitting]."))
|
|
// create a light tube/bulb item and put it in the user's hand
|
|
drop_light_tube(user)
|
|
return
|
|
|
|
var/protected = FALSE
|
|
|
|
if(istype(user))
|
|
var/obj/item/organ/stomach/maybe_stomach = user.get_organ_slot(ORGAN_SLOT_STOMACH)
|
|
if(istype(maybe_stomach, /obj/item/organ/stomach/ethereal))
|
|
var/obj/item/organ/stomach/ethereal/stomach = maybe_stomach
|
|
if(stomach.drain_time > world.time)
|
|
return
|
|
to_chat(user, span_notice("You start channeling some power through the [fitting] into your body."))
|
|
stomach.drain_time = world.time + LIGHT_DRAIN_TIME
|
|
while(do_after(user, LIGHT_DRAIN_TIME, target = src))
|
|
stomach.drain_time = world.time + LIGHT_DRAIN_TIME
|
|
if(istype(stomach))
|
|
to_chat(user, span_notice("You receive some charge from the [fitting]."))
|
|
stomach.adjust_charge(LIGHT_POWER_GAIN)
|
|
else
|
|
to_chat(user, span_warning("You can't receive charge from the [fitting]!"))
|
|
return
|
|
|
|
if(user.gloves)
|
|
var/obj/item/clothing/gloves/electrician_gloves = user.gloves
|
|
if(electrician_gloves.max_heat_protection_temperature && electrician_gloves.max_heat_protection_temperature > 360)
|
|
protected = TRUE
|
|
else
|
|
protected = TRUE
|
|
|
|
if(protected || HAS_TRAIT(user, TRAIT_RESISTHEAT) || HAS_TRAIT(user, TRAIT_RESISTHEATHANDS))
|
|
to_chat(user, span_notice("You remove the light [fitting]."))
|
|
else if(istype(user) && user.dna.check_mutation(/datum/mutation/telekinesis))
|
|
to_chat(user, span_notice("You telekinetically remove the light [fitting]."))
|
|
else
|
|
var/obj/item/bodypart/affecting = user.get_active_hand()
|
|
user.apply_damage(5, BURN, affecting, wound_bonus = CANT_WOUND)
|
|
if(HAS_TRAIT(user, TRAIT_LIGHTBULB_REMOVER))
|
|
to_chat(user, span_notice("You feel your [affecting.plaintext_zone] burning, but the light begins to budge..."))
|
|
if(!do_after(user, 5 SECONDS, target = src))
|
|
return
|
|
user.apply_damage(10, BURN, user.get_active_hand(), wound_bonus = CANT_WOUND)
|
|
to_chat(user, span_notice("You manage to remove the light [fitting], shattering it in process."))
|
|
break_light_tube()
|
|
else
|
|
to_chat(user, span_warning("You try to remove the light [fitting], but you burn your hand on it!"))
|
|
return
|
|
// create a light tube/bulb item and put it in the user's hand
|
|
drop_light_tube(user)
|
|
|
|
/obj/machinery/light/proc/set_major_emergency_light()
|
|
major_emergency = TRUE
|
|
update(trigger = FALSE, play_sound = FALSE) // BUBBER EDIT CHANGE - LIGHTING - Original: update()
|
|
|
|
/obj/machinery/light/proc/unset_major_emergency_light()
|
|
major_emergency = FALSE
|
|
update(trigger = FALSE, play_sound = FALSE) // BUBBER EDIT CHANGE - LIGHTING - Original: update()
|
|
|
|
/obj/machinery/light/proc/drop_light_tube(mob/user)
|
|
var/obj/item/light/light_object = new light_type()
|
|
if(reagents)
|
|
reagents.trans_to(light_object.reagents, LIGHT_REAGENT_CAPACITY)
|
|
QDEL_NULL(reagents)
|
|
light_object.status = status
|
|
light_object.brightness = brightness
|
|
|
|
// light item inherits the switchcount, then zero it
|
|
light_object.switchcount = switchcount
|
|
switchcount = 0
|
|
|
|
light_object.update_appearance()
|
|
light_object.forceMove(loc)
|
|
|
|
if(user) //puts it in our active hand
|
|
light_object.add_fingerprint(user)
|
|
user.put_in_active_hand(light_object)
|
|
|
|
status = LIGHT_EMPTY
|
|
update()
|
|
return light_object
|
|
|
|
/obj/machinery/light/attack_tk(mob/user)
|
|
if(status == LIGHT_EMPTY)
|
|
to_chat(user, span_warning("There is no [fitting] in this light!"))
|
|
return
|
|
|
|
to_chat(user, span_notice("You telekinetically remove the light [fitting]."))
|
|
// create a light tube/bulb item and put it in the user's hand
|
|
var/obj/item/light/light_tube = drop_light_tube()
|
|
return light_tube.attack_tk(user)
|
|
|
|
// break the light and make sparks if was on
|
|
/obj/machinery/light/proc/break_light_tube(skip_sound_and_sparks = FALSE)
|
|
if(status == LIGHT_EMPTY || status == LIGHT_BROKEN)
|
|
return
|
|
|
|
if(!skip_sound_and_sparks)
|
|
if(status == LIGHT_OK || status == LIGHT_BURNED)
|
|
playsound(loc, 'sound/effects/glass/glasshit.ogg', 75, TRUE)
|
|
if(on)
|
|
do_sparks(3, TRUE, src)
|
|
status = LIGHT_BROKEN
|
|
update()
|
|
|
|
/obj/machinery/light/proc/fix()
|
|
if(status == LIGHT_OK)
|
|
return
|
|
status = LIGHT_OK
|
|
brightness = initial(brightness)
|
|
on = TRUE
|
|
update()
|
|
|
|
/obj/machinery/light/zap_act(power, zap_flags)
|
|
var/explosive = zap_flags & ZAP_MACHINE_EXPLOSIVE
|
|
zap_flags &= ~(ZAP_MACHINE_EXPLOSIVE | ZAP_OBJ_DAMAGE)
|
|
. = ..()
|
|
if(explosive)
|
|
explosion(src, flame_range = 5, adminlog = FALSE)
|
|
qdel(src)
|
|
|
|
// called when area power state changes
|
|
/obj/machinery/light/power_change()
|
|
SHOULD_CALL_PARENT(FALSE)
|
|
var/area/local_area = get_room_area()
|
|
set_on(local_area.lightswitch && local_area.power_light)
|
|
|
|
// called when heated
|
|
|
|
/obj/machinery/light/should_atmos_process(datum/gas_mixture/air, exposed_temperature)
|
|
return exposed_temperature > 673
|
|
|
|
/obj/machinery/light/atmos_expose(datum/gas_mixture/air, exposed_temperature)
|
|
if(prob(max(0, exposed_temperature - 673))) //0% at <400C, 100% at >500C
|
|
break_light_tube()
|
|
|
|
/obj/machinery/light/proc/on_light_eater(obj/machinery/light/source, datum/light_eater)
|
|
SIGNAL_HANDLER
|
|
break_light_tube()
|
|
return COMPONENT_BLOCK_LIGHT_EATER
|
|
|
|
/obj/machinery/light/on_saboteur(datum/source, disrupt_duration)
|
|
. = ..()
|
|
break_light_tube()
|
|
return TRUE
|
|
|
|
/obj/machinery/light/proc/grey_tide(datum/source, list/grey_tide_areas)
|
|
SIGNAL_HANDLER
|
|
|
|
for(var/area_type in grey_tide_areas)
|
|
if(!istype(get_area(src), area_type))
|
|
continue
|
|
INVOKE_ASYNC(src, PROC_REF(flicker))
|
|
|
|
/obj/machinery/light/floor
|
|
name = "floor light"
|
|
desc = "A lightbulb you can walk on without breaking it, amazing."
|
|
icon = 'icons/obj/lighting.dmi'
|
|
base_state = "floor" // base description and icon_state
|
|
icon_state = "floor"
|
|
brightness = 4
|
|
light_angle = 360
|
|
layer = BELOW_CATWALK_LAYER
|
|
plane = FLOOR_PLANE
|
|
light_type = /obj/item/light/bulb
|
|
fitting = "floor bulb"
|
|
nightshift_brightness = 4
|
|
fire_brightness = 4.5
|
|
|
|
/obj/machinery/light/floor/get_turfs_to_mount_on()
|
|
return list(get_turf(src))
|
|
|
|
/obj/machinery/light/floor/is_mountable_turf(turf/target)
|
|
return !isgroundlessturf(target)
|
|
|
|
/obj/machinery/light/floor/get_moutable_objects()
|
|
var/static/list/attachables = list(
|
|
/obj/structure/thermoplastic,
|
|
/obj/structure/lattice/catwalk,
|
|
)
|
|
|
|
return attachables
|
|
|
|
/obj/machinery/light/floor/get_light_offset()
|
|
return list(0, 0)
|
|
|
|
/obj/machinery/light/floor/broken
|
|
status = LIGHT_BROKEN
|
|
icon_state = "floor-broken"
|
|
|
|
/obj/machinery/light/floor/burned
|
|
status = LIGHT_BURNED
|
|
icon_state = "floor-burned"
|
|
|
|
/obj/machinery/light/floor/empty
|
|
icon_state = "floor-empty"
|
|
start_with_cell = FALSE
|
|
status = LIGHT_EMPTY
|
|
|
|
/obj/machinery/light/floor/transport
|
|
name = "transport light"
|
|
break_if_moved = FALSE
|
|
// has to render above tram things (trams are stupid)
|
|
layer = BELOW_OPEN_DOOR_LAYER
|
|
plane = GAME_PLANE
|
|
|
|
#undef NIGHTSHIFT_COLOR_MODIFIER // BUBBER EDIT ADDITION - LIGHTING
|