Files
Aurora.3/code/modules/power/gravitygenerator.dm
Batrachophreno 0c7ab8baa7 Lemurian Sea (#22686)
changes:
  - refactor: "Refactors Gravity Generator UI from HTML to TGUI."
- rscadd: "Adds sector-based modifier var 'overmap_hazards_multiplier'
for generating total overmap hazard count."
  - soundadd: "Adds new Lemurian Sea 'welcome' announcements."
- rscadd: "Added Lemurian Sea gravitic anomalies as overmap hazards and
random events."
  - rscadd: "Adds ADPI/The Voices."
- rscadd: "Adds ADPI Panel for modmins to send ADPI messages to a single
character or all characters from their respective pools, or custom
messages."
- balance: "Vaurca Hivenet communication, the Hivenet Manifest, and
Hivenet Echoes are now disabled while the ship is in Lemurian Sea
sectors."
2026-06-13 16:25:49 +00:00

510 lines
16 KiB
Plaintext

#define POWER_IDLE 0
#define POWER_UP 1
#define POWER_DOWN 2
#define GRAV_OPERATIONAL 0
#define GRAV_NEEDS_SCREWDRIVER 1
#define GRAV_NEEDS_WELDING 2
#define GRAV_NEEDS_PLASTEEL 3
#define GRAV_NEEDS_WRENCH 4
#define AREA_ERRNONE 0
#define AREA_STATION 1
#define AREA_SPACE 2
#define AREA_SPECIAL 3
//
// Abstract Generator
//
/obj/structure/machinery/gravity_generator
name = "gravity generator"
desc = "A complex and energy-hungry device which produces a graviton field over a modest radius when active."
icon = 'icons/obj/machinery/gravity_generator.dmi'
anchored = TRUE
density = TRUE
use_power = POWER_USE_OFF
unacidable = TRUE
var/sprite_number = 0
light_color = LIGHT_COLOR_CYAN
light_power = 1.4
light_range = 6
interact_offline = TRUE
/obj/structure/machinery/gravity_generator/ex_act(severity)
if(severity == 1) // Very sturdy.
set_broken()
/obj/structure/machinery/gravity_generator/update_icon()
..()
icon_state = "[get_status()]_[sprite_number]"
/obj/structure/machinery/gravity_generator/proc/get_status()
return "off"
// You aren't allowed to move.
/obj/structure/machinery/gravity_generator/Move()
. = ..()
qdel(src)
/obj/structure/machinery/gravity_generator/proc/set_broken()
stat |= BROKEN
/obj/structure/machinery/gravity_generator/proc/set_fix()
stat &= ~BROKEN
/obj/structure/machinery/gravity_generator/part/Destroy()
set_broken()
if(main_part)
qdel(main_part)
return ..()
//
// Part generator which is mostly there for looks
//
/obj/structure/machinery/gravity_generator/part
var/obj/structure/machinery/gravity_generator/main/main_part = null
/obj/structure/machinery/gravity_generator/part/attackby(obj/item/attacking_item, mob/user)
return main_part.attackby(attacking_item, user)
/obj/structure/machinery/gravity_generator/part/get_status()
return main_part.get_status()
/obj/structure/machinery/gravity_generator/part/attack_hand(mob/user as mob)
return main_part.attack_hand(user)
/obj/structure/machinery/gravity_generator/part/set_broken()
..()
if(main_part && !(main_part.stat & BROKEN))
main_part.set_broken()
//
// Generator which spawns with the station.
//
/obj/structure/machinery/gravity_generator/main/station/Initialize()
. = ..()
setup_parts()
middle.AddOverlays("activated")
update_list(TRUE)
addtimer(CALLBACK(src, PROC_REF(round_startset)), 100)
/obj/structure/machinery/gravity_generator/main/station/proc/round_startset()
if(round_start >= 1)
round_start--
set_light(8,1,LIGHT_COLOR_CYAN)
//
// Generator an admin can spawn
//
/obj/structure/machinery/gravity_generator/main/station/admin/Initialize()
. = ..()
round_start = 1
//
// Main Generator with the main code
//
/obj/structure/machinery/gravity_generator/main
icon_state = "on_8"
idle_power_usage = 5 KILO WATTS
active_power_usage = 10 KILO WATTS
power_channel = AREA_USAGE_ENVIRON
sprite_number = 8
interact_offline = 1
/// Whether the gravity generator is currently active.
var/on = TRUE
/// If the main breaker is on/off, to enable/disable gravity.
var/breaker = TRUE
/// If the generator is idle, charging, or down.
var/charging_state = POWER_IDLE
/// How much charge the gravity generator has, goes down when breaker is shut, and shuts down at 0.
var/charge_count = 100
/// The gravity core overlay currently used.
var/current_overlay = null
/// Currently configured gravity strength.
var/setting = 1.0
/// Audio for when the gravgen is on
var/datum/looping_sound/gravgen/soundloop
var/list/sprite_parts = list()
var/obj/middle = null
/// When broken, what stage it is at (GRAV_NEEDS_SCREWDRIVER:0) (GRAV_NEEDS_WELDING:1) (GRAV_NEEDS_PLASTEEL:2) (GRAV_NEEDS_WRENCH:3)
var/broken_state = GRAV_OPERATIONAL
var/list/localareas = list()
var/round_start = 2 //To help stop a bug with round start
var/panel_open_heavy = 0
/obj/structure/machinery/gravity_generator/main/Initialize()
. = ..()
soundloop = new(src, start_immediately = FALSE)
addtimer(CALLBACK(src, PROC_REF(updateareas)), 10)
return INITIALIZE_HINT_LATELOAD
/obj/structure/machinery/gravity_generator/main/LateInitialize()
..()
if(SSatlas.current_map.use_overmap && !linked)
var/my_sector = GLOB.map_sectors["[z]"]
if (istype(my_sector, /obj/effect/overmap/visitable))
attempt_hook_up(my_sector)
if(linked)
linked.gravity_generator = src
/obj/structure/machinery/gravity_generator/main/Destroy()
LOG_DEBUG("Gravity Generator Destroyed")
investigate_log("was destroyed!", "gravity")
on = 0
QDEL_NULL(soundloop)
update_list(TRUE)
for(var/obj/structure/machinery/gravity_generator/part/O in sprite_parts)
O.main_part = null
qdel(O)
linked?.gravity_generator = null
return ..()
/obj/structure/machinery/gravity_generator/main/proc/setup_parts()
var/turf/our_turf = get_turf(src)
// 9x9 block obtained from the bottom middle of the block
var/list/spawn_turfs = block(locate(our_turf.x - 1, our_turf.y + 2, our_turf.z), locate(our_turf.x + 1, our_turf.y, our_turf.z))
var/count = 10
for(var/turf/T in spawn_turfs)
count--
if(T == our_turf) // Skip our turf.
continue
var/obj/structure/machinery/gravity_generator/part/part = new(T)
if(count == 5) // Middle
middle = part
if(count <= 3) // Their sprite is the top part of the generator
part.density = 0
part.layer = MOB_LAYER + 0.1
part.sprite_number = count
part.main_part = src
sprite_parts += part
part.update_icon()
/obj/structure/machinery/gravity_generator/main/proc/connected_parts()
return sprite_parts.len == 8
/obj/structure/machinery/gravity_generator/main/set_broken()
..()
for(var/obj/structure/machinery/gravity_generator/M in sprite_parts)
if(!(M.stat & BROKEN))
M.set_broken()
middle.ClearOverlays()
charge_count = 0
breaker = 0
set_power()
disable()
investigate_log("has broken down.", "gravity")
/obj/structure/machinery/gravity_generator/main/set_fix()
..()
for(var/obj/structure/machinery/gravity_generator/M in sprite_parts)
if(M.stat & BROKEN)
M.set_fix()
broken_state = 0
update_icon()
set_power()
// Interaction
// Fixing the gravity generator.
/obj/structure/machinery/gravity_generator/main/attackby(obj/item/attacking_item, mob/user)
var/old_broken_state = broken_state
switch(broken_state)
if(GRAV_NEEDS_SCREWDRIVER)
if(attacking_item.tool_behaviour == TOOL_SCREWDRIVER)
to_chat(user, SPAN_NOTICE("You secure the screws of the framework."))
attacking_item.play_tool_sound(get_turf(src), 50)
broken_state++
if(GRAV_NEEDS_WELDING)
if(attacking_item.tool_behaviour == TOOL_WELDER)
var/obj/item/weldingtool/WT = attacking_item
if(WT.use(1, user))
to_chat(user, SPAN_NOTICE("You mend the damaged framework."))
playsound(src.loc, 'sound/items/welder_pry.ogg', 50, 1)
broken_state++
if(GRAV_NEEDS_PLASTEEL)
if(istype(attacking_item, /obj/item/stack/material/plasteel))
var/obj/item/stack/material/plasteel/PS = attacking_item
if(PS.amount >= 10)
PS.use(10)
to_chat(user, SPAN_NOTICE("You add the plating to the framework."))
playsound(src.loc, 'sound/machines/click.ogg', 75, 1)
broken_state++
else
to_chat(user, SPAN_NOTICE("You need 10 sheets of plasteel."))
if(GRAV_NEEDS_WRENCH)
if(attacking_item.tool_behaviour == TOOL_WRENCH)
to_chat(user, SPAN_NOTICE("You secure the plating to the framework."))
attacking_item.play_tool_sound(get_turf(src), 75)
set_fix()
else
..()
if(attacking_item.tool_behaviour == TOOL_CROWBAR)
if(panel_open_heavy)
attacking_item.play_tool_sound(get_turf(src), 50)
to_chat(user, SPAN_NOTICE("You replace the back panel."))
panel_open_heavy = 0
else
attacking_item.play_tool_sound(get_turf(src), 50)
to_chat(user, SPAN_NOTICE("You open the back panel."))
panel_open_heavy = 1
if(old_broken_state != broken_state)
update_icon()
/obj/structure/machinery/gravity_generator/main/attack_hand(mob/user as mob)
if(..(user))
return
ui_interact(user)
/obj/structure/machinery/gravity_generator/main/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "GravityGenerator", name)
ui.open()
/obj/structure/machinery/gravity_generator/main/ui_data(mob/user)
var/list/data = list()
data["breaker"] = breaker
data["charge_count"] = charge_count
data["charging_state"] = charging_state
data["on"] = on
data["operational"] = (stat & BROKEN) ? FALSE : TRUE
return data
/obj/structure/machinery/gravity_generator/main/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
switch(action)
if("gentoggle")
breaker = !breaker
set_power()
. = TRUE
/obj/structure/machinery/gravity_generator/main/power_change()
..()
breaker = (stat & NOPOWER) ? FALSE : TRUE
set_power()
investigate_log("has [stat & NOPOWER ? "lost" : "regained"] power.", "gravity")
/obj/structure/machinery/gravity_generator/main/proc/eshutoff()
if(charge_count > 0)
charge_count = 0
playsound(src.loc, 'sound/effects/EMPulse.ogg', 100, 1)
// SSradiation.radiate(src, 100)
disable()
if(middle)
middle.ClearOverlays()
if(prob(1)) //It will spawn a small one and eat the generator. Won't cause any other issues considering it's a 1x1 and will go away on it's own.
new /obj/singularity(src.loc)
if(prob(33)) //Releasing all that power at once is dangerous.
empulse(src.loc, 2, 4)
set_light(10,1,LIGHT_COLOR_FLARE)
sleep(5)
set_light(5,0.5,LIGHT_COLOR_FIRE)
sleep(5)
set_light(0,0,"#000000")
/obj/structure/machinery/gravity_generator/main/get_status()
if(stat & BROKEN)
return "fix[min(broken_state, 3)]"
return on || charging_state != POWER_IDLE ? "on" : "off"
/obj/structure/machinery/gravity_generator/main/update_icon()
..()
for(var/obj/O in sprite_parts)
O.update_icon()
// Set the charging state based on power/breaker.
/obj/structure/machinery/gravity_generator/main/proc/set_power()
var/new_state = FALSE
if(stat & (NOPOWER|BROKEN) || !breaker)
new_state = FALSE
else if(breaker)
new_state = TRUE
charging_state = new_state ? POWER_UP : POWER_DOWN // Startup sequence animation.
investigate_log("is now [charging_state == POWER_UP ? "charging" : "discharging"].", "gravity")
update_icon()
/obj/structure/machinery/gravity_generator/main/proc/enable()
charging_state = POWER_IDLE
var/gravity_changed = FALSE
if(!on)
gravity_changed = TRUE
on = TRUE
update_use_power(POWER_USE_ACTIVE)
soundloop.start()
// Sound the alert if gravity was just enabled or disabled.
var/area/area = get_area(src)
var/areadisplayname = get_area_display_name(area)
update_icon()
if(!area.has_gravity())
soundloop.start(src)
investigate_log("was brought online and is now producing gravity for this level.", "gravity")
message_admins("The gravity generator was brought online. (<A href='byond://?_src_=holder;adminplayerobservecoodjump=1;X=[x];Y=[y];Z=[z]'>[areadisplayname]</a>)")
update_list(gravity_changed)
shake_everyone()
src.updateUsrDialog()
/obj/structure/machinery/gravity_generator/main/proc/disable()
charging_state = POWER_IDLE
var/gravity_changed = FALSE
if(on)
gravity_changed = TRUE
on = FALSE
update_use_power(POWER_USE_IDLE)
soundloop.stop()
// Sound the alert if gravity was just enabled or disabled.
var/area/area = get_area(src)
var/areadisplayname = get_area_display_name(area)
if(area.has_gravity())
soundloop.stop(src)
investigate_log("was brought offline and there is now no gravity for this level.", "gravity")
message_admins("The gravity generator was brought offline with no backup generator. (<A href='byond://?_src_=holder;adminplayerobservecoodjump=1;X=[x];Y=[y];Z=[z]'>[areadisplayname]</a>)")
update_list(gravity_changed)
shake_everyone()
src.updateUsrDialog()
// Charge/Discharge and turn on/off gravity when you reach 0/100 percent.
// Also emit radiation and handle the overlays.
/obj/structure/machinery/gravity_generator/main/process()
if(stat & BROKEN)
return
// if(on || charging_state != POWER_IDLE)
// SSradiation.radiate(src, 20)
if(charging_state != POWER_IDLE)
if(charging_state == POWER_UP && charge_count >= 100)
enable()
else if(charging_state == POWER_DOWN && charge_count <= 0)
disable()
else
if(charging_state == POWER_UP)
charge_count += rand(3,5)
else if(charging_state == POWER_DOWN)
charge_count -= rand(3,5)
if(charge_count % 4 == 0 && prob(75)) // Let them know it is charging/discharging.
playsound(src.loc, 'sound/effects/EMPulse.ogg', 100, 1)
var/overlay_state = null
switch(charge_count)
if(0 to 20)
overlay_state = null
set_light(0,0,"#000000")
if(21 to 40)
overlay_state = "startup"
set_light(4,0.2,LIGHT_COLOR_BLUE)
if(41 to 60)
overlay_state = "idle"
set_light(6,0.5,"#7D9BFF") //More of a washed out perywinkle than blue but shut up.
if(61 to 80)
overlay_state = "activating"
set_light(6,0.8,"#7DC3FF")
if(81 to 100)
overlay_state = "activated"
set_light(8,1,LIGHT_COLOR_CYAN)
if(overlay_state != current_overlay)
if(middle)
middle.ClearOverlays()
if(overlay_state)
middle.AddOverlays(overlay_state)
current_overlay = overlay_state
/// Shake everyone on the z level to let them know that gravity was enagaged/disenagaged.
/obj/structure/machinery/gravity_generator/main/proc/shake_everyone()
var/turf/our_turf = get_turf(src)
var/list/connected_z_levels = GetConnectedZlevels(our_turf.z)
for(var/mob/living/M in GLOB.mob_list)
if(M.z in connected_z_levels)
M.update_gravity(M.mob_has_gravity())
if(M.client)
if(!M) return
shake_camera(M, 5, 1)
M.playsound_local(our_turf, 'sound/effects/alert.ogg', 100, vary = TRUE, falloff_distance = 0.5)
/obj/structure/machinery/gravity_generator/main/proc/update_list(var/gravity_changed = FALSE)
var/turf/T = get_turf(src.loc)
if(T)
if(!SSmachinery.gravity_generators)
SSmachinery.gravity_generators = list()
if(on && gravity_changed)
for(var/area/A in localareas)
A.gravitychange(TRUE)
SSmachinery.gravity_generators += src
else if (!on)
for(var/area/A in localareas)
A.gravitychange(FALSE)
SSmachinery.gravity_generators -= src
/obj/structure/machinery/gravity_generator/main/proc/updateareas()
for(var/area/A in GLOB.the_station_areas)
if(!(get_area_type(A) == AREA_STATION))
continue
localareas += A
/obj/structure/machinery/gravity_generator/main/proc/get_area_type(var/area/A = get_area(src))
if (A.name == "Space")
return AREA_SPACE
else if(A.alwaysgravity == TRUE || A.nevergravity == TRUE)
return AREA_SPECIAL
else
return AREA_STATION
/obj/structure/machinery/gravity_generator/main/proc/throw_up_and_down()
to_world("<h2 class='alert'>Station Announcement:</h2>")
to_world(SPAN_DANGER("Warning! Localized gravity failure, buckle yourself securely now! Brace! Brace!"))
disable()
addtimer(CALLBACK(src, PROC_REF(throw_carbons_down)), 5 SECONDS)
/obj/structure/machinery/gravity_generator/main/proc/throw_carbons_down()
enable()
var/turf/our_turf = get_turf(src)
var/list/connected_z_levels = GetConnectedZlevels(our_turf.z)
for(var/mob/living/M in GLOB.mob_list)
if(M.z in connected_z_levels)
if(ishuman(M))
var/mob/living/carbon/human/H = M
var/obj/item/clothing/shoes/magboots/boots = H.get_equipped_item(slot_shoes)
if(istype(boots) || H.buckled_to)
to_chat(M, SPAN_WARNING("You feel a surge of nausea and g-force, but you avoid being thrown around!"))
continue
to_chat(M, SPAN_DANGER("Suddenly the gravity pushed you up to the ceiling and dropped you back on the floor with great force!"))
M.fall_impact(levels_fallen = 1)
#undef POWER_IDLE
#undef POWER_UP
#undef POWER_DOWN
#undef GRAV_OPERATIONAL
#undef GRAV_NEEDS_SCREWDRIVER
#undef GRAV_NEEDS_WELDING
#undef GRAV_NEEDS_PLASTEEL
#undef GRAV_NEEDS_WRENCH
#undef AREA_ERRNONE
#undef AREA_STATION
#undef AREA_SPACE
#undef AREA_SPECIAL