#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. ([areadisplayname])") 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. ([areadisplayname])") 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("