mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-06-07 07:09:17 +01:00
c5dce84be8
## About The Pull Request Adds announce_to_ghosts()/notify_ghosts() calls to a bunch of different things. **THIS INCLUDES:** - Powersink being activated/reaching critical (explosion) heat capacity. - His Grace being awoken. - Hot Potatoes being armed. - Ascension Rituals being completed. - Eyesnatcher victims. - Ovens exploding as a result of the Aurora Caelus event. - Wizard Imposter spawns. - Rock-Paper-Scissors with death as the result of Helbital consumption. - BSA impact sites. - Spontaneous Appendicitis. - The purchasing of a badass syndie balloon. - The Supermatter beginning to delaminate. This was everything that I could think of that would be worth announcing to deadchat. These were all chosen with consideration to questions like "how easy would it be to spam deadchat with this?" and "will observers actually see the interesting thing happen, or just the aftermath?". Not gonna lie, I've really become an observer main as of recently. Maybe that's being reflected in my recent PRs. Who's to say? Deadchat Announcement Variety Pack 2 will probably never come out. Sorry. ## Why It's Good For The Game Gives deadchat a better indiciation of when/where something **REALLY FUNNY** is about to happen. Draws attention to certain things that are likely to gather an audience anyways, but sooner (for your viewing pleasure). In simple terms, it helps the observers observe things better. Some cases, such as the aurora caelus or helbitaljanken, are occurrences so rare that they deserve the audience. ## Changelog 🆑 Rhials qol: Observers now recieve an alert when a powersink is activated/about to explode. qol: His Grace being awoken now alerts observers, to give you a headstart on your murderbone ghost ring. qol: Ascension Rituals being completed will also alert observers, for basically the same reason. qol: Arming a hot potato will now alert observers. Catch! qol: Eyesnatcher victims will now notify observers, and invite them to laugh at their state of misery and impotence. qol: Observers will be notified of any acute references to The Simpsons or other 20th Television America copyright properties. qol: Wizard Imposter spawns alert observers, much like any other ghost role event should. qol: Playing Rock-Paper-Scissors with death will now alert the observers and invite them to watch. Better not choke! qol: Observers now get an orbit link for BSA impact sites. Why does it keep teleporting me to the AI upload?? qol: Spontaneous Appendicitis now alerts deadchat. qol: The purchasing of a badass syndie balloon now alerts deadchat. You might not be any more powerful, but at least you have an audience. qol: When beginning to delaminate, the Supermatter will alert observers and invite them to watch the fireworks. /🆑
398 lines
12 KiB
Plaintext
398 lines
12 KiB
Plaintext
|
|
///BSA unlocked by head ID swipes
|
|
GLOBAL_VAR_INIT(bsa_unlock, FALSE)
|
|
|
|
// Crew has to build a bluespace cannon
|
|
// Cargo orders part for high price
|
|
// Requires high amount of power
|
|
// Requires high level stock parts
|
|
/datum/station_goal/bluespace_cannon
|
|
name = "Bluespace Artillery"
|
|
|
|
/datum/station_goal/bluespace_cannon/get_report()
|
|
return list(
|
|
"<blockquote>Our military presence is inadequate in your sector.",
|
|
"We need you to construct BSA-[rand(1,99)] Artillery position aboard your station.",
|
|
"",
|
|
"Base parts are available for shipping via cargo.",
|
|
"-Nanotrasen Naval Command</blockquote>",
|
|
).Join("\n")
|
|
|
|
/datum/station_goal/bluespace_cannon/on_report()
|
|
//Unlock BSA parts
|
|
var/datum/supply_pack/engineering/bsa/P = SSshuttle.supply_packs[/datum/supply_pack/engineering/bsa]
|
|
P.special_enabled = TRUE
|
|
|
|
/datum/station_goal/bluespace_cannon/check_completion()
|
|
if(..())
|
|
return TRUE
|
|
var/obj/machinery/bsa/full/B = locate()
|
|
if(B && !B.machine_stat)
|
|
return TRUE
|
|
return FALSE
|
|
|
|
/obj/machinery/bsa
|
|
icon = 'icons/obj/machines/particle_accelerator.dmi'
|
|
density = TRUE
|
|
anchored = TRUE
|
|
|
|
/obj/machinery/bsa/wrench_act(mob/living/user, obj/item/tool)
|
|
. = ..()
|
|
default_unfasten_wrench(user, tool, time = 1 SECONDS)
|
|
return TOOL_ACT_TOOLTYPE_SUCCESS
|
|
|
|
/obj/machinery/bsa/back
|
|
name = "Bluespace Artillery Generator"
|
|
desc = "Generates cannon pulse. Needs to be linked with a fusor."
|
|
icon_state = "power_box"
|
|
|
|
/obj/machinery/bsa/back/Initialize(mapload)
|
|
. = ..()
|
|
AddComponent(/datum/component/simple_rotation)
|
|
|
|
/obj/machinery/bsa/back/multitool_act(mob/living/user, obj/item/I)
|
|
if(!multitool_check_buffer(user, I)) //make sure it has a data buffer
|
|
return
|
|
var/obj/item/multitool/M = I
|
|
M.buffer = src
|
|
to_chat(user, span_notice("You store linkage information in [I]'s buffer."))
|
|
return TRUE
|
|
|
|
/obj/machinery/bsa/front
|
|
name = "Bluespace Artillery Bore"
|
|
desc = "Do not stand in front of cannon during operation. Needs to be linked with a fusor."
|
|
icon_state = "emitter_center"
|
|
|
|
/obj/machinery/bsa/front/Initialize(mapload)
|
|
. = ..()
|
|
AddComponent(/datum/component/simple_rotation)
|
|
|
|
/obj/machinery/bsa/front/multitool_act(mob/living/user, obj/item/I)
|
|
if(!multitool_check_buffer(user, I)) //make sure it has a data buffer
|
|
return
|
|
var/obj/item/multitool/M = I
|
|
M.buffer = src
|
|
to_chat(user, span_notice("You store linkage information in [I]'s buffer."))
|
|
return TRUE
|
|
|
|
/obj/machinery/bsa/middle
|
|
name = "Bluespace Artillery Fusor"
|
|
desc = "Contents classified by Nanotrasen Naval Command. Needs to be linked with the other BSA parts using a multitool."
|
|
icon_state = "fuel_chamber"
|
|
var/datum/weakref/back_ref
|
|
var/datum/weakref/front_ref
|
|
|
|
/obj/machinery/bsa/middle/Initialize(mapload)
|
|
. = ..()
|
|
AddComponent(/datum/component/simple_rotation)
|
|
|
|
/obj/machinery/bsa/middle/multitool_act(mob/living/user, obj/item/I)
|
|
if(!multitool_check_buffer(user, I))
|
|
return
|
|
var/obj/item/multitool/M = I
|
|
if(M.buffer)
|
|
if(istype(M.buffer, /obj/machinery/bsa/back))
|
|
back_ref = WEAKREF(M.buffer)
|
|
to_chat(user, span_notice("You link [src] with [M.buffer]."))
|
|
M.buffer = null
|
|
else if(istype(M.buffer, /obj/machinery/bsa/front))
|
|
front_ref = WEAKREF(M.buffer)
|
|
to_chat(user, span_notice("You link [src] with [M.buffer]."))
|
|
M.buffer = null
|
|
else
|
|
to_chat(user, span_warning("[I]'s data buffer is empty!"))
|
|
return TRUE
|
|
|
|
/obj/machinery/bsa/middle/proc/check_completion()
|
|
var/obj/machinery/bsa/front/front = front_ref?.resolve()
|
|
var/obj/machinery/bsa/back/back = back_ref?.resolve()
|
|
if(!front || !back)
|
|
return "No linked parts detected!"
|
|
if(!front.anchored || !back.anchored || !anchored)
|
|
return "Linked parts unwrenched!"
|
|
if(front.y != y || back.y != y || !(front.x > x && back.x < x || front.x < x && back.x > x) || front.z != z || back.z != z)
|
|
return "Parts misaligned!"
|
|
if(!has_space())
|
|
return "Not enough free space!"
|
|
|
|
/obj/machinery/bsa/middle/proc/has_space()
|
|
var/cannon_dir = get_cannon_direction()
|
|
var/width = 10
|
|
var/offset
|
|
switch(cannon_dir)
|
|
if(EAST)
|
|
offset = -4
|
|
if(WEST)
|
|
offset = -6
|
|
else
|
|
return FALSE
|
|
|
|
var/turf/base = get_turf(src)
|
|
for(var/turf/T as anything in CORNER_BLOCK_OFFSET(base, width, 3, offset, -1))
|
|
if(T.density || isspaceturf(T))
|
|
return FALSE
|
|
return TRUE
|
|
|
|
/obj/machinery/bsa/middle/proc/get_cannon_direction()
|
|
var/obj/machinery/bsa/front/front = front_ref?.resolve()
|
|
var/obj/machinery/bsa/back/back = back_ref?.resolve()
|
|
if(!front || !back)
|
|
return
|
|
if(front.x > x && back.x < x)
|
|
return EAST
|
|
else if(front.x < x && back.x > x)
|
|
return WEST
|
|
|
|
|
|
/obj/machinery/bsa/full
|
|
name = "Bluespace Artillery"
|
|
desc = "Long range bluespace artillery."
|
|
icon = 'icons/obj/lavaland/cannon.dmi'
|
|
icon_state = "cannon_west"
|
|
var/static/mutable_appearance/top_layer
|
|
var/ex_power = 3
|
|
var/power_used_per_shot = 2000000 //enough to kil standard apc - todo : make this use wires instead and scale explosion power with it
|
|
var/ready
|
|
pixel_y = -32
|
|
pixel_x = -192
|
|
bound_width = 352
|
|
bound_x = -192
|
|
appearance_flags = LONG_GLIDE //Removes default TILE_BOUND
|
|
|
|
/obj/machinery/bsa/full/wrench_act(mob/living/user, obj/item/I)
|
|
return FALSE
|
|
|
|
/obj/machinery/bsa/full/proc/get_front_turf()
|
|
switch(dir)
|
|
if(WEST)
|
|
return locate(x - 7,y,z)
|
|
if(EAST)
|
|
return locate(x + 7,y,z)
|
|
return get_turf(src)
|
|
|
|
/obj/machinery/bsa/full/proc/get_back_turf()
|
|
switch(dir)
|
|
if(WEST)
|
|
return locate(x + 5,y,z)
|
|
if(EAST)
|
|
return locate(x - 5,y,z)
|
|
return get_turf(src)
|
|
|
|
/obj/machinery/bsa/full/proc/get_target_turf()
|
|
switch(dir)
|
|
if(WEST)
|
|
return locate(1,y,z)
|
|
if(EAST)
|
|
return locate(world.maxx,y,z)
|
|
return get_turf(src)
|
|
|
|
/obj/machinery/bsa/full/Initialize(mapload, cannon_direction = WEST)
|
|
. = ..()
|
|
switch(cannon_direction)
|
|
if(WEST)
|
|
setDir(WEST)
|
|
icon_state = "cannon_west"
|
|
if(EAST)
|
|
setDir(EAST)
|
|
pixel_x = -128
|
|
bound_x = -128
|
|
icon_state = "cannon_east"
|
|
get_layer()
|
|
reload()
|
|
|
|
/obj/machinery/bsa/full/proc/get_layer()
|
|
top_layer = mutable_appearance(icon, layer = ABOVE_MOB_LAYER)
|
|
SET_PLANE_EXPLICIT(top_layer, GAME_PLANE_UPPER, src)
|
|
switch(dir)
|
|
if(WEST)
|
|
top_layer.icon_state = "top_west"
|
|
if(EAST)
|
|
top_layer.icon_state = "top_east"
|
|
add_overlay(top_layer)
|
|
|
|
/obj/machinery/bsa/full/on_changed_z_level(turf/old_turf, turf/new_turf, same_z_layer, notify_contents)
|
|
if(same_z_layer)
|
|
return ..()
|
|
cut_overlay(top_layer)
|
|
get_layer()
|
|
return ..()
|
|
|
|
/obj/machinery/bsa/full/proc/fire(mob/user, turf/bullseye)
|
|
reload()
|
|
|
|
var/turf/point = get_front_turf()
|
|
var/turf/target = get_target_turf()
|
|
var/atom/movable/blocker
|
|
for(var/T in get_line(get_step(point, dir), target))
|
|
var/turf/tile = T
|
|
if(SEND_SIGNAL(tile, COMSIG_ATOM_BSA_BEAM) & COMSIG_ATOM_BLOCKS_BSA_BEAM)
|
|
blocker = tile
|
|
else
|
|
for(var/AM in tile)
|
|
var/atom/movable/stuff = AM
|
|
if(SEND_SIGNAL(stuff, COMSIG_ATOM_BSA_BEAM) & COMSIG_ATOM_BLOCKS_BSA_BEAM)
|
|
blocker = stuff
|
|
break
|
|
if(blocker)
|
|
target = tile
|
|
break
|
|
else
|
|
SSexplosions.highturf += tile //also fucks everything else on the turf
|
|
point.Beam(target, icon_state = "bsa_beam", time = 5 SECONDS, maxdistance = world.maxx) //ZZZAP
|
|
new /obj/effect/temp_visual/bsa_splash(point, dir)
|
|
|
|
notify_ghosts("The Bluespace Artillery has been fired!", source = bullseye, header = "KABOOM!")
|
|
if(!blocker)
|
|
message_admins("[ADMIN_LOOKUPFLW(user)] has launched an artillery strike targeting [ADMIN_VERBOSEJMP(bullseye)].")
|
|
user.log_message("has launched an artillery strike targeting [AREACOORD(bullseye)].", LOG_GAME)
|
|
explosion(bullseye, devastation_range = ex_power, heavy_impact_range = ex_power*2, light_impact_range = ex_power*4, explosion_cause = src)
|
|
else
|
|
message_admins("[ADMIN_LOOKUPFLW(user)] has launched an artillery strike targeting [ADMIN_VERBOSEJMP(bullseye)] but it was blocked by [blocker] at [ADMIN_VERBOSEJMP(target)].")
|
|
user.log_message("has launched an artillery strike targeting [AREACOORD(bullseye)] but it was blocked by [blocker] at [AREACOORD(target)].", LOG_GAME)
|
|
|
|
|
|
/obj/machinery/bsa/full/proc/reload()
|
|
ready = FALSE
|
|
use_power(power_used_per_shot)
|
|
addtimer(CALLBACK(src,"ready_cannon"),600)
|
|
|
|
/obj/machinery/bsa/full/proc/ready_cannon()
|
|
ready = TRUE
|
|
|
|
/obj/structure/filler
|
|
name = "big machinery part"
|
|
density = TRUE
|
|
anchored = TRUE
|
|
invisibility = INVISIBILITY_ABSTRACT
|
|
var/obj/machinery/parent
|
|
|
|
/obj/structure/filler/ex_act()
|
|
return FALSE
|
|
|
|
/obj/machinery/computer/bsa_control
|
|
name = "bluespace artillery control"
|
|
use_power = NO_POWER_USE
|
|
circuit = /obj/item/circuitboard/computer/bsa_control
|
|
icon = 'icons/obj/machines/particle_accelerator.dmi'
|
|
icon_state = "control_boxp"
|
|
icon_keyboard = null
|
|
icon_screen = null
|
|
|
|
var/datum/weakref/cannon_ref
|
|
var/notice
|
|
var/target
|
|
var/area_aim = FALSE //should also show areas for targeting
|
|
|
|
/obj/machinery/computer/bsa_control/ui_state(mob/user)
|
|
return GLOB.physical_state
|
|
|
|
/obj/machinery/computer/bsa_control/ui_interact(mob/user, datum/tgui/ui)
|
|
. = ..()
|
|
ui = SStgui.try_update_ui(user, src, ui)
|
|
if(!ui)
|
|
ui = new(user, src, "BluespaceArtillery", name)
|
|
ui.open()
|
|
|
|
/obj/machinery/computer/bsa_control/ui_data()
|
|
var/obj/machinery/bsa/full/cannon = cannon_ref?.resolve()
|
|
var/list/data = list()
|
|
data["ready"] = cannon ? cannon.ready : FALSE
|
|
data["connected"] = cannon
|
|
data["notice"] = notice
|
|
data["unlocked"] = GLOB.bsa_unlock
|
|
if(target)
|
|
data["target"] = get_target_name()
|
|
return data
|
|
|
|
/obj/machinery/computer/bsa_control/ui_act(action, params)
|
|
. = ..()
|
|
if(.)
|
|
return
|
|
|
|
switch(action)
|
|
if("build")
|
|
cannon_ref = WEAKREF(deploy())
|
|
. = TRUE
|
|
if("fire")
|
|
fire(usr)
|
|
. = TRUE
|
|
if("recalibrate")
|
|
calibrate(usr)
|
|
. = TRUE
|
|
update_appearance()
|
|
|
|
/obj/machinery/computer/bsa_control/proc/calibrate(mob/user)
|
|
if(!GLOB.bsa_unlock)
|
|
return
|
|
var/list/gps_locators = list()
|
|
for(var/datum/component/gps/G in GLOB.GPS_list) //nulls on the list somehow
|
|
if(G.tracking)
|
|
gps_locators[G.gpstag] = G
|
|
|
|
var/list/options = gps_locators
|
|
if(area_aim)
|
|
options += GLOB.teleportlocs
|
|
var/victim = tgui_input_list(user, "Select target", "Artillery Targeting", options)
|
|
if(isnull(victim))
|
|
return
|
|
if(isnull(options[victim]))
|
|
return
|
|
target = options[victim]
|
|
log_game("[key_name(user)] has aimed the artillery strike at [target].")
|
|
|
|
|
|
/obj/machinery/computer/bsa_control/proc/get_target_name()
|
|
if(istype(target, /area))
|
|
return get_area_name(target, TRUE)
|
|
else if(istype(target, /datum/component/gps))
|
|
var/datum/component/gps/G = target
|
|
return G.gpstag
|
|
|
|
/obj/machinery/computer/bsa_control/proc/get_impact_turf()
|
|
if(obj_flags & EMAGGED)
|
|
return get_turf(src)
|
|
else if(istype(target, /area))
|
|
return pick(get_area_turfs(target))
|
|
else if(istype(target, /datum/component/gps))
|
|
var/datum/component/gps/G = target
|
|
return get_turf(G.parent)
|
|
|
|
/obj/machinery/computer/bsa_control/proc/fire(mob/user)
|
|
var/obj/machinery/bsa/full/cannon = cannon_ref?.resolve()
|
|
if(!cannon)
|
|
notice = "No Cannon Exists!"
|
|
return
|
|
if(cannon.machine_stat)
|
|
notice = "Cannon unpowered!"
|
|
return
|
|
notice = null
|
|
var/turf/target_turf = get_impact_turf()
|
|
cannon.fire(user, target_turf)
|
|
|
|
/obj/machinery/computer/bsa_control/proc/deploy(force=FALSE)
|
|
var/obj/machinery/bsa/full/prebuilt = locate() in range(7) //In case of adminspawn
|
|
if(prebuilt)
|
|
return prebuilt
|
|
|
|
var/obj/machinery/bsa/middle/centerpiece = locate() in range(7)
|
|
if(!centerpiece)
|
|
notice = "No BSA parts detected nearby."
|
|
return null
|
|
notice = centerpiece.check_completion()
|
|
if(notice)
|
|
return null
|
|
//Totally nanite construction system not an immersion breaking spawning
|
|
var/datum/effect_system/fluid_spread/smoke/fourth_wall_guard = new
|
|
fourth_wall_guard.set_up(4, holder = src, location = get_turf(centerpiece))
|
|
fourth_wall_guard.start()
|
|
var/obj/machinery/bsa/full/cannon = new(get_turf(centerpiece),centerpiece.get_cannon_direction())
|
|
QDEL_NULL(centerpiece.front_ref)
|
|
QDEL_NULL(centerpiece.back_ref)
|
|
qdel(centerpiece)
|
|
return cannon
|
|
/obj/machinery/computer/bsa_control/emag_act(mob/user, obj/item/card/emag/emag_card)
|
|
if(obj_flags & EMAGGED)
|
|
return
|
|
obj_flags |= EMAGGED
|
|
to_chat(user, span_warning("You emag [src] and hear the focusing crystal short out."))
|