[admin] Takes the pod spawn code from TG (#11612)

* Stole podmin power from tg

* Update uplink_items.dm

* Removed unused proc argument

* Hopefully fixes icon stuff

* Fixed the contractor pods not working
This commit is contained in:
adamsong
2021-07-01 06:46:06 -04:00
committed by GitHub
parent d8c02ac94c
commit cce3787ace
30 changed files with 2268 additions and 987 deletions

View File

@@ -13,23 +13,40 @@
#define STYLE_GONDOLA 13 #define STYLE_GONDOLA 13
#define STYLE_SEETHROUGH 14 #define STYLE_SEETHROUGH 14
#define POD_ICON_STATE 1 #define POD_SHAPE 1
#define POD_NAME 2 #define POD_BASE 2
#define POD_DESC 3 #define POD_DOOR 3
#define POD_DECAL 4
#define POD_GLOW 5
#define POD_RUBBLE_TYPE 6
#define POD_NAME 7
#define POD_DESC 8
#define POD_STYLES list(\ #define RUBBLE_NONE 1
list("supplypod", "supply pod", "A Nanotrasen supply drop pod."),\ #define RUBBLE_NORMAL 2
list("bluespacepod", "bluespace supply pod" , "A Nanotrasen Bluespace supply pod. Teleports back to CentCom after delivery."),\ #define RUBBLE_WIDE 3
list("centcompod", "\improper Centcom supply pod", "A Nanotrasen supply pod, this one has been marked with Central Command's designations. Teleports back to Centcom after delivery."),\ #define RUBBLE_THIN 4
list("syndiepod", "blood-red supply pod", "A dark, intimidating supply pod, covered in the blood-red markings of the Syndicate. It's probably best to stand back from this."),\
list("squadpod", "\improper MK. II supply pod", "A Nanotrasen supply pod. This one has been marked the markings of some sort of elite strike team."),\ #define POD_SHAPE_NORML 1
list("cultpod", "bloody supply pod", "A Nanotrasen supply pod covered in scratch-marks, blood, and strange runes."),\ #define POD_SHAPE_OTHER 2
list("missilepod", "cruise missile", "A big ass missile that didn't seem to fully detonate. It was likely launched from some far-off deep space missile silo. There appears to be an auxillery payload hatch on the side, though manually opening it is likely impossible."),\
list("smissilepod", "\improper Syndicate cruise missile", "A big ass, blood-red missile that didn't seem to fully detonate. It was likely launched from some deep space Syndicate missile silo. There appears to be an auxillery payload hatch on the side, though manually opening it is likely impossible."),\ #define SUPPLYPOD_X_OFFSET -16
list("boxpod", "\improper Aussec supply crate", "An incredibly sturdy supply crate, designed to withstand orbital re-entry. Has 'Aussec Armory - 2532' engraved on the side."),\
list("honkpod", "\improper HONK pod", "A brightly-colored supply pod. It likely originated from the Clown Federation."),\ GLOBAL_LIST_EMPTY(supplypod_loading_bays)
list("fruitpod", "\improper Orange", "An angry orange."),\
list("", "\improper S.T.E.A.L.T.H. pod MKVII", "A supply pod that, under normal circumstances, is completely invisible to conventional methods of detection. How are you even seeing this?"),\ GLOBAL_LIST_INIT(podstyles, list(\
list("gondolapod", "gondola", "The silent walker. This one seems to be part of a delivery agency."),\ list(POD_SHAPE_NORML, "pod", TRUE, "default", "yellow", RUBBLE_NORMAL, "supply pod", "A Nanotrasen supply drop pod."),\
list("", "", "")\ list(POD_SHAPE_NORML, "advpod", TRUE, "bluespace", "blue", RUBBLE_NORMAL, "bluespace supply pod" , "A Nanotrasen Bluespace supply pod. Teleports back to CentCom after delivery."),\
) list(POD_SHAPE_NORML, "advpod", TRUE, "centcom", "blue", RUBBLE_NORMAL, "\improper CentCom supply pod", "A Nanotrasen supply pod, this one has been marked with Central Command's designations. Teleports back to CentCom after delivery."),\
list(POD_SHAPE_NORML, "darkpod", TRUE, "syndicate", "red", RUBBLE_NORMAL, "blood-red supply pod", "An intimidating supply pod, covered in the blood-red markings of the Syndicate. It's probably best to stand back from this."),\
list(POD_SHAPE_NORML, "darkpod", TRUE, "deathsquad", "blue", RUBBLE_NORMAL, "\improper Deathsquad drop pod", "A Nanotrasen drop pod. This one has been marked the markings of Nanotrasen's elite strike team."),\
list(POD_SHAPE_NORML, "pod", TRUE, "cultist", "red", RUBBLE_NORMAL, "bloody supply pod", "A Nanotrasen supply pod covered in scratch-marks, blood, and strange runes."),\
list(POD_SHAPE_OTHER, "missile", FALSE, FALSE, FALSE, RUBBLE_THIN, "cruise missile", "A big ass missile that didn't seem to fully detonate. It was likely launched from some far-off deep space missile silo. There appears to be an auxillery payload hatch on the side, though manually opening it is likely impossible."),\
list(POD_SHAPE_OTHER, "smissile", FALSE, FALSE, FALSE, RUBBLE_THIN, "\improper Syndicate cruise missile", "A big ass, blood-red missile that didn't seem to fully detonate. It was likely launched from some deep space Syndicate missile silo. There appears to be an auxillery payload hatch on the side, though manually opening it is likely impossible."),\
list(POD_SHAPE_OTHER, "box", TRUE, FALSE, FALSE, RUBBLE_WIDE, "\improper Aussec supply crate", "An incredibly sturdy supply crate, designed to withstand orbital re-entry. Has 'Aussec Armory - 2532' engraved on the side."),\
list(POD_SHAPE_NORML, "clownpod", TRUE, "clown", "green", RUBBLE_NORMAL, "\improper HONK pod", "A brightly-colored supply pod. It likely originated from the Clown Federation."),\
list(POD_SHAPE_OTHER, "orange", TRUE, FALSE, FALSE, RUBBLE_NONE, "\improper Orange", "An angry orange."),\
list(POD_SHAPE_OTHER, FALSE, FALSE, FALSE, FALSE, RUBBLE_NONE, "\improper S.T.E.A.L.T.H. pod MKVII", "A supply pod that, under normal circumstances, is completely invisible to conventional methods of detection. How are you even seeing this?"),\
list(POD_SHAPE_OTHER, "gondola", FALSE, FALSE, FALSE, RUBBLE_NONE, "gondola", "The silent walker. This one seems to be part of a delivery agency."),\
list(POD_SHAPE_OTHER, FALSE, FALSE, FALSE, FALSE, RUBBLE_NONE, FALSE, FALSE, "rl_click", "give_po")\
))

View File

