diff --git a/code/game/objects/structures/droppod.dm b/code/game/objects/structures/droppod.dm
new file mode 100644
index 0000000000..3afef81584
--- /dev/null
+++ b/code/game/objects/structures/droppod.dm
@@ -0,0 +1,133 @@
+/obj/structure/drop_pod
+ name = "drop pod"
+ desc = "Standard Commonwealth drop pod. There are file marks where the serial number should be, however."
+ icon = 'icons/obj/structures/droppod.dmi'
+ icon_state = "pod"
+ density = TRUE
+ anchored = TRUE
+
+ var/polite = FALSE // polite ones don't violently murder everything
+ var/finished = FALSE
+ var/datum/gas_mixture/pod_air/air
+
+/obj/structure/drop_pod/polite
+ polite = TRUE
+
+/obj/structure/drop_pod/New(newloc, atom/movable/A, auto_open = FALSE)
+ ..()
+ if(A)
+ A.forceMove(src) // helo
+ podfall(auto_open)
+ air = new(1000)
+
+/obj/structure/drop_pod/proc/podfall(auto_open)
+ set waitfor = FALSE // sleeping in new otherwise
+
+ var/turf/T = get_turf(src)
+ if(!T)
+ warning("Drop pod wasn't spawned on a turf")
+ return
+
+ moveToNullspace()
+ icon_state = "[initial(icon_state)]_falling"
+
+ // Show warning on 3x3 area centred on our drop spot
+ var/list/turfs_nearby = block(get_step(T, SOUTHWEST), get_step(T, NORTHEAST))
+ for(var/turf/TN in turfs_nearby)
+ new /obj/effect/temporary_effect/shuttle_landing(TN)
+
+ // Wait a minute
+ sleep(4 SECONDS)
+
+ // Wheeeeeee
+ pixel_z = 300
+ alpha = 0
+ forceMove(T)
+ playsound(T, 'sound/effects/droppod.ogg', 50, 1)
+ animate(src, pixel_z = 0, time = 3 SECONDS, easing = SINE_EASING|EASE_OUT)
+ animate(src, alpha = 255, time = 1 SECOND, flags = ANIMATION_PARALLEL)
+ filters += filter(type="drop_shadow", x=-64, y=100, size=10)
+ animate(filters[filters.len], x=0, y=0, size=0, time=3 SECONDS, flags=ANIMATION_PARALLEL, easing=SINE_EASING|EASE_OUT)
+ sleep(2 SECONDS)
+ new /obj/effect/effect/smoke(T)
+ sleep(1 SECOND)
+ filters = null
+
+ // CRONCH
+ playsound(src, 'sound/effects/meteorimpact.ogg', 50, 1)
+ if(!polite)
+ for(var/atom/A in view(1, T))
+ if(A == src)
+ continue
+ A.ex_act(2)
+ else
+ for(var/turf/simulated/floor/F in view(1, T))
+ F.burn_tile(900)
+
+ for(var/obj/O in T)
+ if(O == src)
+ continue
+ qdel(O)
+ for(var/mob/living/L in T)
+ L.gib()
+
+ // Landed! Simmer
+ icon_state = "[initial(icon_state)]"
+
+ if(auto_open)
+ sleep(2 SECONDS)
+ open_pod()
+ visible_message("\The [src] pops open!")
+ else
+ for(var/mob/M in src)
+ to_chat(M, "You've landed! Open the hatch if you think it's safe! \The [src] has enough air to last for a while...")
+
+/obj/structure/drop_pod/proc/open_pod()
+ if(finished)
+ return
+ icon_state = "[initial(icon_state)]_open"
+ playsound(src, 'sound/effects/magnetclamp.ogg', 100, 1)
+ for(var/atom/movable/AM in src)
+ AM.forceMove(loc)
+ AM.set_dir(SOUTH) // cus
+ qdel_null(air)
+ finished = TRUE
+
+/obj/structure/drop_pod/attack_hand(mob/living/user)
+ if(istype(user) && (Adjacent(user) || (user in src)) && !user.incapacitated())
+ if(finished)
+ to_chat(user, "Nothing left to do with it now. Maybe you can break it down into materials.")
+ else
+ open_pod()
+ user.visible_message("[user] opens \the [src]!","You open \the [src]!")
+
+/obj/structure/drop_pod/attackby(obj/item/O, mob/user)
+ if(O.is_wrench())
+ if(finished)
+ to_chat(user, "You start breaking down \the [src].")
+ if(do_after(user, 10 SECONDS, src, exclusive = TASK_ALL_EXCLUSIVE))
+ var/obj/item/stack/S = new /obj/item/stack/material/plasteel(loc)
+ S.amount = 10
+ qdel(src)
+ playsound(src, O.usesound, 50, 1)
+ else
+ to_chat(user, "\The [src] hasn't been opened yet. Do that first.")
+ return ..()
+
+/obj/structure/drop_pod/return_air()
+ return return_air_for_internal_lifeform()
+
+/obj/structure/drop_pod/return_air_for_internal_lifeform()
+ return air
+
+// This is about 0.896m^3 of atmosphere, which is enough to last for quite a while.
+/datum/gas_mixture/pod_air
+ volume = 2500
+ temperature = 293.150
+ total_moles = 104
+
+/datum/gas_mixture/pod_air/New()
+ . = ..()
+ gas = list(
+ "oxygen" = 21,
+ "nitrogen" = 79)
diff --git a/code/modules/admin/admin_verb_lists.dm b/code/modules/admin/admin_verb_lists.dm
index aa37774d35..9fbabaafd5 100644
--- a/code/modules/admin/admin_verb_lists.dm
+++ b/code/modules/admin/admin_verb_lists.dm
@@ -141,6 +141,7 @@ var/list/admin_verbs_fun = list(
/datum/admins/proc/call_drop_pod,
/client/proc/smite,
/client/proc/admin_lightning_strike,
+ /client/proc/cmd_admin_droppod_deploy
)
var/list/admin_verbs_spawn = list(
@@ -149,6 +150,7 @@ var/list/admin_verbs_spawn = list(
/datum/admins/proc/check_custom_items,
/datum/admins/proc/spawn_plant,
/datum/admins/proc/spawn_atom, //allows us to spawn instances,
+ /client/proc/cmd_admin_droppod_spawn,
/client/proc/respawn_character,
/client/proc/virus2_editor,
/client/proc/spawn_chemdisp_cartridge,
diff --git a/code/modules/admin/admin_verb_lists_vr.dm b/code/modules/admin/admin_verb_lists_vr.dm
index 597c229478..0cc95ff8c6 100644
--- a/code/modules/admin/admin_verb_lists_vr.dm
+++ b/code/modules/admin/admin_verb_lists_vr.dm
@@ -155,7 +155,8 @@ var/list/admin_verbs_fun = list(
/client/proc/smite,
/client/proc/smite_vr, //VOREStation Add,
/client/proc/admin_lightning_strike,
- /client/proc/resize //VOREStation Add,
+ /client/proc/resize, //VOREStation Add,
+ /client/proc/cmd_admin_droppod_deploy
)
var/list/admin_verbs_spawn = list(
@@ -164,6 +165,7 @@ var/list/admin_verbs_spawn = list(
/datum/admins/proc/check_custom_items,
/datum/admins/proc/spawn_plant,
/datum/admins/proc/spawn_atom, //allows us to spawn instances,
+ /client/proc/cmd_admin_droppod_spawn,
/client/proc/respawn_character,
/client/proc/spawn_character_mob, //VOREStation Add,
/client/proc/virus2_editor,
diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm
index a581d3fb82..c41116686c 100644
--- a/code/modules/admin/verbs/randomverbs.dm
+++ b/code/modules/admin/verbs/randomverbs.dm
@@ -390,7 +390,7 @@ Traitors and the like can also be revived with the previous role mostly intact.
if(location == "Cancel" || !location)
return
- var/announce = tgui_alert(src,"Announce as if they had just arrived?", "Announce", list("Yes", "No", "Cancel"))
+ var/announce = tgui_alert(src,"Announce as if they had just arrived?", "Announce", list("No", "Yes", "Cancel"))
if(announce == "Cancel")
return
else if(announce == "Yes") //Too bad buttons can't just have 1/0 values and different display strings
@@ -420,7 +420,7 @@ Traitors and the like can also be revived with the previous role mostly intact.
else if(samejob == USELESS_JOB) //VOREStation Edit - Visitor not Assistant
charjob = USELESS_JOB //VOREStation Edit - Visitor not Assistant
else
- records = tgui_alert(src,"No data core entry detected. Would you like add them to the manifest, and sec/med/HR records?","Records",list("Yes","No","Cancel"))
+ records = tgui_alert(src,"No data core entry detected. Would you like add them to the manifest, and sec/med/HR records?","Records",list("No", "Yes", "Cancel"))
if(records == "Cancel")
return
if(records == "Yes")
@@ -457,17 +457,19 @@ Traitors and the like can also be revived with the previous role mostly intact.
var/mob/living/carbon/human/new_character
var/spawnloc
- var/sparks
+ var/showy
//Where did you want to spawn them?
switch(location)
if("Right Here") //Spawn them on your turf
spawnloc = get_turf(src.mob)
- sparks = tgui_alert(src,"Sparks like they teleported in?", "Showy", list("Yes", "No", "Cancel"))
- if(sparks == "Cancel")
+ showy = tgui_alert(src,"Showy entrance?", "Showy", list("No", "Telesparks", "Drop Pod", "Cancel"))
+ if(showy == "Cancel")
return
- if(sparks == "No")
- sparks = FALSE
+ if(showy == "Drop Pod")
+ showy = tgui_alert(src,"Destructive drop pods cause damage in a 3x3 and may break turfs. Polite drop pods lightly damage the turfs but won't break through.", "Drop Pod", list("Polite", "Destructive", "Cancel")) // reusing var
+ if(showy == "Cancel")
+ return
if("Arrivals") //Spawn them at a latejoin spawnpoint
spawnloc = pick(latejoin)
@@ -483,7 +485,7 @@ Traitors and the like can also be revived with the previous role mostly intact.
new_character = new(spawnloc)
- if(sparks)
+ if(showy == "Telesparks")
anim(spawnloc,new_character,'icons/mob/mob.dmi',,"phasein",,new_character.dir)
playsound(spawnloc, "sparks", 50, 1)
var/datum/effect/effect/system/spark_spread/spk = new(new_character)
@@ -546,9 +548,21 @@ Traitors and the like can also be revived with the previous role mostly intact.
log_admin("[admin] has spawned [player_key]'s character [new_character.real_name].")
message_admins("[admin] has spawned [player_key]'s character [new_character.real_name].", 1)
- to_chat(new_character, "You have been fully spawned. Enjoy the game.")
+
feedback_add_details("admin_verb","RSPCH") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
+
+ // Drop pods
+ if(showy == "Polite")
+ var/turf/T = get_turf(new_character)
+ new /obj/structure/drop_pod/polite(T, new_character)
+ to_chat(new_character, "Please wait for your arrival.")
+ else if(showy == "Destructive")
+ var/turf/T = get_turf(new_character)
+ new /obj/structure/drop_pod(T, new_character)
+ to_chat(new_character, "Please wait for your arrival.")
+ else
+ to_chat(new_character, "You have been fully spawned. Enjoy the game.")
return new_character
@@ -1057,3 +1071,73 @@ Traitors and the like can also be revived with the previous role mostly intact.
else if(isliving(M))
M.ghostize()
qdel(M) //Bye
+
+/client/proc/cmd_admin_droppod_spawn(var/object as text)
+ set name = "Drop Pod Spawn"
+ set desc = "Spawn a new atom/movable in a drop pod where you are."
+ set category = "Fun"
+
+ if(!check_rights(R_SPAWN))
+ return
+
+ var/list/types = typesof(/atom/movable)
+ var/list/matches = new()
+
+ for(var/path in types)
+ if(findtext("[path]", object))
+ matches += path
+
+ if(!matches.len)
+ return
+
+ var/chosen
+ if(matches.len==1)
+ chosen = matches[1]
+ else
+ chosen = tgui_input_list(usr, "Select an atom type", "Spawn Atom", matches)
+ if(!chosen)
+ return
+
+ var/podtype = tgui_alert(src,"Destructive drop pods cause damage in a 3x3 and may break turfs. Polite drop pods lightly damage the turfs but won't break through.", "Drop Pod", list("Polite", "Destructive", "Cancel"))
+ if(podtype == "Cancel")
+ return
+ var/autoopen = tgui_alert(src,"Should the pod open automatically?", "Drop Pod", list("Yes", "No", "Cancel"))
+ if(autoopen == "Cancel")
+ return
+ switch(podtype)
+ if("Destructive")
+ var/atom/movable/AM = new chosen(usr.loc)
+ new /obj/structure/drop_pod(get_turf(usr), AM, autoopen == "Yes" ? TRUE : FALSE)
+ if("Polite")
+ var/atom/movable/AM = new chosen(usr.loc)
+ new /obj/structure/drop_pod/polite(get_turf(usr), AM, autoopen == "Yes" ? TRUE : FALSE)
+
+ feedback_add_details("admin_verb","DPS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
+
+/client/proc/cmd_admin_droppod_deploy()
+ set name = "Drop Pod Deploy"
+ set desc = "Drop an existing mob where you are in a drop pod."
+ set category = "Fun"
+
+ if(!check_rights(R_SPAWN))
+ return
+
+ var/mob/living/L = tgui_input_list(usr, "Select the mob to drop:", "Drop!", living_mob_list)
+ if(!L)
+ return
+
+ var/podtype = tgui_alert(src,"Destructive drop pods cause damage in a 3x3 and may break turfs. Polite drop pods lightly damage the turfs but won't break through.", "Drop Pod", list("Polite", "Destructive", "Cancel"))
+ if(podtype == "Cancel")
+ return
+ var/autoopen = tgui_alert(src,"Should the pod open automatically?", "Drop Pod", list("Yes", "No", "Cancel"))
+ if(autoopen == "Cancel")
+ return
+ if(!L || QDELETED(L))
+ return
+ switch(podtype)
+ if("Destructive")
+ new /obj/structure/drop_pod(get_turf(usr), L, autoopen == "Yes" ? TRUE : FALSE)
+ if("Polite")
+ new /obj/structure/drop_pod/polite(get_turf(usr), L, autoopen == "Yes" ? TRUE : FALSE)
+
+ feedback_add_details("admin_verb","DPD") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
\ No newline at end of file
diff --git a/icons/obj/structures/droppod.dmi b/icons/obj/structures/droppod.dmi
new file mode 100644
index 0000000000..9254c59eeb
Binary files /dev/null and b/icons/obj/structures/droppod.dmi differ
diff --git a/sound/effects/droppod.ogg b/sound/effects/droppod.ogg
new file mode 100644
index 0000000000..161216ff2b
Binary files /dev/null and b/sound/effects/droppod.ogg differ
diff --git a/vorestation.dme b/vorestation.dme
index ea3fdd0832..f1e7b2d321 100644
--- a/vorestation.dme
+++ b/vorestation.dme
@@ -1440,6 +1440,7 @@
#include "code\game\objects\structures\displaycase.dm"
#include "code\game\objects\structures\dogbed.dm"
#include "code\game\objects\structures\door_assembly.dm"
+#include "code\game\objects\structures\droppod.dm"
#include "code\game\objects\structures\electricchair.dm"
#include "code\game\objects\structures\extinguisher.dm"
#include "code\game\objects\structures\fence.dm"