From e1088c328883ca3c45e539a9b4976b7faad65616 Mon Sep 17 00:00:00 2001 From: Aylong Date: Fri, 16 Feb 2024 15:15:38 +0200 Subject: [PATCH 1/5] Map edit. Revert later --- maps/example/example-1.dmm | 36 +++++++++++++++--------------------- maps/using.dm | 4 ++-- 2 files changed, 17 insertions(+), 23 deletions(-) diff --git a/maps/example/example-1.dmm b/maps/example/example-1.dmm index b72409dfaa0df..5b9c244c8dd56 100644 --- a/maps/example/example-1.dmm +++ b/maps/example/example-1.dmm @@ -160,7 +160,6 @@ id_tag = "example_shuttle_port"; pixel_x = -28 }, -/obj/shuttle_landmark/lower_level, /turf/simulated/floor/plating, /area/shuttle/escape) "C" = ( @@ -211,12 +210,8 @@ /obj/machinery/tele_pad, /turf/simulated/floor/tiled, /area/constructionsite) -"L" = ( -/obj/machinery/telecomms/server/map_preset/example, -/turf/simulated/floor/tiled, -/area/constructionsite) "M" = ( -/obj/machinery/telecomms/bus/map_preset/example, +/obj/machinery/door/airlock/atmos, /turf/simulated/floor/tiled, /area/constructionsite) "N" = ( @@ -230,8 +225,7 @@ /turf/simulated/floor/tiled, /area/constructionsite) "P" = ( -/obj/machinery/light, -/obj/machinery/telecomms/processor/map_preset/example, +/obj/item/modular_computer/pda/captain, /turf/simulated/floor/tiled, /area/constructionsite) "Q" = ( @@ -250,15 +244,15 @@ /turf/simulated/floor/tiled, /area/constructionsite) "U" = ( -/obj/machinery/telecomms/broadcaster/map_preset/example, +/obj/item/storage/belt/general/full, /turf/simulated/floor/tiled, /area/constructionsite) "V" = ( -/obj/machinery/telecomms/hub/map_preset/example, +/obj/machinery/vending/cigarette, /turf/simulated/floor/tiled, /area/constructionsite) "W" = ( -/obj/machinery/telecomms/receiver/map_preset/example, +/obj/item/modular_computer/laptop, /turf/simulated/floor/tiled, /area/constructionsite) @@ -1062,7 +1056,7 @@ w c c c -c +U c c c @@ -1096,9 +1090,9 @@ w c c g +P c -c -c +M c c Q @@ -1130,12 +1124,12 @@ w c c c +W c +V c c c -c -W b a a @@ -1169,7 +1163,7 @@ c c c c -L +c b a a @@ -1203,7 +1197,7 @@ c c c c -P +k b a a @@ -1237,7 +1231,7 @@ r c c c -M +c b a a @@ -1271,7 +1265,7 @@ c c c c -V +c b a a @@ -1305,7 +1299,7 @@ c f c c -U +c b a a diff --git a/maps/using.dm b/maps/using.dm index 926908a4411b1..45a4c74d1cea2 100644 --- a/maps/using.dm +++ b/maps/using.dm @@ -1,5 +1,5 @@ //Easily change which map to build by uncommenting ONE below. -//#include "example\map.dm" +#include "example\map.dm" //#include "torch\map.dm" -#include "sierra\map.dm" +//#include "sierra\map.dm" From 485d32860a9a1585388372e9031952874675181a Mon Sep 17 00:00:00 2001 From: Aylong Date: Fri, 16 Feb 2024 16:26:56 +0200 Subject: [PATCH 2/5] Orbit --- baystation12.dme | 2 + code/_onclick/hud/_defines.dm | 8 + code/_onclick/hud/ghost.dm | 51 ++++++ code/modules/mob/new_player/new_player.dm | 1 + code/modules/mob/observer/following.dm | 15 +- code/modules/mob/observer/ghost/ghost.dm | 39 ++++- code/modules/mob/observer/ghost/orbit.dm | 75 +++++++++ icons/mob/screen_ghost.dmi | Bin 0 -> 25658 bytes tgui/packages/tgui/interfaces/Orbit.js | 188 ++++++++++++++++++++++ tgui/public/tgui.bundle.js | 156 +++++++++--------- 10 files changed, 442 insertions(+), 93 deletions(-) create mode 100644 code/_onclick/hud/ghost.dm create mode 100644 code/modules/mob/observer/ghost/orbit.dm create mode 100644 icons/mob/screen_ghost.dmi create mode 100644 tgui/packages/tgui/interfaces/Orbit.js diff --git a/baystation12.dme b/baystation12.dme index a89cc9e7b11e2..dbc6f3b365434 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -165,6 +165,7 @@ #include "code\_onclick\hud\action.dm" #include "code\_onclick\hud\animal.dm" #include "code\_onclick\hud\fullscreen.dm" +#include "code\_onclick\hud\ghost.dm" #include "code\_onclick\hud\global_hud.dm" #include "code\_onclick\hud\gun_mode.dm" #include "code\_onclick\hud\hud.dm" @@ -2456,6 +2457,7 @@ #include "code\modules\mob\observer\ghost\ghost.dm" #include "code\modules\mob\observer\ghost\login.dm" #include "code\modules\mob\observer\ghost\logout.dm" +#include "code\modules\mob\observer\ghost\orbit.dm" #include "code\modules\mob\observer\ghost\say.dm" #include "code\modules\mob\observer\virtual\_constants.dm" #include "code\modules\mob\observer\virtual\base.dm" diff --git a/code/_onclick/hud/_defines.dm b/code/_onclick/hud/_defines.dm index 37276fa1baa25..981f4e62279b4 100644 --- a/code/_onclick/hud/_defines.dm +++ b/code/_onclick/hud/_defines.dm @@ -132,3 +132,11 @@ #define ui_pai_light "NORTH,WEST+3:6" #define ui_pai_rest "NORTH,WEST+4:6" +// Ghosts +#define ui_ghost_toggle_darkness "SOUTH:6,CENTER-3:16" +#define ui_ghost_jumptomob "SOUTH:6,CENTER-2:16" +#define ui_ghost_orbit "SOUTH:6,CENTER-1:16" +#define ui_ghost_reenter_corpse "SOUTH:6,CENTER:16" +#define ui_ghost_teleport "SOUTH:6,CENTER+1:16" +#define ui_ghost_mafia "SOUTH:6,CENTER+2:16" +#define ui_ghost_spawners_menu "SOUTH:6,CENTER-4:16" diff --git a/code/_onclick/hud/ghost.dm b/code/_onclick/hud/ghost.dm new file mode 100644 index 0000000000000..49965009fb797 --- /dev/null +++ b/code/_onclick/hud/ghost.dm @@ -0,0 +1,51 @@ +/obj/screen/ghost + icon = 'icons/mob/screen_ghost.dmi' + +/obj/screen/ghost/MouseExited(location, control, params) + . = ..() + flick(icon_state + "_anim", src) + +/obj/screen/ghost/jumptomob + name = "Jump to mob" + icon_state = "jumptomob" + screen_loc = ui_ghost_jumptomob + +/obj/screen/ghost/jumptomob/Click() + var/mob/observer/ghost/G = usr + G.jumptomob() + +/obj/screen/ghost/orbit + name = "Orbit" + icon_state = "orbit" + screen_loc = ui_ghost_orbit + +/obj/screen/ghost/orbit/Click() + var/mob/observer/ghost/G = usr + G.follow() + +/obj/screen/ghost/reenter_corpse + name = "Reenter corpse" + icon_state = "reenter_corpse" + screen_loc = ui_ghost_reenter_corpse + +/obj/screen/ghost/reenter_corpse/Click() + var/mob/observer/ghost/G = usr + G.reenter_corpse() + +/obj/screen/ghost/teleport + name = "Teleport" + icon_state = "teleport" + screen_loc = ui_ghost_teleport + +/obj/screen/ghost/teleport/Click() + var/mob/observer/ghost/G = usr + G.dead_tele() + +/obj/screen/ghost/toggle_darkness + name = "Toggle Darkness" + icon_state = "toggle_darkness" + screen_loc = ui_ghost_toggle_darkness + +/obj/screen/ghost/toggle_darkness/Click() + var/mob/observer/ghost/G = usr + G.toggle_darkness() diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm index 6f4a4fccb1c1c..7aa5c9eb8c976 100644 --- a/code/modules/mob/new_player/new_player.dm +++ b/code/modules/mob/new_player/new_player.dm @@ -178,6 +178,7 @@ if(!client.holder && !config.antag_hud_allowed) // For new ghosts we remove the verb from even showing up if it's not allowed. observer.verbs -= /mob/observer/ghost/verb/toggle_antagHUD // Poor guys, don't know what they are missing! observer.key = key + observer.add_ghost_buttons() qdel(src) return 1 diff --git a/code/modules/mob/observer/following.dm b/code/modules/mob/observer/following.dm index d1a300cd0746f..1ade3539ef1e2 100644 --- a/code/modules/mob/observer/following.dm +++ b/code/modules/mob/observer/following.dm @@ -13,13 +13,14 @@ GLOB.dir_set_event.unregister(following, src) following = null -/mob/observer/proc/start_following(atom/a) - stop_following() - following = a - GLOB.destroyed_event.register(a, src, PROC_REF(stop_following)) - GLOB.moved_event.register(a, src, PROC_REF(keep_following)) - GLOB.dir_set_event.register(a, src, TYPE_PROC_REF(/atom, recursive_dir_set)) - keep_following(new_loc = get_turf(following)) +/mob/observer/proc/start_following(atom/Atom) + if(!istype(Atom, /obj/screen)) + stop_following() + following = Atom + GLOB.destroyed_event.register(Atom, src, PROC_REF(stop_following)) + GLOB.moved_event.register(Atom, src, PROC_REF(keep_following)) + GLOB.dir_set_event.register(Atom, src, TYPE_PROC_REF(/atom, recursive_dir_set)) + keep_following(new_loc = get_turf(following)) /mob/observer/proc/keep_following(atom/movable/moving_instance, atom/old_loc, atom/new_loc) forceMove(get_turf(new_loc)) diff --git a/code/modules/mob/observer/ghost/ghost.dm b/code/modules/mob/observer/ghost/ghost.dm index 0b750c23a9618..ed563085a8273 100644 --- a/code/modules/mob/observer/ghost/ghost.dm +++ b/code/modules/mob/observer/ghost/ghost.dm @@ -20,6 +20,7 @@ var/global/list/image/ghost_sightless_images = list() //this is a list of images var/is_manifest = FALSE var/next_visibility_toggle = 0 var/can_reenter_corpse + var/thearea var/bootime = 0 var/started_as_observer //This variable is set to 1 when you enter the game as an observer. //If you died in the game and are a ghost - this will remain as null. @@ -154,6 +155,7 @@ Works together with spawning an observer, noted above. ghost.key = key if(ghost.client && !ghost.client.holder && !config.antag_hud_allowed) // For new ghosts we remove the verb from even showing up if it's not allowed. ghost.verbs -= /mob/observer/ghost/verb/toggle_antagHUD // Poor guys, don't know what they are missing! + ghost.add_ghost_buttons() return ghost /mob/observer/ghostize() // Do not create ghosts of ghosts. @@ -222,7 +224,16 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp mind.current.reload_fullscreen() if(!admin_ghosted) announce_ghost_joinleave(mind, 0, "They now occupy their body again.") - return 1 + return TRUE + +/mob/observer/ghost/proc/jumptomob() + var/mob/M = tgui_input_list(usr, "К кому вы хотите телепортироваться?", "Выбрать моба", SSmobs.mob_list) + log_and_message_admins("jumped to [key_name(M)]") + var/turf/T = get_turf(M) + if(T && isturf(T)) + jumpTo(T) + else + to_chat(usr, "Этот моб не находится в игровом мире.") /mob/observer/ghost/verb/toggle_medHUD() set category = "Ghost" @@ -231,10 +242,10 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp if(!client) return if(medHUD) - medHUD = 0 + medHUD = FALSE to_chat(src, SPAN_NOTICE("Medical HUD Disabled")) else - medHUD = 1 + medHUD = TRUE to_chat(src, SPAN_NOTICE("Medical HUD Enabled")) /mob/observer/ghost/verb/toggle_antagHUD() @@ -264,11 +275,12 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp M.antagHUD = 1 to_chat(src, SPAN_NOTICE("AntagHUD Enabled")) -/mob/observer/ghost/verb/dead_tele(A in area_repository.get_areas_by_z_level()) +/mob/observer/ghost/verb/dead_tele() set category = "Ghost" set name = "Teleport" set desc= "Teleport to a location" + var/A = tgui_input_list(usr, "Выберите зону.", "Выбор зоны", area_repository.get_areas_by_z_level()) var/area/thearea = area_repository.get_areas_by_z_level()[A] if(!thearea) to_chat(src, "No area available.") @@ -291,13 +303,12 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp ghost_to_turf(T) else to_chat(src, SPAN_WARNING("Invalid coordinates.")) -/mob/observer/ghost/verb/follow(datum/follow_holder/fh in get_follow_targets()) +/mob/observer/ghost/verb/follow() set category = "Ghost" set name = "Follow" set desc = "Follow and haunt a mob." - if(!fh.show_entry()) return - start_following(fh.followed_instance) + GLOB.orbit_menu.show(src) /mob/observer/ghost/proc/ghost_to_turf(turf/target_turf) if(check_is_holy_turf(target_turf)) @@ -315,7 +326,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp to_chat(src, SPAN_NOTICE("No longer following \the [following]")) ..() -/mob/observer/ghost/keep_following(atom/movable/am, old_loc, new_loc) +/mob/observer/ghost/keep_following(obj/AM, old_loc, new_loc) var/turf/T = get_turf(new_loc) if(check_is_holy_turf(T)) to_chat(src, SPAN_WARNING("You cannot follow something standing on holy grounds!")) @@ -586,3 +597,15 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp M.respawned_time = world.time M.key = key log_and_message_admins("has respawned.", M) + +/mob/observer/ghost/proc/add_ghost_buttons() + var/jumptomob = new /obj/screen/ghost/jumptomob() + var/orbit = new /obj/screen/ghost/orbit() + var/reenter_corpse = new /obj/screen/ghost/reenter_corpse() + var/teleport = new /obj/screen/ghost/teleport() + var/toggle_darkness = new /obj/screen/ghost/toggle_darkness() + client.screen.Add(jumptomob) + client.screen.Add(orbit) + client.screen.Add(reenter_corpse) + client.screen.Add(teleport) + client.screen.Add(toggle_darkness) diff --git a/code/modules/mob/observer/ghost/orbit.dm b/code/modules/mob/observer/ghost/orbit.dm new file mode 100644 index 0000000000000..bc42ced531cdc --- /dev/null +++ b/code/modules/mob/observer/ghost/orbit.dm @@ -0,0 +1,75 @@ +GLOBAL_DATUM_INIT(orbit_menu, /datum/orbit_menu, new) + +/datum/orbit_menu + +/datum/orbit_menu/tgui_state(mob/user) + return GLOB.tgui_observer_state + +/datum/orbit_menu/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Orbit") + ui.set_autoupdate(FALSE) + ui.open() + +/datum/orbit_menu/tgui_act(action, list/params) + if(..()) + return + . = TRUE + + switch(action) + if("orbit") + var/datum/follow_holder/follow_holder = locate(params["ref"]) in get_follow_targets() + var/atom/movable/atom = follow_holder.followed_instance + var/mob/observer/ghost/ghost = usr + if(atom != usr) + ghost.start_following(atom) + return TRUE + if("refresh") + update_tgui_static_data() + return TRUE + +/datum/orbit_menu/tgui_static_data(mob/user) + var/list/data = list() + data["misc"] = list() + data["ghosts"] = list() + data["dead"] = list() + data["npcs"] = list() + data["alive"] = list() + data["antagonists"] = list() + for(var/datum/follow_holder/follow_holder in get_follow_targets()) + var/atom/movable/follow_instance = follow_holder.followed_instance + var/list/serialized = list() + serialized["name"] = follow_instance.name + serialized["ref"] = "[REF(follow_holder)]" + + if(!istype(follow_instance, /mob)) + data["misc"] += list(serialized) + continue + var/mob/mob = follow_instance + if(isobserver(mob)) + data["ghosts"] += list(serialized) + continue + + if(mob.stat == DEAD) + data["dead"] += list(serialized) + continue + + if(mob.mind == null) + data["npcs"] += list(serialized) + continue + + data["alive"] += list(serialized) + + var/mob/observer/ghost/observer = user + if(observer.antagHUD && mob.get_antag_info()) + var/antag_serialized = serialized.Copy() + for(var/antag_category in mob.get_antag_info()) + antag_serialized["antag"] += list(antag_category) + data["antagonists"] += list(antag_serialized) + + return data + +/// Shows the UI to the specified user. +/datum/orbit_menu/proc/show(mob/user) + tgui_interact(user) diff --git a/icons/mob/screen_ghost.dmi b/icons/mob/screen_ghost.dmi new file mode 100644 index 0000000000000000000000000000000000000000..5b04c71d1b63d8238ccfb521389e1a8cc06d958e GIT binary patch literal 25658 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 + createSearch(searchText, (thing) => thing.name); + +const compareString = (a, b) => (a < b ? -1 : a > b); + +const compareNumberedText = (a, b) => { + const aName = a.name; + const bName = b.name; + + if (!aName || !bName) { + return 0; + } + + // Check if aName and bName are the same except for a number at the end + // e.g. Medibot (2) and Medibot (3) + const aNumberMatch = aName.match(PATTERN_NUMBER); + const bNumberMatch = bName.match(PATTERN_NUMBER); + + if ( + aNumberMatch && + bNumberMatch && + aName.replace(PATTERN_NUMBER, '') === bName.replace(PATTERN_NUMBER, '') + ) { + const aNumber = parseInt(aNumberMatch[1], 10); + const bNumber = parseInt(bNumberMatch[1], 10); + + return aNumber - bNumber; + } + + return compareString(aName, bName); +}; + +const BasicSection = (props, context) => { + const { act } = useBackend(context); + const { searchText, source, title } = props; + const things = source.filter(searchFor(searchText)); + things.sort(compareNumberedText); + return ( + source.length > 0 && ( +
+ {things.map((thing) => ( +
+ ) + ); +}; + +const OrbitedButton = (props, context) => { + const { act } = useBackend(context); + const { color, thing } = props; + + return ( +