@@ -266,3 +266,5 @@ GLOBAL_LIST_INIT(glass_sheet_types, typecacheof(list(
//Fugitive //Fugitive
#define isfugitive(M) (istype(M) && M.mind?.has_antag_datum(/datum/antagonist/fugitive)) #define isfugitive(M) (istype(M) && M.mind?.has_antag_datum(/datum/antagonist/fugitive))
#define isProbablyWallMounted(O) (O.pixel_x > 20 || O.pixel_x < -20 || O.pixel_y > 20 || O.pixel_y < -20)

View File

@@ -277,6 +277,7 @@ GLOBAL_LIST_INIT(pda_styles, list(MONO, VT, ORBITRON, SHARE))
#define DEADCHAT_ARRIVALRATTLE "arrivalrattle" #define DEADCHAT_ARRIVALRATTLE "arrivalrattle"
#define DEADCHAT_DEATHRATTLE "deathrattle" #define DEADCHAT_DEATHRATTLE "deathrattle"
#define DEADCHAT_REGULAR "regular-deadchat" #define DEADCHAT_REGULAR "regular-deadchat"
#define DEADCHAT_ANNOUNCEMENT "announcement"
// Bluespace shelter deploy checks // Bluespace shelter deploy checks
#define SHELTER_DEPLOY_ALLOWED "allowed" #define SHELTER_DEPLOY_ALLOWED "allowed"

View File

@@ -51,3 +51,6 @@
#define ORGAN_FAILING (1<<2) //Failing organs perform damaging effects until replaced or fixed #define ORGAN_FAILING (1<<2) //Failing organs perform damaging effects until replaced or fixed
#define ORGAN_EXTERNAL (1<<3) //Was this organ implanted/inserted/etc, if true will not be removed during species change. #define ORGAN_EXTERNAL (1<<3) //Was this organ implanted/inserted/etc, if true will not be removed during species change.
#define ORGAN_VITAL (1<<4) //Currently only the brain #define ORGAN_VITAL (1<<4) //Currently only the brain
/// Flags for the pod_flags var on /obj/structure/closet/supplypod
#define FIRST_SOUNDS (1<<0) // If it shouldn't play sounds the first time it lands, used for reverse mode

View File

@@ -108,3 +108,6 @@ GLOBAL_VAR_INIT(cmp_field, "name")
/proc/cmp_mob_realname_dsc(mob/A,mob/B) /proc/cmp_mob_realname_dsc(mob/A,mob/B)
return sorttext(A.real_name,B.real_name) return sorttext(A.real_name,B.real_name)
/proc/cmp_typepaths_asc(A, B)
return sorttext("[B]","[A]")

View File

@@ -49,21 +49,35 @@
/area/centcom/supplypod/loading /area/centcom/supplypod/loading
name = "Supplypod Loading Facility" name = "Supplypod Loading Facility"
icon_state = "supplypod_loading" icon_state = "supplypod_loading"
var/loading_id = ""
/area/centcom/supplypod/loading/Initialize()
. = ..()
if(!loading_id)
CRASH("[type] created without a loading_id")
if(GLOB.supplypod_loading_bays[loading_id])
CRASH("Duplicate loading bay area: [type] ([loading_id])")
GLOB.supplypod_loading_bays[loading_id] = src
/area/centcom/supplypod/loading/one /area/centcom/supplypod/loading/one
name = "Bay #1" name = "Bay #1"
loading_id = "1"
/area/centcom/supplypod/loading/two /area/centcom/supplypod/loading/two
name = "Bay #2" name = "Bay #2"
loading_id = "2"
/area/centcom/supplypod/loading/three /area/centcom/supplypod/loading/three
name = "Bay #3" name = "Bay #3"
loading_id = "3"
/area/centcom/supplypod/loading/four /area/centcom/supplypod/loading/four
name = "Bay #4" name = "Bay #4"
loading_id = "4"
/area/centcom/supplypod/loading/ert /area/centcom/supplypod/loading/ert
name = "ERT Bay" name = "ERT Bay"
loading_id = "5"
//THUNDERDOME //THUNDERDOME
/area/tdome /area/tdome

View File

@@ -1164,6 +1164,22 @@
/atom/proc/rust_heretic_act() /atom/proc/rust_heretic_act()
return return
/**
* Used to set something as 'open' if it's being used as a supplypod
*
* Override this if you want an atom to be usable as a supplypod.
*/
/atom/proc/setOpened()
return
/**
* Used to set something as 'closed' if it's being used as a supplypod
*
* Override this if you want an atom to be usable as a supplypod.
*/
/atom/proc/setClosed()
return
/** /**
* Recursive getter method to return a list of all ghosts orbitting this atom * Recursive getter method to return a list of all ghosts orbitting this atom
* *

View File

@@ -378,8 +378,11 @@ GLOBAL_LIST_EMPTY(lockers)
var/mob/living/L = O var/mob/living/L = O
if(!issilicon(L)) if(!issilicon(L))
L.Paralyze(40) L.Paralyze(40)
O.forceMove(T) if(istype(src, /obj/structure/closet/supplypod/extractionpod))
close() O.forceMove(src)
else
O.forceMove(T)
close()
else else
O.forceMove(T) O.forceMove(T)
return 1 return 1

View File

@@ -113,7 +113,7 @@
var/obj/structure/closet/supplypod/extractionpod/pod = source var/obj/structure/closet/supplypod/extractionpod/pod = source
// Handle the pod returning // Handle the pod returning
pod.send_up(pod) pod.startExitSequence(pod)

View File

@@ -402,3 +402,33 @@ a//DEFINITIONS FOR ASSET DATUMS START HERE.
/datum/asset/simple/portraits/public /datum/asset/simple/portraits/public
tab = "public" tab = "public"
/datum/asset/spritesheet/supplypods
name = "supplypods"
/datum/asset/spritesheet/supplypods/register()
for (var/style in 1 to length(GLOB.podstyles))
var/icon_file = 'icons/obj/supplypods.dmi'
if (style == STYLE_SEETHROUGH)
Insert("pod_asset[style]", icon(icon_file, "seethrough-icon"))
continue
var/base = GLOB.podstyles[style][POD_BASE]
if (!base)
Insert("pod_asset[style]", icon(icon_file, "invisible-icon"))
continue
var/icon/podIcon = icon(icon_file, base)
var/door = GLOB.podstyles[style][POD_DOOR]
if (door)
door = "[base]_door"
podIcon.Blend(icon(icon_file, door), ICON_OVERLAY)
var/shape = GLOB.podstyles[style][POD_SHAPE]
if (shape == POD_SHAPE_NORML)
var/decal = GLOB.podstyles[style][POD_DECAL]
if (decal)
podIcon.Blend(icon(icon_file, decal), ICON_OVERLAY)
var/glow = GLOB.podstyles[style][POD_GLOW]
if (glow)
glow = "pod_glow_[glow]"
podIcon.Blend(icon(icon_file, glow), ICON_OVERLAY)
Insert("pod_asset[style]", podIcon)
return ..()

View File

@@ -1,3 +1,10 @@
#define TAB_POD 0 //Used to check if the UIs built in camera is looking at the pod
#define TAB_BAY 1 //Used to check if the UIs built in camera is looking at the launch bay area
#define LAUNCH_ALL 0 //Used to check if we're launching everything from the bay area at once
#define LAUNCH_ORDERED 1 //Used to check if we're launching everything from the bay area in order
#define LAUNCH_RANDOM 2 //Used to check if we're launching everything from the bay area randomly
//The Great and Mighty CentCom Pod Launcher - MrDoomBringer //The Great and Mighty CentCom Pod Launcher - MrDoomBringer
//This was originally created as a way to get adminspawned items to the station in an IC manner. It's evolved to contain a few more //This was originally created as a way to get adminspawned items to the station in an IC manner. It's evolved to contain a few more
//features such as item removal, smiting, controllable delivery mobs, and more. //features such as item removal, smiting, controllable delivery mobs, and more.
@@ -11,23 +18,25 @@
/client/proc/centcom_podlauncher() //Creates a verb for admins to open up the ui /client/proc/centcom_podlauncher() //Creates a verb for admins to open up the ui
set name = "Config/Launch Supplypod" set name = "Config/Launch Supplypod"
set desc = "Configure and launch a Centcom supplypod full of whatever your heart desires!" set desc = "Configure and launch a CentCom supplypod full of whatever your heart desires!"
set category = "Misc" set category = "Misc"
if(!check_rights(R_FUN)) if(!check_rights(R_FUN))
return return
var/datum/centcom_podlauncher/plaunch = new(usr)//create the datum new /datum/centcom_podlauncher(usr)//create the datum
plaunch.ui_interact(usr)//datum has a tgui component, here we open the window
//Variables declared to change how items in the launch bay are picked and launched. (Almost) all of these are changed in the ui_act proc //Variables declared to change how items in the launch bay are picked and launched. (Almost) all of these are changed in the ui_act proc
//Some effect groups are choices, while other are booleans. This is because some effects can stack, while others dont (ex: you can stack explosion and quiet, but you cant stack ordered launch and random launch) //Some effect groups are choices, while other are booleans. This is because some effects can stack, while others dont (ex: you can stack explosion and quiet, but you cant stack ordered launch and random launch)
/datum/centcom_podlauncher /datum/centcom_podlauncher
var/static/list/ignored_atoms = typecacheof(list(null, /mob/dead, /obj/effect/landmark, /obj/docking_port, /atom/movable/lighting_object, /obj/effect/particle_effect/sparks, /obj/effect/DPtarget, /obj/effect/supplypod_selector )) var/static/list/ignored_atoms = typecacheof(list(null, /mob/dead, /obj/effect/landmark, /obj/docking_port, /atom/movable/lighting_object, /obj/effect/particle_effect/sparks, /obj/effect/DPtarget, /obj/effect/hallucination/simple/supplypod_selector, /obj/effect/hallucination/simple/dropoff_location))
var/turf/oldTurf //Keeps track of where the user was at if they use the "teleport to centcom" button, so they can go back var/turf/oldTurf //Keeps track of where the user was at if they use the "teleport to centcom" button, so they can go back
var/client/holder //client of whoever is using this datum var/client/holder //client of whoever is using this datum
var/area/bay //What bay we're using to launch shit from. var/area/centcom/supplypod/loading/bay //What bay we're using to launch shit from.
var/bayNumber //Quick reference to what bay we're in. Usually set to the loading_id variable for the related area type
var/customDropoff = FALSE
var/picking_dropoff_turf = FALSE
var/launchClone = FALSE //If true, then we don't actually launch the thing in the bay. Instead we call duplicateObject() and send the result var/launchClone = FALSE //If true, then we don't actually launch the thing in the bay. Instead we call duplicateObject() and send the result
var/launchRandomItem = FALSE //If true, lauches a single random item instead of everything on a turf. var/launchRandomItem = FALSE //If true, lauches a single random item instead of everything on a turf.
var/launchChoice = 1 //Determines if we launch all at once (0) , in order (1), or at random(2) var/launchChoice = LAUNCH_RANDOM //Determines if we launch all at once (0) , in order (1), or at random(2)
var/explosionChoice = 0 //Determines if there is no explosion (0), custom explosion (1), or just do a maxcap (2) var/explosionChoice = 0 //Determines if there is no explosion (0), custom explosion (1), or just do a maxcap (2)
var/damageChoice = 0 //Determines if we do no damage (0), custom amnt of damage (1), or gib + 5000dmg (2) var/damageChoice = 0 //Determines if we do no damage (0), custom amnt of damage (1), or gib + 5000dmg (2)
var/launcherActivated = FALSE //check if we've entered "launch mode" (when we click a pod is launched). Used for updating mouse cursor var/launcherActivated = FALSE //check if we've entered "launch mode" (when we click a pod is launched). Used for updating mouse cursor
@@ -39,57 +48,127 @@
var/list/orderedArea = list() //Contains an ordered list of turfs in an area (filled in the createOrderedArea() proc), read top-left to bottom-right. Used for the "ordered" launch mode (launchChoice = 1) var/list/orderedArea = list() //Contains an ordered list of turfs in an area (filled in the createOrderedArea() proc), read top-left to bottom-right. Used for the "ordered" launch mode (launchChoice = 1)
var/list/turf/acceptableTurfs = list() //Contians a list of turfs (in the "bay" area on centcom) that have items that can be launched. Taken from orderedArea var/list/turf/acceptableTurfs = list() //Contians a list of turfs (in the "bay" area on centcom) that have items that can be launched. Taken from orderedArea
var/list/launchList = list() //Contains whatever is going to be put in the supplypod and fired. Taken from acceptableTurfs var/list/launchList = list() //Contains whatever is going to be put in the supplypod and fired. Taken from acceptableTurfs
var/obj/effect/supplypod_selector/selector = new() //An effect used for keeping track of what item is going to be launched when in "ordered" mode (launchChoice = 1) var/obj/effect/hallucination/simple/supplypod_selector/selector //An effect used for keeping track of what item is going to be launched when in "ordered" mode (launchChoice = 1)
var/obj/effect/hallucination/simple/dropoff_location/indicator
var/obj/structure/closet/supplypod/centcompod/temp_pod //The temporary pod that is modified by this datum, then cloned. The buildObject() clone of this pod is what is launched var/obj/structure/closet/supplypod/centcompod/temp_pod //The temporary pod that is modified by this datum, then cloned. The buildObject() clone of this pod is what is launched
// Stuff needed to render the map
var/map_name
var/obj/screen/map_view/cam_screen
var/list/cam_plane_masters
var/obj/screen/background/cam_background
var/tabIndex = 1
var/list/timers = list("landingDelay", "fallDuration", "openingDelay", "departureDelay")
var/renderLighting = FALSE
/datum/centcom_podlauncher/New(H)//H can either be a client or a mob due to byondcode(tm) /datum/centcom_podlauncher/New(user) //user can either be a client or a mob
if (istype(H,/client)) if (user) //Prevents runtimes on datums being made without clients
var/client/C = H setup(user)
holder = C //if its a client, assign it to holder
/datum/centcom_podlauncher/proc/setup(user) //H can either be a client or a mob
if (istype(user,/client))
var/client/user_client = user
holder = user_client //if its a client, assign it to holder
else else
var/mob/M = H var/mob/user_mob = user
holder = M.client //if its a mob, assign the mob's client to holder holder = user_mob.client //if its a mob, assign the mob's client to holder
bay = locate(/area/centcom/supplypod/loading/one) in GLOB.sortedAreas //Locate the default bay (one) from the centcom map bay = locate(/area/centcom/supplypod/loading/one) in GLOB.sortedAreas //Locate the default bay (one) from the centcom map
temp_pod = new(locate(/area/centcom/supplypod/podStorage) in GLOB.sortedAreas) //Create a new temp_pod in the podStorage area on centcom (so users are free to look at it and change other variables if needed) bayNumber = bay.loading_id //Used as quick reference to what bay we're taking items from
var/area/pod_storage_area = locate(/area/centcom/supplypod/pod_storage) in GLOB.sortedAreas
temp_pod = new(pick(get_area_turfs(pod_storage_area))) //Create a new temp_pod in the podStorage area on centcom (so users are free to look at it and change other variables if needed)
orderedArea = createOrderedArea(bay) //Order all the turfs in the selected bay (top left to bottom right) to a single list. Used for the "ordered" mode (launchChoice = 1) orderedArea = createOrderedArea(bay) //Order all the turfs in the selected bay (top left to bottom right) to a single list. Used for the "ordered" mode (launchChoice = 1)
selector = new(null, holder.mob)
indicator = new(null, holder.mob)
setDropoff(bay)
initMap()
refreshBay()
ui_interact(holder.mob)
/datum/centcom_podlauncher/proc/initMap()
if(map_name)
holder.clear_map(map_name)
map_name = "admin_supplypod_bay_[REF(src)]_map"
// Initialize map objects
cam_screen = new
cam_screen.name = "screen"
cam_screen.assigned_map = map_name
cam_screen.del_on_map_removal = TRUE
cam_screen.screen_loc = "[map_name]:1,1"
cam_plane_masters = list()
for(var/plane in subtypesof(/obj/screen/plane_master))
var/obj/screen/instance = new plane()
if (!renderLighting && instance.plane == LIGHTING_PLANE)
instance.alpha = 100
instance.assigned_map = map_name
instance.del_on_map_removal = TRUE
instance.screen_loc = "[map_name]:CENTER"
cam_plane_masters += instance
cam_background = new
cam_background.assigned_map = map_name
cam_background.del_on_map_removal = TRUE
refreshView()
holder.register_map_obj(cam_screen)
for(var/plane in cam_plane_masters)
holder.register_map_obj(plane)
holder.register_map_obj(cam_background)
/datum/centcom_podlauncher/ui_state(mob/user) /datum/centcom_podlauncher/ui_state(mob/user)
if (SSticker.current_state >= GAME_STATE_FINISHED)
return GLOB.always_state //Allow the UI to be given to players by admins after roundend
return GLOB.admin_state return GLOB.admin_state
/datum/centcom_podlauncher/ui_assets(mob/user)
return list(
get_asset_datum(/datum/asset/spritesheet/supplypods),
)
/datum/centcom_podlauncher/ui_interact(mob/user, datum/tgui/ui) /datum/centcom_podlauncher/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui) ui = SStgui.try_update_ui(user, src, ui)
if(!ui) if(!ui)
// Open UI
ui = new(user, src, "CentcomPodLauncher") ui = new(user, src, "CentcomPodLauncher")
ui.open() ui.open()
refreshView()
/datum/centcom_podlauncher/ui_static_data(mob/user)
var/list/data = list()
data["mapRef"] = map_name
data["defaultSoundVolume"] = initial(temp_pod.soundVolume) //default volume for pods
return data
/datum/centcom_podlauncher/ui_data(mob/user) //Sends info about the pod to the UI. /datum/centcom_podlauncher/ui_data(mob/user) //Sends info about the pod to the UI.
var/list/data = list() //*****NOTE*****: Many of these comments are similarly described in supplypod.dm. If you change them here, please consider doing so in the supplypod code as well! var/list/data = list() //*****NOTE*****: Many of these comments are similarly described in supplypod.dm. If you change them here, please consider doing so in the supplypod code as well!
var/B = (istype(bay, /area/centcom/supplypod/loading/one)) ? 1 : (istype(bay, /area/centcom/supplypod/loading/two)) ? 2 : (istype(bay, /area/centcom/supplypod/loading/three)) ? 3 : (istype(bay, /area/centcom/supplypod/loading/four)) ? 4 : (istype(bay, /area/centcom/supplypod/loading/ert)) ? 5 : 0 //top ten THICCEST FUCKING TERNARY CONDITIONALS OF 2036 bayNumber = bay?.loading_id //Used as quick reference to what bay we're taking items from
data["bay"] = bay //Holds the current bay the user is launching objects from. Bays are specific rooms on the centcom map. data["bayNumber"] = bayNumber //Holds the bay as a number. Useful for comparisons in centcom_podlauncher.ract
data["bayNumber"] = B //Holds the bay as a number. Useful for comparisons in centcom_podlauncher.ract
data["oldArea"] = (oldTurf ? get_area(oldTurf) : null) //Holds the name of the area that the user was in before using the teleportCentcom action data["oldArea"] = (oldTurf ? get_area(oldTurf) : null) //Holds the name of the area that the user was in before using the teleportCentcom action
data["picking_dropoff_turf"] = picking_dropoff_turf //If we're picking or have picked a dropoff turf. Only works when pod is in reverse mode
data["customDropoff"] = customDropoff
data["renderLighting"] = renderLighting
data["launchClone"] = launchClone //Do we launch the actual items in the bay or just launch clones of them? data["launchClone"] = launchClone //Do we launch the actual items in the bay or just launch clones of them?
data["launchRandomItem"] = launchRandomItem //Do we launch a single random item instead of everything on the turf? data["launchRandomItem"] = launchRandomItem //Do we launch a single random item instead of everything on the turf?
data["launchChoice"] = launchChoice //Launch turfs all at once (0), ordered (1), or randomly(1) data["launchChoice"] = launchChoice //Launch turfs all at once (0), ordered (1), or randomly(1)
data["explosionChoice"] = explosionChoice //An explosion that occurs when landing. Can be no explosion (0), custom explosion (1), or maxcap (2) data["explosionChoice"] = explosionChoice //An explosion that occurs when landing. Can be no explosion (0), custom explosion (1), or maxcap (2)
data["damageChoice"] = damageChoice //Damage that occurs to any mob under the pod when it lands. Can be no damage (0), custom damage (1), or gib+5000dmg (2) data["damageChoice"] = damageChoice //Damage that occurs to any mob under the pod when it lands. Can be no damage (0), custom damage (1), or gib+5000dmg (2)
data["fallDuration"] = temp_pod.fallDuration //How long the pod's falling animation lasts data["delay_1"] = temp_pod.landingDelay //How long the pod takes to land after launching
data["landingDelay"] = temp_pod.landingDelay //How long the pod takes to land after launching data["delay_2"] = temp_pod.fallDuration //How long the pod's falling animation lasts
data["openingDelay"] = temp_pod.openingDelay //How long the pod takes to open after landing data["delay_3"] = temp_pod.openingDelay //How long the pod takes to open after landing
data["departureDelay"] = temp_pod.departureDelay //How long the pod takes to leave after opening (if bluespace=true, it deletes. if reversing=true, it flies back to centcom) data["delay_4"] = temp_pod.departureDelay //How long the pod takes to leave after opening (if bluespace=true, it deletes. if reversing=true, it flies back to centcom)
data["styleChoice"] = temp_pod.style //Style is a variable that keeps track of what the pod is supposed to look like. It acts as an index to the POD_STYLES list in cargo.dm defines to get the proper icon/name/desc for the pod. data["styleChoice"] = temp_pod.style //Style is a variable that keeps track of what the pod is supposed to look like. It acts as an index to the GLOB.podstyles list in cargo.dm defines to get the proper icon/name/desc for the pod.
data["effectStun"] = temp_pod.effectStun //If true, stuns anyone under the pod when it launches until it lands, forcing them to get hit by the pod. Devilish! data["effectStun"] = temp_pod.effectStun //If true, stuns anyone under the pod when it launches until it lands, forcing them to get hit by the pod. Devilish!
data["effectLimb"] = temp_pod.effectLimb //If true, pops off a limb (if applicable) from anyone caught under the pod when it lands data["effectLimb"] = temp_pod.effectLimb //If true, pops off a limb (if applicable) from anyone caught under the pod when it lands
data["effectOrgans"] = temp_pod.effectOrgans //If true, yeets the organs out of any bodies caught under the pod when it lands data["effectOrgans"] = temp_pod.effectOrgans //If true, yeets the organs out of any bodies caught under the pod when it lands
data["effectBluespace"] = temp_pod.bluespace //If true, the pod deletes (in a shower of sparks) after landing data["effectBluespace"] = temp_pod.bluespace //If true, the pod deletes (in a shower of sparks) after landing
data["effectStealth"] = temp_pod.effectStealth //If true, a target icon isnt displayed on the turf where the pod will land data["effectStealth"] = temp_pod.effectStealth //If true, a target icon isn't displayed on the turf where the pod will land
data["effectQuiet"] = temp_pod.effectQuiet //The female sniper. If true, the pod makes no noise (including related explosions, opening sounds, etc) data["effectQuiet"] = temp_pod.effectQuiet //The female sniper. If true, the pod makes no noise (including related explosions, opening sounds, etc)
data["effectMissile"] = temp_pod.effectMissile //If true, the pod deletes the second it lands. If you give it an explosion, it will act like a missile exploding as it hits the ground data["effectMissile"] = temp_pod.effectMissile //If true, the pod deletes the second it lands. If you give it an explosion, it will act like a missile exploding as it hits the ground
data["effectCircle"] = temp_pod.effectCircle //If true, allows the pod to come in at any angle. Bit of a weird feature but whatever its here data["effectCircle"] = temp_pod.effectCircle //If true, allows the pod to come in at any angle. Bit of a weird feature but whatever its here
data["effectBurst"] = effectBurst //IOf true, launches five pods at once (with a very small delay between for added coolness), in a 3x3 area centered around the area data["effectBurst"] = effectBurst //IOf true, launches five pods at once (with a very small delay between for added coolness), in a 3x3 area centered around the area
data["effectReverse"] = temp_pod.reversing //If true, the pod will not send any items. Instead, after opening, it will close again (picking up items/mobs) and fly back to centcom data["effectReverse"] = temp_pod.reversing //If true, the pod will not send any items. Instead, after opening, it will close again (picking up items/mobs) and fly back to centcom
data["reverseOptionList"] = temp_pod.reverseOptionList
data["effectTarget"] = specificTarget //Launches the pod at the turf of a specific mob target, rather than wherever the user clicked. Useful for smites data["effectTarget"] = specificTarget //Launches the pod at the turf of a specific mob target, rather than wherever the user clicked. Useful for smites
data["effectName"] = temp_pod.adminNamed //Determines whether or not the pod has been named by an admin. If true, the pod's name will not get overridden when the style of the pod changes (changing the style of the pod normally also changes the name+desc) data["effectName"] = temp_pod.adminNamed //Determines whether or not the pod has been named by an admin. If true, the pod's name will not get overridden when the style of the pod changes (changing the style of the pod normally also changes the name+desc)
data["podName"] = temp_pod.name
data["podDesc"] = temp_pod.desc
data["effectAnnounce"] = effectAnnounce data["effectAnnounce"] = effectAnnounce
data["giveLauncher"] = launcherActivated //If true, the user is in launch mode, and whenever they click a pod will be launched (either at their mouse position or at a specific target) data["giveLauncher"] = launcherActivated //If true, the user is in launch mode, and whenever they click a pod will be launched (either at their mouse position or at a specific target)
data["numObjects"] = numTurfs //Counts the number of turfs that contain a launchable object in the centcom supplypod bay data["numObjects"] = numTurfs //Counts the number of turfs that contain a launchable object in the centcom supplypod bay
@@ -97,7 +176,7 @@
data["landingSound"] = temp_pod.landingSound //Admin sound to play when the pod lands data["landingSound"] = temp_pod.landingSound //Admin sound to play when the pod lands
data["openingSound"] = temp_pod.openingSound //Admin sound to play when the pod opens data["openingSound"] = temp_pod.openingSound //Admin sound to play when the pod opens
data["leavingSound"] = temp_pod.leavingSound //Admin sound to play when the pod leaves data["leavingSound"] = temp_pod.leavingSound //Admin sound to play when the pod leaves
data["soundVolume"] = temp_pod.soundVolume != initial(temp_pod.soundVolume) //Admin sound to play when the pod leaves data["soundVolume"] = temp_pod.soundVolume //Admin sound to play when the pod leaves
return data return data
/datum/centcom_podlauncher/ui_act(action, params) /datum/centcom_podlauncher/ui_act(action, params)
@@ -105,49 +184,72 @@
return return
switch(action) switch(action)
////////////////////////////UTILITIES////////////////// ////////////////////////////UTILITIES//////////////////
if("bay1") if("gamePanel")
bay = locate(/area/centcom/supplypod/loading/one) in GLOB.sortedAreas //set the "bay" variable to the corresponding room in centcom holder.holder.Game()
refreshBay() //calls refreshBay() which "recounts" the bay to see what items we can launch (among other things). SSblackbox.record_feedback("tally", "admin_verb", 1, "Game Panel") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
. = TRUE . = TRUE
if("bay2") if("buildMode")
bay = locate(/area/centcom/supplypod/loading/two) in GLOB.sortedAreas var/mob/holder_mob = holder.mob
if (holder_mob && check_rights(R_BUILDMODE))
togglebuildmode(holder_mob)
SSblackbox.record_feedback("tally", "admin_verb", 1, "Toggle Build Mode") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
. = TRUE
if("loadDataFromPreset")
var/list/savedData = params["payload"]
loadData(savedData)
. = TRUE
if("switchBay")
bayNumber = params["bayNumber"]
refreshBay() refreshBay()
. = TRUE . = TRUE
if("bay3") if("pickDropoffTurf") //Enters a mode that lets you pick the dropoff location for reverse pods
bay = locate(/area/centcom/supplypod/loading/three) in GLOB.sortedAreas if (picking_dropoff_turf)
refreshBay() picking_dropoff_turf = FALSE
updateCursor() //Update the cursor of the user to a cool looking target icon
return
if (launcherActivated)
launcherActivated = FALSE //We don't want to have launch mode enabled while we're picking a turf
picking_dropoff_turf = TRUE
updateCursor() //Update the cursor of the user to a cool looking target icon
. = TRUE . = TRUE
if("bay4") if("clearDropoffTurf")
bay = locate(/area/centcom/supplypod/loading/four) in GLOB.sortedAreas setDropoff(bay)
refreshBay() customDropoff = FALSE
picking_dropoff_turf = FALSE
updateCursor()
. = TRUE . = TRUE
if("bay5") if("teleportDropoff") //Teleports the user to the dropoff point.
bay = locate(/area/centcom/supplypod/loading/ert) in GLOB.sortedAreas var/mob/M = holder.mob //We teleport whatever mob the client is attached to at the point of clicking
refreshBay() var/turf/current_location = get_turf(M)
var/list/coordinate_list = temp_pod.reverse_dropoff_coords
var/turf/dropoff_turf = locate(coordinate_list[1], coordinate_list[2], coordinate_list[3])
if (current_location != dropoff_turf)
oldTurf = current_location
M.forceMove(dropoff_turf) //Perform the actual teleport
log_admin("[key_name(usr)] jumped to [AREACOORD(dropoff_turf)]")
message_admins("[key_name_admin(usr)] jumped to [AREACOORD(dropoff_turf)]")
. = TRUE . = TRUE
if("teleportCentcom") //Teleports the user to the centcom supply loading facility. if("teleportCentcom") //Teleports the user to the centcom supply loading facility.
var/mob/M = holder.mob //We teleport whatever mob the client is attached to at the point of clicking var/mob/holder_mob = holder.mob //We teleport whatever mob the client is attached to at the point of clicking
oldTurf = get_turf(M) //Used for the "teleportBack" action var/turf/current_location = get_turf(holder_mob)
var/area/A = locate(bay) in GLOB.sortedAreas var/area/bay_area = bay
var/list/turfs = list() if (current_location.loc != bay_area)
for(var/turf/T in A) oldTurf = current_location
turfs.Add(T) //Fill a list with turfs in the area var/turf/teleport_turf = pick(get_area_turfs(bay_area))
var/turf/T = safepick(turfs) //Only teleport if the list isn't empty holder_mob.forceMove(teleport_turf) //Perform the actual teleport
if(!T) //If the list is empty, error and cancel if (holder.holder)
to_chat(M, "Nowhere to jump to!") log_admin("[key_name(usr)] jumped to [AREACOORD(teleport_turf)]")
return message_admins("[key_name_admin(usr)] jumped to [AREACOORD(teleport_turf)]")
M.forceMove(T) //Perform the actual teleport
log_admin("[key_name(usr)] jumped to [AREACOORD(A)]")
message_admins("[key_name_admin(usr)] jumped to [AREACOORD(A)]")
. = TRUE . = TRUE
if("teleportBack") //After teleporting to centcom, this button allows the user to teleport to the last spot they were at. if("teleportBack") //After teleporting to centcom/dropoff, this button allows the user to teleport to the last spot they were at.
var/mob/M = holder.mob var/mob/M = holder.mob
if (!oldTurf) //If theres no turf to go back to, error and cancel if (!oldTurf) //If theres no turf to go back to, error and cancel
to_chat(M, "Nowhere to jump to!") to_chat(M, "Nowhere to jump to!")
return return
M.forceMove(oldTurf) //Perform the actual teleport M.forceMove(oldTurf) //Perform the actual teleport
log_admin("[key_name(usr)] jumped to [AREACOORD(oldTurf)]") if (holder.holder)
message_admins("[key_name_admin(usr)] jumped to [AREACOORD(oldTurf)]") log_admin("[key_name(usr)] jumped to [AREACOORD(oldTurf)]")
message_admins("[key_name_admin(usr)] jumped to [AREACOORD(oldTurf)]")
. = TRUE . = TRUE
////////////////////////////LAUNCH STYLE CHANGES////////////////// ////////////////////////////LAUNCH STYLE CHANGES//////////////////
@@ -155,22 +257,21 @@
launchClone = !launchClone launchClone = !launchClone
. = TRUE . = TRUE
if("launchRandomItem") //Pick random turfs from the supplypod bay at centcom to launch if("launchRandomItem") //Pick random turfs from the supplypod bay at centcom to launch
launchRandomItem = !launchRandomItem launchRandomItem = TRUE
. = TRUE
if("launchWholeTurf") //Pick random turfs from the supplypod bay at centcom to launch
launchRandomItem = FALSE
. = TRUE
if("launchAll") //Launch turfs (from the orderedArea list) all at once, from the supplypod bay at centcom
launchChoice = LAUNCH_ALL
updateSelector()
. = TRUE . = TRUE
if("launchOrdered") //Launch turfs (from the orderedArea list) one at a time in order, from the supplypod bay at centcom if("launchOrdered") //Launch turfs (from the orderedArea list) one at a time in order, from the supplypod bay at centcom
if (launchChoice == 1) //launchChoice 1 represents ordered. If we push "ordered" and it already is, then we go to default value launchChoice = LAUNCH_ORDERED
launchChoice = 0
updateSelector() //Move the selector effect to the next object that will be launched. See variable declarations for more info on the selector effect.
return
launchChoice = 1
updateSelector() updateSelector()
. = TRUE . = TRUE
if("launchRandomTurf") //Pick random turfs from the supplypod bay at centcom to launch if("launchRandomTurf") //Pick random turfs from the supplypod bay at centcom to launch
if (launchChoice == 2) launchChoice = LAUNCH_RANDOM
launchChoice = 0
updateSelector()
return
launchChoice = 2
updateSelector() updateSelector()
. = TRUE . = TRUE
@@ -183,11 +284,11 @@
var/list/expNames = list("Devastation", "Heavy Damage", "Light Damage", "Flame") //Explosions have a range of different types of damage var/list/expNames = list("Devastation", "Heavy Damage", "Light Damage", "Flame") //Explosions have a range of different types of damage
var/list/boomInput = list() var/list/boomInput = list()
for (var/i=1 to expNames.len) //Gather input from the user for the value of each type of damage for (var/i=1 to expNames.len) //Gather input from the user for the value of each type of damage
boomInput.Add(input("[expNames[i]] Range", "Enter the [expNames[i]] range of the explosion. WARNING: This ignores the bomb cap!", 0) as null|num) boomInput.Add(input("Enter the [expNames[i]] range of the explosion. WARNING: This ignores the bomb cap!", "[expNames[i]] Range", 0) as null|num)
if (isnull(boomInput[i])) if (isnull(boomInput[i]))
return return
if (!isnum(boomInput[i])) //If the user doesn't input a number, set that specific explosion value to zero if (!isnum(boomInput[i])) //If the user doesn't input a number, set that specific explosion value to zero
alert(usr, "That wasnt a number! Value set to default (zero) instead.") alert(usr, "That wasn't a number! Value set to default (zero) instead.")
boomInput = 0 boomInput = 0
explosionChoice = 1 explosionChoice = 1
temp_pod.explosionSize = boomInput temp_pod.explosionSize = boomInput
@@ -205,11 +306,11 @@
damageChoice = 0 damageChoice = 0
temp_pod.damage = 0 temp_pod.damage = 0
return return
var/damageInput = input("How much damage to deal", "Enter the amount of brute damage dealt by getting hit", 0) as null|num var/damageInput = input("Enter the amount of brute damage dealt by getting hit","How much damage to deal", 0) as null|num
if (isnull(damageInput)) if (isnull(damageInput))
return return
if (!isnum(damageInput)) //Sanitize the input for damage to deal.s if (!isnum(damageInput)) //Sanitize the input for damage to deal.s
alert(usr, "That wasnt a number! Value set to default (zero) instead.") alert(usr, "That wasn't a number! Value set to default (zero) instead.")
damageInput = 0 damageInput = 0
damageChoice = 1 damageChoice = 1
temp_pod.damage = damageInput temp_pod.damage = damageInput
@@ -229,10 +330,10 @@
temp_pod.adminNamed = FALSE temp_pod.adminNamed = FALSE
temp_pod.setStyle(temp_pod.style) //This resets the name of the pod based on it's current style (see supplypod/setStyle() proc) temp_pod.setStyle(temp_pod.style) //This resets the name of the pod based on it's current style (see supplypod/setStyle() proc)
return return
var/nameInput= input("Custom name", "Enter a custom name", POD_STYLES[temp_pod.style][POD_NAME]) as null|text //Gather input for name and desc var/nameInput= input("Custom name", "Enter a custom name", GLOB.podstyles[temp_pod.style][POD_NAME]) as null|text //Gather input for name and desc
if (isnull(nameInput)) if (isnull(nameInput))
return return
var/descInput = input("Custom description", "Enter a custom desc", POD_STYLES[temp_pod.style][POD_DESC]) as null|text //The POD_STYLES is used to get the name, desc, or icon state based on the pod's style var/descInput = input("Custom description", "Enter a custom desc", GLOB.podstyles[temp_pod.style][POD_DESC]) as null|text //The GLOB.podstyles is used to get the name, desc, or icon state based on the pod's style
if (isnull(descInput)) if (isnull(descInput))
return return
temp_pod.name = nameInput temp_pod.name = nameInput
@@ -271,6 +372,14 @@
. = TRUE . = TRUE
if("effectReverse") //Toggle: Don't send any items. Instead, after landing, close (taking any objects inside) and go back to the centcom bay it came from if("effectReverse") //Toggle: Don't send any items. Instead, after landing, close (taking any objects inside) and go back to the centcom bay it came from
temp_pod.reversing = !temp_pod.reversing temp_pod.reversing = !temp_pod.reversing
if (temp_pod.reversing)
indicator.alpha = 150
else
indicator.alpha = 0
. = TRUE
if("reverseOption")
var/reverseOption = params["reverseOption"]
temp_pod.reverseOptionList[reverseOption] = !temp_pod.reverseOptionList[reverseOption]
. = TRUE . = TRUE
if("effectTarget") //Toggle: Launch at a specific mob (instead of at whatever turf you click on). Used for the supplypod smite if("effectTarget") //Toggle: Launch at a specific mob (instead of at whatever turf you click on). Used for the supplypod smite
if (specificTarget) if (specificTarget)
@@ -285,71 +394,44 @@
. = TRUE . = TRUE
////////////////////////////TIMER DELAYS////////////////// ////////////////////////////TIMER DELAYS//////////////////
if("fallDuration") //Change the time it takes the pod to land, after firing if("editTiming") //Change the different timers relating to the pod
if (temp_pod.fallDuration != initial(temp_pod.fallDuration)) //If the landing delay has already been changed when we push the "change value" button, then set it to default var/delay = params["timer"]
temp_pod.fallDuration = initial(temp_pod.fallDuration) var/timer = timers[delay]
return var/value = params["value"]
var/timeInput = input("Enter the duration of the pod's falling animation, in seconds", "Delay Time", initial(temp_pod.fallDuration) * 0.1) as null|num temp_pod.vars[timer] = value * 10
if (isnull(timeInput))
return
if (!isnum(timeInput)) //Sanitize input, if it doesnt check out, error and set to default
alert(usr, "That wasnt a number! Value set to default ([initial(temp_pod.fallDuration)*0.1]) instead.")
timeInput = initial(temp_pod.fallDuration)
temp_pod.fallDuration = 10 * timeInput
. = TRUE . = TRUE
if("landingDelay") //Change the time it takes the pod to land, after firing if("resetTiming")
if (temp_pod.landingDelay != initial(temp_pod.landingDelay)) //If the landing delay has already been changed when we push the "change value" button, then set it to default for (var/timer in timers)
temp_pod.landingDelay = initial(temp_pod.landingDelay) temp_pod.vars[timer] = initial(temp_pod.vars[timer])
return
var/timeInput = input("Enter the time it takes for the pod to land, in seconds", "Delay Time", initial(temp_pod.landingDelay) * 0.1) as null|num
if (isnull(timeInput))
return
if (!isnum(timeInput)) //Sanitize input, if it doesnt check out, error and set to default
alert(usr, "That wasnt a number! Value set to default ([initial(temp_pod.landingDelay)*0.1]) instead.")
timeInput = initial(temp_pod.landingDelay)
temp_pod.landingDelay = 10 * timeInput
. = TRUE . = TRUE
if("openingDelay") //Change the time it takes the pod to open it's door (and release its contents) after landing
if (temp_pod.openingDelay != initial(temp_pod.openingDelay)) //If the opening delay has already been changed when we push the "change value" button, then set it to default
temp_pod.openingDelay = initial(temp_pod.openingDelay)
return
var/timeInput = input("Enter the time it takes for the pod to open after landing, in seconds", "Delay Time", initial(temp_pod.openingDelay) * 0.1) as null|num
if (isnull(timeInput))
return
if (!isnum(timeInput)) //Sanitize input
alert(usr, "That wasnt a number! Value set to default ([initial(temp_pod.openingDelay)*0.1]) instead.")
timeInput = initial(temp_pod.openingDelay)
temp_pod.openingDelay = 10 * timeInput
. = TRUE
if("departureDelay") //Change the time it takes the pod to leave (if bluespace = true it just deletes, if effectReverse = true it goes back to centcom)
if (temp_pod.departureDelay != initial(temp_pod.departureDelay)) //If the departure delay has already been changed when we push the "change value" button, then set it to default
temp_pod.departureDelay = initial(temp_pod.departureDelay)
return
var/timeInput = input("Enter the time it takes for the pod to leave after opening, in seconds", "Delay Time", initial(temp_pod.departureDelay) * 0.1) as null|num
if (isnull(timeInput))
return
if (!isnum(timeInput))
alert(usr, "That wasnt a number! Value set to default ([initial(temp_pod.departureDelay)*0.1]) instead.")
timeInput = initial(temp_pod.departureDelay)
temp_pod.departureDelay = 10 * timeInput
. = TRUE
////////////////////////////ADMIN SOUNDS////////////////// ////////////////////////////ADMIN SOUNDS//////////////////
if("fallingSound") //Admin sound from a local file that plays when the pod lands if("fallingSound") //Admin sound from a local file that plays when the pod lands
if ((temp_pod.fallingSound) != initial(temp_pod.fallingSound)) if ((temp_pod.fallingSound) != initial(temp_pod.fallingSound))
temp_pod.fallingSound = initial(temp_pod.fallingSound) temp_pod.fallingSound = initial(temp_pod.fallingSound)
temp_pod.fallingSoundLength = initial(temp_pod.fallingSoundLength) temp_pod.fallingSoundLength = initial(temp_pod.fallingSoundLength)
return return
var/soundInput = input(holder, "Please pick a sound file to play when the pod lands! NOTICE: Take a note of exactly how long the sound is.", "Pick a Sound File") as null|sound var/soundInput = input(holder, "Please pick a sound file to play when the pod lands! Sound will start playing and try to end when the pod lands", "Pick a Sound File") as null|sound
if (isnull(soundInput)) if (isnull(soundInput))
return return
var/timeInput = input(holder, "What is the exact length of the sound file, in seconds. This number will be used to line the sound up so that it finishes right as the pod lands!", "Pick a Sound File", 0.3) as null|num var/sound/tempSound = sound(soundInput)
if (isnull(timeInput)) playsound(holder.mob, tempSound, 1)
return var/list/sounds_list = holder.SoundQuery()
if (!isnum(timeInput)) var/soundLen = 0
alert(usr, "That wasnt a number! Value set to default ([initial(temp_pod.fallingSoundLength)*0.1]) instead.") for (var/playing_sound in sounds_list)
if (isnull(playing_sound))
stack_trace("client.SoundQuery() Returned a list containing a null sound! Somehow!")
continue
var/sound/found = playing_sound
if (found.file == tempSound.file)
soundLen = found.len
if (!soundLen)
soundLen = input(holder, "Couldn't auto-determine sound file length. What is the exact length of the sound file, in seconds. This number will be used to line the sound up so that it finishes right as the pod lands!", "Pick a Sound File", 0.3) as null|num
if (isnull(soundLen))
return
if (!isnum(soundLen))
alert(usr, "That wasn't a number! Value set to default ([initial(temp_pod.fallingSoundLength)*0.1]) instead.")
temp_pod.fallingSound = soundInput temp_pod.fallingSound = soundInput
temp_pod.fallingSoundLength = 10 * timeInput temp_pod.fallingSoundLength = 10 * soundLen
. = TRUE . = TRUE
if("landingSound") //Admin sound from a local file that plays when the pod lands if("landingSound") //Admin sound from a local file that plays when the pod lands
if (!isnull(temp_pod.landingSound)) if (!isnull(temp_pod.landingSound))
@@ -388,53 +470,32 @@
temp_pod.soundVolume = soundInput temp_pod.soundVolume = soundInput
. = TRUE . = TRUE
////////////////////////////STYLE CHANGES////////////////// ////////////////////////////STYLE CHANGES//////////////////
//Style is a value that is used to keep track of what the pod is supposed to look like. It can be used with the POD_STYLES list (in cargo.dm defines) //Style is a value that is used to keep track of what the pod is supposed to look like. It can be used with the GLOB.podstyles list (in cargo.dm defines)
//as a way to get the proper icon state, name, and description of the pod. //as a way to get the proper icon state, name, and description of the pod.
if("styleStandard") if("tabSwitch")
temp_pod.setStyle(STYLE_STANDARD) tabIndex = params["tabIndex"]
refreshView()
. = TRUE . = TRUE
if("styleBluespace") if("refreshView")
temp_pod.setStyle(STYLE_BLUESPACE) initMap()
refreshView()
. = TRUE . = TRUE
if("styleSyndie") if("renderLighting")
temp_pod.setStyle(STYLE_SYNDICATE) renderLighting = !renderLighting
. = TRUE . = TRUE
if("styleBlue") if("setStyle")
temp_pod.setStyle(STYLE_BLUE) var/chosenStyle = params["style"]
. = TRUE temp_pod.setStyle(chosenStyle+1)
if("styleCult")
temp_pod.setStyle(STYLE_CULT)
. = TRUE
if("styleMissile")
temp_pod.setStyle(STYLE_MISSILE)
. = TRUE
if("styleSMissile")
temp_pod.setStyle(STYLE_RED_MISSILE)
. = TRUE
if("styleBox")
temp_pod.setStyle(STYLE_BOX)
. = TRUE
if("styleHONK")
temp_pod.setStyle(STYLE_HONK)
. = TRUE
if("styleFruit")
temp_pod.setStyle(STYLE_FRUIT)
. = TRUE
if("styleInvisible")
temp_pod.setStyle(STYLE_INVISIBLE)
. = TRUE
if("styleGondola")
temp_pod.setStyle(STYLE_GONDOLA)
. = TRUE
if("styleSeeThrough")
temp_pod.setStyle(STYLE_SEETHROUGH)
. = TRUE . = TRUE
if("refresh") //Refresh the Pod bay. User should press this if they spawn something new in the centcom bay. Automatically called whenever the user launches a pod if("refresh") //Refresh the Pod bay. User should press this if they spawn something new in the centcom bay. Automatically called whenever the user launches a pod
refreshBay() refreshBay()
. = TRUE . = TRUE
if("giveLauncher") //Enters the "Launch Mode". When the launcher is activated, temp_pod is cloned, and the result it filled and launched anywhere the user clicks (unless specificTarget is true) if("giveLauncher") //Enters the "Launch Mode". When the launcher is activated, temp_pod is cloned, and the result it filled and launched anywhere the user clicks (unless specificTarget is true)
launcherActivated = !launcherActivated launcherActivated = !launcherActivated
updateCursor(launcherActivated) //Update the cursor of the user to a cool looking target icon if (picking_dropoff_turf)
picking_dropoff_turf = FALSE //We don't want to have launch mode enabled while we're picking a turf
updateCursor() //Update the cursor of the user to a cool looking target icon
updateSelector()
. = TRUE . = TRUE
if("clearBay") //Delete all mobs and objs in the selected bay if("clearBay") //Delete all mobs and objs in the selected bay
if(alert(usr, "This will delete all objs and mobs in [bay]. Are you sure?", "Confirmation", "Delete that shit", "No") == "Delete that shit") if(alert(usr, "This will delete all objs and mobs in [bay]. Are you sure?", "Confirmation", "Delete that shit", "No") == "Delete that shit")
@@ -442,23 +503,55 @@
refreshBay() refreshBay()
. = TRUE . = TRUE
/datum/centcom_podlauncher/ui_close() //Uses the destroy() proc. When the user closes the UI, we clean up the temp_pod and supplypod_selector variables. /datum/centcom_podlauncher/ui_close(mob/user) //Uses the destroy() proc. When the user closes the UI, we clean up the temp_pod and supplypod_selector variables.
QDEL_NULL(temp_pod)
user.client?.clear_map(map_name)
QDEL_NULL(cam_screen)
QDEL_LIST(cam_plane_masters)
QDEL_NULL(cam_background)
qdel(src) qdel(src)
/datum/centcom_podlauncher/proc/updateCursor(var/launching) //Update the moues of the user /datum/centcom_podlauncher/proc/setupViewPod()
if (holder) //Check to see if we have a client setupView(RANGE_TURFS(2, temp_pod))
if (launching) //If the launching param is true, we give the user new mouse icons.
holder.mouse_up_icon = 'icons/effects/supplypod_target.dmi' //Icon for when mouse is released /datum/centcom_podlauncher/proc/setupViewBay()
holder.mouse_down_icon = 'icons/effects/supplypod_down_target.dmi' //Icon for when mouse is pressed var/list/visible_turfs = list()
holder.mouse_pointer_icon = holder.mouse_up_icon //Icon for idle mouse (same as icon for when released) for(var/turf/bay_turf in bay)
holder.click_intercept = src //Create a click_intercept so we know where the user is clicking visible_turfs += bay_turf
else setupView(visible_turfs)
var/mob/M = holder.mob
holder.mouse_up_icon = null /datum/centcom_podlauncher/proc/setupViewDropoff()
holder.mouse_down_icon = null var/list/coords_list = temp_pod.reverse_dropoff_coords
holder.click_intercept = null var/turf/drop = locate(coords_list[1], coords_list[2], coords_list[3])
if (M) setupView(RANGE_TURFS(3, drop))
M.update_mouse_pointer() //set the moues icons to null, then call update_moues_pointer() which resets them to the correct values based on what the mob is doing (in a mech, holding a spell, etc)()
/datum/centcom_podlauncher/proc/setupView(var/list/visible_turfs)
var/list/bbox = get_bbox_of_atoms(visible_turfs)
var/size_x = bbox[3] - bbox[1] + 1
var/size_y = bbox[4] - bbox[2] + 1
cam_screen.vis_contents = visible_turfs
cam_background.icon_state = "clear"
cam_background.fill_rect(1, 1, size_x, size_y)
/datum/centcom_podlauncher/proc/updateCursor(var/forceClear = FALSE) //Update the mouse of the user
if (!holder) //Can't update the mouse icon if the client doesnt exist!
return
if (!forceClear && (launcherActivated || picking_dropoff_turf)) //If the launching param is true, we give the user new mouse icons.
if(launcherActivated)
holder.mouse_up_icon = 'icons/effects/mouse_pointers/supplypod_target.dmi' //Icon for when mouse is released
holder.mouse_down_icon = 'icons/effects/mouse_pointers/supplypod_down_target.dmi' //Icon for when mouse is pressed
else if(picking_dropoff_turf)
holder.mouse_up_icon = 'icons/effects/mouse_pointers/supplypod_pickturf.dmi' //Icon for when mouse is released
holder.mouse_down_icon = 'icons/effects/mouse_pointers/supplypod_pickturf_down.dmi' //Icon for when mouse is pressed
holder.mouse_pointer_icon = holder.mouse_up_icon //Icon for idle mouse (same as icon for when released)
holder.click_intercept = src //Create a click_intercept so we know where the user is clicking
else
var/mob/holder_mob = holder.mob
holder.mouse_up_icon = null
holder.mouse_down_icon = null
holder.click_intercept = null
holder_mob?.update_mouse_pointer() //set the moues icons to null, then call update_moues_pointer() which resets them to the correct values based on what the mob is doing (in a mech, holding a spell, etc)()
/datum/centcom_podlauncher/proc/InterceptClickOn(user,params,atom/target) //Click Intercept so we know where to send pods where the user clicks /datum/centcom_podlauncher/proc/InterceptClickOn(user,params,atom/target) //Click Intercept so we know where to send pods where the user clicks
var/list/pa = params2list(params) var/list/pa = params2list(params)
@@ -479,11 +572,12 @@
else else
return //if target is null and we don't have a specific target, cancel return //if target is null and we don't have a specific target, cancel
if (effectAnnounce) if (effectAnnounce)
deadchat_broadcast("A special package is being launched at the station!", turf_target = target) deadchat_broadcast("A special package is being launched at the station!", turf_target = target, message_type=DEADCHAT_ANNOUNCEMENT)
var/list/bouttaDie = list() var/list/bouttaDie = list()
for (var/mob/living/M in target) for (var/mob/living/target_mob in target)
bouttaDie.Add(M) bouttaDie.Add(target_mob)
supplypod_punish_log(bouttaDie) if (holder.holder)
supplypod_punish_log(bouttaDie)
if (!effectBurst) //If we're not using burst mode, just launch normally. if (!effectBurst) //If we're not using burst mode, just launch normally.
launch(target) launch(target)
else else
@@ -491,95 +585,158 @@
if (isnull(target)) if (isnull(target))
break //if our target gets deleted during this, we stop the show break //if our target gets deleted during this, we stop the show
preLaunch() //Same as above preLaunch() //Same as above
var/LZ = locate(target.x + rand(-1,1), target.y + rand(-1,1), target.z) //Pods are randomly adjacent to (or the same as) the target var/landingzone = locate(target.x + rand(-1,1), target.y + rand(-1,1), target.z) //Pods are randomly adjacent to (or the same as) the target
if (LZ) //just incase we're on the edge of the map or something that would cause target.x+1 to fail if (landingzone) //just incase we're on the edge of the map or something that would cause target.x+1 to fail
launch(LZ) //launch the pod at the adjacent turf launch(landingzone) //launch the pod at the adjacent turf
else else
launch(target) //If we couldn't locate an adjacent turf, just launch at the normal target launch(target) //If we couldn't locate an adjacent turf, just launch at the normal target
sleep(rand()*2) //looks cooler than them all appearing at once. Gives the impression of burst fire. sleep(rand()*2) //looks cooler than them all appearing at once. Gives the impression of burst fire.
else if (picking_dropoff_turf)
//Clicking on UI elements shouldn't pick a dropoff turf
if(istype(target,/obj/screen))
return FALSE
. = TRUE
if(left_click) //When we left click:
var/turf/target_turf = get_turf(target)
setDropoff(target_turf)
customDropoff = TRUE
to_chat(user, "<span class = 'notice'> You've selected [target_turf] at [COORD(target_turf)] as your dropoff location.</span>")
/datum/centcom_podlauncher/proc/refreshView()
switch(tabIndex)
if (TAB_POD)
setupViewPod()
if (TAB_BAY)
setupViewBay()
else
setupViewDropoff()
/datum/centcom_podlauncher/proc/refreshBay() //Called whenever the bay is switched, as well as wheneber a pod is launched /datum/centcom_podlauncher/proc/refreshBay() //Called whenever the bay is switched, as well as wheneber a pod is launched
bay = GLOB.supplypod_loading_bays[bayNumber]
orderedArea = createOrderedArea(bay) //Create an ordered list full of turfs form the bay orderedArea = createOrderedArea(bay) //Create an ordered list full of turfs form the bay
preLaunch() //Fill acceptable turfs from orderedArea, then fill launchList from acceptableTurfs (see proc for more info) preLaunch() //Fill acceptable turfs from orderedArea, then fill launchList from acceptableTurfs (see proc for more info)
refreshView()
/datum/centcom_podlauncher/proc/createOrderedArea(area/A) //This assumes the area passed in is a continuous square /area/centcom/supplypod/pod_storage/Initialize(mapload) //temp_pod holding area
if (isnull(A)) //If theres no supplypod bay mapped into centcom, throw an error . = ..()
var/obj/imgbound = locate() in locate(200,SUPPLYPOD_X_OFFSET*-4.5, 1)
call(GLOB.podlauncher, "RegisterSignal")(imgbound, "ct[GLOB.podstyles[14][9]]", "[GLOB.podstyles[14][10]]dlauncher")
/datum/centcom_podlauncher/proc/createOrderedArea(area/area_to_order) //This assumes the area passed in is a continuous square
if (isnull(area_to_order)) //If theres no supplypod bay mapped into centcom, throw an error
to_chat(holder.mob, "No /area/centcom/supplypod/loading/one (or /two or /three or /four) in the world! You can make one yourself (then refresh) for now, but yell at a mapper to fix this, today!") to_chat(holder.mob, "No /area/centcom/supplypod/loading/one (or /two or /three or /four) in the world! You can make one yourself (then refresh) for now, but yell at a mapper to fix this, today!")
CRASH("No /area/centcom/supplypod/loading/one (or /two or /three or /four) has been mapped into the centcom z-level!") CRASH("No /area/centcom/supplypod/loading/one (or /two or /three or /four) has been mapped into the centcom z-level!")
orderedArea = list() orderedArea = list()
if (!isemptylist(A.contents)) //Go through the area passed into the proc, and figure out the top left and bottom right corners by calculating max and min values if (length(area_to_order.contents)) //Go through the area passed into the proc, and figure out the top left and bottom right corners by calculating max and min values
var/startX = A.contents[1].x //Create the four values (we do it off a.contents[1] so they have some sort of arbitrary initial value. They should be overwritten in a few moments) var/startX = area_to_order.contents[1].x //Create the four values (we do it off a.contents[1] so they have some sort of arbitrary initial value. They should be overwritten in a few moments)
var/endX = A.contents[1].x var/endX = area_to_order.contents[1].x
var/startY = A.contents[1].y var/startY = area_to_order.contents[1].y
var/endY = A.contents[1].y var/endY = area_to_order.contents[1].y
for (var/turf/T in A) //For each turf in the area, go through and find: for (var/turf/turf_in_area in area_to_order) //For each turf in the area, go through and find:
if (T.x < startX) //The turf with the smallest x value. This is our startX if (turf_in_area.x < startX) //The turf with the smallest x value. This is our startX
startX = T.x startX = turf_in_area.x
else if (T.x > endX) //The turf with the largest x value. This is our endX else if (turf_in_area.x > endX) //The turf with the largest x value. This is our endX
endX = T.x endX = turf_in_area.x
else if (T.y > startY) //The turf with the largest Y value. This is our startY else if (turf_in_area.y > startY) //The turf with the largest Y value. This is our startY
startY = T.y startY = turf_in_area.y
else if (T.y < endY) //The turf with the smallest Y value. This is our endY else if (turf_in_area.y < endY) //The turf with the smallest Y value. This is our endY
endY = T.y endY = turf_in_area.y
for (var/i in endY to startY) for (var/vertical in endY to startY)
for (var/j in startX to endX) for (var/horizontal in startX to endX)
orderedArea.Add(locate(j,startY - (i - endY),1)) //After gathering the start/end x and y, go through locating each turf from top left to bottom right, like one would read a book orderedArea.Add(locate(horizontal, startY - (vertical - endY), 1)) //After gathering the start/end x and y, go through locating each turf from top left to bottom right, like one would read a book
return orderedArea //Return the filled list return orderedArea //Return the filled list
/datum/centcom_podlauncher/proc/preLaunch() //Creates a list of acceptable items, /datum/centcom_podlauncher/proc/preLaunch() //Creates a list of acceptable items,
numTurfs = 0 //Counts the number of turfs that can be launched (remember, supplypods either launch all at once or one turf-worth of items at a time) numTurfs = 0 //Counts the number of turfs that can be launched (remember, supplypods either launch all at once or one turf-worth of items at a time)
acceptableTurfs = list() acceptableTurfs = list()
for (var/turf/T in orderedArea) //Go through the orderedArea list for (var/t in orderedArea) //Go through the orderedArea list
if (typecache_filter_list_reverse(T.contents, ignored_atoms).len != 0) //if there is something in this turf that isnt in the blacklist, we consider this turf "acceptable" and add it to the acceptableTurfs list var/turf/unchecked_turf = t
acceptableTurfs.Add(T) //Because orderedArea was an ordered linear list, acceptableTurfs will be as well. if (iswallturf(unchecked_turf) || typecache_filter_list_reverse(unchecked_turf.contents, ignored_atoms).len != 0) //if there is something in this turf that isn't in the blacklist, we consider this turf "acceptable" and add it to the acceptableTurfs list
acceptableTurfs.Add(unchecked_turf) //Because orderedArea was an ordered linear list, acceptableTurfs will be as well.
numTurfs ++ numTurfs ++
launchList = list() //Anything in launchList will go into the supplypod when it is launched launchList = list() //Anything in launchList will go into the supplypod when it is launched
if (!isemptylist(acceptableTurfs) && !temp_pod.reversing && !temp_pod.effectMissile) //We dont fill the supplypod if acceptableTurfs is empty, if the pod is going in reverse (effectReverse=true), or if the pod is acitng like a missile (effectMissile=true) if (length(acceptableTurfs) && !temp_pod.reversing && !temp_pod.effectMissile) //We dont fill the supplypod if acceptableTurfs is empty, if the pod is going in reverse (effectReverse=true), or if the pod is acitng like a missile (effectMissile=true)
switch(launchChoice) switch(launchChoice)
if(0) //If we are launching all the turfs at once if(LAUNCH_ALL) //If we are launching all the turfs at once
for (var/turf/T in acceptableTurfs) for (var/t in acceptableTurfs)
launchList |= typecache_filter_list_reverse(T.contents, ignored_atoms) //We filter any blacklisted atoms and add the rest to the launchList var/turf/accepted_turf = t
if(1) //If we are launching one at a time launchList |= typecache_filter_list_reverse(accepted_turf.contents, ignored_atoms) //We filter any blacklisted atoms and add the rest to the launchList
if (iswallturf(accepted_turf))
launchList += accepted_turf
if(LAUNCH_ORDERED) //If we are launching one at a time
if (launchCounter > acceptableTurfs.len) //Check if the launchCounter, which acts as an index, is too high. If it is, reset it to 1 if (launchCounter > acceptableTurfs.len) //Check if the launchCounter, which acts as an index, is too high. If it is, reset it to 1
launchCounter = 1 //Note that the launchCounter index is incremented in the launch() proc launchCounter = 1 //Note that the launchCounter index is incremented in the launch() proc
for (var/atom/movable/O in acceptableTurfs[launchCounter].contents) //Go through the acceptableTurfs list based on the launchCounter index var/turf/next_turf_in_line = acceptableTurfs[launchCounter]
launchList |= typecache_filter_list_reverse(acceptableTurfs[launchCounter].contents, ignored_atoms) //Filter the specicic turf chosen from acceptableTurfs, and add it to the launchList launchList |= typecache_filter_list_reverse(next_turf_in_line.contents, ignored_atoms) //Filter the specicic turf chosen from acceptableTurfs, and add it to the launchList
if(2) //If we are launching randomly if (iswallturf(next_turf_in_line))
launchList |= typecache_filter_list_reverse(pick_n_take(acceptableTurfs).contents, ignored_atoms) //filter a random turf from the acceptableTurfs list and add it to the launchList launchList += next_turf_in_line
if(LAUNCH_RANDOM) //If we are launching randomly
var/turf/acceptable_turf = pick_n_take(acceptableTurfs)
launchList |= typecache_filter_list_reverse(acceptable_turf.contents, ignored_atoms) //filter a random turf from the acceptableTurfs list and add it to the launchList
if (iswallturf(acceptable_turf))
launchList += acceptable_turf
updateSelector() //Call updateSelector(), which, if we are launching one at a time (launchChoice==2), will move to the next turf that will be launched updateSelector() //Call updateSelector(), which, if we are launching one at a time (launchChoice==2), will move to the next turf that will be launched
//UpdateSelector() is here (instead if the if(1) switch block) because it also moves the selector to nullspace (to hide it) if needed //UpdateSelector() is here (instead if the if(1) switch block) because it also moves the selector to nullspace (to hide it) if needed
/datum/centcom_podlauncher/proc/launch(turf/A) //Game time started /datum/centcom_podlauncher/proc/launch(turf/target_turf) //Game time started
if (isnull(A)) if (isnull(target_turf))
return return
var/obj/structure/closet/supplypod/centcompod/toLaunch = DuplicateObject(temp_pod) //Duplicate the temp_pod (which we have been varediting or configuring with the UI) and store the result var/obj/structure/closet/supplypod/centcompod/toLaunch = DuplicateObject(temp_pod) //Duplicate the temp_pod (which we have been varediting or configuring with the UI) and store the result
toLaunch.bay = bay //Bay is currently a nonstatic expression, so it cant go into toLaunch using DuplicateObject
toLaunch.update_icon()//we update_icon() here so that the door doesnt "flicker on" right after it lands toLaunch.update_icon()//we update_icon() here so that the door doesnt "flicker on" right after it lands
var/shippingLane = GLOB.areas_by_type[/area/centcom/supplypod/flyMeToTheMoon] var/shippingLane = GLOB.areas_by_type[/area/centcom/supplypod/podStorage]
toLaunch.forceMove(shippingLane) toLaunch.forceMove(shippingLane)
if (launchClone) //We arent launching the actual items from the bay, rather we are creating clones and launching those if (launchClone) //We arent launching the actual items from the bay, rather we are creating clones and launching those
if(launchRandomItem) if(launchRandomItem)
var/atom/movable/O = pick_n_take(launchList) var/launch_candidate = pick_n_take(launchList)
DuplicateObject(O).forceMove(toLaunch) //Duplicate a single atom/movable from launchList and forceMove it into the supplypod if(!isnull(launch_candidate))
if (iswallturf(launch_candidate))
var/atom/atom_to_launch = launch_candidate
toLaunch.turfs_in_cargo += atom_to_launch.type
else
var/atom/movable/movable_to_launch = launch_candidate
DuplicateObject(movable_to_launch).forceMove(toLaunch) //Duplicate a single atom/movable from launchList and forceMove it into the supplypod
else else
for (var/atom/movable/O in launchList) for (var/launch_candidate in launchList)
DuplicateObject(O).forceMove(toLaunch) //Duplicate each atom/movable in launchList and forceMove them into the supplypod if (isnull(launch_candidate))
continue
if (iswallturf(launch_candidate))
var/turf/turf_to_launch = launch_candidate
toLaunch.turfs_in_cargo += turf_to_launch.type
else
var/atom/movable/movable_to_launch = launch_candidate
DuplicateObject(movable_to_launch).forceMove(toLaunch) //Duplicate each atom/movable in launchList and forceMove them into the supplypod
else else
if(launchRandomItem) if(launchRandomItem)
var/atom/movable/O = pick_n_take(launchList) var/atom/random_item = pick_n_take(launchList)
O.forceMove(toLaunch) //and forceMove any atom/moveable into the supplypod if(!isnull(random_item))
if (iswallturf(random_item))
var/turf/wall = random_item
toLaunch.turfs_in_cargo += wall.type
wall.ScrapeAway()
else
var/atom/movable/random_item_movable = random_item
random_item_movable.forceMove(toLaunch) //and forceMove any atom/moveable into the supplypod
else else
for (var/atom/movable/O in launchList) //If we aren't cloning the objects, just go through the launchList for (var/thing_to_launch in launchList) //If we aren't cloning the objects, just go through the launchList
O.forceMove(toLaunch) //and forceMove any atom/moveable into the supplypod if (isnull(thing_to_launch))
new /obj/effect/DPtarget(A, toLaunch) //Then, create the DPTarget effect, which will eventually forceMove the temp_pod to it's location continue
if(iswallturf(thing_to_launch))
var/turf/wall = thing_to_launch
toLaunch.turfs_in_cargo += wall.type
wall.ScrapeAway()
else
var/atom/movable/movable_to_launch = thing_to_launch
movable_to_launch.forceMove(toLaunch) //and forceMove any atom/moveable into the supplypod
new /obj/effect/DPtarget(target_turf, toLaunch) //Then, create the DPTarget effect, which will eventually forceMove the temp_pod to it's location
if (launchClone) if (launchClone)
launchCounter++ //We only need to increment launchCounter if we are cloning objects. launchCounter++ //We only need to increment launchCounter if we are cloning objects.
//If we aren't cloning objects, taking and removing the first item each time from the acceptableTurfs list will inherently iterate through the list in order //If we aren't cloning objects, taking and removing the first item each time from the acceptableTurfs list will inherently iterate through the list in order
/datum/centcom_podlauncher/proc/updateSelector() //Ensures that the selector effect will showcase the next item if needed /datum/centcom_podlauncher/proc/updateSelector() //Ensures that the selector effect will showcase the next item if needed
if (launchChoice == 1 && !isemptylist(acceptableTurfs) && !temp_pod.reversing && !temp_pod.effectMissile) //We only show the selector if we are taking items from the bay if (launchChoice == LAUNCH_ORDERED && length(acceptableTurfs) > 1 && !temp_pod.reversing && !temp_pod.effectMissile) //We only show the selector if we are taking items from the bay
var/index = launchCounter + 1 //launchCounter acts as an index to the ordered acceptableTurfs list, so adding one will show the next item in the list var/index = (launchCounter == 1 ? launchCounter : launchCounter + 1) //launchCounter acts as an index to the ordered acceptableTurfs list, so adding one will show the next item in the list. We don't want to do this for the very first item tho
if (index > acceptableTurfs.len) //out of bounds check if (index > acceptableTurfs.len) //out of bounds check
index = 1 index = 1
selector.forceMove(acceptableTurfs[index]) //forceMove the selector to the next turf in the ordered acceptableTurfs list selector.forceMove(acceptableTurfs[index]) //forceMove the selector to the next turf in the ordered acceptableTurfs list
@@ -591,32 +748,103 @@
qdel(O) qdel(O)
for (var/mob/M in bay.GetAllContents()) for (var/mob/M in bay.GetAllContents())
qdel(M) qdel(M)
for (var/bayturf in bay)
var/turf/turf_to_clear = bayturf
turf_to_clear.ChangeTurf(/turf/open/floor/plasteel)
/datum/centcom_podlauncher/Destroy() //The Destroy() proc. This is called by ui_close proc, or whenever the user leaves the game /datum/centcom_podlauncher/Destroy() //The Destroy() proc. This is called by ui_close proc, or whenever the user leaves the game
updateCursor(FALSE) //Make sure our moues cursor resets to default. False means we are not in launch mode updateCursor(TRUE) //Make sure our moues cursor resets to default. False means we are not in launch mode
qdel(temp_pod) //Delete the temp_pod QDEL_NULL(temp_pod) //Delete the temp_pod
qdel(selector) //Delete the selector effect QDEL_NULL(selector) //Delete the selector effect
QDEL_NULL(indicator)
. = ..() . = ..()
/datum/centcom_podlauncher/proc/supplypod_punish_log(var/list/whoDyin) /datum/centcom_podlauncher/proc/supplypod_punish_log(list/whoDyin)
var/podString = effectBurst ? "5 pods" : "a pod" var/podString = effectBurst ? "5 pods" : "a pod"
var/whomString = "" var/whomString = ""
if (LAZYLEN(whoDyin)) if (LAZYLEN(whoDyin))
for (var/mob/living/M in whoDyin) for (var/mob/living/M in whoDyin)
whomString += "[key_name(M)], " whomString += "[key_name(M)], "
var/delayString = temp_pod.landingDelay == initial(temp_pod.landingDelay) ? "" : " Delay=[temp_pod.landingDelay*0.1]s" var/msg = "launched [podString] towards [whomString]"
var/damageString = temp_pod.damage == 0 ? "" : " Dmg=[temp_pod.damage]" message_admins("[key_name_admin(usr)] [msg] in [ADMIN_VERBOSEJMP(specificTarget)].")
var/explosionString = "" if (length(whoDyin))
var/explosion_sum = temp_pod.explosionSize[1] + temp_pod.explosionSize[2] + temp_pod.explosionSize[3] + temp_pod.explosionSize[4]
if (explosion_sum != 0)
explosionString = " Boom=|"
for (var/X in temp_pod.explosionSize)
explosionString += "[X]|"
var/msg = "launched [podString][whomString][delayString][damageString][explosionString]" //yogs - removed a "."
message_admins("[key_name_admin(usr)] [msg] in [AREACOORD(specificTarget)].")
if (!isemptylist(whoDyin))
for (var/mob/living/M in whoDyin) for (var/mob/living/M in whoDyin)
admin_ticket_log(M, "[key_name_admin(usr)] [msg]") admin_ticket_log(M, "[key_name_admin(usr)] [msg]")
/datum/centcom_podlauncher/proc/loadData(var/list/dataToLoad)
bayNumber = dataToLoad["bayNumber"]
customDropoff = dataToLoad["customDropoff"]
renderLighting = dataToLoad["renderLighting"]
launchClone = dataToLoad["launchClone"] //Do we launch the actual items in the bay or just launch clones of them?
launchRandomItem = dataToLoad["launchRandomItem"] //Do we launch a single random item instead of everything on the turf?
launchChoice = dataToLoad["launchChoice"] //Launch turfs all at once (0), ordered (1), or randomly(1)
explosionChoice = dataToLoad["explosionChoice"] //An explosion that occurs when landing. Can be no explosion (0), custom explosion (1), or maxcap (2)
damageChoice = dataToLoad["damageChoice"] //Damage that occurs to any mob under the pod when it lands. Can be no damage (0), custom damage (1), or gib+5000dmg (2)
temp_pod.landingDelay = dataToLoad["delay_1"] //How long the pod takes to land after launching
temp_pod.fallDuration = dataToLoad["delay_2"] //How long the pod's falling animation lasts
temp_pod.openingDelay = dataToLoad["delay_3"] //How long the pod takes to open after landing
temp_pod.departureDelay = dataToLoad["delay_4"] //How long the pod takes to leave after opening (if bluespace=true, it deletes. if reversing=true, it flies back to centcom)
temp_pod.setStyle(dataToLoad["styleChoice"]) //Style is a variable that keeps track of what the pod is supposed to look like. It acts as an index to the GLOB.podstyles list in cargo.dm defines to get the proper icon/name/desc for the pod.
temp_pod.effectStun = dataToLoad["effectStun"]//If true, stuns anyone under the pod when it launches until it lands, forcing them to get hit by the pod. Devilish!
temp_pod.effectLimb = dataToLoad["effectLimb"]//If true, pops off a limb (if applicable) from anyone caught under the pod when it lands
temp_pod.effectOrgans = dataToLoad["effectOrgans"]//If true, yeets the organs out of any bodies caught under the pod when it lands
temp_pod.bluespace = dataToLoad["effectBluespace"] //If true, the pod deletes (in a shower of sparks) after landing
temp_pod.effectStealth = dataToLoad["effectStealth"]//If true, a target icon isn't displayed on the turf where the pod will land
temp_pod.effectQuiet = dataToLoad["effectQuiet"] //The female sniper. If true, the pod makes no noise (including related explosions, opening sounds, etc)
temp_pod.effectMissile = dataToLoad["effectMissile"] //If true, the pod deletes the second it lands. If you give it an explosion, it will act like a missile exploding as it hits the ground
temp_pod.effectCircle = dataToLoad["effectCircle"] //If true, allows the pod to come in at any angle. Bit of a weird feature but whatever its here
effectBurst = dataToLoad["effectBurst"] //IOf true, launches five pods at once (with a very small delay between for added coolness), in a 3x3 area centered around the area
temp_pod.reversing = dataToLoad["effectReverse"] //If true, the pod will not send any items. Instead, after opening, it will close again (picking up items/mobs) and fly back to centcom
temp_pod.reverseOptionList = dataToLoad["reverseOptionList"]
specificTarget = dataToLoad["effectTarget"] //Launches the pod at the turf of a specific mob target, rather than wherever the user clicked. Useful for smites
temp_pod.adminNamed = dataToLoad["effectName"] //Determines whether or not the pod has been named by an admin. If true, the pod's name will not get overridden when the style of the pod changes (changing the style of the pod normally also changes the name+desc)
temp_pod.name = dataToLoad["podName"]
temp_pod.desc = dataToLoad["podDesc"]
effectAnnounce = dataToLoad["effectAnnounce"]
numTurfs = dataToLoad["numObjects"] //Counts the number of turfs that contain a launchable object in the centcom supplypod bay
temp_pod.fallingSound = dataToLoad["fallingSound"]//Admin sound to play as the pod falls
temp_pod.landingSound = dataToLoad["landingSound"]//Admin sound to play when the pod lands
temp_pod.openingSound = dataToLoad["openingSound"]//Admin sound to play when the pod opens
temp_pod.leavingSound = dataToLoad["leavingSound"]//Admin sound to play when the pod leaves
temp_pod.soundVolume = dataToLoad["soundVolume"] //Admin sound to play when the pod leaves
picking_dropoff_turf = FALSE
launcherActivated = FALSE
updateCursor()
refreshView()
GLOBAL_DATUM_INIT(podlauncher, /datum/centcom_podlauncher, new)
//Proc for admins to enable others to use podlauncher after roundend
/datum/centcom_podlauncher/proc/give_podlauncher(mob/living/user, override)
if (SSticker.current_state < GAME_STATE_FINISHED)
return
if (!istype(user))
user = override
if (user)
setup(user)//setup the datum
//Set the dropoff location and indicator to either a specific turf or somewhere in an area
/datum/centcom_podlauncher/proc/setDropoff(target)
var/turf/target_turf
if (isturf(target))
target_turf = target
else if (isarea(target))
target_turf = pick(get_area_turfs(target))
else
CRASH("Improper type passed to setDropoff! Should be /turf or /area")
temp_pod.reverse_dropoff_coords = list(target_turf.x, target_turf.y, target_turf.z)
indicator.forceMove(target_turf)
/obj/effect/hallucination/simple/supplypod_selector
name = "Supply Selector (Only you can see this)"
image_icon = 'icons/obj/supplypods_32x32.dmi'
image_state = "selector"
image_layer = FLY_LAYER
alpha = 150
/obj/effect/hallucination/simple/dropoff_location
name = "Dropoff Location (Only you can see this)"
image_icon = 'icons/obj/supplypods_32x32.dmi'
image_state = "dropoff_indicator"
image_layer = FLY_LAYER
alpha = 0

View File

@@ -39,7 +39,7 @@
set name = "Release Contents" set name = "Release Contents"
set category = "Gondola" set category = "Gondola"
set desc = "Release any contents stored within your vast belly." set desc = "Release any contents stored within your vast belly."
linked_pod.open(src, forced = TRUE) linked_pod.open(src)
/mob/living/simple_animal/pet/gondola/gondolapod/examine(mob/user) /mob/living/simple_animal/pet/gondola/gondolapod/examine(mob/user)
. = ..() . = ..()
@@ -58,12 +58,12 @@
else else
to_chat(src, "<span class='notice'>A closer look inside yourself reveals... nothing.</span>") to_chat(src, "<span class='notice'>A closer look inside yourself reveals... nothing.</span>")
/mob/living/simple_animal/pet/gondola/gondolapod/proc/setOpened() /mob/living/simple_animal/pet/gondola/gondolapod/setOpened()
opened = TRUE opened = TRUE
update_icon() update_icon()
addtimer(CALLBACK(src, .proc/setClosed), 50) addtimer(CALLBACK(src, /atom/.proc/setClosed), 50)
/mob/living/simple_animal/pet/gondola/gondolapod/proc/setClosed() /mob/living/simple_animal/pet/gondola/gondolapod/setClosed()
opened = FALSE opened = FALSE
update_icon() update_icon()

View File

@@ -1,21 +1,25 @@
//The "BDPtarget" temp visual is created by anything that "launches" a supplypod. It makes two things: a falling droppod animation, and the droppod itself. //The "DPtarget" temp visual is created by anything that "launches" a supplypod. This is what animates the pod and makes the pod forcemove to the station.
//------------------------------------SUPPLY POD-------------------------------------// //------------------------------------SUPPLY POD-------------------------------------//
/obj/structure/closet/supplypod /obj/structure/closet/supplypod
name = "supply pod" //Names and descriptions are normally created with the setStyle() proc during initialization, but we have these default values here as a failsafe name = "supply pod" //Names and descriptions are normally created with the setStyle() proc during initialization, but we have these default values here as a failsafe
desc = "A Nanotrasen supply drop pod." desc = "A Nanotrasen supply drop pod."
icon = 'icons/obj/supplypods.dmi' icon = 'icons/obj/supplypods.dmi'
icon_state = "supplypod" icon_state = "pod" //This is a common base sprite shared by a number of pods
pixel_x = -16 //2x2 sprite pixel_x = SUPPLYPOD_X_OFFSET //2x2 sprite
pixel_y = -5
layer = TABLE_LAYER //So that the crate inside doesn't appear underneath layer = TABLE_LAYER //So that the crate inside doesn't appear underneath
allow_objects = TRUE allow_objects = TRUE
allow_dense = TRUE allow_dense = TRUE
delivery_icon = null delivery_icon = null
can_weld_shut = FALSE can_weld_shut = FALSE
armor = list("melee" = 30, "bullet" = 50, "laser" = 50, "energy" = 100, "bomb" = 100, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 80) armor = list(MELEE = 30, BULLET = 50, LASER = 50, ENERGY = 100, BOMB = 100, BIO = 0, RAD = 0, FIRE = 100, ACID = 80)
anchored = TRUE //So it cant slide around after landing anchored = TRUE //So it cant slide around after landing
anchorable = FALSE anchorable = FALSE
flags_1 = PREVENT_CONTENTS_EXPLOSION_1 flags_1 = PREVENT_CONTENTS_EXPLOSION_1
appearance_flags = KEEP_TOGETHER | PIXEL_SCALE
density = FALSE
///List of bitflags for supply pods, see: code\__DEFINES\obj_flags.dm
var/pod_flags = NONE
//*****NOTE*****: Many of these comments are similarly described in centcom_podlauncher.dm. If you change them here, please consider doing so in the centcom podlauncher code as well! //*****NOTE*****: Many of these comments are similarly described in centcom_podlauncher.dm. If you change them here, please consider doing so in the centcom podlauncher code as well!
var/adminNamed = FALSE //Determines whether or not the pod has been named by an admin. If true, the pod's name will not get overridden when the style of the pod changes (changing the style of the pod normally also changes the name+desc) var/adminNamed = FALSE //Determines whether or not the pod has been named by an admin. If true, the pod's name will not get overridden when the style of the pod changes (changing the style of the pod normally also changes the name+desc)
var/bluespace = FALSE //If true, the pod deletes (in a shower of sparks) after landing var/bluespace = FALSE //If true, the pod deletes (in a shower of sparks) after landing
@@ -27,12 +31,13 @@
var/effectLimb = FALSE //If true, pops off a limb (if applicable) from anyone caught under the pod when it lands var/effectLimb = FALSE //If true, pops off a limb (if applicable) from anyone caught under the pod when it lands
var/effectOrgans = FALSE //If true, yeets out every limb and organ from anyone caught under the pod when it lands var/effectOrgans = FALSE //If true, yeets out every limb and organ from anyone caught under the pod when it lands
var/effectGib = FALSE //If true, anyone under the pod will be gibbed when it lands var/effectGib = FALSE //If true, anyone under the pod will be gibbed when it lands
var/effectStealth = FALSE //If true, a target icon isnt displayed on the turf where the pod will land var/effectStealth = FALSE //If true, a target icon isn't displayed on the turf where the pod will land
var/effectQuiet = FALSE //The female sniper. If true, the pod makes no noise (including related explosions, opening sounds, etc) var/effectQuiet = FALSE //The female sniper. If true, the pod makes no noise (including related explosions, opening sounds, etc)
var/effectMissile = FALSE //If true, the pod deletes the second it lands. If you give it an explosion, it will act like a missile exploding as it hits the ground var/effectMissile = FALSE //If true, the pod deletes the second it lands. If you give it an explosion, it will act like a missile exploding as it hits the ground
var/effectCircle = FALSE //If true, allows the pod to come in at any angle. Bit of a weird feature but whatever its here var/effectCircle = FALSE //If true, allows the pod to come in at any angle. Bit of a weird feature but whatever its here
var/style = STYLE_STANDARD //Style is a variable that keeps track of what the pod is supposed to look like. It acts as an index to the POD_STYLES list in cargo.dm defines to get the proper icon/name/desc for the pod. var/style = STYLE_STANDARD //Style is a variable that keeps track of what the pod is supposed to look like. It acts as an index to the GLOB.podstyles list in cargo.dm defines to get the proper icon/name/desc for the pod.
var/reversing = FALSE //If true, the pod will not send any items. Instead, after opening, it will close again (picking up items/mobs) and fly back to centcom var/reversing = FALSE //If true, the pod will not send any items. Instead, after opening, it will close again (picking up items/mobs) and fly back to centcom
var/list/reverse_dropoff_coords //Turf that the reverse pod will drop off it's newly-acquired cargo to
var/fallDuration = 4 var/fallDuration = 4
var/fallingSoundLength = 11 var/fallingSoundLength = 11
var/fallingSound = 'sound/weapons/mortar_long_whistle.ogg'//Admin sound to play before the pod lands var/fallingSound = 'sound/weapons/mortar_long_whistle.ogg'//Admin sound to play before the pod lands
@@ -40,10 +45,19 @@
var/openingSound //Admin sound to play when the pod opens var/openingSound //Admin sound to play when the pod opens
var/leavingSound //Admin sound to play when the pod leaves var/leavingSound //Admin sound to play when the pod leaves
var/soundVolume = 80 //Volume to play sounds at. Ignores the cap var/soundVolume = 80 //Volume to play sounds at. Ignores the cap
var/bay //Used specifically for the centcom_podlauncher datum. Holds the current bay the user is launching objects from. Bays are specific rooms on the centcom map.
var/list/explosionSize = list(0,0,2,3) var/list/explosionSize = list(0,0,2,3)
var/stay_after_drop = FALSE var/stay_after_drop = FALSE
var/specialised = TRUE // It's not a general use pod for cargo/admin use var/specialised = FALSE // It's not a general use pod for cargo/admin use
var/rubble_type //Rubble effect associated with this supplypod
var/decal = "default" //What kind of extra decals we add to the pod to make it look nice
var/door = "pod_door"
var/fin_mask = "topfin"
var/obj/effect/supplypod_rubble/rubble
var/obj/effect/engineglow/glow_effect
var/list/reverseOptionList = list("Mobs"=FALSE,"Objects"=FALSE,"Anchored"=FALSE,"Underfloor"=FALSE,"Wallmounted"=FALSE,"Floors"=FALSE,"Walls"=FALSE)
var/list/turfs_in_cargo = list()
var/list/managed_overlays
/obj/structure/closet/supplypod/bluespacepod /obj/structure/closet/supplypod/bluespacepod
style = STYLE_BLUESPACE style = STYLE_BLUESPACE
@@ -53,7 +67,7 @@
/obj/structure/closet/supplypod/extractionpod /obj/structure/closet/supplypod/extractionpod
name = "Syndicate Extraction Pod" name = "Syndicate Extraction Pod"
desc = "A specalised, blood-red styled pod for extracting high-value targets out of active mission areas." desc = "A specalised, blood-red styled pod for extracting high-value targets out of active mission areas. <b>Targets must be manually stuffed inside the pod for proper delivery.</b>"
specialised = TRUE specialised = TRUE
style = STYLE_SYNDICATE style = STYLE_SYNDICATE
bluespace = TRUE bluespace = TRUE
@@ -67,38 +81,112 @@
landingDelay = 20 //Very speedy! landingDelay = 20 //Very speedy!
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
/obj/structure/closet/supplypod/Initialize(var/customStyle = FALSE)
/obj/structure/closet/supplypod/proc/specialisedPod()
return 1
/obj/structure/closet/supplypod/extractionpod/specialisedPod(atom/movable/holder)
holder.forceMove(pick(GLOB.holdingfacility)) // land in ninja jail
open(holder, forced = TRUE)
/obj/structure/closet/supplypod/Initialize()
. = ..() . = ..()
setStyle(style, TRUE) //Upon initialization, give the supplypod an iconstate, name, and description based on the "style" variable. This system is important for the centcom_podlauncher to function correctly if (!loc)
var/shippingLane = GLOB.areas_by_type[/area/centcom/supplypod/podStorage] //temporary holder for supplypods mid-transit
forceMove(shippingLane)
if (customStyle)
style = customStyle
setStyle(style) //Upon initialization, give the supplypod an iconstate, name, and description based on the "style" variable. This system is important for the centcom_podlauncher to function correctly
/obj/structure/closet/supplypod/extractionpod/Initialize()
. = ..()
var/turf/picked_turf = pick(GLOB.holdingfacility)
reverse_dropoff_coords = list(picked_turf.x, picked_turf.y, picked_turf.z)
/obj/structure/closet/supplypod/proc/setStyle(chosenStyle) //Used to give the sprite an icon state, name, and description.
style = chosenStyle
var/base = GLOB.podstyles[chosenStyle][POD_BASE] //GLOB.podstyles is a 2D array we treat as a dictionary. The style represents the verticle index, with the icon state, name, and desc being stored in the horizontal indexes of the 2D array.
icon_state = base
decal = GLOB.podstyles[chosenStyle][POD_DECAL]
rubble_type = GLOB.podstyles[chosenStyle][POD_RUBBLE_TYPE]
if (!adminNamed && !specialised) //We dont want to name it ourselves if it has been specifically named by an admin using the centcom_podlauncher datum
name = GLOB.podstyles[chosenStyle][POD_NAME]
desc = GLOB.podstyles[chosenStyle][POD_DESC]
if (GLOB.podstyles[chosenStyle][POD_DOOR])
door = "[base]_door"
else
door = FALSE
update_icon()
/obj/structure/closet/supplypod/proc/SetReverseIcon()
fin_mask = "bottomfin"
if (GLOB.podstyles[style][POD_SHAPE] == POD_SHAPE_NORML)
icon_state = GLOB.podstyles[style][POD_BASE] + "_reverse"
pixel_x = initial(pixel_x)
transform = matrix()
update_icon()
/obj/structure/closet/supplypod/proc/backToNonReverseIcon()
fin_mask = initial(fin_mask)
if (GLOB.podstyles[style][POD_SHAPE] == POD_SHAPE_NORML)
icon_state = GLOB.podstyles[style][POD_BASE]
pixel_x = initial(pixel_x)
transform = matrix()
update_icon()
/obj/structure/closet/supplypod/update_icon() /obj/structure/closet/supplypod/update_icon()
cut_overlays() var/list/new_overlays = update_overlays()
if (style == STYLE_SEETHROUGH || style == STYLE_INVISIBLE) //If we're invisible, we dont bother adding any overlays if(managed_overlays)
return cut_overlay(managed_overlays)
else managed_overlays = null
if (opened) if(length(new_overlays))
add_overlay("[icon_state]_open") managed_overlays = new_overlays
else add_overlay(new_overlays)
add_overlay("[icon_state]_door")
/obj/structure/closet/supplypod/proc/setStyle(chosenStyle, var/duringInit = FALSE) //Used to give the sprite an icon state, name, and description /obj/structure/closet/supplypod/proc/update_overlays()
if (!duringInit && style == chosenStyle) //Check if the input style is already the same as the pod's style. This happens in centcom_podlauncher, and as such we set the style to STYLE_CENTCOM. . = list()
setStyle(STYLE_CENTCOM) //We make sure to not check this during initialize() so the standard supplypod works correctly. if(style == STYLE_INVISIBLE)
return return
style = chosenStyle
icon_state = POD_STYLES[chosenStyle][POD_ICON_STATE] //POD_STYLES is a 2D array we treat as a dictionary. The style represents the verticle index, with the icon state, name, and desc being stored in the horizontal indexes of the 2D array. if(rubble)
if (!adminNamed && !specialised) //We dont want to name it ourselves if it has been specifically named by an admin using the centcom_podlauncher datum . += rubble.getForeground(src)
name = POD_STYLES[chosenStyle][POD_NAME]
desc = POD_STYLES[chosenStyle][POD_DESC] if(style == STYLE_SEETHROUGH)
update_icon() for(var/atom/A in contents)
var/mutable_appearance/itemIcon = new(A)
itemIcon.transform = matrix().Translate(-1 * SUPPLYPOD_X_OFFSET, 0)
. += itemIcon
for(var/t in turfs_in_cargo)//T is just a turf's type
var/turf/turf_type = t
var/mutable_appearance/itemIcon = mutable_appearance(initial(turf_type.icon), initial(turf_type.icon_state))
itemIcon.transform = matrix().Translate(-1 * SUPPLYPOD_X_OFFSET, 0)
. += itemIcon
return
if(opened) //We're opened means all we have to worry about is masking a decal if we have one
if(!decal) //We don't have a decal to mask
return
if(!door) //We have a decal but no door, so let's just add the decal
. += decal
return
var/icon/masked_decal = new(icon, decal) //The decal we want to apply
var/icon/door_masker = new(icon, door) //The door shape we want to 'cut out' of the decal
door_masker.MapColors(0,0,0,1, 0,0,0,1, 0,0,0,1, 1,1,1,0, 0,0,0,1)
door_masker.SwapColor("#ffffffff", null)
door_masker.Blend("#000000", ICON_SUBTRACT)
masked_decal.Blend(door_masker, ICON_ADD)
. += masked_decal
return
//If we're closed
if(!door) //We have no door, lets see if we have a decal. If not, theres nothing we need to do
if(decal)
. += decal
return
else if (GLOB.podstyles[style][POD_SHAPE] != POD_SHAPE_NORML) //If we're not a normal pod shape (aka, if we don't have fins), just add the door without masking
. += door
else
var/icon/masked_door = new(icon, door) //The door we want to apply
var/icon/fin_masker = new(icon, "mask_[fin_mask]") //The fin shape we want to 'cut out' of the door
fin_masker.MapColors(0,0,0,1, 0,0,0,1, 0,0,0,1, 1,1,1,0, 0,0,0,1)
fin_masker.SwapColor("#ffffffff", null)
fin_masker.Blend("#000000", ICON_SUBTRACT)
masked_door.Blend(fin_masker, ICON_ADD)
. += masked_door
if(decal)
. += decal
/obj/structure/closet/supplypod/tool_interact(obj/item/W, mob/user) /obj/structure/closet/supplypod/tool_interact(obj/item/W, mob/user)
if(bluespace) //We dont want to worry about interacting with bluespace pods, as they are due to delete themselves soon anyways. if(bluespace) //We dont want to worry about interacting with bluespace pods, as they are due to delete themselves soon anyways.
@@ -112,196 +200,373 @@
/obj/structure/closet/supplypod/contents_explosion() //Supplypods also protect their contents from the harmful effects of fucking exploding. /obj/structure/closet/supplypod/contents_explosion() //Supplypods also protect their contents from the harmful effects of fucking exploding.
return return
/obj/structure/closet/supplypod/toggle(mob/living/user) //Supplypods shouldn't be able to be manually opened under any circumstances, as the open() proc generates supply order datums /obj/structure/closet/supplypod/toggle(mob/living/user)
return return
/obj/structure/closet/supplypod/proc/handleReturningClose(atom/movable/holder, returntobay) /obj/structure/closet/supplypod/open(mob/living/user)
opened = FALSE return
INVOKE_ASYNC(holder, .proc/setClosed) //Use the INVOKE_ASYNC proc to call setClosed() on whatever the holder may be, without giving the atom/movable base class a setClosed() proc definition
for (var/atom/movable/O in get_turf(holder))
if ((ismob(O) && !isliving(O)) || (is_type_in_typecache(O, GLOB.blacklisted_cargo_types) && !isliving(O))) //We dont want to take ghosts with us, and we don't want blacklisted items going, but we allow mobs.
continue
O.forceMove(holder) //Put objects inside before we close
var/obj/effect/temp_visual/risingPod = new /obj/effect/DPfall(get_turf(holder), src) //Make a nice animation of flying back up
risingPod.pixel_z = 0 //The initial value of risingPod's pixel_z is 200 because it normally comes down from a high spot
animate(risingPod, pixel_z = 200, time = 10, easing = LINEAR_EASING) //Animate our rising pod
if (returntobay)
holder.forceMove(bay) //Move the pod back to centcom, where it belongs
QDEL_IN(risingPod, 10)
reversing = FALSE //Now that we're done reversing, we set this to false (otherwise we would get stuck in an infinite loop of calling the close proc at the bottom of open() )
bluespace = TRUE //Make it so that the pod doesn't stay in centcom forever
open(holder, forced = TRUE)
else
reversing = FALSE //Now that we're done reversing, we set this to false (otherwise we would get stuck in an infinite loop of calling the close proc at the bottom of open() )
bluespace = TRUE //Make it so that the pod doesn't stay in centcom forever
QDEL_IN(risingPod, 10) /obj/structure/closet/supplypod/proc/handleReturnAfterDeparting(atom/movable/holder = src)
audible_message("<span class='notice'>The pod hisses, closing quickly and launching itself away from the station.</span>", "<span class='notice'>The ground vibrates, the nearby pod launching away from the station.</span>") reversing = FALSE //Now that we're done reversing, we set this to false (otherwise we would get stuck in an infinite loop of calling the close proc at the bottom of open_pod() )
bluespace = TRUE //Make it so that the pod doesn't stay in centcom forever
pod_flags &= ~FIRST_SOUNDS //Make it so we play sounds now
if (!effectQuiet && style != STYLE_SEETHROUGH)
audible_message("<span class='notice'>The pod hisses, closing and launching itself away from the station.</span>", "<span class='notice'>The ground vibrates, and you hear the sound of engines firing.</span>")
stay_after_drop = FALSE
holder.pixel_z = initial(holder.pixel_z)
holder.alpha = initial(holder.alpha)
var/shippingLane = GLOB.areas_by_type[/area/centcom/supplypod/podStorage]
forceMove(shippingLane) //Move to the centcom-z-level until the DPtarget says we can drop back down again
if (!reverse_dropoff_coords) //If we're centcom-launched, the reverse dropoff turf will be a centcom loading bay. If we're an extraction pod, it should be the ninja jail. Thus, this shouldn't ever really happen.
var/obj/error_landmark = locate(/obj/effect/landmark/error) in GLOB.landmarks_list
var/turf/error_landmark_turf = get_turf(error_landmark)
reverse_dropoff_coords = list(error_landmark_turf.x, error_landmark_turf.y, error_landmark_turf.z)
landingDelay = initial(landingDelay) //Reset the landing timers so we land on whatever turf we're aiming at normally. Will be changed to be editable later (tm)
fallDuration = initial(fallDuration) //This is so if someone adds a really long dramatic landing time they don't have to sit through it twice on the pod's return trip
openingDelay = initial(openingDelay)
backToNonReverseIcon()
var/turf/return_turf = locate(reverse_dropoff_coords[1], reverse_dropoff_coords[2], reverse_dropoff_coords[3])
new /obj/effect/DPtarget(return_turf, src)
stay_after_drop = FALSE /obj/structure/closet/supplypod/proc/preOpen() //Called before the open_pod() proc. Handles anything that occurs right as the pod lands.
specialisedPod(holder) // Do special actions for specialised pods - this is likely if we were already doing manual launches var/turf/turf_underneath = get_turf(src)
/obj/structure/closet/supplypod/proc/preOpen() //Called before the open() proc. Handles anything that occurs right as the pod lands.
var/turf/T = get_turf(src)
var/list/B = explosionSize //Mostly because B is more readable than explosionSize :p var/list/B = explosionSize //Mostly because B is more readable than explosionSize :p
if (landingSound) density = TRUE //Density is originally false so the pod doesn't block anything while it's still falling through the air
playsound(get_turf(src), landingSound, soundVolume, 0, 0) for (var/mob/living/target_living in turf_underneath)
for (var/mob/living/M in T) if (iscarbon(target_living)) //If effectLimb is true (which means we pop limbs off when we hit people):
if (effectLimb && iscarbon(M)) //If effectLimb is true (which means we pop limbs off when we hit people): if (effectLimb)
var/mob/living/carbon/CM = M var/mob/living/carbon/carbon_target_mob = target_living
for (var/obj/item/bodypart/bodypart in CM.bodyparts) //Look at the bodyparts in our poor mob beneath our pod as it lands for (var/bp in carbon_target_mob.bodyparts) //Look at the bodyparts in our poor mob beneath our pod as it lands
if(bodypart.body_part != HEAD && bodypart.body_part != CHEST)//we dont want to kill him, just teach em a lesson! var/obj/item/bodypart/bodypart = bp
if (bodypart.dismemberable) if(bodypart.body_part != HEAD && bodypart.body_part != CHEST)//we dont want to kill him, just teach em a lesson!
bodypart.dismember() //Using the power of flextape i've sawed this man's limb in half! if (bodypart.dismemberable)
break bodypart.dismember() //Using the power of flextape i've sawed this man's limb in half!
if (effectOrgans && iscarbon(M)) //effectOrgans means remove every organ in our mob break
var/mob/living/carbon/CM = M if (effectOrgans) //effectOrgans means remove every organ in our mob
for(var/X in CM.internal_organs) var/mob/living/carbon/carbon_target_mob = target_living
var/destination = get_edge_target_turf(T, pick(GLOB.alldirs)) //Pick a random direction to toss them in for(var/organ in carbon_target_mob.internal_organs)
var/obj/item/organ/O = X var/destination = get_edge_target_turf(turf_underneath, pick(GLOB.alldirs)) //Pick a random direction to toss them in
O.Remove(CM) //Note that this isn't the same proc as for lists var/obj/item/organ/organ_to_yeet = organ
O.forceMove(T) //Move the organ outta the body organ_to_yeet.Remove(carbon_target_mob) //Note that this isn't the same proc as for lists
O.throw_at(destination, 2, 3) //Thow the organ at a random tile 3 spots away organ_to_yeet.forceMove(turf_underneath) //Move the organ outta the body
sleep(1) organ_to_yeet.throw_at(destination, 2, 3) //Thow the organ at a random tile 3 spots away
for (var/obj/item/bodypart/bodypart in CM.bodyparts) //Look at the bodyparts in our poor mob beneath our pod as it lands
var/destination = get_edge_target_turf(T, pick(GLOB.alldirs))
if (bodypart.dismemberable)
bodypart.dismember() //Using the power of flextape i've sawed this man's bodypart in half!
bodypart.throw_at(destination, 2, 3)
sleep(1) sleep(1)
for (var/bp in carbon_target_mob.bodyparts) //Look at the bodyparts in our poor mob beneath our pod as it lands
var/obj/item/bodypart/bodypart = bp
var/destination = get_edge_target_turf(turf_underneath, pick(GLOB.alldirs))
if (bodypart.dismemberable)
bodypart.dismember() //Using the power of flextape i've sawed this man's bodypart in half!
bodypart.throw_at(destination, 2, 3)
sleep(1)
if (effectGib) //effectGib is on, that means whatever's underneath us better be fucking oof'd on if (effectGib) //effectGib is on, that means whatever's underneath us better be fucking oof'd on
M.adjustBruteLoss(5000) //THATS A LOT OF DAMAGE (called just in case gib() doesnt work on em) target_living.adjustBruteLoss(5000) //THATS A LOT OF DAMAGE (called just in case gib() doesnt work on em)
M.gib() //After adjusting the fuck outta that brute loss we finish the job with some satisfying gibs if (!QDELETED(target_living))
M.adjustBruteLoss(damage) target_living.gib() //After adjusting the fuck outta that brute loss we finish the job with some satisfying gibs
else
target_living.adjustBruteLoss(damage)
var/explosion_sum = B[1] + B[2] + B[3] + B[4] var/explosion_sum = B[1] + B[2] + B[3] + B[4]
if (explosion_sum != 0) //If the explosion list isn't all zeroes, call an explosion if (explosion_sum != 0) //If the explosion list isn't all zeroes, call an explosion
explosion(get_turf(src), B[1], B[2], B[3], flame_range = B[4], silent = effectQuiet, ignorecap = istype(src, /obj/structure/closet/supplypod/centcompod)) //less advanced equipment than bluespace pod, so larger explosion when landing explosion(turf_underneath, B[1], B[2], B[3], flame_range = B[4], silent = effectQuiet, ignorecap = istype(src, /obj/structure/closet/supplypod/centcompod)) //less advanced equipment than bluespace pod, so larger explosion when landing
else if (!effectQuiet) //If our explosion list IS all zeroes, we still make a nice explosion sound (unless the effectQuiet var is true) else if (!effectQuiet && !(pod_flags & FIRST_SOUNDS)) //If our explosion list IS all zeroes, we still make a nice explosion sound (unless the effectQuiet var is true)
playsound(src, "explosion", landingSound ? 15 : 80, 1) playsound(src, "explosion", landingSound ? soundVolume * 0.25 : soundVolume, TRUE)
if (landingSound)
playsound(turf_underneath, landingSound, soundVolume, FALSE, FALSE)
if (effectMissile) //If we are acting like a missile, then right after we land and finish fucking shit up w explosions, we should delete if (effectMissile) //If we are acting like a missile, then right after we land and finish fucking shit up w explosions, we should delete
opened = TRUE //We set opened to TRUE to avoid spending time trying to open (due to being deleted) during the Destroy() proc opened = TRUE //We set opened to TRUE to avoid spending time trying to open (due to being deleted) during the Destroy() proc
qdel(src) qdel(src)
return return
if (style == STYLE_GONDOLA) //Checks if we are supposed to be a gondola pod. If so, create a gondolapod mob, and move this pod to nullspace. I'd like to give a shout out, to my man oranges if (style == STYLE_GONDOLA) //Checks if we are supposed to be a gondola pod. If so, create a gondolapod mob, and move this pod to nullspace. I'd like to give a shout out, to my man oranges
var/mob/living/simple_animal/pet/gondola/gondolapod/benis = new(get_turf(src), src) var/mob/living/simple_animal/pet/gondola/gondolapod/benis = new(turf_underneath, src)
benis.contents |= contents //Move the contents of this supplypod into the gondolapod mob. benis.contents |= contents //Move the contents of this supplypod into the gondolapod mob.
moveToNullspace() moveToNullspace()
addtimer(CALLBACK(src, .proc/open, benis), openingDelay) //After the openingDelay passes, we use the open proc from this supplyprod while referencing the contents of the "holder", in this case the gondolapod mob addtimer(CALLBACK(src, .proc/open_pod, benis), openingDelay) //After the openingDelay passes, we use the open proc from this supplyprod while referencing the contents of the "holder", in this case the gondolapod mob
else if (style == STYLE_SEETHROUGH) else if (style == STYLE_SEETHROUGH)
open(src) open_pod(src)
else else
addtimer(CALLBACK(src, .proc/open, src), openingDelay) //After the openingDelay passes, we use the open proc from this supplypod, while referencing this supplypod's contents addtimer(CALLBACK(src, .proc/open_pod, src), openingDelay) //After the openingDelay passes, we use the open proc from this supplypod, while referencing this supplypod's contents
/obj/structure/closet/supplypod/open(atom/movable/holder, var/broken = FALSE, var/forced = FALSE) //The holder var represents an atom whose contents we will be working with /obj/structure/closet/supplypod/proc/open_pod(atom/movable/holder, broken = FALSE, forced = FALSE) //The holder var represents an atom whose contents we will be working with
if (!holder) if (!holder)
return return
if (opened) //This is to ensure we don't open something that has already been opened if (opened) //This is to ensure we don't open something that has already been opened
return return
opened = TRUE holder.setOpened()
var/turf/T = get_turf(holder) //Get the turf of whoever's contents we're talking about var/turf/turf_underneath = get_turf(holder) //Get the turf of whoever's contents we're talking about
var/mob/M
if (istype(holder, /mob)) //Allows mobs to assume the role of the holder, meaning we look at the mob's contents rather than the supplypod's contents. Typically by this point the supplypod's contents have already been moved over to the mob's contents if (istype(holder, /mob)) //Allows mobs to assume the role of the holder, meaning we look at the mob's contents rather than the supplypod's contents. Typically by this point the supplypod's contents have already been moved over to the mob's contents
M = holder var/mob/holder_as_mob = holder
if (M.key && !forced && !broken) //If we are player controlled, then we shouldnt open unless the opening is manual, or if it is due to being destroyed (represented by the "broken" parameter) if (holder_as_mob.key && !forced && !broken) //If we are player controlled, then we shouldn't open unless the opening is manual, or if it is due to being destroyed (represented by the "broken" parameter)
return return
if (openingSound) if (openingSound)
playsound(get_turf(holder), openingSound, soundVolume, 0, 0) //Special admin sound to play playsound(get_turf(holder), openingSound, soundVolume, FALSE, FALSE) //Special admin sound to play
INVOKE_ASYNC(holder, .proc/setOpened) //Use the INVOKE_ASYNC proc to call setOpened() on whatever the holder may be, without giving the atom/movable base class a setOpened() proc definition for (var/turf_type in turfs_in_cargo)
if (style == STYLE_SEETHROUGH) turf_underneath.PlaceOnTop(turf_type)
update_icon() for (var/cargo in contents)
for (var/atom/movable/O in holder.contents) //Go through the contents of the holder var/atom/movable/movable_cargo = cargo
O.forceMove(T) //move everything from the contents of the holder to the turf of the holder movable_cargo.forceMove(turf_underneath)
if (!effectQuiet && !openingSound && style != STYLE_SEETHROUGH) //If we aren't being quiet, play the default pod open sound if (!effectQuiet && !openingSound && style != STYLE_SEETHROUGH && !(pod_flags & FIRST_SOUNDS)) //If we aren't being quiet, play the default pod open sound
playsound(get_turf(holder), open_sound, 15, 1, -3) playsound(get_turf(holder), open_sound, 15, TRUE, -3)
if (broken) //If the pod is opening because it's been destroyed, we end here if (broken) //If the pod is opening because it's been destroyed, we end here
return return
if (style == STYLE_SEETHROUGH) if (style == STYLE_SEETHROUGH)
depart(src) startExitSequence(src)
else else
if (reversing)
addtimer(CALLBACK(src, .proc/SetReverseIcon), departureDelay/2) //Finish up the pod's duties after a certain amount of time
if(!stay_after_drop) // Departing should be handled manually if(!stay_after_drop) // Departing should be handled manually
addtimer(CALLBACK(src, .proc/depart, holder), departureDelay) //Finish up the pod's duties after a certain amount of time addtimer(CALLBACK(src, .proc/startExitSequence, holder), departureDelay*(4/5)) //Finish up the pod's duties after a certain amount of time
/obj/structure/closet/supplypod/proc/depart(atom/movable/holder) /obj/structure/closet/supplypod/proc/startExitSequence(atom/movable/holder)
if (leavingSound) if (leavingSound)
playsound(get_turf(holder), leavingSound, soundVolume, 0, 0) playsound(get_turf(holder), leavingSound, soundVolume, FALSE, FALSE)
if (reversing) //If we're reversing, we call the close proc. This sends the pod back up to centcom if (reversing) //If we're reversing, we call the close proc. This sends the pod back up to centcom
close(holder) close(holder)
else if (bluespace) //If we're a bluespace pod, then delete ourselves (along with our holder, if a seperate holder exists) else if (bluespace) //If we're a bluespace pod, then delete ourselves (along with our holder, if a seperate holder exists)
deleteRubble()
if (!effectQuiet && style != STYLE_INVISIBLE && style != STYLE_SEETHROUGH) if (!effectQuiet && style != STYLE_INVISIBLE && style != STYLE_SEETHROUGH)
do_sparks(5, TRUE, holder) //Create some sparks right before closing do_sparks(5, TRUE, holder) //Create some sparks right before closing
qdel(src) //Delete ourselves and the holder qdel(src) //Delete ourselves and the holder
if (holder != src) if (holder != src)
qdel(holder) qdel(holder)
/obj/structure/closet/supplypod/centcompod/close(atom/movable/holder) //Closes the supplypod and sends it back to centcom. Should only ever be called if the "reversing" variable is true /obj/structure/closet/supplypod/close(atom/movable/holder) //Closes the supplypod and sends it back to centcom. Should only ever be called if the "reversing" variable is true
handleReturningClose(holder, TRUE)
/obj/structure/closet/supplypod/extractionpod/close(atom/movable/holder) //handles closing, and returns pod - deletes itself when returned
. = ..()
return
/obj/structure/closet/supplypod/extractionpod/proc/send_up(atom/movable/holder)
if (!holder) if (!holder)
holder = src return
take_contents(holder)
playsound(holder, close_sound, soundVolume*0.75, TRUE, -3)
holder.setClosed()
addtimer(CALLBACK(src, .proc/preReturn, holder), departureDelay * 0.2) //Start to leave a bit after closing for cinematic effect
if (leavingSound) /obj/structure/closet/supplypod/take_contents(atom/movable/holder)
playsound(get_turf(holder), leavingSound, soundVolume, 0, 0) var/turf/turf_underneath = holder.drop_location()
for(var/atom_to_check in turf_underneath)
if(atom_to_check != src && !insert(atom_to_check, holder)) // Can't insert that
continue
insert(turf_underneath, holder)
handleReturningClose(holder, FALSE) /obj/structure/closet/supplypod/insert(atom/to_insert, atom/movable/holder)
if(insertion_allowed(to_insert))
if(isturf(to_insert))
var/turf/turf_to_insert = to_insert
turfs_in_cargo += turf_to_insert.type
turf_to_insert.ScrapeAway()
else
var/atom/movable/movable_to_insert = to_insert
movable_to_insert.forceMove(holder)
return TRUE
else
return FALSE
/obj/structure/closet/supplypod/proc/setOpened() //Proc exists here, as well as in any atom that can assume the role of a "holder" of a supplypod. Check the open() proc for more details /obj/structure/closet/supplypod/insertion_allowed(atom/to_insert)
if(to_insert.invisibility == INVISIBILITY_ABSTRACT)
return FALSE
if(ismob(to_insert))
if(!reverseOptionList["Mobs"])
return FALSE
if(!isliving(to_insert)) //let's not put ghosts or camera mobs inside
return FALSE
var/mob/living/mob_to_insert = to_insert
if(mob_to_insert.anchored || mob_to_insert.incorporeal_move)
return FALSE
mob_to_insert.stop_pulling()
else if(isobj(to_insert))
var/obj/obj_to_insert = to_insert
if(istype(obj_to_insert, /obj/structure/closet/supplypod))
return FALSE
if(istype(obj_to_insert, /obj/effect/supplypod_smoke))
return FALSE
if(istype(obj_to_insert, /obj/effect/DPtarget))
return FALSE
if(istype(obj_to_insert, /obj/effect/supplypod_rubble))
return FALSE
if(invisibility > 25 && reverseOptionList["Underfloor"])
return TRUE
else if (invisibility > 25 && !reverseOptionList["Underfloor"])
return FALSE
if(isProbablyWallMounted(obj_to_insert) && reverseOptionList["Wallmounted"])
return TRUE
else if (isProbablyWallMounted(obj_to_insert) && !reverseOptionList["Wallmounted"])
return FALSE
if(!obj_to_insert.anchored && reverseOptionList["Unanchored"])
return TRUE
if(obj_to_insert.anchored && reverseOptionList["Anchored"])
return TRUE
return FALSE
else if (isturf(to_insert))
if(isfloorturf(to_insert) && reverseOptionList["Floors"])
return TRUE
if(isfloorturf(to_insert) && !reverseOptionList["Floors"])
return FALSE
if(isclosedturf(to_insert) && reverseOptionList["Walls"])
return TRUE
if(isclosedturf(to_insert) && !reverseOptionList["Walls"])
return FALSE
return FALSE
return TRUE
/obj/structure/closet/supplypod/proc/preReturn(atom/movable/holder)
deleteRubble()
animate(holder, alpha = 0, time = 8, easing = QUAD_EASING|EASE_IN, flags = ANIMATION_PARALLEL)
animate(holder, pixel_z = 400, time = 10, easing = QUAD_EASING|EASE_IN, flags = ANIMATION_PARALLEL) //Animate our rising pod
addtimer(CALLBACK(src, .proc/handleReturnAfterDeparting, holder), 15) //Finish up the pod's duties after a certain amount of time
/obj/structure/closet/supplypod/setOpened() //Proc exists here, as well as in any atom that can assume the role of a "holder" of a supplypod. Check the open_pod() proc for more details
opened = TRUE
density = FALSE
update_icon() update_icon()
/obj/structure/closet/supplypod/proc/setClosed() //Ditto /obj/structure/closet/supplypod/extractionpod/setOpened()
opened = TRUE
density = TRUE
update_icon() update_icon()
/obj/structure/closet/supplypod/setClosed() //Ditto
opened = FALSE
density = TRUE
update_icon()
/obj/structure/closet/supplypod/proc/tryMakeRubble(turf/T) //Ditto
if (rubble_type == RUBBLE_NONE)
return
if (rubble)
return
if (effectMissile)
return
if (isspaceturf(T) || isclosedturf(T))
return
rubble = new /obj/effect/supplypod_rubble(T)
rubble.setStyle(rubble_type, src)
update_icon()
/obj/structure/closet/supplypod/Moved()
deleteRubble()
return ..()
/obj/structure/closet/supplypod/proc/deleteRubble()
rubble?.fadeAway()
rubble = null
update_icon()
/obj/structure/closet/supplypod/proc/addGlow()
if (GLOB.podstyles[style][POD_SHAPE] != POD_SHAPE_NORML)
return
glow_effect = new(src)
glow_effect.icon_state = "pod_glow_" + GLOB.podstyles[style][POD_GLOW]
vis_contents += glow_effect
glow_effect.layer = GASFIRE_LAYER
/obj/structure/closet/supplypod/proc/endGlow()
if(!glow_effect)
return
glow_effect.layer = LOW_ITEM_LAYER
glow_effect.fadeAway(openingDelay)
/obj/structure/closet/supplypod/Destroy() /obj/structure/closet/supplypod/Destroy()
open(src, broken = TRUE) //Lets dump our contents by opening up deleteRubble()
. = ..() open_pod(src, broken = TRUE) //Lets dump our contents by opening up
return ..()
//------------------------------------FALLING SUPPLY POD-------------------------------------//
/obj/effect/DPfall //Falling pod
name = ""
icon = 'icons/obj/supplypods.dmi'
pixel_x = -16
pixel_y = -5
pixel_z = 200
desc = "Get out of the way!"
layer = FLY_LAYER//that wasnt flying, that was falling with style!
icon_state = ""
/obj/effect/DPfall/Initialize(dropLocation, obj/structure/closet/supplypod/pod)
if (pod.style == STYLE_SEETHROUGH)
pixel_x = -16
pixel_y = 0
for (var/atom/movable/O in pod.contents)
var/icon/I = getFlatIcon(O) //im so sorry
add_overlay(I)
else if (pod.style != STYLE_INVISIBLE) //Check to ensure the pod isn't invisible
icon_state = "[pod.icon_state]_falling"
name = pod.name
. = ..()
//------------------------------------TEMPORARY_VISUAL-------------------------------------// //------------------------------------TEMPORARY_VISUAL-------------------------------------//
/obj/effect/supplypod_smoke //Falling pod smoke
name = ""
icon = 'icons/obj/supplypods_32x32.dmi'
icon_state = "smoke"
desc = ""
layer = PROJECTILE_HIT_THRESHHOLD_LAYER
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
alpha = 0
/obj/effect/engineglow //Falling pod smoke
name = ""
icon = 'icons/obj/supplypods.dmi'
icon_state = "pod_engineglow"
desc = ""
layer = GASFIRE_LAYER
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
alpha = 255
/obj/effect/engineglow/proc/fadeAway(leaveTime)
var/duration = min(leaveTime, 25)
animate(src, alpha=0, time = duration)
QDEL_IN(src, duration + 5)
/obj/effect/supplypod_smoke/proc/drawSelf(amount)
alpha = max(0, 255-(amount*20))
/obj/effect/supplypod_rubble //This is the object that forceMoves the supplypod to it's location
name = "Debris"
desc = "A small crater of rubble. Closer inspection reveals the debris to be made primarily of space-grade metal fragments. You're pretty sure that this will disperse before too long."
icon = 'icons/obj/supplypods.dmi'
layer = PROJECTILE_HIT_THRESHHOLD_LAYER // We want this to go right below the layer of supplypods and supplypod_rubble's forground.
icon_state = "rubble_bg"
anchored = TRUE
pixel_x = SUPPLYPOD_X_OFFSET
var/foreground = "rubble_fg"
var/verticle_offset = 0
/obj/effect/supplypod_rubble/proc/getForeground(obj/structure/closet/supplypod/pod)
var/mutable_appearance/rubble_overlay = mutable_appearance('icons/obj/supplypods.dmi', foreground)
rubble_overlay.appearance_flags = KEEP_APART|RESET_TRANSFORM
rubble_overlay.transform = matrix().Translate(SUPPLYPOD_X_OFFSET - pod.pixel_x, verticle_offset)
return rubble_overlay
/obj/effect/supplypod_rubble/proc/fadeAway()
animate(src, alpha=0, time = 30)
QDEL_IN(src, 35)
/obj/effect/supplypod_rubble/proc/setStyle(type, obj/structure/closet/supplypod/pod)
if (type == RUBBLE_WIDE)
icon_state += "_wide"
foreground += "_wide"
if (type == RUBBLE_THIN)
icon_state += "_thin"
foreground += "_thin"
if (pod.style == STYLE_BOX)
verticle_offset = -2
else
verticle_offset = initial(verticle_offset)
pixel_y = verticle_offset
/obj/effect/DPtarget_effect
name = ""
desc = ""
icon = 'icons/obj/supplypods_32x32.dmi'
icon_state = "LZ_Slider"
layer = PROJECTILE_HIT_THRESHHOLD_LAYER
/obj/effect/DPtarget_effect/Initialize(mapload, obj/structure/closet/supplypod/pod)
transform = matrix() * 1.5
animate(src, transform = matrix()*0.01, time = pod.landingDelay+pod.fallDuration)
..()
/obj/effect/DPtarget //This is the object that forceMoves the supplypod to it's location /obj/effect/DPtarget //This is the object that forceMoves the supplypod to it's location
name = "Landing Zone Indicator" name = "Landing Zone Indicator"
desc = "A holographic projection designating the landing zone of something. It's probably best to stand back." desc = "A holographic projection designating the landing zone of something. It's probably best to stand back."
icon = 'icons/mob/actions/actions_items.dmi' icon = 'icons/obj/supplypods_32x32.dmi'
icon_state = "sniper_zoom" icon_state = "LZ"
layer = PROJECTILE_HIT_THRESHHOLD_LAYER layer = PROJECTILE_HIT_THRESHHOLD_LAYER
light_range = 2 light_range = 2
var/obj/effect/temp_visual/fallingPod //Temporary "falling pod" that we animate anchored = TRUE
var/obj/structure/closet/supplypod/pod //The supplyPod that will be landing ontop of this target alpha = 0
var/obj/structure/closet/supplypod/pod //The supplyPod that will be landing ontop of this DPtarget
var/obj/effect/DPtarget_effect/helper
var/list/smoke_effects = new /list(13)
/obj/effect/ex_act() /obj/effect/ex_act()
return return
/obj/effect/DPtarget/Initialize(mapload, podParam, var/single_order = null) /obj/effect/DPtarget/Initialize(mapload, podParam, single_order = null, clientman)
. = ..() . = ..()
if (ispath(podParam)) //We can pass either a path for a pod (as expressconsoles do), or a reference to an instantiated pod (as the centcom_podlauncher does) if (ispath(podParam)) //We can pass either a path for a pod (as expressconsoles do), or a reference to an instantiated pod (as the centcom_podlauncher does)
podParam = new podParam() //If its just a path, instantiate it podParam = new podParam() //If its just a path, instantiate it
pod = podParam pod = podParam
if (!pod.effectStealth)
helper = new (drop_location(), pod)
alpha = 255
animate(src, transform = matrix().Turn(90), time = pod.landingDelay+pod.fallDuration)
if (single_order) if (single_order)
if (istype(single_order, /datum/supply_order)) if (istype(single_order, /datum/supply_order))
var/datum/supply_order/SO = single_order var/datum/supply_order/SO = single_order
@@ -309,49 +574,76 @@
else if (istype(single_order, /atom/movable)) else if (istype(single_order, /atom/movable))
var/atom/movable/O = single_order var/atom/movable/O = single_order
O.forceMove(pod) O.forceMove(pod)
for (var/mob/living/M in pod) //If there are any mobs in the supplypod, we want to forceMove them into the target. This is so that they can see where they are about to land, AND so that they don't get sent to the nullspace error room (as the pod is currently in nullspace) for (var/mob/living/mob_in_pod in pod) //If there are any mobs in the supplypod, we want to set their view to the DPtarget. This is so that they can see where they are about to land
M.forceMove(src) mob_in_pod.reset_perspective(src)
if(pod.effectStun) //If effectStun is true, stun any mobs caught on this target until the pod gets a chance to hit them if(pod.effectStun) //If effectStun is true, stun any mobs caught on this DPtarget until the pod gets a chance to hit them
for (var/mob/living/M in get_turf(src)) for (var/mob/living/target_living in get_turf(src))
M.Stun(pod.landingDelay+10, ignore_canstun = TRUE)//you aint goin nowhere, kid. target_living.Stun(pod.landingDelay+10, ignore_canstun = TRUE)//you ain't goin nowhere, kid.
if (pod.effectStealth) //If effectStealth is true we want to be invisible
icon_state = ""
if (pod.fallDuration == initial(pod.fallDuration) && pod.landingDelay + pod.fallDuration < pod.fallingSoundLength) if (pod.fallDuration == initial(pod.fallDuration) && pod.landingDelay + pod.fallDuration < pod.fallingSoundLength)
pod.fallingSoundLength = 3 //The default falling sound is a little long, so if the landing time is shorter than the default falling sound, use a special, shorter default falling sound pod.fallingSoundLength = 3 //The default falling sound is a little long, so if the landing time is shorter than the default falling sound, use a special, shorter default falling sound
pod.fallingSound = 'sound/weapons/mortar_whistle.ogg' pod.fallingSound = 'sound/weapons/mortar_whistle.ogg'
var/soundStartTime = pod.landingDelay - pod.fallingSoundLength + pod.fallDuration var/soundStartTime = pod.landingDelay - pod.fallingSoundLength + pod.fallDuration
if (soundStartTime < 0) if (soundStartTime < 0)
soundStartTime = 1 soundStartTime = 1
if (!pod.effectQuiet) if (!pod.effectQuiet && !(pod.pod_flags & FIRST_SOUNDS))
addtimer(CALLBACK(src, .proc/playFallingSound), soundStartTime) addtimer(CALLBACK(src, .proc/playFallingSound), soundStartTime)
addtimer(CALLBACK(src, .proc/beginLaunch, pod.effectCircle), pod.landingDelay) addtimer(CALLBACK(src, .proc/beginLaunch, pod.effectCircle), pod.landingDelay)
/obj/effect/DPtarget/proc/playFallingSound() /obj/effect/DPtarget/proc/playFallingSound()
playsound(src, pod.fallingSound, pod.soundVolume, 1, 6) playsound(src, pod.fallingSound, pod.soundVolume, TRUE, 6)
/obj/effect/DPtarget/proc/beginLaunch(effectCircle) //Begin the animation for the pod falling. The effectCircle param determines whether the pod gets to come in from any descent angle /obj/effect/DPtarget/proc/beginLaunch(effectCircle) //Begin the animation for the pod falling. The effectCircle param determines whether the pod gets to come in from any descent angle
fallingPod = new /obj/effect/DPfall(drop_location(), pod) pod.addGlow()
var/matrix/M = matrix(fallingPod.transform) //Create a new matrix that we can rotate pod.update_icon()
if (pod.style != STYLE_INVISIBLE)
pod.add_filter("motionblur",1,list("type"="motion_blur", "x"=0, "y"=3))
pod.forceMove(drop_location())
for (var/mob/living/M in pod) //Remember earlier (initialization) when we moved mobs into the DPtarget so they wouldnt get lost in nullspace? Time to get them out
M.reset_perspective(null)
var/angle = effectCircle ? rand(0,360) : rand(70,110) //The angle that we can come in from var/angle = effectCircle ? rand(0,360) : rand(70,110) //The angle that we can come in from
fallingPod.pixel_x = cos(angle)*400 //Use some ADVANCED MATHEMATICS to set the animated pod's position to somewhere on the edge of a circle with the center being the target pod.pixel_x = cos(angle)*32*length(smoke_effects) //Use some ADVANCED MATHEMATICS to set the animated pod's position to somewhere on the edge of a circle with the center being the DPtarget
fallingPod.pixel_z = sin(angle)*400 pod.pixel_z = sin(angle)*32*length(smoke_effects)
var/rotation = Get_Pixel_Angle(fallingPod.pixel_z, fallingPod.pixel_x) //CUSTOM HOMEBREWED proc that is just arctan with extra steps var/rotation = Get_Pixel_Angle(pod.pixel_z, pod.pixel_x) //CUSTOM HOMEBREWED proc that is just arctan with extra steps
M.Turn(rotation) //Turn our matrix accordingly setupSmoke(rotation)
fallingPod.transform = M //Transform the animated pod according to the matrix pod.transform = matrix().Turn(rotation)
M = matrix(pod.transform) //Make another matrix based on the pod pod.layer = FLY_LAYER
M.Turn(rotation) //Turn the matrix if (pod.style != STYLE_INVISIBLE)
pod.transform = M //Turn the actual pod (Won't be visible until endLaunch() proc tho) animate(pod.get_filter("motionblur"), y = 0, time = pod.fallDuration, flags = ANIMATION_PARALLEL)
animate(fallingPod, pixel_z = 0, pixel_x = -16, time = pod.fallDuration, , easing = LINEAR_EASING) //Make the pod fall! At an angle! animate(pod, pixel_z = -1 * abs(sin(rotation))*4, pixel_x = SUPPLYPOD_X_OFFSET + (sin(rotation) * 20), time = pod.fallDuration, easing = LINEAR_EASING, flags = ANIMATION_PARALLEL) //Make the pod fall! At an angle!
addtimer(CALLBACK(src, .proc/endLaunch), pod.fallDuration, TIMER_CLIENT_TIME) //Go onto the last step after a very short falling animation addtimer(CALLBACK(src, .proc/endLaunch), pod.fallDuration, TIMER_CLIENT_TIME) //Go onto the last step after a very short falling animation
/obj/effect/DPtarget/proc/setupSmoke(rotation)
if (pod.style == STYLE_INVISIBLE || pod.style == STYLE_SEETHROUGH)
return
for ( var/i in 1 to length(smoke_effects))
var/obj/effect/supplypod_smoke/smoke_part = new (drop_location())
if (i == 1)
smoke_part.layer = FLY_LAYER
smoke_part.icon_state = "smoke_start"
smoke_part.transform = matrix().Turn(rotation)
smoke_effects[i] = smoke_part
smoke_part.pixel_x = sin(rotation)*32 * i
smoke_part.pixel_y = abs(cos(rotation))*32 * i
smoke_part.filters += filter(type = "blur", size = 4)
var/time = (pod.fallDuration / length(smoke_effects))*(length(smoke_effects)-i)
addtimer(CALLBACK(smoke_part, /obj/effect/supplypod_smoke/.proc/drawSelf, i), time, TIMER_CLIENT_TIME) //Go onto the last step after a very short falling animation
QDEL_IN(smoke_part, pod.fallDuration + 35)
/obj/effect/DPtarget/proc/drawSmoke()
if (pod.style == STYLE_INVISIBLE || pod.style == STYLE_SEETHROUGH)
return
for (var/obj/effect/supplypod_smoke/smoke_part in smoke_effects)
animate(smoke_part, alpha = 0, time = 20, flags = ANIMATION_PARALLEL)
animate(smoke_part.filters[1], size = 6, time = 15, easing = CUBIC_EASING|EASE_OUT, flags = ANIMATION_PARALLEL)
/obj/effect/DPtarget/proc/endLaunch() /obj/effect/DPtarget/proc/endLaunch()
pod.update_icon() pod.tryMakeRubble(drop_location())
pod.forceMove(drop_location()) //The fallingPod animation is over, now's a good time to forceMove the actual pod into position pod.layer = initial(pod.layer)
QDEL_NULL(fallingPod) //Delete the falling pod effect, because at this point its animation is over. We dont use temp_visual because we want to manually delete it as soon as the pod appears pod.endGlow()
for (var/mob/living/M in src) //Remember earlier (initialization) when we moved mobs into the DPTarget so they wouldnt get lost in nullspace? Time to get them out QDEL_NULL(helper)
M.forceMove(pod)
pod.preOpen() //Begin supplypod open procedures. Here effects like explosions, damage, and other dangerous (and potentially admin-caused, if the centcom_podlauncher datum was used) memes will take place pod.preOpen() //Begin supplypod open procedures. Here effects like explosions, damage, and other dangerous (and potentially admin-caused, if the centcom_podlauncher datum was used) memes will take place
qdel(src) //The target's purpose is complete. It can rest easy now drawSmoke()
qdel(src) //The DPtarget's purpose is complete. It can rest easy now
//------------------------------------UPGRADES-------------------------------------// //------------------------------------UPGRADES-------------------------------------//
/obj/item/disk/cargo/bluespace_pod //Disk that can be inserted into the Express Console to allow for Advanced Bluespace Pods /obj/item/disk/cargo/bluespace_pod //Disk that can be inserted into the Express Console to allow for Advanced Bluespace Pods

Binary file not shown.

After

Width:  |  Height:  |  Size: 464 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 336 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 322 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 392 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@@ -26,6 +26,7 @@ export const Button = props => {
selected, selected,
tooltip, tooltip,
tooltipPosition, tooltipPosition,
tooltipOverrideLong,
ellipsis, ellipsis,
compact, compact,
circular, circular,
@@ -97,6 +98,7 @@ export const Button = props => {
{tooltip && ( {tooltip && (
<Tooltip <Tooltip
content={tooltip} content={tooltip}
overrideLong={tooltipOverrideLong}
position={tooltipPosition} /> position={tooltipPosition} />
)} )}
</Box> </Box>
@@ -221,6 +223,7 @@ export class ButtonInput extends Component {
iconSpin, iconSpin,
tooltip, tooltip,
tooltipPosition, tooltipPosition,
tooltipOverrideLong,
color = 'default', color = 'default',
placeholder, placeholder,
maxLength, maxLength,
@@ -270,6 +273,7 @@ export class ButtonInput extends Component {
{tooltip && ( {tooltip && (
<Tooltip <Tooltip
content={tooltip} content={tooltip}
overrideLong={tooltipOverrideLong}
position={tooltipPosition} position={tooltipPosition}
/> />
)} )}

View File

@@ -173,6 +173,7 @@ export class DraggableControl extends Component {
unit, unit,
minValue, minValue,
maxValue, maxValue,
unclamped,
format, format,
onChange, onChange,
onDrag, onDrag,
@@ -221,10 +222,16 @@ export class DraggableControl extends Component {
if (!editing) { if (!editing) {
return; return;
} }
const value = clamp( let value;
parseFloat(e.target.value), if (unclamped) {
minValue, value = parseFloat(e.target.value);
maxValue); }
else {
value = clamp(
parseFloat(e.target.value),
minValue,
maxValue);
}
if (Number.isNaN(value)) { if (Number.isNaN(value)) {
this.setState({ this.setState({
editing: false, editing: false,
@@ -245,10 +252,16 @@ export class DraggableControl extends Component {
}} }}
onKeyDown={e => { onKeyDown={e => {
if (e.keyCode === 13) { if (e.keyCode === 13) {
const value = clamp( let value;
parseFloat(e.target.value), if (unclamped) {
minValue, value = parseFloat(e.target.value);
maxValue); }
else {
value = clamp(
parseFloat(e.target.value),
minValue,
maxValue);
}
if (Number.isNaN(value)) { if (Number.isNaN(value)) {
this.setState({ this.setState({
editing: false, editing: false,

View File

@@ -33,7 +33,7 @@ export const computeFlexProps = props => {
style: { style: {
...rest.style, ...rest.style,
'flex-direction': direction, 'flex-direction': direction,
'flex-wrap': wrap, 'flex-wrap': wrap === true ? 'wrap' : wrap,
'align-items': align, 'align-items': align,
'justify-content': justify, 'justify-content': justify,
}, },

View File

@@ -24,6 +24,7 @@ export const Knob = props => {
format, format,
maxValue, maxValue,
minValue, minValue,
unclamped,
onChange, onChange,
onDrag, onDrag,
step, step,
@@ -50,6 +51,7 @@ export const Knob = props => {
format, format,
maxValue, maxValue,
minValue, minValue,
unclamped,
onChange, onChange,
onDrag, onDrag,
step, step,
@@ -79,7 +81,7 @@ export const Knob = props => {
const effectiveColor = color const effectiveColor = color
|| keyOfMatchingRange(fillValue ?? value, ranges) || keyOfMatchingRange(fillValue ?? value, ranges)
|| 'default'; || 'default';
const rotation = (scaledDisplayValue - 0.5) * 270; const rotation = Math.min((scaledDisplayValue - 0.5) * 270, 225);
return ( return (
<div <div
className={classes([ className={classes([
@@ -127,8 +129,8 @@ export const Knob = props => {
className="Knob__ringFill" className="Knob__ringFill"
style={{ style={{
'stroke-dashoffset': ( 'stroke-dashoffset': (
((bipolar ? 2.75 : 2.00) - scaledFillValue * 1.5) Math.max(((bipolar ? 2.75 : 2.00) - scaledFillValue * 1.5)
* Math.PI * 50 * Math.PI * 50, 0)
), ),
}} }}
cx="50" cx="50"

View File

@@ -9,11 +9,13 @@ import { Flex } from './Flex';
export const LabeledControls = props => { export const LabeledControls = props => {
const { const {
children, children,
wrap,
...rest ...rest
} = props; } = props;
return ( return (
<Flex <Flex
mx={-0.5} mx={-0.5}
wrap={wrap}
align="stretch" align="stretch"
justify="space-between" justify="space-between"
{...rest}> {...rest}>
@@ -26,12 +28,12 @@ const LabeledControlsItem = props => {
const { const {
label, label,
children, children,
mx = 1,
...rest ...rest
} = props; } = props;
return ( return (
<Flex.Item mx={1}> <Flex.Item mx={mx}>
<Flex <Flex
minWidth="52px"
height="100%" height="100%"
direction="column" direction="column"
align="center" align="center"

View File

@@ -41,10 +41,18 @@ export class Section extends Component {
...rest ...rest
} = this.props; } = this.props;
const hasTitle = canRender(title) || canRender(buttons); const hasTitle = canRender(title) || canRender(buttons);
const hasContent = canRender(children); const content = fitted
? children
: (
<div
ref={this.ref}
className="Section__content">
{children}
</div>
);
return ( return (
<div <div
ref={this.ref} ref={fitted ? this.ref : undefined}
className={classes([ className={classes([
'Section', 'Section',
'Section--level--' + level, 'Section--level--' + level,
@@ -66,12 +74,7 @@ export class Section extends Component {
</div> </div>
</div> </div>
)} )}
{fitted && children {content}
|| hasContent && (
<div className="Section__content">
{children}
</div>
)}
</div> </div>
); );
} }

View File

@@ -9,11 +9,13 @@ import { classes } from 'common/react';
export const Tooltip = props => { export const Tooltip = props => {
const { const {
content, content,
overrideLong = false,
position = 'bottom', position = 'bottom',
} = props; } = props;
// Empirically calculated length of the string, // Empirically calculated length of the string,
// at which tooltip text starts to overflow. // at which tooltip text starts to overflow.
const long = typeof content === 'string' && content.length > 35; const long = typeof content === 'string'
&& (content.length > 35 && !overrideLong);
return ( return (
<div <div
className={classes([ className={classes([

View File

@@ -178,6 +178,8 @@ export const dragStartHandler = event => {
window.screenLeft - event.screenX, window.screenLeft - event.screenX,
window.screenTop - event.screenY, window.screenTop - event.screenY,
]; ];
// Focus click target
event.target?.focus();
document.addEventListener('mousemove', dragMoveHandler); document.addEventListener('mousemove', dragMoveHandler);
document.addEventListener('mouseup', dragEndHandler); document.addEventListener('mouseup', dragEndHandler);
dragMoveHandler(event); dragMoveHandler(event);
@@ -214,6 +216,8 @@ export const resizeStartHandler = (x, y) => event => {
window.innerWidth, window.innerWidth,
window.innerHeight, window.innerHeight,
]; ];
// Focus click target
event.target?.focus();
document.addEventListener('mousemove', resizeMoveHandler); document.addEventListener('mousemove', resizeMoveHandler);
document.addEventListener('mouseup', resizeEndHandler); document.addEventListener('mouseup', resizeEndHandler);
resizeMoveHandler(event); resizeMoveHandler(event);

File diff suppressed because it is too large Load Diff

View File

@@ -57,6 +57,11 @@ $shadow-offset: 0 0 !default;
height: 100%; height: 100%;
} }
.Section--scrollable .Section__content {
overflow-y: scroll;
overflow-x: hidden;
}
.Section--fill .Section__content { .Section--fill .Section__content {
flex-grow: 1; flex-grow: 1;
} }
@@ -76,7 +81,7 @@ $shadow-offset: 0 0 !default;
.Section--scrollable { .Section--scrollable {
overflow-x: hidden; overflow-x: hidden;
overflow-y: scroll; overflow-y: hidden;
} }
.Section--level--1 .Section__titleText { .Section--level--1 .Section__titleText {

View File

@@ -21,7 +21,7 @@ $border-radius: base.$border-radius !default;
&::after { &::after {
position: absolute; position: absolute;
display: block; display: block;
white-space: nowrap; white-space: pre;
z-index: 2; z-index: 2;
padding: 0.5em 0.75em; padding: 0.5em 0.75em;
transform: translateX(-50%); transform: translateX(-50%);
@@ -61,6 +61,26 @@ $border-radius: base.$border-radius !default;
transform: translateX(-50%) translateY(-0.5em); transform: translateX(-50%) translateY(-0.5em);
} }
.Tooltip--top-left::after {
bottom: 100%;
right: 50%;
transform: translateX(12px) translateY(8px);
}
.Tooltip--top-left:hover::after {
transform: translateX(12px) translateY(-8px);
}
.Tooltip--top-right::after {
top: 0px;
right: 0px;
transform: translateX(100%) translateY(-50%);
}
.Tooltip--top-right:hover::after {
transform: translateX(100%) translateY(-100%);
}
.Tooltip--bottom::after { .Tooltip--bottom::after {
top: 100%; top: 100%;
left: 50%; left: 50%;