diff --git a/code/__DEFINES/cargo.dm b/code/__DEFINES/cargo.dm
index 2939952f863..e3228ba0625 100644
--- a/code/__DEFINES/cargo.dm
+++ b/code/__DEFINES/cargo.dm
@@ -15,11 +15,12 @@
#define POD_SHAPE 1
#define POD_BASE 2
-#define POD_DECAL 3
-#define POD_GLOW 4
-#define POD_RUBBLE_TYPE 5
-#define POD_NAME 6
-#define POD_DESC 7
+#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 RUBBLE_NONE 1
#define RUBBLE_NORMAL 2
@@ -29,19 +30,23 @@
#define POD_SHAPE_NORML 1
#define POD_SHAPE_OTHER 2
-#define POD_STYLES list(\
- list(POD_SHAPE_NORML, "pod", "default", "yellow", RUBBLE_NORMAL, "supply pod", "A Nanotrasen supply drop pod."),\
- list(POD_SHAPE_NORML, "advpod", "bluespace", "blue", RUBBLE_NORMAL, "bluespace supply pod" , "A Nanotrasen Bluespace supply pod. Teleports back to CentCom after delivery."),\
- list(POD_SHAPE_NORML, "advpod", "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", "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", "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", "cultist", "red", RUBBLE_NORMAL, "bloody supply pod", "A Nanotrasen supply pod covered in scratch-marks, blood, and strange runes."),\
- list(POD_SHAPE_OTHER, "missile", null, "yellow", 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", null, "yellow", 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", null, "yellow", 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", "clown", "green", RUBBLE_NORMAL, "\improper HONK pod", "A brightly-colored supply pod. It likely originated from the Clown Federation."),\
- list(POD_SHAPE_OTHER, "orange", null, "yellow", RUBBLE_NONE, "\improper Orange", "An angry orange."),\
- list(POD_SHAPE_OTHER, "", null, "yellow", 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", null, "yellow", RUBBLE_NONE, "gondola", "The silent walker. This one seems to be part of a delivery agency."),\
- list(POD_SHAPE_OTHER, "", null, "yellow", RUBBLE_NONE, "", "")\
-)
+#define SUPPLYPOD_X_OFFSET -16
+
+GLOBAL_LIST_EMPTY(supplypod_loading_bays)
+
+GLOBAL_LIST_INIT(podstyles, list(\
+ list(POD_SHAPE_NORML, "pod", TRUE, "default", "yellow", RUBBLE_NORMAL, "supply pod", "A Nanotrasen supply drop pod."),\
+ 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")\
+))
diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm
index 1a0d829993c..e2b1cb76664 100644
--- a/code/__DEFINES/is_helpers.dm
+++ b/code/__DEFINES/is_helpers.dm
@@ -211,6 +211,7 @@ GLOBAL_LIST_INIT(glass_sheet_types, typecacheof(list(
#define isshuttleturf(T) (length(T.baseturfs) && (/turf/baseturf_skipover/shuttle in T.baseturfs))
+#define isProbablyWallMounted(O) (O.pixel_x > 20 || O.pixel_x < -20 || O.pixel_y > 20 || O.pixel_y < -20)
#define isbook(O) (is_type_in_typecache(O, GLOB.book_types))
GLOBAL_LIST_INIT(book_types, typecacheof(list(
diff --git a/code/game/area/areas/centcom.dm b/code/game/area/areas/centcom.dm
index ba81401a72e..fce13a4040e 100644
--- a/code/game/area/areas/centcom.dm
+++ b/code/game/area/areas/centcom.dm
@@ -44,21 +44,35 @@
/area/centcom/supplypod/loading
name = "Supplypod Loading Facility"
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
name = "Bay #1"
+ loading_id = "1"
/area/centcom/supplypod/loading/two
name = "Bay #2"
+ loading_id = "2"
/area/centcom/supplypod/loading/three
name = "Bay #3"
+ loading_id = "3"
/area/centcom/supplypod/loading/four
name = "Bay #4"
+ loading_id = "4"
/area/centcom/supplypod/loading/ert
name = "ERT Bay"
+ loading_id = "5"
//THUNDERDOME
/area/tdome
diff --git a/code/game/machinery/mechlaunchpad.dm b/code/game/machinery/mechlaunchpad.dm
index fb36387e49b..049f3e7d3eb 100644
--- a/code/game/machinery/mechlaunchpad.dm
+++ b/code/game/machinery/mechlaunchpad.dm
@@ -53,7 +53,8 @@
*/
/obj/machinery/mechpad/proc/launch(obj/machinery/mechpad/where)
var/obj/structure/closet/supplypod/mechpod/pod = new()
- pod.reverse_dropoff_turf = get_turf(where)
+ var/turf/target_turf = get_turf(where)
+ pod.reverse_dropoff_coords = list(target_turf.x, target_turf.y, target_turf.z)
new /obj/effect/pod_landingzone(get_turf(src), pod)
/obj/structure/closet/supplypod/mechpod
diff --git a/code/game/objects/effects/misc.dm b/code/game/objects/effects/misc.dm
index 8d1957fe1fd..ca00f6a9be0 100644
--- a/code/game/objects/effects/misc.dm
+++ b/code/game/objects/effects/misc.dm
@@ -40,10 +40,6 @@
density = TRUE
layer = FLY_LAYER
-/obj/effect/supplypod_selector
- icon_state = "supplypod_selector"
- layer = FLY_LAYER
-
//Makes a tile fully lit no matter what
/obj/effect/fullbright
icon = 'icons/effects/alphacolors.dmi'
diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm
index e258486dfc4..e5bf8ed3739 100644
--- a/code/modules/admin/verbs/randomverbs.dm
+++ b/code/modules/admin/verbs/randomverbs.dm
@@ -1132,7 +1132,6 @@ Traitors and the like can also be revived with the previous role mostly intact.
plaunch.temp_pod.damage = 40//bring the mother fuckin ruckus
plaunch.temp_pod.explosionSize = list(0,0,0,2)
plaunch.temp_pod.effectStun = TRUE
- plaunch.ui_interact(usr)
return //We return here because punish_log() is handled by the centcom_podlauncher datum
if(ADMIN_PUNISHMENT_MAZING)
if(!puzzle_imprison(target))
diff --git a/code/modules/asset_cache/asset_list_items.dm b/code/modules/asset_cache/asset_list_items.dm
index 08e2937ee39..1bf176d0e33 100644
--- a/code/modules/asset_cache/asset_list_items.dm
+++ b/code/modules/asset_cache/asset_list_items.dm
@@ -307,6 +307,36 @@
InsertAll("", each, GLOB.alldirs)
..()
+/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 ..()
+
// Representative icons for each research design
/datum/asset/spritesheet/research_designs
name = "design"
diff --git a/code/modules/cargo/centcom_podlauncher.dm b/code/modules/cargo/centcom_podlauncher.dm
index cfb4af2b889..dd0574a3be3 100644
--- a/code/modules/cargo/centcom_podlauncher.dm
+++ b/code/modules/cargo/centcom_podlauncher.dm
@@ -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
//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.
@@ -13,21 +20,21 @@
set name = "Config/Launch Supplypod"
set desc = "Configure and launch a CentCom supplypod full of whatever your heart desires!"
set category = "Admin - Events"
- var/datum/centcom_podlauncher/plaunch = new(usr)//create the datum
- plaunch.ui_interact(usr)//datum has a tgui component, here we open the window
+ new /datum/centcom_podlauncher(usr)//create the datum
//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)
/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/pod_landingzone, /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/pod_landingzone, /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/client/holder //client of whoever is using this datum
- var/area/bay //What bay we're using to launch shit from.
- var/turf/dropoff_turf //If we're reversing, where the reverse pods go
- var/picking_dropoff_turf
+ 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/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/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
@@ -39,48 +46,115 @@
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/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
+ // 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)
- if (istype(H,/client))
- var/client/C = H
- holder = C //if its a client, assign it to holder
+/datum/centcom_podlauncher/New(user) //user can either be a client or a mob
+ if (user) //Prevents runtimes on datums being made without clients
+ setup(user)
+
+/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
- var/mob/M = H
- holder = M.client //if its a mob, assign the mob's client to holder
+ var/mob/user_mob = user
+ 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
- temp_pod = new(locate(/area/centcom/supplypod/pod_storage) 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)
+ 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)
+ 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
+/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)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
+ // Open UI
ui = new(user, src, "CentcomPodLauncher")
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.
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
- data["bay"] = bay //Holds the current bay the user is launching objects from. Bays are specific rooms on the centcom map.
- data["bayNumber"] = B //Holds the bay as a number. Useful for comparisons in centcom_podlauncher.ract
+ bayNumber = bay?.loading_id //Used as quick reference to what bay we're taking items from
+ data["bayNumber"] = bayNumber //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["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["dropoff_turf"] = dropoff_turf //The turf that reverse pods will drop their newly acquired cargo off at
+ 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["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["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["fallDuration"] = temp_pod.fallDuration //How long the pod's falling animation lasts
- data["landingDelay"] = temp_pod.landingDelay //How long the pod takes to land after launching
- data["openingDelay"] = 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["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["delay_1"] = 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["delay_3"] = temp_pod.openingDelay //How long the pod takes to open after landing
+ 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 GLOB.podstyles list in cargo.dm defines to get the proper icon/name/desc for the pod.
data["effectShrapnel"] = temp_pod.effectShrapnel //If true, creates a cloud of shrapnel of a decided type and magnitude on landing
+ data["shrapnelType"] = "[temp_pod.shrapnel_type]" //Path2String
+ data["shrapnelMagnitude"] = temp_pod.shrapnel_magnitude
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["effectOrgans"] = temp_pod.effectOrgans //If true, yeets the organs out of any bodies caught under the pod when it lands
@@ -91,8 +165,11 @@
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["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["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["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
@@ -100,7 +177,7 @@
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["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
/datum/centcom_podlauncher/ui_act(action, params)
@@ -108,64 +185,72 @@
return
switch(action)
////////////////////////////UTILITIES//////////////////
- if("bay1")
- bay = locate(/area/centcom/supplypod/loading/one) in GLOB.sortedAreas //set the "bay" variable to the corresponding room in centcom
- refreshBay() //calls refreshBay() which "recounts" the bay to see what items we can launch (among other things).
+ if("gamePanel")
+ holder.holder.Game()
+ 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
- if("bay2")
- bay = locate(/area/centcom/supplypod/loading/two) in GLOB.sortedAreas
- refreshBay()
+ if("buildMode")
+ var/mob/holder_mob = holder.mob
+ if (holder_mob)
+ 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("bay3")
- bay = locate(/area/centcom/supplypod/loading/three) in GLOB.sortedAreas
- refreshBay()
+ if("loadDataFromPreset")
+ var/list/savedData = params["payload"]
+ loadData(savedData)
. = TRUE
- if("bay4")
- bay = locate(/area/centcom/supplypod/loading/four) in GLOB.sortedAreas
- refreshBay()
- . = TRUE
- if("bay5")
- bay = locate(/area/centcom/supplypod/loading/ert) in GLOB.sortedAreas
+ if("switchBay")
+ bayNumber = params["bayNumber"]
refreshBay()
. = TRUE
if("pickDropoffTurf") //Enters a mode that lets you pick the dropoff location for reverse pods
if (picking_dropoff_turf)
picking_dropoff_turf = FALSE
- updateCursor(FALSE, FALSE) //Update the cursor of the user to a cool looking target icon
+ 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(FALSE, TRUE) //Update the cursor of the user to a cool looking target icon
+ updateCursor() //Update the cursor of the user to a cool looking target icon
. = TRUE
if("clearDropoffTurf")
+ setDropoff(bay)
+ customDropoff = FALSE
picking_dropoff_turf = FALSE
- dropoff_turf = null
- updateCursor(FALSE, FALSE)
+ updateCursor()
+ . = TRUE
+ if("teleportDropoff") //Teleports the user to the dropoff point.
+ var/mob/M = holder.mob //We teleport whatever mob the client is attached to at the point of clicking
+ 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
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
- oldTurf = get_turf(M) //Used for the "teleportBack" action
- var/area/A = locate(bay) in GLOB.sortedAreas
- var/list/turfs = list()
- for(var/turf/T in A)
- turfs.Add(T) //Fill a list with turfs in the area
- if (!length(turfs)) //If the list is empty, error and cancel
- to_chat(M, "Nowhere to jump to!")
- return //Only teleport if the list isn't empty
- var/turf/T = pick(turfs)
- M.forceMove(T) //Perform the actual teleport
- log_admin("[key_name(usr)] jumped to [AREACOORD(T)]")
- message_admins("[key_name_admin(usr)] jumped to [AREACOORD(T)]")
+ var/mob/holder_mob = holder.mob //We teleport whatever mob the client is attached to at the point of clicking
+ var/turf/current_location = get_turf(holder_mob)
+ var/area/bay_area = bay
+ if (current_location.loc != bay_area)
+ oldTurf = current_location
+ var/turf/teleport_turf = pick(get_area_turfs(bay_area))
+ holder_mob.forceMove(teleport_turf) //Perform the actual teleport
+ if (holder.holder)
+ log_admin("[key_name(usr)] jumped to [AREACOORD(teleport_turf)]")
+ message_admins("[key_name_admin(usr)] jumped to [AREACOORD(teleport_turf)]")
. = 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
if (!oldTurf) //If theres no turf to go back to, error and cancel
to_chat(M, "Nowhere to jump to!")
return
M.forceMove(oldTurf) //Perform the actual teleport
- log_admin("[key_name(usr)] jumped to [AREACOORD(oldTurf)]")
- message_admins("[key_name_admin(usr)] jumped to [AREACOORD(oldTurf)]")
+ if (holder.holder)
+ log_admin("[key_name(usr)] jumped to [AREACOORD(oldTurf)]")
+ message_admins("[key_name_admin(usr)] jumped to [AREACOORD(oldTurf)]")
. = TRUE
////////////////////////////LAUNCH STYLE CHANGES//////////////////
@@ -173,22 +258,21 @@
launchClone = !launchClone
. = TRUE
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
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 = 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
+ launchChoice = LAUNCH_ORDERED
updateSelector()
. = TRUE
if("launchRandomTurf") //Pick random turfs from the supplypod bay at centcom to launch
- if (launchChoice == 2)
- launchChoice = 0
- updateSelector()
- return
- launchChoice = 2
+ launchChoice = LAUNCH_RANDOM
updateSelector()
. = TRUE
@@ -247,10 +331,10 @@
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)
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))
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))
return
temp_pod.name = nameInput
@@ -306,6 +390,14 @@
. = 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
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
if("effectTarget") //Toggle: Launch at a specific mob (instead of at whatever turf you click on). Used for the supplypod smite
if (specificTarget)
@@ -320,71 +412,44 @@
. = TRUE
////////////////////////////TIMER DELAYS//////////////////
- if("fallDuration") //Change the time it takes the pod to land, after firing
- 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
- temp_pod.fallDuration = initial(temp_pod.fallDuration)
- return
- 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
- if (isnull(timeInput))
- return
- if (!isnum(timeInput)) //Sanitize input, if it doesnt check out, error and set to default
- alert(usr, "That wasn't a number! Value set to default ([initial(temp_pod.fallDuration)*0.1]) instead.")
- timeInput = initial(temp_pod.fallDuration)
- temp_pod.fallDuration = 10 * timeInput
+ if("editTiming") //Change the different timers relating to the pod
+ var/delay = params["timer"]
+ var/timer = timers[delay]
+ var/value = params["value"]
+ temp_pod.vars[timer] = value * 10
. = TRUE
- if("landingDelay") //Change the time it takes the pod to land, after firing
- 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
- temp_pod.landingDelay = initial(temp_pod.landingDelay)
- 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 wasn't a number! Value set to default ([initial(temp_pod.landingDelay)*0.1]) instead.")
- timeInput = initial(temp_pod.landingDelay)
- temp_pod.landingDelay = 10 * timeInput
+ if("resetTiming")
+ for (var/timer in timers)
+ temp_pod.vars[timer] = initial(temp_pod.vars[timer])
. = 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 wasn't 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 wasn't 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//////////////////
- if("fallSound") //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))
temp_pod.fallingSound = initial(temp_pod.fallingSound)
temp_pod.fallingSoundLength = initial(temp_pod.fallingSoundLength)
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))
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
- if (isnull(timeInput))
- return
- if (!isnum(timeInput))
- alert(usr, "That wasn't a number! Value set to default ([initial(temp_pod.fallingSoundLength)*0.1]) instead.")
+ var/sound/tempSound = sound(soundInput)
+ playsound(holder.mob, tempSound, 1)
+ var/list/sounds_list = holder.SoundQuery()
+ var/soundLen = 0
+ 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.fallingSoundLength = 10 * timeInput
+ temp_pod.fallingSoundLength = 10 * soundLen
. = TRUE
if("landingSound") //Admin sound from a local file that plays when the pod lands
if (!isnull(temp_pod.landingSound))
@@ -423,53 +488,32 @@
temp_pod.soundVolume = soundInput
. = TRUE
////////////////////////////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.
- if("styleStandard")
- temp_pod.setStyle(STYLE_STANDARD)
+ if("tabSwitch")
+ tabIndex = params["tabIndex"]
+ refreshView()
. = TRUE
- if("styleBluespace")
- temp_pod.setStyle(STYLE_BLUESPACE)
+ if("refreshView")
+ initMap()
+ refreshView()
. = TRUE
- if("styleSyndie")
- temp_pod.setStyle(STYLE_SYNDICATE)
+ if("renderLighting")
+ renderLighting = !renderLighting
. = TRUE
- if("styleBlue")
- temp_pod.setStyle(STYLE_BLUE)
- . = TRUE
- 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)
+ if("setStyle")
+ var/chosenStyle = params["style"]
+ temp_pod.setStyle(chosenStyle+1)
. = 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
refreshBay()
. = 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
- updateCursor(launcherActivated, FALSE) //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
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")
@@ -477,28 +521,55 @@
refreshBay()
. = 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)
-/datum/centcom_podlauncher/proc/updateCursor(launching, turf_picking) //Update the mouse of the user
+/datum/centcom_podlauncher/proc/setupViewPod()
+ setupView(RANGE_TURFS(2, temp_pod))
+
+/datum/centcom_podlauncher/proc/setupViewBay()
+ var/list/visible_turfs = list()
+ for(var/turf/bay_turf in bay)
+ visible_turfs += bay_turf
+ setupView(visible_turfs)
+
+/datum/centcom_podlauncher/proc/setupViewDropoff()
+ var/list/coords_list = temp_pod.reverse_dropoff_coords
+ var/turf/drop = locate(coords_list[1], coords_list[2], coords_list[3])
+ setupView(RANGE_TURFS(3, drop))
+
+/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 (launching || turf_picking) //If the launching param is true, we give the user new mouse icons.
- if(launching)
+ 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
- if(turf_picking)
+ 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/M = holder.mob
+ var/mob/holder_mob = holder.mob
holder.mouse_up_icon = null
holder.mouse_down_icon = null
holder.click_intercept = null
- if (M)
- 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)()
+ 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
var/list/pa = params2list(params)
@@ -521,9 +592,10 @@
if (effectAnnounce)
deadchat_broadcast("A special package is being launched at the station!", turf_target = target, message_type=DEADCHAT_ANNOUNCEMENT)
var/list/bouttaDie = list()
- for (var/mob/living/M in target)
- bouttaDie.Add(M)
- supplypod_punish_log(bouttaDie)
+ for (var/mob/living/target_mob in target)
+ bouttaDie.Add(target_mob)
+ if (holder.holder)
+ supplypod_punish_log(bouttaDie)
if (!effectBurst) //If we're not using burst mode, just launch normally.
launch(target)
else
@@ -531,9 +603,9 @@
if (isnull(target))
break //if our target gets deleted during this, we stop the show
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
- if (LZ) //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
+ 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 (landingzone) //just incase we're on the edge of the map or something that would cause target.x+1 to fail
+ launch(landingzone) //launch the pod at the adjacent turf
else
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.
@@ -544,94 +616,145 @@
. = TRUE
if(left_click) //When we left click:
- dropoff_turf = get_turf(target)
- to_chat(user, " You've selected [dropoff_turf] at [COORD(dropoff_turf)] as your dropoff location.")
+ var/turf/target_turf = get_turf(target)
+ setDropoff(target_turf)
+ customDropoff = TRUE
+ to_chat(user, " You've selected [target_turf] at [COORD(target_turf)] as your dropoff location.")
+
+/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
+ bay = GLOB.supplypod_loading_bays[bayNumber]
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)
+ refreshView()
-/datum/centcom_podlauncher/proc/createOrderedArea(area/A) //This assumes the area passed in is a continuous square
- if (isnull(A)) //If theres no supplypod bay mapped into centcom, throw an error
+/area/centcom/supplypod/pod_storage/Initialize(mapload) //temp_pod holding area
+ . = ..()
+ 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!")
CRASH("No /area/centcom/supplypod/loading/one (or /two or /three or /four) has been mapped into the centcom z-level!")
orderedArea = list()
- if (length(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
- 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/endX = A.contents[1].x
- var/startY = A.contents[1].y
- var/endY = A.contents[1].y
- for (var/turf/T in A) //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
- startX = T.x
- else if (T.x > endX) //The turf with the largest x value. This is our endX
- endX = T.x
- else if (T.y > startY) //The turf with the largest Y value. This is our startY
- startY = T.y
- else if (T.y < endY) //The turf with the smallest Y value. This is our endY
- endY = T.y
- for (var/i in endY to startY)
- for (var/j 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
+ 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 = 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 = area_to_order.contents[1].x
+ var/startY = area_to_order.contents[1].y
+ var/endY = area_to_order.contents[1].y
+ for (var/turf/turf_in_area in area_to_order) //For each turf in the area, go through and find:
+ if (turf_in_area.x < startX) //The turf with the smallest x value. This is our startX
+ startX = turf_in_area.x
+ else if (turf_in_area.x > endX) //The turf with the largest x value. This is our endX
+ endX = turf_in_area.x
+ else if (turf_in_area.y > startY) //The turf with the largest Y value. This is our startY
+ startY = turf_in_area.y
+ else if (turf_in_area.y < endY) //The turf with the smallest Y value. This is our endY
+ endY = turf_in_area.y
+ for (var/vertical in endY to startY)
+ for (var/horizontal in startX to endX)
+ 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
/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)
acceptableTurfs = list()
- for (var/turf/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 isn't in the blacklist, we consider this turf "acceptable" and add it to the acceptableTurfs list
- acceptableTurfs.Add(T) //Because orderedArea was an ordered linear list, acceptableTurfs will be as well.
+ for (var/t in orderedArea) //Go through the orderedArea list
+ var/turf/unchecked_turf = t
+ 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 ++
launchList = list() //Anything in launchList will go into the supplypod when it is launched
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)
- if(0) //If we are launching all the turfs at once
- for (var/turf/T in acceptableTurfs)
- launchList |= typecache_filter_list_reverse(T.contents, ignored_atoms) //We filter any blacklisted atoms and add the rest to the launchList
- if(1) //If we are launching one at a time
+ if(LAUNCH_ALL) //If we are launching all the turfs at once
+ for (var/t in acceptableTurfs)
+ var/turf/accepted_turf = t
+ 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
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
- launchList |= typecache_filter_list_reverse(acceptableTurfs[launchCounter].contents, ignored_atoms) //Filter the specicic turf chosen from acceptableTurfs, and add it to the launchList
- if(2) //If we are launching randomly
- 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
+ var/turf/next_turf_in_line = acceptableTurfs[launchCounter]
+ 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 (iswallturf(next_turf_in_line))
+ 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() 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
- if (isnull(A))
+/datum/centcom_podlauncher/proc/launch(turf/target_turf) //Game time started
+ if (isnull(target_turf))
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
- if(dropoff_turf)
- toLaunch.reverse_dropoff_turf = dropoff_turf
- else
- toLaunch.reverse_dropoff_turf = 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
var/shippingLane = GLOB.areas_by_type[/area/centcom/supplypod/supplypod_temp_holding]
toLaunch.forceMove(shippingLane)
if (launchClone) //We arent launching the actual items from the bay, rather we are creating clones and launching those
if(launchRandomItem)
- var/atom/movable/O = pick_n_take(launchList)
- DuplicateObject(O).forceMove(toLaunch) //Duplicate a single atom/movable from launchList and forceMove it into the supplypod
+ var/launch_candidate = pick_n_take(launchList)
+ 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
- for (var/atom/movable/O in launchList)
- DuplicateObject(O).forceMove(toLaunch) //Duplicate each atom/movable in launchList and forceMove them into the supplypod
+ for (var/launch_candidate in launchList)
+ 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
if(launchRandomItem)
- var/atom/movable/O = pick_n_take(launchList)
- O.forceMove(toLaunch) //and forceMove any atom/moveable into the supplypod
+ var/atom/random_item = pick_n_take(launchList)
+ 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
- for (var/atom/movable/O 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
- new /obj/effect/pod_landingzone(A, toLaunch) //Then, create the DPTarget effect, which will eventually forceMove the temp_pod to it's location
+ for (var/thing_to_launch in launchList) //If we aren't cloning the objects, just go through the launchList
+ if (isnull(thing_to_launch))
+ 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/pod_landingzone(target_turf, toLaunch) //Then, create the DPTarget effect, which will eventually forceMove the temp_pod to it's location
if (launchClone)
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
/datum/centcom_podlauncher/proc/updateSelector() //Ensures that the selector effect will showcase the next item if needed
- if (launchChoice == 1 && length(acceptableTurfs) && !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
+ 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 : 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
index = 1
selector.forceMove(acceptableTurfs[index]) //forceMove the selector to the next turf in the ordered acceptableTurfs list
@@ -643,11 +766,15 @@
qdel(O)
for (var/mob/M in bay.GetAllContents())
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
- updateCursor(FALSE, FALSE) //Make sure our moues cursor resets to default. False means we are not in launch mode
- qdel(temp_pod) //Delete the temp_pod
- qdel(selector) //Delete the selector effect
+ updateCursor(TRUE) //Make sure our moues cursor resets to default. False means we are not in launch mode
+ QDEL_NULL(temp_pod) //Delete the temp_pod
+ QDEL_NULL(selector) //Delete the selector effect
+ QDEL_NULL(indicator)
. = ..()
/datum/centcom_podlauncher/proc/supplypod_punish_log(list/whoDyin)
@@ -657,17 +784,88 @@
for (var/mob/living/M in whoDyin)
whomString += "[key_name(M)], "
- var/delayString = temp_pod.landingDelay == initial(temp_pod.landingDelay) ? "" : " Delay=[temp_pod.landingDelay*0.1]s"
- var/damageString = temp_pod.damage == 0 ? "" : " Dmg=[temp_pod.damage]"
- var/explosionString = ""
- 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] towards [whomString] [delayString][damageString][explosionString]"
+ var/msg = "launched [podString] towards [whomString]"
message_admins("[key_name_admin(usr)] [msg] in [ADMIN_VERBOSEJMP(specificTarget)].")
if (length(whoDyin))
for (var/mob/living/M in whoDyin)
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.effectShrapnel = dataToLoad["effectShrapnel"] //If true, creates a cloud of shrapnel of a decided type and magnitude on landing
+ temp_pod.shrapnel_type = text2path(dataToLoad["shrapnelType"])
+ temp_pod.shrapnel_magnitude = dataToLoad["shrapnelMagnitude"]
+ 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
diff --git a/code/modules/cargo/supplypod.dm b/code/modules/cargo/supplypod.dm
index 139a0975a96..f354cd4f1d8 100644
--- a/code/modules/cargo/supplypod.dm
+++ b/code/modules/cargo/supplypod.dm
@@ -1,5 +1,3 @@
-#define SUPPLYPOD_X_OFFSET -16
-
//The "pod_landingzone" 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-------------------------------------//
/obj/structure/closet/supplypod
@@ -37,9 +35,9 @@
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/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/turf/reverse_dropoff_turf //Turf that the reverse pod will drop off it's newly-acquired cargo to
+ var/list/reverse_dropoff_coords //Turf that the reverse pod will drop off it's newly-acquired cargo to
var/fallDuration = 4
var/fallingSoundLength = 11
var/fallingSound = 'sound/weapons/mortar_long_whistle.ogg'//Admin sound to play before the pod lands
@@ -59,6 +57,8 @@
var/effectShrapnel = FALSE
var/shrapnel_type = /obj/projectile/bullet/shrapnel
var/shrapnel_magnitude = 3
+ var/list/reverseOptionList = list("Mobs"=FALSE,"Objects"=FALSE,"Anchored"=FALSE,"Underfloor"=FALSE,"Wallmounted"=FALSE,"Floors"=FALSE,"Walls"=FALSE)
+ var/list/turfs_in_cargo = list()
/obj/structure/closet/supplypod/bluespacepod
style = STYLE_BLUESPACE
@@ -82,44 +82,47 @@
landingDelay = 20 //Very speedy!
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
-/obj/structure/closet/supplypod/Initialize(turf/spawn_location)
+/obj/structure/closet/supplypod/Initialize(var/customStyle = FALSE)
. = ..()
- if (!spawn_location)
+ if (!loc)
var/shippingLane = GLOB.areas_by_type[/area/centcom/supplypod/supplypod_temp_holding] //temporary holder for supplypods mid-transit
forceMove(shippingLane)
- 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 (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()
. = ..()
- reverse_dropoff_turf = pick(GLOB.holdingfacility)
+ 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, duringInit = FALSE) //Used to give the sprite an icon state, name, and description. Should only be called once
- 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.
- setStyle(STYLE_CENTCOM) //We make sure to not check this during initialize() so the standard supplypod works correctly.
- return
+/obj/structure/closet/supplypod/proc/setStyle(chosenStyle) //Used to give the sprite an icon state, name, and description.
style = chosenStyle
- var/base = POD_STYLES[chosenStyle][POD_BASE] //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.
+ 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 = POD_STYLES[chosenStyle][POD_DECAL]
- rubble_type = POD_STYLES[chosenStyle][POD_RUBBLE_TYPE]
+ 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 = POD_STYLES[chosenStyle][POD_NAME]
- desc = POD_STYLES[chosenStyle][POD_DESC]
- door = "[base]_door"
+ 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 (POD_STYLES[style][POD_SHAPE] == POD_SHAPE_NORML)
- icon_state = POD_STYLES[style][POD_BASE] + "_reverse"
+ 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 (POD_STYLES[style][POD_SHAPE] == POD_SHAPE_NORML)
- icon_state = POD_STYLES[style][POD_BASE]
+ 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()
@@ -138,11 +141,19 @@
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)
@@ -151,8 +162,12 @@
masked_decal.Blend(door_masker, ICON_ADD)
. += masked_decal
else //If we're closed
- if (POD_STYLES[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
+ 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
@@ -185,7 +200,7 @@
/obj/structure/closet/supplypod/proc/handleReturnAfterDeparting(atom/movable/holder = src)
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
+ pod_flags &= ~FIRST_SOUNDS //Make it so we play sounds now
if (!effectQuiet && style != STYLE_SEETHROUGH)
audible_message("The pod hisses, closing and launching itself away from the station.", "The ground vibrates, and you hear the sound of engines firing.")
stay_after_drop = FALSE
@@ -193,62 +208,70 @@
holder.alpha = initial(holder.alpha)
var/shippingLane = GLOB.areas_by_type[/area/centcom/supplypod/supplypod_temp_holding]
forceMove(shippingLane) //Move to the centcom-z-level until the pod_landingzone says we can drop back down again
- if (!reverse_dropoff_turf) //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.
- reverse_dropoff_turf = locate(/area/centcom/supplypod/loading/one) in GLOB.sortedAreas
+ 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()
- new /obj/effect/pod_landingzone(reverse_dropoff_turf, src)
+ var/turf/return_turf = locate(reverse_dropoff_coords[1], reverse_dropoff_coords[2], reverse_dropoff_coords[3])
+ new /obj/effect/pod_landingzone(return_turf, src)
/obj/structure/closet/supplypod/proc/preOpen() //Called before the open_pod() proc. Handles anything that occurs right as the pod lands.
- var/turf/T = get_turf(src)
+ var/turf/turf_underneath = get_turf(src)
var/list/B = explosionSize //Mostly because B is more readable than explosionSize :p
density = TRUE //Density is originally false so the pod doesn't block anything while it's still falling through the air
- if (landingSound)
- playsound(get_turf(src), landingSound, soundVolume, FALSE, FALSE)
AddComponent(/datum/component/pellet_cloud, projectile_type=shrapnel_type, magnitude=shrapnel_magnitude)
if(effectShrapnel)
SEND_SIGNAL(src, COMSIG_SUPPLYPOD_LANDED)
- for (var/mob/living/M in T)
- if (effectLimb && iscarbon(M)) //If effectLimb is true (which means we pop limbs off when we hit people):
- var/mob/living/carbon/CM = M
- for (var/obj/item/bodypart/bodypart in CM.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!
- if (bodypart.dismemberable)
- bodypart.dismember() //Using the power of flextape i've sawed this man's limb in half!
- break
- if (effectOrgans && iscarbon(M)) //effectOrgans means remove every organ in our mob
- var/mob/living/carbon/CM = M
- for(var/X in CM.internal_organs)
- var/destination = get_edge_target_turf(T, pick(GLOB.alldirs)) //Pick a random direction to toss them in
- var/obj/item/organ/O = X
- O.Remove(CM) //Note that this isn't the same proc as for lists
- O.forceMove(T) //Move the organ outta the body
- O.throw_at(destination, 2, 3) //Thow the organ at a random tile 3 spots away
- sleep(1)
- 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)
+ for (var/mob/living/target_living in turf_underneath)
+ if (iscarbon(target_living)) //If effectLimb is true (which means we pop limbs off when we hit people):
+ if (effectLimb)
+ var/mob/living/carbon/carbon_target_mob = target_living
+ 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
+ if(bodypart.body_part != HEAD && bodypart.body_part != CHEST)//we dont want to kill him, just teach em a lesson!
+ if (bodypart.dismemberable)
+ bodypart.dismember() //Using the power of flextape i've sawed this man's limb in half!
+ break
+ if (effectOrgans) //effectOrgans means remove every organ in our mob
+ var/mob/living/carbon/carbon_target_mob = target_living
+ for(var/organ in carbon_target_mob.internal_organs)
+ var/destination = get_edge_target_turf(turf_underneath, pick(GLOB.alldirs)) //Pick a random direction to toss them in
+ var/obj/item/organ/organ_to_yeet = organ
+ organ_to_yeet.Remove(carbon_target_mob) //Note that this isn't the same proc as for lists
+ organ_to_yeet.forceMove(turf_underneath) //Move the organ outta the body
+ organ_to_yeet.throw_at(destination, 2, 3) //Thow the organ at a random tile 3 spots away
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
- M.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
- M.adjustBruteLoss(damage)
+ target_living.adjustBruteLoss(5000) //THATS A LOT OF DAMAGE (called just in case gib() doesnt work on em)
+ if (!QDELETED(target_living))
+ 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]
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
- 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, TRUE)
+ 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 && !(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 ? 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
opened = TRUE //We set opened to TRUE to avoid spending time trying to open (due to being deleted) during the Destroy() proc
qdel(src)
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
- 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.
moveToNullspace()
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
@@ -263,17 +286,19 @@
if (opened) //This is to ensure we don't open something that has already been opened
return
holder.setOpened()
- var/turf/T = get_turf(holder) //Get the turf of whoever's contents we're talking about
- var/mob/M
+ var/turf/turf_underneath = get_turf(holder) //Get the turf of whoever's contents we're talking about
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
- if (M.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)
+ var/mob/holder_as_mob = holder
+ 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
if (openingSound)
playsound(get_turf(holder), openingSound, soundVolume, FALSE, FALSE) //Special admin sound to play
- for (var/atom/movable/O in holder.contents) //Go through the contents of the holder
- O.forceMove(T) //move everything from the contents of the holder to the turf of the holder
- if (!effectQuiet && !openingSound && style != STYLE_SEETHROUGH) //If we aren't being quiet, play the default pod open sound
+ for (var/turf_type in turfs_in_cargo)
+ turf_underneath.PlaceOnTop(turf_type)
+ for (var/cargo in contents)
+ var/atom/movable/movable_cargo = cargo
+ movable_cargo.forceMove(turf_underneath)
+ 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, TRUE, -3)
if (broken) //If the pod is opening because it's been destroyed, we end here
return
@@ -283,9 +308,11 @@
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
- addtimer(CALLBACK(src, .proc/startExitSequence, 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/startExitSequence(atom/movable/holder)
+ if (leavingSound)
+ 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
close(holder)
else if (bluespace) //If we're a bluespace pod, then delete ourselves (along with our holder, if a seperate holder exists)
@@ -300,47 +327,80 @@
if (!holder)
return
take_contents(holder)
- playsound(holder, close_sound, close_sound_volume, TRUE, -3)
+ playsound(holder, close_sound, soundVolume*0.75, TRUE, -3)
holder.setClosed()
- addtimer(CALLBACK(src, .proc/preReturn, holder), 10) //Start to leave a second after closing for cinematic effect
+ addtimer(CALLBACK(src, .proc/preReturn, holder), departureDelay * 0.2) //Start to leave a bit after closing for cinematic effect
/obj/structure/closet/supplypod/take_contents(atom/movable/holder)
- var/atom/L = holder.drop_location()
- for(var/atom/movable/AM in L)
- if(AM != src && !insert(AM, holder)) // Can't insert that
+ 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)
-/obj/structure/closet/supplypod/insert(atom/movable/AM, atom/movable/holder)
- if(insertion_allowed(AM))
- AM.forceMove(holder)
+/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/insertion_allowed(atom/movable/AM)
- if(ismob(AM))
- if(!isliving(AM)) //let's not put ghosts or camera mobs inside closets...
+/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
- var/mob/living/L = AM
- if(L.anchored || L.incorporeal_move)
+ if(!isliving(to_insert)) //let's not put ghosts or camera mobs inside
return FALSE
- L.stop_pulling()
+ 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(AM))
- if((!allow_dense && AM.density) || AM.anchored || AM.has_buckled_mobs())
+ else if(isobj(to_insert))
+ var/obj/obj_to_insert = to_insert
+ if(istype(obj_to_insert, /obj/structure/closet/supplypod))
return FALSE
- else if(isitem(AM) && !HAS_TRAIT(AM, TRAIT_NODROP))
+ if(istype(obj_to_insert, /obj/effect/supplypod_smoke))
+ return FALSE
+ if(istype(obj_to_insert, /obj/effect/pod_landingzone))
+ return FALSE
+ if(istype(obj_to_insert, /obj/effect/supplypod_rubble))
+ return FALSE
+ if((obj_to_insert.comp_lookup && obj_to_insert.comp_lookup[COMSIG_OBJ_HIDE]) && reverseOptionList["Underfloor"])
return TRUE
- else if(!allow_objects && !istype(AM, /obj/effect/dummy/chameleon))
+ else if ((obj_to_insert.comp_lookup && obj_to_insert.comp_lookup[COMSIG_OBJ_HIDE]) && !reverseOptionList["Underfloor"])
return FALSE
- else
+ 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)
- if (leavingSound)
- playsound(get_turf(holder), leavingSound, soundVolume, FALSE, FALSE)
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
@@ -384,10 +444,10 @@
update_icon()
/obj/structure/closet/supplypod/proc/addGlow()
- if (POD_STYLES[style][POD_SHAPE] != POD_SHAPE_NORML)
+ if (GLOB.podstyles[style][POD_SHAPE] != POD_SHAPE_NORML)
return
glow_effect = new(src)
- glow_effect.icon_state = "pod_glow_" + POD_STYLES[style][POD_GLOW]
+ glow_effect.icon_state = "pod_glow_" + GLOB.podstyles[style][POD_GLOW]
vis_contents += glow_effect
glow_effect.layer = GASFIRE_LAYER
@@ -508,18 +568,18 @@
else if (istype(single_order, /atom/movable))
var/atom/movable/O = single_order
O.forceMove(pod)
- for (var/mob/living/M in pod) //If there are any mobs in the supplypod, we want to set their view to the pod_landingzone. This is so that they can see where they are about to land
- M.reset_perspective(src)
+ 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 pod_landingzone. This is so that they can see where they are about to land
+ mob_in_pod.reset_perspective(src)
if(pod.effectStun) //If effectStun is true, stun any mobs caught on this pod_landingzone until the pod gets a chance to hit them
- for (var/mob/living/M in get_turf(src))
- M.Stun(pod.landingDelay+10, ignore_canstun = TRUE)//you ain't goin nowhere, kid.
+ for (var/mob/living/target_living in get_turf(src))
+ target_living.Stun(pod.landingDelay+10, ignore_canstun = TRUE)//you ain't goin nowhere, kid.
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.fallingSound = 'sound/weapons/mortar_whistle.ogg'
var/soundStartTime = pod.landingDelay - pod.fallingSoundLength + pod.fallDuration
if (soundStartTime < 0)
soundStartTime = 1
- if (!pod.effectQuiet && (pod.pod_flags & FIRST_SOUNDS))
+ if (!pod.effectQuiet && !(pod.pod_flags & FIRST_SOUNDS))
addtimer(CALLBACK(src, .proc/playFallingSound), soundStartTime)
addtimer(CALLBACK(src, .proc/beginLaunch, pod.effectCircle), pod.landingDelay)
@@ -550,25 +610,25 @@
if (pod.style == STYLE_INVISIBLE || pod.style == STYLE_SEETHROUGH)
return
for ( var/i in 1 to length(smoke_effects))
- var/obj/effect/supplypod_smoke/S = new (drop_location())
+ var/obj/effect/supplypod_smoke/smoke_part = new (drop_location())
if (i == 1)
- S.layer = FLY_LAYER
- S.icon_state = "smoke_start"
- S.transform = matrix().Turn(rotation)
- smoke_effects[i] = S
- S.pixel_x = sin(rotation)*32 * i
- S.pixel_y = abs(cos(rotation))*32 * i
- S.filters += filter(type = "blur", size = 4)
+ 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(S, /obj/effect/supplypod_smoke/.proc/drawSelf, i), time, TIMER_CLIENT_TIME) //Go onto the last step after a very short falling animation
- QDEL_IN(S, pod.fallDuration + 35)
+ 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/pod_landingzone/proc/drawSmoke()
if (pod.style == STYLE_INVISIBLE || pod.style == STYLE_SEETHROUGH)
return
- for (var/obj/effect/supplypod_smoke/S in smoke_effects)
- animate(S, alpha = 0, time = 20, flags = ANIMATION_PARALLEL)
- animate(S.filters[1], size = 6, time = 15, easing = CUBIC_EASING|EASE_OUT, flags = ANIMATION_PARALLEL)
+ 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/pod_landingzone/proc/endLaunch()
pod.tryMakeRubble(drop_location())
@@ -587,5 +647,3 @@
icon_state = "cargodisk"
inhand_icon_state = "card-id"
w_class = WEIGHT_CLASS_SMALL
-
-#undef SUPPLYPOD_X_OFFSET
diff --git a/icons/obj/supplypods.dmi b/icons/obj/supplypods.dmi
index 4dfc996f45b..156d3cea245 100644
Binary files a/icons/obj/supplypods.dmi and b/icons/obj/supplypods.dmi differ
diff --git a/icons/obj/supplypods_32x32.dmi b/icons/obj/supplypods_32x32.dmi
index a7607f716f7..855132f6494 100644
Binary files a/icons/obj/supplypods_32x32.dmi and b/icons/obj/supplypods_32x32.dmi differ
diff --git a/tgui/package.json b/tgui/package.json
index c4f08bde369..8ff10fac306 100644
--- a/tgui/package.json
+++ b/tgui/package.json
@@ -6,31 +6,31 @@
"packages/*"
],
"dependencies": {
- "@babel/core": "^7.6.2",
- "@babel/plugin-transform-jscript": "^7.2.0",
- "@babel/preset-env": "^7.6.2",
+ "@babel/core": "^7.11.1",
+ "@babel/plugin-transform-jscript": "^7.10.4",
+ "@babel/preset-env": "^7.11.0",
"babel-eslint": "^10.0.3",
- "babel-loader": "^8.0.6",
- "babel-plugin-inferno": "^6.1.0",
+ "babel-loader": "^8.1.0",
+ "babel-plugin-inferno": "^6.1.1",
"babel-plugin-transform-remove-console": "^6.9.4",
"common": "workspace:*",
- "css-loader": "^3.2.0",
+ "css-loader": "^4.2.1",
"cssnano": "^4.1.10",
"eslint": "^7.4.0",
"eslint-plugin-react": "^7.17.0",
- "extract-css-chunks-webpack-plugin": "^4.6.0",
+ "extract-css-chunks-webpack-plugin": "^4.7.5",
"file-loader": "^6.0.0",
"inferno": "^7.4.2",
"optimize-css-assets-webpack-plugin": "^5.0.3",
"pnp-webpack-plugin": "^1.6.4",
- "sass": "^1.22.12",
- "sass-loader": "^9.0.2",
- "style-loader": "^1.0.0",
- "terser-webpack-plugin": "^3.0.6",
+ "sass": "^1.26.10",
+ "sass-loader": "^9.0.3",
+ "style-loader": "^1.2.1",
+ "terser-webpack-plugin": "^4.1.0",
"url-loader": "^4.1.0",
- "webpack": "^4.40.2",
- "webpack-build-notifier": "^2.0.0",
- "webpack-bundle-analyzer": "^3.5.1",
+ "webpack": "^4.44.1",
+ "webpack-build-notifier": "^2.1.0",
+ "webpack-bundle-analyzer": "^3.8.0",
"webpack-cli": "^3.3.12"
}
}
diff --git a/tgui/packages/tgui-dev-server/package.json b/tgui/packages/tgui-dev-server/package.json
index f1ab17a2643..25ddccb371a 100644
--- a/tgui/packages/tgui-dev-server/package.json
+++ b/tgui/packages/tgui-dev-server/package.json
@@ -6,10 +6,10 @@
"axios": "^0.19.2",
"common": "workspace:*",
"esm": "^3.2.25",
- "glob": "^7.1.4",
+ "glob": "^7.1.6",
"source-map": "^0.7.3",
- "stacktrace-parser": "^0.1.7",
- "webpack": "^4.40.2",
- "ws": "^7.1.2"
+ "stacktrace-parser": "^0.1.10",
+ "webpack": "^4.44.1",
+ "ws": "^7.3.1"
}
}
diff --git a/tgui/packages/tgui/components/Button.js b/tgui/packages/tgui/components/Button.js
index e1ace064283..5f61be93909 100644
--- a/tgui/packages/tgui/components/Button.js
+++ b/tgui/packages/tgui/components/Button.js
@@ -26,6 +26,7 @@ export const Button = props => {
selected,
tooltip,
tooltipPosition,
+ tooltipOverrideLong,
ellipsis,
compact,
circular,
@@ -97,6 +98,7 @@ export const Button = props => {
{tooltip && (
- Reverse Drop-off Location: - {data.dropoff_turf ? data.dropoff_turf : 'None'} -
-- [Enable Reverse Mode for this feature] -
-'+(n?e:Y(e,!0))+"\n":""+(n?e:Y(e,!0))+"\n"},t.blockquote=function(e){return"\n"+e+"\n"},t.html=function(e){return e},t.heading=function(e,t,n,r){return this.options.headerIds?"
"+e+"
\n"},t.table=function(e,t){return t&&(t=""+t+""),""+e+""},t.br=function(){return this.options.xhtml?""+Q(u.message+"",!0)+"";throw u}}return ne.options=ne.setOptions=function(e){return X(ne.defaults,e),ee(ne.defaults),ne},ne.getDefaults=J,ne.defaults=te,ne.use=function(e){var t=X({},e);if(e.renderer&&function(){var n=ne.defaults.renderer||new U,r=function(t){var r=n[t];n[t]=function(){for(var o=arguments.length,i=new Array(o),a=0;a
'+(n?e:ee(e,!0))+"\n":""+(n?e:ee(e,!0))+"\n"}return e}(),t.blockquote=function(){function e(e){return"\n"+e+"\n"}return e}(),t.html=function(){function e(e){return e}return e}(),t.heading=function(){function e(e,t,n,r){return this.options.headerIds?"
"+e+"
\n"}return e}(),t.table=function(){function e(e,t){return t&&(t=""+t+""),""+e+""}return e}(),t.br=function(){function e(){return this.options.xhtml?""+se(c.message+"",!0)+"";throw c}}return pe.options=pe.setOptions=function(e){return ue(pe.defaults,e),fe(pe.defaults),pe},pe.getDefaults=le,pe.defaults=de,pe.use=function(e){var t=ue({},e);if(e.renderer&&function(){var n=pe.defaults.renderer||new te,r=function(){function t(t){var r=n[t];n[t]=function(){for(var o=arguments.length,i=new Array(o),a=0;a