diff --git a/code/game/area/areas/shuttles.dm b/code/game/area/areas/shuttles.dm
index 1d17c4afc7f..36ce50c4792 100644
--- a/code/game/area/areas/shuttles.dm
+++ b/code/game/area/areas/shuttles.dm
@@ -94,7 +94,6 @@
name = "Abandoned Ship Pod"
////////////////////////////Single-area shuttles////////////////////////////
-
/area/shuttle/transit
name = "Hyperspace"
desc = "Weeeeee"
@@ -212,3 +211,65 @@
/area/shuttle/caravan/freighter3
name = "Tiny Freighter"
+
+// ----------- Arena Shuttle
+/area/shuttle_arena
+ name = "arena"
+ has_gravity = STANDARD_GRAVITY
+ requires_power = FALSE
+
+/obj/effect/forcefield/arena_shuttle
+ name = "portal"
+ timeleft = 0
+ var/list/warp_points = list()
+
+/obj/effect/forcefield/arena_shuttle/Initialize()
+ . = ..()
+ for(var/obj/effect/landmark/shuttle_arena_safe/exit in GLOB.landmarks_list)
+ warp_points += exit
+
+/obj/effect/forcefield/arena_shuttle/Bumped(atom/movable/AM)
+ if(!isliving(AM))
+ return
+
+ var/mob/living/L = AM
+ if(L.pulling && istype(L.pulling, /obj/item/bodypart/head))
+ to_chat(L, "Your offering is accepted. You may pass.", confidential = TRUE)
+ qdel(L.pulling)
+ var/turf/LA = get_turf(pick(warp_points))
+ L.forceMove(LA)
+ L.hallucination = 0
+ to_chat(L, "The battle is won. Your bloodlust subsides.", confidential = TRUE)
+ for(var/obj/item/chainsaw/doomslayer/chainsaw in L)
+ qdel(chainsaw)
+ var/obj/item/skeleton_key/key = new(L)
+ L.put_in_hands(key)
+ else
+ to_chat(L, "You are not yet worthy of passing. Drag a severed head to the barrier to be allowed entry to the hall of champions.", confidential = TRUE)
+
+/obj/effect/landmark/shuttle_arena_safe
+ name = "hall of champions"
+ desc = "For the winners."
+
+/obj/effect/landmark/shuttle_arena_entrance
+ name = "\proper the arena"
+ desc = "A lava filled battlefield."
+
+/obj/effect/forcefield/arena_shuttle_entrance
+ name = "portal"
+ timeleft = 0
+ var/list/warp_points = list()
+
+/obj/effect/forcefield/arena_shuttle_entrance/Bumped(atom/movable/AM)
+ if(!isliving(AM))
+ return
+
+ if(!warp_points.len)
+ for(var/obj/effect/landmark/shuttle_arena_entrance/S in GLOB.landmarks_list)
+ warp_points |= S
+
+ var/obj/effect/landmark/LA = pick(warp_points)
+ var/mob/living/M = AM
+ M.forceMove(get_turf(LA))
+ to_chat(M, "You're trapped in a deadly arena! To escape, you'll need to drag a severed head to the escape portals.", confidential = TRUE)
+ M.apply_status_effect(STATUS_EFFECT_MAYHEM)
diff --git a/code/modules/admin/fun_balloon.dm b/code/modules/admin/fun_balloon.dm
index 6a2330d2e09..577d89380b8 100644
--- a/code/modules/admin/fun_balloon.dm
+++ b/code/modules/admin/fun_balloon.dm
@@ -5,6 +5,7 @@
icon_state = "syndballoon"
anchored = TRUE
var/popped = FALSE
+ var/pop_sound_effect = 'sound/items/party_horn.ogg'
/obj/effect/fun_balloon/Initialize()
. = ..()
@@ -28,24 +29,55 @@
/obj/effect/fun_balloon/proc/pop()
visible_message("[src] pops!")
- playsound(get_turf(src), 'sound/items/party_horn.ogg', 50, TRUE, -1)
+ playsound(get_turf(src), pop_sound_effect, 50, TRUE, -1)
qdel(src)
-//ATTACK GHOST IGNORING PARENT RETURN VALUE
-/obj/effect/fun_balloon/attack_ghost(mob/user)
- if(!user.client || !user.client.holder || popped)
- return
- var/confirmation = alert("Pop [src]?","Fun Balloon","Yes","No")
- if(confirmation == "Yes" && !popped)
- popped = TRUE
- effect()
- pop()
-
+// ----------- Sentience Balloon
/obj/effect/fun_balloon/sentience
name = "sentience fun balloon"
desc = "When this pops, things are gonna get more aware around here."
- var/effect_range = 3
var/group_name = "a bunch of giant spiders"
+ var/effect_range = 3
+
+/obj/effect/fun_balloon/sentience/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "SentienceFunBalloon", name)
+ ui.open()
+
+/obj/effect/fun_balloon/sentience/ui_data(mob/user)
+ var/list/data = list()
+ data["group_name"] = group_name
+ data["range"] = effect_range
+ return data
+
+/obj/effect/fun_balloon/sentience/ui_state(mob/user)
+ return GLOB.admin_state
+
+/obj/effect/fun_balloon/sentience/ui_status(mob/user)
+ if(popped)
+ return UI_CLOSE
+ return ..()
+
+/obj/effect/fun_balloon/sentience/ui_act(action, list/params)
+ . = ..()
+ if(.)
+ return
+
+ switch(action)
+ if("group_name")
+ group_name = params["updated_name"]
+
+ if("effect_range")
+ effect_range = params["updated_range"]
+
+ if("pop")
+ if(!popped)
+ popped = TRUE
+ effect()
+ pop()
+
+ return TRUE
/obj/effect/fun_balloon/sentience/effect()
var/list/bodies = list()
@@ -64,6 +96,7 @@
body.key = C.key
new /obj/effect/temp_visual/gravpush(get_turf(body))
+// ----------- Emergency Shuttle Balloon
/obj/effect/fun_balloon/sentience/emergency_shuttle
name = "shuttle sentience fun balloon"
var/trigger_time = 60
@@ -73,6 +106,7 @@
if(SSshuttle.emergency && (SSshuttle.emergency.timeLeft() <= trigger_time) && (SSshuttle.emergency.mode == SHUTTLE_CALL))
. = TRUE
+// ----------- Scatter Balloon
/obj/effect/fun_balloon/scatter
name = "scatter fun balloon"
desc = "When this pops, you're not going to be around here anymore."
@@ -85,6 +119,8 @@
M.forceMove(T)
to_chat(M, "Pop!", confidential = TRUE)
+// ----------- Station Crash
+// Can't think of anywhere better to put it right now
/obj/effect/station_crash
name = "station crash"
desc = "With no survivors!"
@@ -113,68 +149,3 @@
desc = "Absolute Destruction. Will crash the shuttle far into the station."
min_crash_strength = 15
max_crash_strength = 25
-
-
-//Arena
-
-/obj/effect/forcefield/arena_shuttle
- name = "portal"
- timeleft = 0
- var/list/warp_points = list()
-
-/obj/effect/forcefield/arena_shuttle/Initialize()
- . = ..()
- for(var/obj/effect/landmark/shuttle_arena_safe/exit in GLOB.landmarks_list)
- warp_points += exit
-
-/obj/effect/forcefield/arena_shuttle/Bumped(atom/movable/AM)
- if(!isliving(AM))
- return
-
- var/mob/living/L = AM
- if(L.pulling && istype(L.pulling, /obj/item/bodypart/head))
- to_chat(L, "Your offering is accepted. You may pass.", confidential = TRUE)
- qdel(L.pulling)
- var/turf/LA = get_turf(pick(warp_points))
- L.forceMove(LA)
- L.hallucination = 0
- to_chat(L, "The battle is won. Your bloodlust subsides.", confidential = TRUE)
- for(var/obj/item/chainsaw/doomslayer/chainsaw in L)
- qdel(chainsaw)
- var/obj/item/skeleton_key/key = new(L)
- L.put_in_hands(key)
- else
- to_chat(L, "You are not yet worthy of passing. Drag a severed head to the barrier to be allowed entry to the hall of champions.", confidential = TRUE)
-
-/obj/effect/landmark/shuttle_arena_safe
- name = "hall of champions"
- desc = "For the winners."
-
-/obj/effect/landmark/shuttle_arena_entrance
- name = "\proper the arena"
- desc = "A lava filled battlefield."
-
-
-/obj/effect/forcefield/arena_shuttle_entrance
- name = "portal"
- timeleft = 0
- var/list/warp_points = list()
-
-/obj/effect/forcefield/arena_shuttle_entrance/Bumped(atom/movable/AM)
- if(!isliving(AM))
- return
-
- if(!warp_points.len)
- for(var/obj/effect/landmark/shuttle_arena_entrance/S in GLOB.landmarks_list)
- warp_points |= S
-
- var/obj/effect/landmark/LA = pick(warp_points)
- var/mob/living/M = AM
- M.forceMove(get_turf(LA))
- to_chat(M, "You're trapped in a deadly arena! To escape, you'll need to drag a severed head to the escape portals.", confidential = TRUE)
- M.apply_status_effect(STATUS_EFFECT_MAYHEM)
-
-/area/shuttle_arena
- name = "arena"
- has_gravity = STANDARD_GRAVITY
- requires_power = FALSE
diff --git a/tgui/packages/tgui/interfaces/SentienceFunBalloon.js b/tgui/packages/tgui/interfaces/SentienceFunBalloon.js
new file mode 100644
index 00000000000..8a9ddc23995
--- /dev/null
+++ b/tgui/packages/tgui/interfaces/SentienceFunBalloon.js
@@ -0,0 +1,52 @@
+import { useBackend } from "../backend";
+import { Button, NumberInput, Section, Stack, Input, LabeledList } from '../components';
+import { Window } from "../layouts";
+
+export const SentienceFunBalloon = (props, context) => {
+ const { act, data } = useBackend(context);
+ const { group_name, range } = data;
+ return (
+
+
+
+
+
+
+
+
+ );
+};