mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-08-24 13:30:42 +01:00
Adds the Odyssey gamemode. (#18972)
https://forums.aurorastation.org/topic/20198-mission-briefing-auroras-gamemode-revolution To-do: - [x] Finish storyteller verbs. - [x] Storyteller landmarks. - [x] Proper storyteller spawning. Right now the gamemode system is happy with just picking one storyteller and no actors. - [x] Antagonist whitelists code. - [x] Adding the Storyteller whitelist. - [x] Mission map loading code. - [x] Map in a bunch of missions. - [ ] Storyteller adminhelps. --------- Co-authored-by: Matt Atlas <liermattia@gmail.com> Co-authored-by: DreamySkrell <>
This commit is contained in:
co-authored by
Matt Atlas
DreamySkrell <>
parent
e1f5de6298
commit
1da20ad33f
@@ -3,27 +3,27 @@
|
||||
// A mob that the AI controls to look around the station with.
|
||||
// It streams chunks as it moves around, which will show it what the AI can and cannot see.
|
||||
|
||||
/mob/abstract/eye/cameranet
|
||||
/mob/abstract/eye/freelook
|
||||
// Generic version of the AI eye without the AI-specific handling, for things like the Camera MIU mask.
|
||||
name = "Inactive Camera Eye"
|
||||
name_suffix = "Camera Eye"
|
||||
living_eye = FALSE
|
||||
|
||||
/mob/abstract/eye/cameranet/Initialize()
|
||||
/mob/abstract/eye/freelook/Initialize()
|
||||
. = ..()
|
||||
visualnet = GLOB.cameranet
|
||||
|
||||
/mob/abstract/eye/aiEye
|
||||
/mob/abstract/eye/freelook/aiEye
|
||||
name = "Inactive AI Eye"
|
||||
name_suffix = "AI Eye"
|
||||
icon_state = "AI-eye"
|
||||
living_eye = FALSE
|
||||
|
||||
/mob/abstract/eye/aiEye/Initialize()
|
||||
/mob/abstract/eye/freelook/aiEye/Initialize()
|
||||
. = ..()
|
||||
visualnet = GLOB.cameranet
|
||||
|
||||
/mob/abstract/eye/aiEye/setLoc(var/T, var/cancel_tracking = 1)
|
||||
/mob/abstract/eye/freelook/aiEye/setLoc(var/T, var/cancel_tracking = 1)
|
||||
. = ..()
|
||||
if(. && isAI(owner))
|
||||
var/mob/living/silicon/ai/ai = owner
|
||||
@@ -55,7 +55,7 @@
|
||||
|
||||
/mob/living/silicon/ai/proc/create_eyeobj(var/newloc = get_turf(src))
|
||||
if(eyeobj) destroy_eyeobj()
|
||||
eyeobj = new /mob/abstract/eye/aiEye(newloc)
|
||||
eyeobj = new /mob/abstract/eye/freelook/aiEye(newloc)
|
||||
eyeobj.possess(src)
|
||||
|
||||
/atom/proc/move_camera_by_click()
|
||||
|
||||
@@ -91,11 +91,13 @@
|
||||
return
|
||||
to_chat(owner, SPAN_NOTICE("You scrub [A.name] off the blueprints."))
|
||||
log_and_message_admins("deleted area [A.name] via station blueprints.")
|
||||
var/background_area = /area/space
|
||||
var/background_area = world.area
|
||||
var/obj/effect/overmap/visitable/sector/sector = GLOB.map_sectors["[A.z]"]
|
||||
var/obj/effect/overmap/visitable/sector/exoplanet/exoplanet = sector
|
||||
if(istype(exoplanet))
|
||||
background_area = exoplanet.planetary_area
|
||||
if(SSodyssey.scenario && (GET_Z(owner) in SSodyssey.scenario_zlevels))
|
||||
background_area = SSodyssey.scenario.base_area
|
||||
for(var/turf/T in A.contents)
|
||||
ChangeArea(T, background_area)
|
||||
if(!locate(/turf) in A)
|
||||
@@ -309,11 +311,13 @@
|
||||
return
|
||||
to_chat(owner, SPAN_NOTICE("You scrub [A.name] off the blueprints."))
|
||||
log_and_message_admins("deleted area [A.name] from [our_shuttle.name] via shuttle blueprints.")
|
||||
var/background_area = /area/space
|
||||
var/background_area = world.area
|
||||
var/obj/effect/overmap/visitable/sector/sector = GLOB.map_sectors["[A.z]"]
|
||||
var/obj/effect/overmap/visitable/sector/exoplanet/exoplanet = sector
|
||||
if(istype(exoplanet))
|
||||
background_area = exoplanet.planetary_area
|
||||
if(SSodyssey.scenario && (GET_Z(owner) in SSodyssey.scenario_zlevels))
|
||||
background_area = SSodyssey.scenario.base_area
|
||||
for(var/turf/T in A.contents)
|
||||
ChangeArea(T, background_area)
|
||||
if(!(locate(/turf) in A))
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
// CAMERA CHUNK
|
||||
//
|
||||
// A 16x16 grid of the map with a list of turfs that can be seen, are visible and are dimmed.
|
||||
// Allows the Eye to stream these chunks and know what it can and cannot see.
|
||||
|
||||
#define UPDATE_BUFFER 25 // 2.5 seconds
|
||||
|
||||
// CHUNK
|
||||
@@ -109,13 +114,13 @@
|
||||
|
||||
// Visualnet adds and removes eyes.
|
||||
|
||||
/datum/chunk/proc/add_eye(mob/abstract/eye/eye)
|
||||
/datum/chunk/proc/add_eye(mob/abstract/eye/freelook/eye)
|
||||
seenby += eye
|
||||
eye.visibleChunks += src
|
||||
if(eye.owner && eye.owner.client)
|
||||
eye.owner.client.images += obscured
|
||||
|
||||
/datum/chunk/proc/remove_eye(mob/abstract/eye/eye)
|
||||
/datum/chunk/proc/remove_eye(mob/abstract/eye/freelook/eye)
|
||||
seenby -= eye
|
||||
eye.visibleChunks -= src
|
||||
if(eye.owner && eye.owner.client)
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
if(click_handler_type)
|
||||
owner.PushClickHandler(click_handler_type)
|
||||
setLoc(owner)
|
||||
visualnet.update_eye_chunks(src, TRUE)
|
||||
visualnet?.update_eye_chunks(src, TRUE)
|
||||
|
||||
/mob/abstract/eye/proc/release(var/mob/user)
|
||||
if(owner != user || !user)
|
||||
@@ -125,7 +125,7 @@
|
||||
if(owner_follows_eye)
|
||||
owner.forceMove(loc)
|
||||
|
||||
visualnet.update_eye_chunks(src)
|
||||
visualnet?.update_eye_chunks(src)
|
||||
return TRUE
|
||||
|
||||
/mob/abstract/eye/proc/getLoc()
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
|
||||
// Updates what the eye can see. It is recommended you use this when the eye moves or it's location is set.
|
||||
|
||||
/datum/visualnet/proc/update_eye_chunks(mob/abstract/eye/eye, var/full_update = FALSE)
|
||||
/datum/visualnet/proc/update_eye_chunks(mob/abstract/eye/freelook/eye, var/full_update = FALSE)
|
||||
. = list()
|
||||
var/turf/T = get_turf(eye)
|
||||
if(T)
|
||||
@@ -74,7 +74,7 @@
|
||||
var/datum/chunk/c = chunk
|
||||
c.add_eye(eye)
|
||||
|
||||
/datum/visualnet/proc/remove_eye(mob/abstract/eye/eye)
|
||||
/datum/visualnet/proc/remove_eye(mob/abstract/eye/freelook/eye)
|
||||
for(var/chunk in eye.visibleChunks)
|
||||
var/datum/chunk/c = chunk
|
||||
c.remove_eye(eye)
|
||||
|
||||
@@ -0,0 +1,196 @@
|
||||
/mob/abstract/ghost
|
||||
stat = DEAD
|
||||
layer = OBSERVER_LAYER
|
||||
plane = OBSERVER_PLANE
|
||||
|
||||
/// Toggle darkness.
|
||||
var/see_darkness = FALSE
|
||||
/// Is the ghost able to see things humans can't?
|
||||
var/ghostvision = FALSE
|
||||
/// This variable generally controls whether a ghost has restrictions on where it can go or not (ex. if the ghost can bypass holy places).
|
||||
var/has_ghost_restrictions = TRUE
|
||||
/// If the ghost has antagHUD.
|
||||
var/antagHUD = 0
|
||||
/// Necessary for seeing wires.
|
||||
var/obj/item/device/multitool/ghost_multitool
|
||||
/// The POI we're orbiting.
|
||||
var/orbiting_ref
|
||||
|
||||
/mob/abstract/ghost/Initialize(mapload)
|
||||
. = ..()
|
||||
sight |= SEE_TURFS | SEE_MOBS | SEE_OBJS | SEE_SELF
|
||||
see_invisible = SEE_INVISIBLE_OBSERVER
|
||||
add_verb(src, /mob/abstract/ghost/proc/dead_tele)
|
||||
ghost_multitool = new(src)
|
||||
|
||||
/mob/abstract/ghost/Destroy()
|
||||
QDEL_NULL(ghost_multitool)
|
||||
return ..()
|
||||
|
||||
/mob/abstract/ghost/Topic(href, href_list)
|
||||
if (href_list["track"])
|
||||
if(istype(href_list["track"],/mob))
|
||||
var/mob/target = locate(href_list["track"]) in GLOB.mob_list
|
||||
if(target)
|
||||
ManualFollow(target)
|
||||
else
|
||||
var/atom/target = locate(href_list["track"])
|
||||
if(istype(target))
|
||||
ManualFollow(target)
|
||||
|
||||
/mob/abstract/ghost/ClickOn(var/atom/A, var/params)
|
||||
if(!canClick())
|
||||
return
|
||||
setClickCooldown(4)
|
||||
// You are responsible for checking config.ghost_interaction when you override this function
|
||||
// Not all of them require checking, see below
|
||||
A.attack_ghost(src)
|
||||
|
||||
/mob/abstract/ghost/Post_Incorpmove()
|
||||
orbiting?.end_orbit(src)
|
||||
|
||||
/mob/abstract/ghost/orbit()
|
||||
set_dir(2)//reset dir so the right directional sprites show up
|
||||
return ..()
|
||||
|
||||
/mob/abstract/ghost/verb/toggle_darkness()
|
||||
set name = "Toggle Darkness"
|
||||
set category = "Ghost"
|
||||
|
||||
see_darkness = !see_darkness
|
||||
update_sight()
|
||||
|
||||
/mob/abstract/ghost/proc/update_sight()
|
||||
set_sight(sight|SEE_TURFS|SEE_MOBS|SEE_OBJS)
|
||||
set_see_invisible(SEE_INVISIBLE_LEVEL_TWO)
|
||||
|
||||
if (!see_darkness)
|
||||
set_see_invisible(SEE_INVISIBLE_NOLIGHTING)
|
||||
else
|
||||
set_see_invisible(ghostvision ? SEE_INVISIBLE_OBSERVER : SEE_INVISIBLE_LIVING)
|
||||
|
||||
/mob/abstract/ghost/verb/toggle_ghostsee()
|
||||
set name = "Toggle Ghost Vision"
|
||||
set category = "Ghost"
|
||||
set desc = "Toggles your ability to see things only ghosts can see, like ghosts."
|
||||
|
||||
ghostvision = !ghostvision
|
||||
update_sight()
|
||||
to_chat(usr, SPAN_NOTICE("You [(ghostvision ? "now" : "no longer")] have ghost vision."))
|
||||
|
||||
/mob/abstract/ghost/proc/dead_tele()
|
||||
set name = "Teleport"
|
||||
set category = "Ghost"
|
||||
set desc= "Teleport to a location."
|
||||
|
||||
if(!istype(usr, /mob/abstract/ghost))
|
||||
to_chat(usr, SPAN_WARNING("You need to be a ghost!"))
|
||||
return
|
||||
|
||||
var/area_name = tgui_input_list(src, "Select an area to teleport to.", "Teleport", GLOB.ghostteleportlocs)
|
||||
|
||||
remove_verb(usr, /mob/abstract/ghost/proc/dead_tele)
|
||||
ADD_VERB_IN(usr, 30, /mob/abstract/ghost/proc/dead_tele)
|
||||
|
||||
var/area/thearea = GLOB.ghostteleportlocs[area_name]
|
||||
if(!thearea)
|
||||
return
|
||||
|
||||
var/list/L = list()
|
||||
var/holyblock = FALSE
|
||||
|
||||
if(usr.invisibility <= SEE_INVISIBLE_LIVING || (usr.mind in cult.current_antagonists))
|
||||
for(var/turf/T in get_area_turfs(thearea))
|
||||
if(!T.holy && has_ghost_restrictions)
|
||||
L+=T
|
||||
else
|
||||
holyblock = TRUE
|
||||
else
|
||||
for(var/turf/T in get_area_turfs(thearea))
|
||||
L+=T
|
||||
|
||||
if(!L || !L.len)
|
||||
if(holyblock && has_ghost_restrictions)
|
||||
to_chat(usr, SPAN_WARNING("This area has been entirely made into sacred grounds, you cannot enter it while you are in this plane of existence!"))
|
||||
return
|
||||
else
|
||||
to_chat(usr, "No area available.")
|
||||
return
|
||||
|
||||
var/turf/P = pick(L)
|
||||
if(on_restricted_level(P.z) && has_ghost_restrictions)
|
||||
to_chat(usr, "You can not teleport to this area.")
|
||||
return
|
||||
|
||||
orbiting?.end_orbit(src)
|
||||
usr.forceMove(pick(L))
|
||||
|
||||
/mob/abstract/ghost/verb/follow()
|
||||
set name = "Follow"
|
||||
set category = "Ghost"
|
||||
set desc = "Follow and haunt a mob."
|
||||
|
||||
var/datum/tgui_module/follow_menu/GM = new /datum/tgui_module/follow_menu(usr)
|
||||
GM.ui_interact(usr)
|
||||
|
||||
// This is the ghost's follow verb with an argument
|
||||
/mob/abstract/ghost/proc/ManualFollow(var/atom/movable/target)
|
||||
if(!target)
|
||||
return
|
||||
|
||||
//Stops orbit if there's any; TG doesn't do this, but if you don't it breaks the orbiting reference
|
||||
//if you are jumping from one mob to another, hence why we're doing it here
|
||||
orbiting?.end_orbit(src)
|
||||
|
||||
var/list/icon_dimensions = get_icon_dimensions(target.icon)
|
||||
var/orbitsize = (icon_dimensions["width"] + icon_dimensions["height"]) * 0.5
|
||||
orbitsize -= (orbitsize/ICON_SIZE_ALL)*(ICON_SIZE_ALL*0.25)
|
||||
|
||||
var/rot_seg = 30 //Let's make it simple and it's just a circle
|
||||
|
||||
orbit(target,orbitsize, FALSE, 20, rot_seg)
|
||||
|
||||
to_chat(src, SPAN_NOTICE("Now following \the <b>[target]</b>."))
|
||||
update_sight()
|
||||
|
||||
/mob/abstract/ghost/proc/on_restricted_level(var/check)
|
||||
if(!check)
|
||||
check = z
|
||||
//Check if they are a staff member
|
||||
if(check_rights(R_MOD|R_ADMIN|R_DEV, show_msg=FALSE, user=src))
|
||||
return FALSE
|
||||
|
||||
//Check if the z level is in the restricted list
|
||||
if (!(check in SSatlas.current_map.restricted_levels))
|
||||
return FALSE
|
||||
|
||||
return TRUE
|
||||
|
||||
/mob/abstract/ghost/verb/analyze_air()
|
||||
set name = "Analyze Air"
|
||||
set category = "Ghost"
|
||||
|
||||
// Shamelessly copied from the Gas Analyzers
|
||||
if(!isturf(loc))
|
||||
return
|
||||
|
||||
var/datum/gas_mixture/environment = loc.return_air()
|
||||
|
||||
var/pressure = environment.return_pressure()
|
||||
var/total_moles = environment.total_moles
|
||||
|
||||
to_chat(src, SPAN_NOTICE("<B>Results:</B>"))
|
||||
if(abs(pressure - ONE_ATMOSPHERE) < 10)
|
||||
to_chat(src, SPAN_NOTICE("Pressure: [round(pressure,0.1)] kPa"))
|
||||
else
|
||||
to_chat(src, SPAN_WARNING("Pressure: [round(pressure,0.1)] kPa"))
|
||||
if(total_moles)
|
||||
for(var/g in environment.gas)
|
||||
to_chat(src, SPAN_NOTICE("[gas_data.name[g]]: [round((environment.gas[g] / total_moles) * 100)]% ([round(environment.gas[g], 0.01)] moles)"))
|
||||
to_chat(src, SPAN_NOTICE("Temperature: [round(environment.temperature-T0C,0.1)]°C ([round(environment.temperature,0.1)]K)"))
|
||||
to_chat(src, SPAN_NOTICE("Heat Capacity: [round(environment.heat_capacity(),0.1)]"))
|
||||
|
||||
/mob/abstract/ghost/verb/view_manifest()
|
||||
set name = "Show Crew Manifest"
|
||||
set category = "Ghost"
|
||||
SSrecords.open_manifest_tgui(usr)
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
/mob/abstract/observer/LateLogin()
|
||||
/mob/abstract/ghost/observer/LateLogin()
|
||||
..()
|
||||
if (ghostimage)
|
||||
ghostimage.icon_state = src.icon_state
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
/mob/abstract/observer/Logout()
|
||||
/mob/abstract/ghost/observer/Logout()
|
||||
..()
|
||||
// This is one of very few spawn()s that we cannot get rid of
|
||||
// Yes it needs to be like this
|
||||
+79
-237
@@ -1,53 +1,44 @@
|
||||
/mob/abstract/observer
|
||||
/mob/abstract/ghost/observer
|
||||
name = "ghost"
|
||||
desc = "It's a g-g-g-g-ghooooost!" //jinkies!
|
||||
icon = 'icons/mob/mob.dmi'
|
||||
icon_state = "ghost"
|
||||
layer = OBSERVER_LAYER
|
||||
plane = OBSERVER_PLANE
|
||||
stat = DEAD
|
||||
density = 0
|
||||
canmove = 0
|
||||
blinded = 0
|
||||
anchored = 1 // don't get pushed around
|
||||
invisibility = INVISIBILITY_OBSERVER
|
||||
simulated = FALSE
|
||||
var/can_reenter_corpse
|
||||
var/datum/hud/hud = null // hud
|
||||
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 ghsot - this will remain as null.
|
||||
//Note that this is not a reliable way to determine if admins started as observers, since they change mobs a lot.
|
||||
var/has_enabled_antagHUD = 0
|
||||
var/medHUD = 0
|
||||
var/antagHUD = 0
|
||||
universal_speak = 1
|
||||
// var/atom/movable/following = null
|
||||
var/admin_ghosted = 0
|
||||
var/anonsay = 0
|
||||
var/image/ghostimage = null //this mobs ghost image, for deleting and stuff
|
||||
var/ghostvision = 1 //is the ghost able to see things humans can't?
|
||||
var/seedarkness = 1
|
||||
|
||||
var/is_manifest = 0
|
||||
var/ghost_cooldown = 0
|
||||
|
||||
var/obj/item/device/multitool/ghost_multitool
|
||||
incorporeal_move = INCORPOREAL_GHOST
|
||||
|
||||
mob_thinks = FALSE
|
||||
|
||||
/// The POI we're orbiting (orbit menu)
|
||||
var/orbiting_ref
|
||||
/// If the ghost can re-enter their corpse.
|
||||
var/can_reenter_corpse
|
||||
/// The ghost's HUD datum.
|
||||
var/datum/hud/hud = null
|
||||
/// This variable is set to 1 when you enter the game as an observer. Remains null if you died in the game and are a ghost. Not reliable for admins; they change mobs a lot.
|
||||
var/started_as_observer
|
||||
/// If the ghost has enabled antagHUD.
|
||||
var/has_enabled_antagHUD = 0
|
||||
/// If the ghost has enabled medHUD.
|
||||
var/medHUD = 0
|
||||
/// If this is an adminghost.
|
||||
var/admin_ghosted = 0
|
||||
/// If this ghost has enabled chat anonymization.
|
||||
var/anonsay = 0
|
||||
/// This mob's ghost image, for deleting and stuff.
|
||||
var/image/ghostimage
|
||||
/// If the ghost can be seen through cult shenanigans.
|
||||
var/is_manifest = 0
|
||||
/// Cooldown for ghost abilities, such as move_item().
|
||||
var/ghost_cooldown = 0
|
||||
|
||||
/mob/abstract/observer/New(mob/body)
|
||||
if (istype(body, /mob/abstract/observer))
|
||||
/mob/abstract/ghost/observer/Initialize(mapload, mob/body)
|
||||
. = ..()
|
||||
if (istype(body, /mob/abstract/ghost/observer))
|
||||
return//A ghost can't become a ghost.
|
||||
|
||||
sight |= SEE_TURFS | SEE_MOBS | SEE_OBJS | SEE_SELF
|
||||
see_invisible = SEE_INVISIBLE_OBSERVER
|
||||
add_verb(src, /mob/abstract/observer/proc/dead_tele)
|
||||
|
||||
set_stat(DEAD)
|
||||
|
||||
ghostimage = image(src.icon,src,src.icon_state)
|
||||
@@ -96,32 +87,16 @@
|
||||
name = capitalize(pick(first_names_male)) + " " + capitalize(pick(last_names))
|
||||
real_name = name
|
||||
|
||||
ghost_multitool = new(src)
|
||||
..()
|
||||
|
||||
/mob/abstract/observer/Destroy()
|
||||
qdel(ghost_multitool)
|
||||
ghost_multitool = null
|
||||
|
||||
/mob/abstract/ghost/observer/Destroy()
|
||||
if (ghostimage)
|
||||
SSmobs.ghost_darkness_images -= ghostimage
|
||||
qdel(ghostimage)
|
||||
ghostimage = null
|
||||
updateallghostimages()
|
||||
|
||||
return ..()
|
||||
|
||||
/mob/abstract/observer/Topic(href, href_list)
|
||||
if (href_list["track"])
|
||||
if(istype(href_list["track"],/mob))
|
||||
var/mob/target = locate(href_list["track"]) in GLOB.mob_list
|
||||
if(target)
|
||||
ManualFollow(target)
|
||||
else
|
||||
var/atom/target = locate(href_list["track"])
|
||||
if(istype(target))
|
||||
ManualFollow(target)
|
||||
|
||||
/mob/abstract/observer/proc/initialise_postkey(set_timers = TRUE)
|
||||
/mob/abstract/ghost/observer/proc/initialise_postkey(set_timers = TRUE)
|
||||
//This function should be run after a ghost has been created and had a ckey assigned
|
||||
if (!set_timers)
|
||||
return
|
||||
@@ -135,19 +110,19 @@
|
||||
if (!get_death_time(CREW))
|
||||
set_death_time(CREW, world.time)
|
||||
|
||||
/mob/abstract/observer/attackby(obj/item/attacking_item, mob/user)
|
||||
/mob/abstract/ghost/observer/attackby(obj/item/attacking_item, mob/user)
|
||||
if(istype(attacking_item, /obj/item/book/tome))
|
||||
var/mob/abstract/observer/M = src
|
||||
var/mob/abstract/ghost/observer/M = src
|
||||
M.manifest(user)
|
||||
|
||||
/mob/abstract/observer/CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
|
||||
/mob/abstract/ghost/observer/CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
|
||||
return 1
|
||||
/*
|
||||
Transfer_mind is there to check if mob is being deleted/not going to have a body.
|
||||
Works together with spawning an observer, noted above.
|
||||
*/
|
||||
|
||||
/mob/abstract/observer/Life(seconds_per_tick, times_fired)
|
||||
/mob/abstract/ghost/observer/Life(seconds_per_tick, times_fired)
|
||||
..()
|
||||
if(!loc) return
|
||||
if(!client) return 0
|
||||
@@ -164,20 +139,7 @@ Works together with spawning an observer, noted above.
|
||||
if(medHUD)
|
||||
process_medHUD(src)
|
||||
|
||||
/mob/abstract/observer/proc/on_restricted_level(var/check)
|
||||
if(!check)
|
||||
check = z
|
||||
//Check if they are a staff member
|
||||
if(check_rights(R_MOD|R_ADMIN|R_DEV, show_msg=FALSE, user=src))
|
||||
return FALSE
|
||||
|
||||
//Check if the z level is in the restricted list
|
||||
if (!(check in SSatlas.current_map.restricted_levels))
|
||||
return FALSE
|
||||
|
||||
return TRUE
|
||||
|
||||
/mob/abstract/observer/proc/teleport_to_spawn(var/message)
|
||||
/mob/abstract/ghost/observer/proc/teleport_to_spawn(var/message)
|
||||
if(!message)
|
||||
message = "You can not freely observe on this z-level."
|
||||
|
||||
@@ -187,14 +149,13 @@ Works together with spawning an observer, noted above.
|
||||
to_chat(src, SPAN_NOTICE("[message]"))
|
||||
forceMove(O.loc)
|
||||
|
||||
|
||||
/mob/abstract/observer/proc/process_medHUD(var/mob/M)
|
||||
/mob/abstract/ghost/observer/proc/process_medHUD(var/mob/M)
|
||||
var/client/C = M.client
|
||||
for(var/mob/living/carbon/human/patient in oview(M, 14))
|
||||
C.images += patient.hud_list[HEALTH_HUD]
|
||||
C.images += patient.hud_list[STATUS_HUD_OOC]
|
||||
|
||||
/mob/abstract/observer/proc/assess_targets(list/target_list, mob/abstract/observer/U)
|
||||
/mob/abstract/ghost/observer/proc/assess_targets(list/target_list, mob/abstract/ghost/observer/U)
|
||||
var/client/C = U.client
|
||||
for(var/mob/living/carbon/human/target in target_list)
|
||||
C.images += target.hud_list[SPECIALROLE_HUD]
|
||||
@@ -205,7 +166,7 @@ Works together with spawning an observer, noted above.
|
||||
/mob/proc/ghostize(var/can_reenter_corpse = TRUE, var/should_set_timer = TRUE)
|
||||
if(ckey)
|
||||
CutOverlays(image('icons/effects/effects.dmi', "zzz_glow")) // not very efficient but ghostize isn't called /too/ often.
|
||||
var/mob/abstract/observer/ghost = new(src) //Transfer safety to observer spawning proc.
|
||||
var/mob/abstract/ghost/observer/ghost = new(src, src) //Transfer safety to observer spawning proc.
|
||||
ghost.can_reenter_corpse = can_reenter_corpse
|
||||
ghost.timeofdeath = src.stat == DEAD ? src.timeofdeath : world.time
|
||||
|
||||
@@ -213,7 +174,7 @@ Works together with spawning an observer, noted above.
|
||||
ghost.initialise_postkey(should_set_timer)
|
||||
if(ghost.client)
|
||||
if(!ghost.client.holder && !GLOB.config.antag_hud_allowed) // For new ghosts we remove the verb from even showing up if it's not allowed.
|
||||
remove_verb(ghost, /mob/abstract/observer/verb/toggle_antagHUD) // Poor guys, don't know what they are missing!
|
||||
remove_verb(ghost, /mob/abstract/ghost/observer/verb/toggle_antagHUD) // Poor guys, don't know what they are missing!
|
||||
ghost.client.init_verbs()
|
||||
return ghost
|
||||
|
||||
@@ -243,20 +204,20 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
var/turf/location = get_turf(src)
|
||||
message_admins("[key_name_admin(usr)] has ghosted. (<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[location.x];Y=[location.y];Z=[location.z]'>JMP</a>)")
|
||||
log_game("[key_name_admin(usr)] has ghosted.")
|
||||
var/mob/abstract/observer/ghost = ghostize(0) //0 parameter is so we can never re-enter our body, "Charlie, you can never come baaaack~" :3
|
||||
var/mob/abstract/ghost/observer/ghost = ghostize(0) //0 parameter is so we can never re-enter our body, "Charlie, you can never come baaaack~" :3
|
||||
ghost.timeofdeath = world.time // Because the living mob won't have a time of death and we want the respawn timer to work properly.
|
||||
announce_ghost_joinleave(ghost)
|
||||
|
||||
/mob/abstract/observer/can_use_hands()
|
||||
/mob/abstract/ghost/observer/can_use_hands()
|
||||
return FALSE
|
||||
|
||||
/mob/abstract/observer/is_active()
|
||||
/mob/abstract/ghost/observer/is_active()
|
||||
return FALSE
|
||||
|
||||
/mob/abstract/observer/set_stat()
|
||||
/mob/abstract/ghost/observer/set_stat()
|
||||
stat = DEAD // They are also always dead
|
||||
|
||||
/mob/abstract/observer/verb/reenter_corpse()
|
||||
/mob/abstract/ghost/observer/verb/reenter_corpse()
|
||||
set category = "Ghost"
|
||||
set name = "Re-enter Corpse"
|
||||
if(!client) return
|
||||
@@ -284,7 +245,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
announce_ghost_joinleave(mind, 0, "They now occupy their body again.")
|
||||
return 1
|
||||
|
||||
/mob/abstract/observer/verb/toggle_medHUD()
|
||||
/mob/abstract/ghost/observer/verb/toggle_medHUD()
|
||||
set category = "Ghost"
|
||||
set name = "Toggle MedicHUD"
|
||||
set desc = "Toggles Medical HUD allowing you to see how everyone is doing"
|
||||
@@ -297,7 +258,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
medHUD = 1
|
||||
to_chat(src, SPAN_NOTICE("<B>Medical HUD Enabled</B>"))
|
||||
|
||||
/mob/abstract/observer/verb/scan_target()
|
||||
/mob/abstract/ghost/observer/verb/scan_target()
|
||||
set category = "Ghost"
|
||||
set name = "Medical Scan Target"
|
||||
set desc = "Analyse the health of whatever you are following."
|
||||
@@ -313,7 +274,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
else
|
||||
to_chat(src, SPAN_WARNING("This isn't a scannable target."))
|
||||
|
||||
/mob/abstract/observer/verb/toggle_antagHUD()
|
||||
/mob/abstract/ghost/observer/verb/toggle_antagHUD()
|
||||
set category = "Ghost"
|
||||
set name = "Toggle AntagHUD"
|
||||
set desc = "Toggles AntagHUD allowing you to see who is the antagonist"
|
||||
@@ -324,7 +285,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
if(!GLOB.config.antag_hud_allowed && (!client.holder || aux_staff))
|
||||
to_chat(src, SPAN_WARNING("Admins have disabled this for this round."))
|
||||
return
|
||||
var/mob/abstract/observer/M = src
|
||||
var/mob/abstract/ghost/observer/M = src
|
||||
if(jobban_isbanned(M, "AntagHUD"))
|
||||
to_chat(src, SPAN_DANGER("You have been banned from using this feature"))
|
||||
return
|
||||
@@ -341,145 +302,40 @@ 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("<B>AntagHUD Enabled</B>"))
|
||||
|
||||
/mob/abstract/observer/proc/dead_tele(A in GLOB.ghostteleportlocs)
|
||||
set category = "Ghost"
|
||||
set name = "Teleport"
|
||||
set desc= "Teleport to a location"
|
||||
if(!istype(usr, /mob/abstract/observer))
|
||||
to_chat(usr, "Not when you're not dead!")
|
||||
return
|
||||
remove_verb(usr, /mob/abstract/observer/proc/dead_tele)
|
||||
ADD_VERB_IN(usr, 30, /mob/abstract/observer/proc/dead_tele)
|
||||
var/area/thearea = GLOB.ghostteleportlocs[A]
|
||||
if(!thearea) return
|
||||
|
||||
var/list/L = list()
|
||||
var/holyblock = 0
|
||||
|
||||
if(usr.invisibility <= SEE_INVISIBLE_LIVING || (usr.mind in cult.current_antagonists))
|
||||
for(var/turf/T in get_area_turfs(thearea))
|
||||
if(!T.holy)
|
||||
L+=T
|
||||
else
|
||||
holyblock = 1
|
||||
else
|
||||
for(var/turf/T in get_area_turfs(thearea))
|
||||
L+=T
|
||||
|
||||
if(!L || !L.len)
|
||||
if(holyblock)
|
||||
to_chat(usr, SPAN_WARNING("This area has been entirely made into sacred grounds, you cannot enter it while you are in this plane of existence!"))
|
||||
return
|
||||
else
|
||||
to_chat(usr, "No area available.")
|
||||
return
|
||||
|
||||
var/turf/P = pick(L)
|
||||
if(on_restricted_level(P.z))
|
||||
to_chat(usr, "You can not teleport to this area")
|
||||
return
|
||||
|
||||
usr.abstract_move(pick(L))
|
||||
|
||||
/mob/abstract/observer/verb/follow()
|
||||
set category = "Ghost"
|
||||
set name = "Follow" // "Haunt"
|
||||
set desc = "Follow and haunt a mob."
|
||||
|
||||
var/datum/tgui_module/ghost_menu/GM = new /datum/tgui_module/ghost_menu(usr)
|
||||
GM.ui_interact(usr)
|
||||
|
||||
// This is the ghost's follow verb with an argument
|
||||
/mob/abstract/observer/proc/ManualFollow(atom/movable/target)
|
||||
if(!target)
|
||||
return
|
||||
|
||||
//Stops orbit if there's any; TG doesn't do this, but if you don't it breaks the orbiting reference
|
||||
//if you are jumping from one mob to another, hence why we're doing it here
|
||||
orbiting?.end_orbit(src)
|
||||
|
||||
var/list/icon_dimensions = get_icon_dimensions(target.icon)
|
||||
var/orbitsize = (icon_dimensions["width"] + icon_dimensions["height"]) * 0.5
|
||||
orbitsize -= (orbitsize/ICON_SIZE_ALL)*(ICON_SIZE_ALL*0.25)
|
||||
|
||||
var/rot_seg = 30 //Let's make it simple and it's just a circle
|
||||
|
||||
orbit(target,orbitsize, FALSE, 20, rot_seg)
|
||||
|
||||
to_chat(src, SPAN_NOTICE("Now following \the <b>[target]</b>."))
|
||||
updateghostsight()
|
||||
|
||||
/mob/abstract/observer/orbit()
|
||||
set_dir(2)//reset dir so the right directional sprites show up
|
||||
return ..()
|
||||
|
||||
/mob/proc/check_holy(var/turf/T)
|
||||
return 0
|
||||
|
||||
/mob/abstract/observer/check_holy(var/turf/T)
|
||||
/mob/abstract/ghost/observer/check_holy(var/turf/T)
|
||||
if(check_rights(R_ADMIN|R_FUN, 0, src))
|
||||
return 0
|
||||
|
||||
return (T && T.holy) && (invisibility <= SEE_INVISIBLE_LIVING || (mind in cult.current_antagonists))
|
||||
|
||||
/mob/abstract/observer/verb/jumptomob(input in getmobs()) //Moves the ghost instead of just changing the ghosts's eye -Nodrak
|
||||
/mob/abstract/ghost/observer/verb/jumptomob(input in getmobs()) //Moves the ghost instead of just changing the ghosts's eye -Nodrak
|
||||
set category = "Ghost"
|
||||
set name = "Jump to Mob"
|
||||
set desc = "Teleport to a mob"
|
||||
|
||||
if(istype(src, /mob/abstract/observer)) //Make sure they're an observer!
|
||||
var/mob/source_mob = src //Source mob
|
||||
|
||||
if(istype(usr, /mob/abstract/ghost/observer)) //Make sure they're an observer!
|
||||
var/target = getmobs()[input]
|
||||
if(!target) return
|
||||
var/turf/T = get_turf(target) //Turf of the destination mob
|
||||
|
||||
if(T && isturf(T)) //Make sure the turf exists, then move the source to that destination.
|
||||
source_mob.abstract_move(T)
|
||||
abstract_move(T)
|
||||
else
|
||||
to_chat(src, "This mob is not located in the game world.")
|
||||
|
||||
/mob/abstract/observer/memory()
|
||||
/mob/abstract/ghost/observer/memory()
|
||||
set hidden = 1
|
||||
to_chat(src, SPAN_WARNING("You are dead! You have no mind to store memory!"))
|
||||
|
||||
/mob/abstract/observer/add_memory()
|
||||
/mob/abstract/ghost/observer/add_memory()
|
||||
set hidden = 1
|
||||
to_chat(src, SPAN_WARNING("You are dead! You have no mind to store memory!"))
|
||||
|
||||
/mob/abstract/observer/verb/analyze_air()
|
||||
set name = "Analyze Air"
|
||||
set category = "Ghost"
|
||||
|
||||
if(!istype(usr, /mob/abstract/observer)) return
|
||||
|
||||
// Shamelessly copied from the Gas Analyzers
|
||||
if (!( istype(usr.loc, /turf) ))
|
||||
return
|
||||
|
||||
var/datum/gas_mixture/environment = usr.loc.return_air()
|
||||
|
||||
var/pressure = environment.return_pressure()
|
||||
var/total_moles = environment.total_moles
|
||||
|
||||
to_chat(src, SPAN_NOTICE("<B>Results:</B>"))
|
||||
if(abs(pressure - ONE_ATMOSPHERE) < 10)
|
||||
to_chat(src, SPAN_NOTICE("Pressure: [round(pressure,0.1)] kPa"))
|
||||
else
|
||||
to_chat(src, SPAN_WARNING("Pressure: [round(pressure,0.1)] kPa"))
|
||||
if(total_moles)
|
||||
for(var/g in environment.gas)
|
||||
to_chat(src, SPAN_NOTICE("[gas_data.name[g]]: [round((environment.gas[g] / total_moles) * 100)]% ([round(environment.gas[g], 0.01)] moles)"))
|
||||
to_chat(src, SPAN_NOTICE("Temperature: [round(environment.temperature-T0C,0.1)]°C ([round(environment.temperature,0.1)]K)"))
|
||||
to_chat(src, SPAN_NOTICE("Heat Capacity: [round(environment.heat_capacity(),0.1)]"))
|
||||
|
||||
/mob/abstract/observer/verb/view_manifest()
|
||||
set name = "Show Crew Manifest"
|
||||
set category = "Ghost"
|
||||
SSrecords.open_manifest_tgui(usr)
|
||||
|
||||
//This is called when a ghost is drag clicked to something.
|
||||
/mob/abstract/observer/MouseDrop(atom/over)
|
||||
/mob/abstract/ghost/observer/MouseDrop(atom/over)
|
||||
if(!usr || !over) return
|
||||
if(isobserver(usr) && usr.client && isliving(over))
|
||||
var/mob/living/M = over
|
||||
@@ -496,7 +352,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
|
||||
return ..()
|
||||
|
||||
/mob/abstract/observer/proc/try_possession(var/mob/living/M)
|
||||
/mob/abstract/ghost/observer/proc/try_possession(var/mob/living/M)
|
||||
if(!GLOB.config.ghosts_can_possess_animals)
|
||||
to_chat(usr, SPAN_WARNING("Ghosts are not permitted to possess animals."))
|
||||
return 0
|
||||
@@ -505,7 +361,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
return M.do_possession(src)
|
||||
|
||||
//Used for drawing on walls with blood puddles as a spooky ghost.
|
||||
/mob/abstract/observer/verb/bloody_doodle()
|
||||
/mob/abstract/ghost/observer/verb/bloody_doodle()
|
||||
set category = "Ghost"
|
||||
set name = "Write in blood"
|
||||
set desc = "If the round is sufficiently spooky, write a short message in blood on the floor or a wall. Remember, no IC in OOC or OOC in IC."
|
||||
@@ -573,19 +429,19 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
W.add_hiddenprint(src)
|
||||
W.visible_message(SPAN_WARNING("Invisible fingers crudely paint something in blood on [T]..."))
|
||||
|
||||
/mob/abstract/observer/pointed(atom/A as mob|obj|turf in view())
|
||||
/mob/abstract/ghost/observer/pointed(atom/A as mob|obj|turf in view())
|
||||
if(!..())
|
||||
return 0
|
||||
src.visible_message("<span class='deadsay'><b>[src]</b> points to [A]</span>")
|
||||
return 1
|
||||
|
||||
/mob/abstract/observer/proc/manifest(mob/user)
|
||||
/mob/abstract/ghost/observer/proc/manifest(mob/user)
|
||||
is_manifest = 0
|
||||
if(!is_manifest)
|
||||
is_manifest = 1
|
||||
add_verb(src, /mob/abstract/observer/proc/toggle_visibility_verb)
|
||||
add_verb(src, /mob/abstract/observer/proc/ghost_whisper)
|
||||
add_verb(src, /mob/abstract/observer/proc/move_item)
|
||||
add_verb(src, /mob/abstract/ghost/observer/proc/toggle_visibility_verb)
|
||||
add_verb(src, /mob/abstract/ghost/observer/proc/ghost_whisper)
|
||||
add_verb(src, /mob/abstract/ghost/observer/proc/move_item)
|
||||
|
||||
if(src.invisibility != 0)
|
||||
user.visible_message( \
|
||||
@@ -600,7 +456,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
)
|
||||
|
||||
|
||||
/mob/abstract/observer/proc/toggle_icon(var/icon)
|
||||
/mob/abstract/ghost/observer/proc/toggle_icon(var/icon)
|
||||
if(!client)
|
||||
return
|
||||
|
||||
@@ -615,14 +471,14 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
var/image/J = image('icons/mob/mob.dmi', loc = src, icon_state = icon)
|
||||
client.images += J
|
||||
|
||||
/mob/abstract/observer/proc/toggle_visibility_verb()
|
||||
/mob/abstract/ghost/observer/proc/toggle_visibility_verb()
|
||||
set category = "Ghost"
|
||||
set name = "Toggle Visibility"
|
||||
set desc = "Allows you to turn (in)visible (almost) at will."
|
||||
|
||||
toggle_visibility()
|
||||
|
||||
/mob/abstract/observer/proc/toggle_visibility(var/forced = 0)
|
||||
/mob/abstract/ghost/observer/proc/toggle_visibility(var/forced = 0)
|
||||
var/toggled_invisible
|
||||
if(!forced && invisibility && world.time < toggled_invisible + 600)
|
||||
to_chat(src, "You must gather strength before you can turn visible again...")
|
||||
@@ -639,7 +495,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
// Give the ghost a cult icon which should be visible only to itself
|
||||
toggle_icon("cult")
|
||||
|
||||
/mob/abstract/observer/proc/ghost_whisper()
|
||||
/mob/abstract/ghost/observer/proc/ghost_whisper()
|
||||
set category = "Ghost"
|
||||
set name = "Spectral Whisper"
|
||||
|
||||
@@ -661,7 +517,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
else
|
||||
to_chat(src, SPAN_DANGER("You have not been pulled past the veil!"))
|
||||
|
||||
/mob/abstract/observer/proc/move_item()
|
||||
/mob/abstract/ghost/observer/proc/move_item()
|
||||
set category = "Ghost"
|
||||
set name = "Move item"
|
||||
set desc = "Move a small item to where you are."
|
||||
@@ -695,7 +551,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
|
||||
ghost_cooldown = world.time + 500
|
||||
|
||||
/mob/abstract/observer/verb/toggle_anonsay()
|
||||
/mob/abstract/ghost/observer/verb/toggle_anonsay()
|
||||
set category = "Ghost"
|
||||
set name = "Toggle Anonymous Chat"
|
||||
set desc = "Toggles showing your key in dead chat."
|
||||
@@ -706,30 +562,16 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
else
|
||||
to_chat(src, "<span class='info'>Your key will be publicly visible again.</span>")
|
||||
|
||||
/mob/abstract/observer/canface()
|
||||
/mob/abstract/ghost/observer/canface()
|
||||
return 1
|
||||
|
||||
/mob/proc/can_admin_interact()
|
||||
return 0
|
||||
|
||||
/mob/abstract/observer/can_admin_interact()
|
||||
/mob/abstract/ghost/observer/can_admin_interact()
|
||||
return check_rights(R_ADMIN, 0, src)
|
||||
|
||||
/mob/abstract/observer/verb/toggle_ghostsee()
|
||||
set name = "Toggle Ghost Vision"
|
||||
set desc = "Toggles your ability to see things only ghosts can see, like other ghosts"
|
||||
set category = "Ghost"
|
||||
ghostvision = !(ghostvision)
|
||||
updateghostsight()
|
||||
to_chat(usr, "You [(ghostvision ? "now" : "no longer")] have ghost vision.")
|
||||
|
||||
/mob/abstract/observer/verb/toggle_darkness()
|
||||
set name = "Toggle Darkness"
|
||||
set category = "Ghost"
|
||||
seedarkness = !(seedarkness)
|
||||
updateghostsight()
|
||||
|
||||
/mob/abstract/observer/proc/updateghostsight()
|
||||
/mob/abstract/ghost/observer/update_sight()
|
||||
//if they are on a restricted level, then set the ghost vision for them.
|
||||
if(on_restricted_level())
|
||||
//On the restricted level they have the same sight as the mob
|
||||
@@ -740,7 +582,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
set_sight(sight|SEE_TURFS|SEE_MOBS|SEE_OBJS)
|
||||
set_see_invisible(SEE_INVISIBLE_LEVEL_TWO)
|
||||
|
||||
if (!seedarkness)
|
||||
if (!see_darkness)
|
||||
set_see_invisible(SEE_INVISIBLE_NOLIGHTING)
|
||||
else
|
||||
set_see_invisible(ghostvision ? SEE_INVISIBLE_OBSERVER : SEE_INVISIBLE_LIVING)
|
||||
@@ -748,13 +590,13 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
updateghostimages()
|
||||
|
||||
/proc/updateallghostimages()
|
||||
for (var/mob/abstract/observer/O in GLOB.player_list)
|
||||
for (var/mob/abstract/ghost/observer/O in GLOB.player_list)
|
||||
O.updateghostimages()
|
||||
|
||||
/mob/abstract/observer/proc/updateghostimages()
|
||||
/mob/abstract/ghost/observer/proc/updateghostimages()
|
||||
if (!client)
|
||||
return
|
||||
if (seedarkness || !ghostvision)
|
||||
if (see_darkness || !ghostvision)
|
||||
client.images -= SSmobs.ghost_darkness_images
|
||||
client.images |= SSmobs.ghost_sightless_images
|
||||
else
|
||||
@@ -764,7 +606,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
if (ghostimage)
|
||||
client.images -= ghostimage //remove ourself
|
||||
|
||||
/mob/abstract/observer/MayRespawn(var/feedback = 0, var/respawn_type = null)
|
||||
/mob/abstract/ghost/observer/MayRespawn(var/feedback = 0, var/respawn_type = null)
|
||||
if(!client)
|
||||
return 0
|
||||
if(GLOB.config.antag_hud_restricted && has_enabled_antagHUD == 1)
|
||||
@@ -798,7 +640,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
if(client && eyeobj)
|
||||
return "|\[<a href='byond://?src=[REF(ghost)];track=[REF(eyeobj)]'>E</a>\]"
|
||||
|
||||
/mob/abstract/observer/extra_ghost_link(var/atom/ghost)
|
||||
/mob/abstract/ghost/observer/extra_ghost_link(var/atom/ghost)
|
||||
if(mind && mind.current)
|
||||
return "|\[<a href='byond://?src=[REF(ghost)];track=[REF(mind.current)]'>B</a>\]"
|
||||
|
||||
@@ -809,7 +651,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
|
||||
|
||||
//Opens the Ghost Spawner Menu
|
||||
/mob/abstract/observer/verb/ghost_spawner()
|
||||
/mob/abstract/ghost/observer/verb/ghost_spawner()
|
||||
set category = "Ghost"
|
||||
set name = "Ghost Spawner"
|
||||
|
||||
@@ -819,7 +661,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
|
||||
SSghostroles.ui_interact(usr)
|
||||
|
||||
/mob/abstract/observer/verb/submitpai()
|
||||
/mob/abstract/ghost/observer/verb/submitpai()
|
||||
set category = "Ghost"
|
||||
set name = "Submit pAI personality"
|
||||
set desc = "Submits you pAI personality to the pAI candidate pool."
|
||||
@@ -829,7 +671,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
return
|
||||
SSpai.recruitWindow(src)
|
||||
|
||||
/mob/abstract/observer/verb/revokepai()
|
||||
/mob/abstract/ghost/observer/verb/revokepai()
|
||||
set category = "Ghost"
|
||||
set name = "Revoke pAI personality"
|
||||
set desc = "Removes you from the pAI candidite pool."
|
||||
@@ -837,10 +679,10 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
if(SSpai.revokeCandidancy(src))
|
||||
to_chat(src, "You have been removed from the pAI candidate pool.")
|
||||
|
||||
/mob/abstract/observer/can_hear_radio(speaker_coverage = list())
|
||||
/mob/abstract/ghost/observer/can_hear_radio(speaker_coverage = list())
|
||||
if(client && (client.prefs.toggles & CHAT_GHOSTRADIO))
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
/mob/abstract/observer/get_speech_bubble_state_modifier()
|
||||
/mob/abstract/ghost/observer/get_speech_bubble_state_modifier()
|
||||
return "ghost"
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
/mob/abstract/observer/say(var/message, var/datum/language/speaking = null, var/verb="says", var/alt_name="", var/ghost_hearing = GHOSTS_ALL_HEAR, var/whisper = FALSE)
|
||||
/mob/abstract/ghost/observer/say(var/message, var/datum/language/speaking = null, var/verb="says", var/alt_name="", var/ghost_hearing = GHOSTS_ALL_HEAR, var/whisper = FALSE)
|
||||
if (!message)
|
||||
return
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
/mob/abstract/ghost/storyteller
|
||||
name = "Storyteller"
|
||||
desc = "You wonder what story will be told today. Hopefully one where your character with 200 euros' worth of custom art doesn't die. That would be a shame. Wouldn't it?"
|
||||
icon = 'icons/mob/mob.dmi'
|
||||
icon_state = "ghost"
|
||||
status_flags = GODMODE
|
||||
invisibility = INVISIBILITY_OBSERVER
|
||||
see_invisible = SEE_INVISIBLE_OBSERVER
|
||||
layer = OBSERVER_LAYER
|
||||
incorporeal_move = INCORPOREAL_GHOST
|
||||
simulated = FALSE
|
||||
|
||||
density = FALSE
|
||||
mob_thinks = FALSE
|
||||
universal_speak = TRUE
|
||||
|
||||
/mob/abstract/ghost/storyteller/Initialize()
|
||||
. = ..()
|
||||
SSghostroles.add_spawn_atom("storyteller", src)
|
||||
|
||||
/mob/abstract/ghost/storyteller/Destroy()
|
||||
SSodyssey.remove_storyteller(src)
|
||||
GLOB.storytellers.remove_antagonist(mind)
|
||||
SSghostroles.remove_spawn_atom("storyteller", src)
|
||||
return ..()
|
||||
|
||||
/mob/abstract/ghost/storyteller/LateLogin()
|
||||
. = ..()
|
||||
var/client/C = client
|
||||
|
||||
// if there's no mind, the initial setup hasn't run
|
||||
if(C && !mind)
|
||||
|
||||
mind = new /datum/mind(key)
|
||||
mind.active = TRUE
|
||||
mind.current = src
|
||||
|
||||
real_name = "Storyteller ([client.ckey])"
|
||||
name = "Storyteller ([client.ckey])"
|
||||
SSodyssey.add_storyteller(src)
|
||||
GLOB.storytellers.add_antagonist(mind)
|
||||
|
||||
/mob/abstract/ghost/storyteller/ghostize(can_reenter_corpse, should_set_timer)
|
||||
. = ..()
|
||||
if(!can_reenter_corpse)
|
||||
SSodyssey.remove_storyteller(src)
|
||||
|
||||
/mob/abstract/ghost/storyteller/say(var/message, var/datum/language/speaking = null, var/verb="says", var/alt_name="", var/ghost_hearing = GHOSTS_ALL_HEAR, var/whisper = FALSE)
|
||||
if (!message)
|
||||
return
|
||||
|
||||
var/msg = sanitize(message)
|
||||
if(!msg)
|
||||
return
|
||||
|
||||
log_ooc("(STORYTELLER) [name]/[key] : [msg]")
|
||||
|
||||
var/list/turf/messageturfs = list() //List of turfs we broadcast to.
|
||||
var/list/mob/messagemobs = list() //List of living mobs nearby who can hear it
|
||||
|
||||
for(var/turf in range(world.view, get_turf(src)))
|
||||
messageturfs += turf
|
||||
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
if(!M.client || istype(M, /mob/abstract/new_player))
|
||||
continue
|
||||
if(isAI(M))
|
||||
var/mob/living/silicon/ai/AI = M
|
||||
if(get_turf(AI.eyeobj) in messageturfs)
|
||||
messagemobs += M
|
||||
continue
|
||||
if(get_turf(M) in messageturfs)
|
||||
messagemobs += M
|
||||
|
||||
var/display_name = key
|
||||
if(client.holder && client.holder.fakekey)
|
||||
display_name = client.holder.fakekey
|
||||
|
||||
msg = process_chat_markup(msg, list("*"))
|
||||
|
||||
var/prefix
|
||||
var/admin_stuff
|
||||
for(var/client/target in GLOB.clients)
|
||||
admin_stuff = ""
|
||||
var/display_remote = FALSE
|
||||
if (target.holder && ((R_MOD|R_ADMIN) & target.holder.rights))
|
||||
display_remote = TRUE
|
||||
if(display_remote)
|
||||
prefix = "(R)"
|
||||
admin_stuff += "/([key])"
|
||||
if(target != client)
|
||||
admin_stuff += "(<A HREF='?src=[REF(target.holder)];adminplayerobservejump=[REF(src)]'>JMP</A>)"
|
||||
if(target.mob in messagemobs)
|
||||
prefix = ""
|
||||
if((target.mob in messagemobs) || display_remote)
|
||||
to_chat(target, SPAN_STORYTELLER("[create_text_tag("STORY", target)] [span("prefix", prefix)]<EM>[display_name][admin_stuff]:</EM> [span("message linkify", msg)]"))
|
||||
|
||||
/mob/abstract/ghost/storyteller/dust()
|
||||
return
|
||||
|
||||
/mob/abstract/ghost/storyteller/gib()
|
||||
return
|
||||
|
||||
/mob/abstract/ghost/storyteller/can_fall()
|
||||
return FALSE
|
||||
|
||||
/mob/abstract/ghost/storyteller/conveyor_act()
|
||||
return
|
||||
|
||||
/mob/abstract/ghost/storyteller/ex_act(var/severity = 2.0)
|
||||
return
|
||||
|
||||
/mob/abstract/ghost/storyteller/singularity_act()
|
||||
return
|
||||
|
||||
/mob/abstract/ghost/storyteller/singularity_pull()
|
||||
return
|
||||
|
||||
/mob/abstract/ghost/storyteller/singuloCanEat()
|
||||
return FALSE
|
||||
|
||||
/mob/abstract/ghost/storyteller/can_hear_radio(list/speaker_coverage)
|
||||
return TRUE
|
||||
|
||||
/mob/abstract/ghost/storyteller/get_speech_bubble_state_modifier()
|
||||
return "ghost"
|
||||
|
||||
/mob/abstract/ghost/storyteller/can_admin_interact()
|
||||
return TRUE
|
||||
|
||||
/mob/abstract/ghost/storyteller/on_restricted_level(var/check)
|
||||
return FALSE
|
||||
|
||||
/mob/abstract/ghost/storyteller/can_ztravel(direction)
|
||||
return TRUE
|
||||
|
||||
/mob/abstract/ghost/storyteller/verb/odyssey_panel()
|
||||
set name = "Odyssey Panel"
|
||||
set category = "Storyteller"
|
||||
|
||||
SSodyssey.ui_interact(src)
|
||||
|
||||
/**
|
||||
* Currently whitelisted in the config behind the head of staff whitelist.
|
||||
* Let's see if they can play nice.
|
||||
*/
|
||||
/datum/ghostspawner/storyteller
|
||||
name = "Storyteller"
|
||||
short_name = "storyteller"
|
||||
desc = "As the Storyteller, you have creative direction over the current round. You are trusted to change, mix up and make interesting experiences for the \
|
||||
players. Use this power with responsibility!"
|
||||
tags = list("Odyssey")
|
||||
loc_type = GS_LOC_ATOM
|
||||
enabled = TRUE
|
||||
|
||||
show_on_job_select = TRUE
|
||||
spawn_mob = /mob/abstract/ghost/storyteller
|
||||
atom_add_message = "A Storyteller position is available!"
|
||||
@@ -0,0 +1,343 @@
|
||||
// Okay, these verbs are a lot of ugly copypaste. The issue is that we don't really have any other choice.
|
||||
// The alternative (and the first thing I tried) was to make the Storyteller into basically admin perms, but that introduces way too many issues.
|
||||
|
||||
/mob/abstract/ghost/storyteller/verb/storyteller_panel()
|
||||
set name = "Storyteller Panel"
|
||||
set category = "Storyteller"
|
||||
|
||||
open_storyteller_panel()
|
||||
|
||||
/mob/abstract/ghost/storyteller/proc/open_storyteller_panel()
|
||||
var/dat = {"
|
||||
<center><B>Storyteller Panel</B></center><hr>\n
|
||||
"}
|
||||
dat += {"
|
||||
<BR>
|
||||
<A href='?src=[REF(src)];create_object=1'>Create Object</A><br>
|
||||
<A href='?src=[REF(src)];create_turf=1'>Create Turf</A><br>
|
||||
<A href='?src=[REF(src)]];create_mob=1'>Create Mob</A><br>
|
||||
"}
|
||||
|
||||
usr << browse(dat, "window=storytellerpanel;size=210x280")
|
||||
|
||||
/mob/abstract/ghost/storyteller/Topic(href, href_list)
|
||||
. = ..()
|
||||
if(href_list["create_object"])
|
||||
if(usr != src)
|
||||
return
|
||||
return create_object(usr)
|
||||
|
||||
else if(href_list["create_turf"])
|
||||
if(usr != src)
|
||||
return
|
||||
return create_turf(usr)
|
||||
|
||||
else if(href_list["create_mob"])
|
||||
if(usr != src)
|
||||
return
|
||||
return create_mob(usr)
|
||||
|
||||
else if(href_list["object_list"])
|
||||
if(!GLOB.config.allow_admin_spawning)
|
||||
to_chat(usr, "Spawning of items is not allowed.")
|
||||
return
|
||||
|
||||
var/atom/loc = usr.loc
|
||||
|
||||
var/dirty_paths
|
||||
if (istext(href_list["object_list"]))
|
||||
dirty_paths = list(href_list["object_list"])
|
||||
else if (istype(href_list["object_list"], /list))
|
||||
dirty_paths = href_list["object_list"]
|
||||
|
||||
var/paths = list()
|
||||
var/removed_paths = list()
|
||||
|
||||
for(var/dirty_path in dirty_paths)
|
||||
var/path = text2path(dirty_path)
|
||||
if(!path)
|
||||
removed_paths += dirty_path
|
||||
continue
|
||||
else if(!ispath(path, /obj) && !ispath(path, /turf) && !ispath(path, /mob))
|
||||
removed_paths += dirty_path
|
||||
continue
|
||||
else if(ispath(path, /obj/effect/bhole))
|
||||
if(!check_rights(R_FUN, 0))
|
||||
removed_paths += dirty_path
|
||||
continue
|
||||
paths += path
|
||||
|
||||
if(!paths ||( length(paths) > 5))
|
||||
return
|
||||
|
||||
var/atom/target
|
||||
var/list/offset = text2list(href_list["offset"],",")
|
||||
var/number = dd_range(1, 100, text2num(href_list["object_count"]))
|
||||
var/X = offset.len > 0 ? text2num(offset[1]) : 0
|
||||
var/Y = offset.len > 1 ? text2num(offset[2]) : 0
|
||||
var/Z = offset.len > 2 ? text2num(offset[3]) : 0
|
||||
var/tmp_dir = href_list["object_dir"]
|
||||
var/obj_dir = tmp_dir ? text2num(tmp_dir) : 2
|
||||
if(!obj_dir || !(obj_dir in list(1,2,4,8,5,6,9,10)))
|
||||
obj_dir = 2
|
||||
var/obj_name = sanitize(href_list["object_name"])
|
||||
switch(href_list["offset_type"])
|
||||
if ("absolute")
|
||||
target = locate(0 + X, 0 + Y, 0 + Z)
|
||||
if ("relative")
|
||||
target = locate(loc.x + X, loc.y + Y, loc.z + Z)
|
||||
|
||||
if(target)
|
||||
for (var/path in paths)
|
||||
for (var/_ in 1 to number)
|
||||
if(ispath(path, /turf))
|
||||
var/turf/O = target
|
||||
var/turf/N = O.ChangeTurf(path)
|
||||
if(N)
|
||||
if(obj_name)
|
||||
N.name = obj_name
|
||||
else
|
||||
var/atom/O = new path(target)
|
||||
if(O)
|
||||
O.set_dir(obj_dir)
|
||||
if(obj_name)
|
||||
O.name = obj_name
|
||||
if(ismob(O))
|
||||
var/mob/M = O
|
||||
M.set_name(obj_name)
|
||||
|
||||
log_and_message_admins("created [number] [english_list(paths)]")
|
||||
|
||||
/mob/abstract/ghost/storyteller/proc/create_object(var/mob/user)
|
||||
if (!create_object_html)
|
||||
var/objectjs = null
|
||||
objectjs = jointext(typesof(/obj), ";")
|
||||
create_object_html = file2text('html/create_object.html')
|
||||
create_object_html = replacetext(create_object_html, "null /* object types */", "\"[objectjs]\"")
|
||||
|
||||
user << browse(replacetext(create_object_html, "/* ref src */", "[REF(src)]"), "window=create_object;size=700x700")
|
||||
|
||||
/mob/abstract/ghost/storyteller/proc/create_turf(var/mob/user)
|
||||
if (!create_turf_html)
|
||||
var/turfjs = null
|
||||
turfjs = jointext(typesof(/turf), ";")
|
||||
create_turf_html = file2text('html/create_object.html')
|
||||
create_turf_html = replacetext(create_turf_html, "null /* object types */", "\"[turfjs]\"")
|
||||
|
||||
user << browse(replacetext(create_turf_html, "/* ref src */", "[REF(src)]"), "window=create_turf;size=700x700")
|
||||
|
||||
/mob/abstract/ghost/storyteller/proc/create_mob(var/mob/user)
|
||||
if (!create_mob_html)
|
||||
var/mobjs = null
|
||||
mobjs = jointext(typesof(/mob), ";")
|
||||
create_mob_html = file2text('html/create_object.html')
|
||||
create_mob_html = replacetext(create_mob_html, "null /* object types */", "\"[mobjs]\"")
|
||||
|
||||
user << browse(replacetext(create_mob_html, "/* ref src */", "[REF(src)]"), "window=create_mob;size=700x700")
|
||||
|
||||
/mob/abstract/ghost/storyteller/verb/open_narrate_panel()
|
||||
set name = "Narrate Panel"
|
||||
set category = "Storyteller"
|
||||
|
||||
var/datum/tgui_module/narrate_panel/NP = new /datum/tgui_module/narrate_panel(usr)
|
||||
NP.ui_interact(usr)
|
||||
|
||||
/mob/abstract/ghost/storyteller/verb/storyteller_direct_narrate(var/mob/M)
|
||||
set name = "Direct Narrate"
|
||||
set category = "Storyteller"
|
||||
|
||||
if(!M)
|
||||
var/list/client_mobs = list()
|
||||
for(var/mob/client_mob in get_mob_with_client_list())
|
||||
client_mobs[client_mob.name] = client_mob
|
||||
var/mob_name = tgui_input_list(src, "Who are you narrating to?", "Direct Narrate", client_mobs)
|
||||
if(mob_name)
|
||||
M = client_mobs[mob_name]
|
||||
|
||||
if(!M)
|
||||
return
|
||||
|
||||
var/msg = html_decode(sanitize(tgui_input_text(src, "What do you want to narrate?", "Direct Narrate", max_length = MAX_PAPER_MESSAGE_LEN)))
|
||||
|
||||
if(!msg)
|
||||
return
|
||||
|
||||
to_chat(M, msg)
|
||||
log_admin("DirectNarrate: [key_name(usr)] to ([M.name]/[M.key]): [msg]")
|
||||
message_admins(SPAN_NOTICE(SPAN_BOLD("DirectNarrate: [key_name(usr)] to ([M.name]/[M.key]): [msg]")), 1)
|
||||
|
||||
/mob/abstract/ghost/storyteller/verb/toggle_build_mode()
|
||||
set name = "Toggle Build Mode"
|
||||
set category = "Storyteller"
|
||||
|
||||
if(usr != src)
|
||||
return
|
||||
|
||||
var/datum/click_handler/handler = GetClickHandler()
|
||||
if(handler.type == /datum/click_handler/build_mode)
|
||||
usr.PopClickHandler()
|
||||
else
|
||||
usr.PushClickHandler(/datum/click_handler/build_mode)
|
||||
|
||||
/mob/abstract/ghost/storyteller/verb/command_report()
|
||||
set name = "Create Command Report"
|
||||
set category = "Storyteller"
|
||||
|
||||
var/reporttitle = sanitizeSafe(tgui_input_text(usr, "Pick a title for the report.", "Title"))
|
||||
if(!reporttitle)
|
||||
reporttitle = "NanoTrasen Update"
|
||||
var/reportbody = sanitize(tgui_input_text(usr, "Please enter anything you want. Anything. Serious.", "Body", multiline = TRUE), extra = FALSE)
|
||||
if(!reportbody)
|
||||
return
|
||||
|
||||
var/announce = tgui_alert(usr, "Should this be announced to the general population?", "Announcement", list("Yes","No"))
|
||||
switch(announce)
|
||||
if("Yes")
|
||||
command_announcement.Announce("[reportbody]", reporttitle, new_sound = 'sound/AI/commandreport.ogg', msg_sanitized = 1);
|
||||
if("No")
|
||||
to_world(SPAN_WARNING("New [SSatlas.current_map.company_name] Update available at all communication consoles."))
|
||||
sound_to_playing_players('sound/AI/commandreport.ogg')
|
||||
|
||||
log_admin("Storyteller [key_name(src)] has created a command report: [reportbody]")
|
||||
message_admins("Storyteller [key_name_admin(src)] has created a command report", 1)
|
||||
|
||||
//New message handling
|
||||
post_comm_message(reporttitle, reportbody)
|
||||
|
||||
/mob/abstract/ghost/storyteller/verb/send_odyssey_message()
|
||||
set name = "Unrestrict Away Site Landing"
|
||||
set category = "Storyteller"
|
||||
|
||||
if(!SSodyssey.site_landing_restricted)
|
||||
to_chat(src, SPAN_WARNING("Site landing is already unrestricted!"))
|
||||
return
|
||||
|
||||
var/reporttitle = sanitizeSafe(tgui_input_text(usr, "Pick a title for the message the Horizon will get.", "Title"))
|
||||
if(!reporttitle)
|
||||
reporttitle = "SCC Sensors Report"
|
||||
var/reportbody = sanitize(tgui_input_text(usr, "Enter the message the Horizon will get. It should at least describe what they're doing here in a general sense, along with the reason why they can land now.", "Body", multiline = TRUE), extra = FALSE)
|
||||
if(!reportbody)
|
||||
return
|
||||
|
||||
var/announce = tgui_alert(usr, "Should this be announced to the general population?", "Announcement", list("Yes","No"))
|
||||
switch(announce)
|
||||
if("Yes")
|
||||
command_announcement.Announce("[reportbody]", reporttitle, new_sound = 'sound/AI/commandreport.ogg', msg_sanitized = 1)
|
||||
if("No")
|
||||
command_announcement.Announce("New [SSatlas.current_map.company_name] update available at all communication consoles.", "[SSatlas.current_map.company_name] Report", new_sound = 'sound/AI/commandreport.ogg', msg_sanitized = 1)
|
||||
|
||||
SSodyssey.scenario.unrestrict_away_site_landing()
|
||||
log_admin("Storyteller [key_name(src)] has lifted the away site landing restrictions: [reportbody]")
|
||||
|
||||
//New message handling
|
||||
post_comm_message(reporttitle, reportbody)
|
||||
|
||||
/mob/abstract/ghost/storyteller/verb/change_mob_name(var/mob/victim)
|
||||
set name = "Change Mob Name"
|
||||
|
||||
var/new_name = tgui_input_text(src, "Enter a new name.", "Change Mob Name", max_length = MAX_NAME_LEN)
|
||||
if(!new_name)
|
||||
return
|
||||
|
||||
log_admin("[key_name(src)] has renamed [victim] to [new_name].")
|
||||
victim.set_name(new_name)
|
||||
|
||||
/mob/abstract/ghost/storyteller/verb/change_obj_name(var/obj/thing)
|
||||
set name = "Change Object Name"
|
||||
|
||||
var/new_name = tgui_input_text(src, "Enter a new name.", "Change Object Name", max_length = MAX_NAME_LEN)
|
||||
if(!new_name)
|
||||
return
|
||||
|
||||
log_admin("[key_name(src)] has renamed [thing] to [new_name].")
|
||||
thing.name = new_name
|
||||
|
||||
/mob/abstract/ghost/storyteller/verb/change_obj_desc(var/obj/thing)
|
||||
set name = "Change Object Description"
|
||||
|
||||
var/new_desc = tgui_input_text(src, "Enter a new description.", "Change Object Description", max_length = MAX_MESSAGE_LEN)
|
||||
if(!new_desc)
|
||||
return
|
||||
|
||||
log_admin("[key_name(src)] has changed [thing]'s description to [new_desc].")
|
||||
thing.desc = new_desc
|
||||
|
||||
/mob/abstract/ghost/storyteller/verb/set_outfit(var/mob/living/carbon/human/H)
|
||||
set name = "Set Outfit"
|
||||
set category = "Storyteller"
|
||||
|
||||
do_dressing(H)
|
||||
|
||||
/mob/abstract/ghost/storyteller/proc/show_traitor_panel(var/mob/M)
|
||||
set name = "Edit Antagonist"
|
||||
set category = "Storyteller"
|
||||
|
||||
if(!istype(M))
|
||||
to_chat(usr, SPAN_WARNING("This can only be used on mobs!"))
|
||||
return
|
||||
|
||||
if(!M.mind)
|
||||
to_chat(usr, SPAN_WARNING("This mob has no mind!"))
|
||||
return
|
||||
|
||||
M.mind.edit_memory()
|
||||
|
||||
/mob/abstract/ghost/storyteller/verb/create_explosion()
|
||||
set name = "Create Explosion"
|
||||
set category = "Storyteller"
|
||||
|
||||
var/turf/epicenter = get_turf(src)
|
||||
var/choice = tgui_input_list(usr, "What size explosion would you like to produce?", "Drop Bomb", list("Small Bomb", "Medium Bomb", "Big Bomb", "Custom Bomb"))
|
||||
switch(choice)
|
||||
if(null)
|
||||
return 0
|
||||
if("Small Bomb")
|
||||
explosion(epicenter, 1, 2, 3, 3)
|
||||
if("Medium Bomb")
|
||||
explosion(epicenter, 2, 3, 4, 4)
|
||||
if("Big Bomb")
|
||||
explosion(epicenter, 3, 5, 7, 5)
|
||||
if("Custom Bomb")
|
||||
var/devastation_range = tgui_input_number(usr, "Set the devastation range (in tiles).", "Devastation")
|
||||
var/heavy_impact_range = tgui_input_number(usr, "Set the heavy impact range (in tiles).", "Heavy")
|
||||
var/light_impact_range = tgui_input_number(usr, "Set the light impact range (in tiles).", "Light")
|
||||
var/flash_range = tgui_input_number(usr, "Set the flash range (in tiles).", "Flash")
|
||||
explosion(epicenter, devastation_range, heavy_impact_range, light_impact_range, flash_range)
|
||||
message_admins(SPAN_NOTICE("[ckey] creating an explosion at [epicenter.loc]."))
|
||||
|
||||
/mob/abstract/ghost/storyteller/verb/delete_atom(atom/O as obj|mob|turf in range(world.view))
|
||||
set name = "Delete"
|
||||
set category = "Storyteller"
|
||||
|
||||
var/action = alert(src, "Are you sure you want to delete:\n[O]\nat ([O.x], [O.y], [O.z])?", "Confirmation", "Yes", "No", "Hard Delete")
|
||||
|
||||
if (action == "No" || !action)
|
||||
return
|
||||
|
||||
if (istype(O, /mob/abstract/ghost/observer))
|
||||
return
|
||||
|
||||
log_admin("[key_name(usr)] deleted [O] at ([O.x],[O.y],[O.z])")
|
||||
message_admins("[key_name_admin(usr)] deleted [O] at ([O.x],[O.y],[O.z])", 1)
|
||||
|
||||
if (isturf(O)) // Can't qdel a turf.
|
||||
var/turf/T = O
|
||||
T.ChangeTurf(/turf/space)
|
||||
return
|
||||
|
||||
if (action == "Yes")
|
||||
qdel(O, TRUE)
|
||||
else
|
||||
// This is naughty, but sometimes necessary.
|
||||
O.Destroy(TRUE) // Because direct del without this breaks things.
|
||||
del(O)
|
||||
|
||||
/mob/abstract/ghost/storyteller/verb/rejuvenate(mob/living/M as mob in range(world.view))
|
||||
set name = "Rejuvenate"
|
||||
set category = "Storyteller"
|
||||
|
||||
if(!istype(M))
|
||||
return
|
||||
|
||||
M.revive()
|
||||
message_admins(SPAN_DANGER("Storyteller [key_name_admin(usr)] healed / revived [key_name_admin(M)]!"), 1)
|
||||
@@ -209,6 +209,10 @@
|
||||
|
||||
/atom/movable/screen/new_player/selection/join_game/Click()
|
||||
var/mob/abstract/new_player/player = usr
|
||||
if(SSticker.prevent_unready && player.ready)
|
||||
tgui_alert(player, "You may not unready during Odyssey setup!", "Odyssey")
|
||||
return
|
||||
|
||||
sound_to(player, click_sound)
|
||||
if(SSticker.current_state <= GAME_STATE_SETTING_UP)
|
||||
if(player.ready)
|
||||
@@ -287,11 +291,15 @@
|
||||
alert(src, "You can not ready up, because you have unacknowledged warnings or notifications. Acknowledge them in OOC->Warnings and Notifications.")
|
||||
return
|
||||
|
||||
if(SSticker.prevent_unready && !readying)
|
||||
tgui_alert(src, "You may not unready during Odyssey setup!", "Odyssey")
|
||||
return
|
||||
|
||||
ready = readying
|
||||
if(ready)
|
||||
last_ready_name = client.prefs.real_name
|
||||
SSticker.update_ready_list(src)
|
||||
else
|
||||
else if(!SSticker.prevent_unready)
|
||||
ready = FALSE
|
||||
|
||||
/mob/abstract/new_player/proc/join_game(href, href_list)
|
||||
@@ -315,7 +323,7 @@
|
||||
if(alert(src, "Are you sure you wish to observe? You will have to wait [GLOB.config.respawn_delay] minutes before being able to respawn.", "Player Setup", "Yes", "No") != "Yes")
|
||||
return FALSE
|
||||
|
||||
var/mob/abstract/observer/observer = new /mob/abstract/observer(src)
|
||||
var/mob/abstract/ghost/observer/observer = new /mob/abstract/ghost/observer(null, src)
|
||||
spawning = 1
|
||||
src.stop_sound_channel(CHANNEL_LOBBYMUSIC) // stop the jams for observers
|
||||
|
||||
@@ -342,7 +350,7 @@
|
||||
observer.real_name = client.prefs.real_name
|
||||
observer.name = observer.real_name
|
||||
if(!client.holder && !GLOB.config.antag_hud_allowed)
|
||||
remove_verb(observer, /mob/abstract/observer/verb/toggle_antagHUD)
|
||||
remove_verb(observer, /mob/abstract/ghost/observer/verb/toggle_antagHUD)
|
||||
observer.ckey = ckey
|
||||
observer.initialise_postkey()
|
||||
observer.client.init_verbs()
|
||||
|
||||
@@ -107,7 +107,13 @@ INITIALIZE_IMMEDIATE(/mob/abstract/new_player)
|
||||
alert(src, "You can not ready up, because you have unacknowledged warnings or notifications. Acknowledge them in OOC->Warnings and Notifications.")
|
||||
return
|
||||
|
||||
ready = text2num(href_list["ready"])
|
||||
var/new_ready_state = text2num(href_list["ready"])
|
||||
|
||||
if(SSticker.prevent_unready && new_ready_state == FALSE)
|
||||
tgui_alert(src, "You may not unready during Odyssey setup!", "Odyssey")
|
||||
return
|
||||
|
||||
ready = new_ready_state
|
||||
else
|
||||
ready = 0
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
if (!M.client || isnewplayer(M))
|
||||
continue
|
||||
if(get_turf(M) in messageturfs)
|
||||
if (isobserver(M))
|
||||
if (isghost(M))
|
||||
ghosts_nearby += M
|
||||
continue
|
||||
else if (isliving(M) && !(type == 2 && isdeaf(M)))
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/proc/examinate(mob/user, atom/target, show_extended)
|
||||
if(user.is_blind() || (user.stat && !isobserver(user)))
|
||||
if(user.is_blind() || (user.stat && !isghost(user)))
|
||||
to_chat(user, SPAN_NOTICE("Something is there, but you cannot see it."))
|
||||
return
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
if(!istype(src, /mob/living/test) && cant_hear())
|
||||
return
|
||||
|
||||
if(speaker && !istype(speaker, /mob/living/test) && (!speaker.client && istype(src,/mob/abstract/observer) && client.prefs.toggles & CHAT_GHOSTEARS && !(speaker in view(src))))
|
||||
if(speaker && !istype(speaker, /mob/living/test) && (!speaker.client && istype(src,/mob/abstract/ghost/observer) && client.prefs.toggles & CHAT_GHOSTEARS && !(speaker in view(src))))
|
||||
//Does the speaker have a client? It's either random stuff that observers won't care about (Experiment 97B says, 'EHEHEHEHEHEHEHE')
|
||||
//Or someone snoring. So we make it where they won't hear it.
|
||||
return
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
//make sure the air can transmit speech - hearer's side
|
||||
var/turf/T = get_turf(src)
|
||||
var/vacuum_proof = ((language && (language.flags & PRESSUREPROOF)) || isobserver(src))
|
||||
var/vacuum_proof = ((language && (language.flags & PRESSUREPROOF)) || isghost(src))
|
||||
if(T && !vacuum_proof) //Ghosts can hear even in vacuum.
|
||||
var/datum/gas_mixture/environment = T.return_air()
|
||||
var/pressure = (environment)? environment.return_pressure() : 0
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
//non-verbal languages are garbled if you can't see the speaker. Yes, this includes if they are inside a closet.
|
||||
if (language && (language.flags & NONVERBAL))
|
||||
if((!speaker || (src.sdisabilities & BLIND || src.blinded) || !(speaker in view(src))) && !isobserver(src))
|
||||
if((!speaker || (src.sdisabilities & BLIND || src.blinded) || !(speaker in view(src))) && !isghost(src))
|
||||
message = stars(message)
|
||||
|
||||
if(!(language && (language.flags & INNATE)) && !say_understands(speaker, language)) // skip understanding checks for INNATE languages
|
||||
@@ -47,7 +47,7 @@
|
||||
message = "<i>[message]</i>"
|
||||
|
||||
var/track = null
|
||||
if(isobserver(src))
|
||||
if(isghost(src))
|
||||
if(speaker_name != speaker.real_name && speaker.real_name)
|
||||
speaker_name = "[speaker.real_name] ([speaker_name])"
|
||||
track = "[ghost_follow_link(speaker, src)] "
|
||||
@@ -214,7 +214,7 @@
|
||||
else
|
||||
track = "<a class='ai_tracking' href='byond://?src=[REF(src)];trackname=[html_encode(speaker_name)];track=[REF(speaker)]'>[speaker_name] ([jobname])</a>"
|
||||
|
||||
if(istype(src, /mob/abstract/observer))
|
||||
if(isghost(src))
|
||||
if(speaker != null)
|
||||
if(speaker_name != speaker.real_name && !isAI(speaker)) //Announce computer and various stuff that broadcasts doesn't use it's real name but AI's can't pretend to be other mobs.
|
||||
speaker_name = "[speaker.real_name] ([speaker_name])"
|
||||
@@ -240,7 +240,7 @@
|
||||
if(vr_mob)
|
||||
to_chat(vr_mob, "[part_a][speaker_name][part_b][formatted]")
|
||||
|
||||
/mob/abstract/observer/on_hear_radio(part_a, speaker_name, track, part_b, formatted)
|
||||
/mob/abstract/ghost/observer/on_hear_radio(part_a, speaker_name, track, part_b, formatted)
|
||||
to_chat(src, "[track][part_a][speaker_name][part_b][formatted]")
|
||||
|
||||
/mob/living/silicon/on_hear_radio(part_a, speaker_name, track, part_b, formatted)
|
||||
|
||||
@@ -232,7 +232,7 @@
|
||||
/mob/abstract/new_player/hear_broadcast(var/datum/language/language, var/mob/speaker, var/speaker_name, var/message)
|
||||
return
|
||||
|
||||
/mob/abstract/observer/hear_broadcast(var/datum/language/language, var/mob/speaker, var/speaker_name, var/message)
|
||||
/mob/abstract/ghost/hear_broadcast(var/datum/language/language, var/mob/speaker, var/speaker_name, var/message)
|
||||
if(speaker.name == speaker_name || antagHUD)
|
||||
to_chat(src, "[ghost_follow_link(speaker, src)] <i><span class='game say'>[language.name], <span class='name'>[speaker_name]</span> [message]</span></i>")
|
||||
else
|
||||
|
||||
@@ -126,7 +126,7 @@
|
||||
return
|
||||
|
||||
for(var/mob/player in GLOB.player_list)
|
||||
if(istype(player,/mob/abstract/observer) || check_special_condition(player))
|
||||
if(isobserver(player) || check_special_condition(player))
|
||||
if(!within_jamming_range(player))
|
||||
to_chat(player, msg)
|
||||
|
||||
|
||||
@@ -256,7 +256,7 @@
|
||||
for(var/mob/player in GLOB.player_list)
|
||||
if(player == speaker)
|
||||
to_chat(player, msg)
|
||||
else if(isobserver(player))
|
||||
else if(isghost(player))
|
||||
to_chat(player, "[ghost_follow_link(speaker, player)] [msg]")
|
||||
else if(!within_jamming_range(player) && check_special_condition(player))
|
||||
if(speaker_encryption_key)
|
||||
|
||||
@@ -1187,7 +1187,7 @@
|
||||
target.show_message(SPAN_NOTICE("You hear a voice that seems to echo around the room: [say]"))
|
||||
usr.show_message(SPAN_NOTICE("You project your mind into [target.real_name]: [say]"))
|
||||
log_say("[key_name(usr)] sent a telepathic message to [key_name(target)]: [say]")
|
||||
for(var/mob/abstract/observer/G in GLOB.dead_mob_list)
|
||||
for(var/mob/abstract/ghost/observer/G in GLOB.dead_mob_list)
|
||||
G.show_message("<i>Telepathic message from <b>[src]</b> to <b>[target]</b>: [say]</i>")
|
||||
|
||||
/mob/living/carbon/human/proc/remoteobserve()
|
||||
|
||||
@@ -567,7 +567,7 @@
|
||||
|
||||
var/mob/M = targets[target]
|
||||
|
||||
if(istype(M, /mob/abstract/observer) || M.stat == DEAD)
|
||||
if(isobserver(M) || M.stat == DEAD)
|
||||
to_chat(src, SPAN_DANGER("[M]'s hivenet implant is inactive!"))
|
||||
return
|
||||
|
||||
@@ -577,12 +577,12 @@
|
||||
|
||||
log_say("[key_name(src)] issued a hivenet order to [key_name(M)]: [text]")
|
||||
|
||||
if(istype(M, /mob/living/carbon/human) && isvaurca(M))
|
||||
if(ishuman(M) && isvaurca(M))
|
||||
to_chat(M, SPAN_DANGER("You feel a buzzing in the back of your head, and your mind fills with the authority of [src.real_name], your ruler:"))
|
||||
to_chat(M, SPAN_NOTICE(" [text]"))
|
||||
else
|
||||
to_chat(M, SPAN_DANGER("Like lead slabs crashing into the ocean, alien thoughts drop into your mind: [text]"))
|
||||
if(istype(M,/mob/living/carbon/human))
|
||||
if(ishuman(M))
|
||||
var/mob/living/carbon/human/H = M
|
||||
if(H.species.name == src.species.name)
|
||||
return
|
||||
|
||||
@@ -302,8 +302,8 @@
|
||||
return ..()
|
||||
|
||||
/obj/effect/golemrune/process()
|
||||
var/mob/abstract/observer/ghost
|
||||
for(var/mob/abstract/observer/O in src.loc)
|
||||
var/mob/abstract/ghost/observer/ghost
|
||||
for(var/mob/abstract/ghost/observer/O in src.loc)
|
||||
if(!O.client)
|
||||
continue
|
||||
if(O.mind && O.mind.current && O.mind.current.stat != DEAD)
|
||||
|
||||
@@ -863,10 +863,10 @@ default behaviour is:
|
||||
if(deaf >= 0)
|
||||
ear_deaf = deaf
|
||||
|
||||
/mob/proc/can_be_possessed_by(var/mob/abstract/observer/possessor)
|
||||
/mob/proc/can_be_possessed_by(var/mob/abstract/ghost/observer/possessor)
|
||||
return istype(possessor) && possessor.client
|
||||
|
||||
/mob/living/can_be_possessed_by(var/mob/abstract/observer/possessor)
|
||||
/mob/living/can_be_possessed_by(var/mob/abstract/ghost/observer/possessor)
|
||||
if(!..())
|
||||
return 0
|
||||
if(!possession_candidate)
|
||||
@@ -879,7 +879,7 @@ default behaviour is:
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/mob/living/proc/do_possession(var/mob/abstract/observer/possessor)
|
||||
/mob/living/proc/do_possession(var/mob/abstract/ghost/observer/possessor)
|
||||
|
||||
if(!(istype(possessor) && possessor.ckey))
|
||||
return 0
|
||||
|
||||
@@ -35,6 +35,6 @@
|
||||
/mob/proc/examine_laws(var/mob/living/silicon/S)
|
||||
return
|
||||
|
||||
/mob/abstract/observer/examine_laws(var/mob/living/silicon/S)
|
||||
/mob/abstract/ghost/observer/examine_laws(var/mob/living/silicon/S)
|
||||
if(antagHUD || is_admin(src))
|
||||
return S.laws.get_laws(src)
|
||||
|
||||
@@ -132,7 +132,7 @@
|
||||
|
||||
return ..()
|
||||
|
||||
/mob/living/silicon/robot/drone/can_be_possessed_by(var/mob/abstract/observer/possessor)
|
||||
/mob/living/silicon/robot/drone/can_be_possessed_by(var/mob/abstract/ghost/observer/possessor)
|
||||
if(!istype(possessor) || !possessor.client || !possessor.ckey)
|
||||
return FALSE
|
||||
if(!GLOB.config.allow_drone_spawn)
|
||||
@@ -148,7 +148,7 @@
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/mob/living/silicon/robot/drone/do_possession(var/mob/abstract/observer/possessor)
|
||||
/mob/living/silicon/robot/drone/do_possession(var/mob/abstract/ghost/observer/possessor)
|
||||
if(!(istype(possessor) && possessor.ckey))
|
||||
return 0
|
||||
if(src.ckey || src.client)
|
||||
@@ -246,7 +246,7 @@
|
||||
assign_drone_to_matrix(src, matrix_tag)
|
||||
master_matrix.message_drones(MATRIX_NOTICE("Energy surges through your circuits. The matriarch has come online."))
|
||||
|
||||
/mob/living/silicon/robot/drone/construction/matriarch/do_possession(mob/abstract/observer/possessor)
|
||||
/mob/living/silicon/robot/drone/construction/matriarch/do_possession(mob/abstract/ghost/observer/possessor)
|
||||
. = ..()
|
||||
SSghostroles.remove_spawn_atom("matriarchmaintdrone", src)
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@
|
||||
return FALSE
|
||||
|
||||
if(!R.key)
|
||||
for(var/mob/abstract/observer/ghost in GLOB.player_list)
|
||||
for(var/mob/abstract/ghost/observer/ghost in GLOB.player_list)
|
||||
if(ghost.mind?.current == R)
|
||||
R.key = ghost.key
|
||||
|
||||
|
||||
@@ -26,6 +26,13 @@
|
||||
scrambled_codes = TRUE
|
||||
status_flags = GODMODE|NOFALL
|
||||
|
||||
/// The BST's original mob. Moved here from /datum/holder to support storytellers.
|
||||
var/mob/original_mob
|
||||
|
||||
/mob/living/silicon/robot/bluespace/Destroy(force)
|
||||
original_mob = null
|
||||
return ..()
|
||||
|
||||
/mob/living/silicon/robot/bluespace/verb/antigrav()
|
||||
set name = "Toggle Gravity"
|
||||
set desc = "Use bluespace technology to ignore gravity."
|
||||
@@ -67,10 +74,10 @@
|
||||
animate(src, alpha = 0, time = 9, easing = QUAD_EASING)
|
||||
|
||||
if(key)
|
||||
if(client.holder && client.holder.original_mob)
|
||||
client.holder.original_mob.key = key
|
||||
if(original_mob)
|
||||
original_mob.key = key
|
||||
else
|
||||
var/mob/abstract/observer/ghost = new(src) //Transfer safety to observer spawning proc.
|
||||
var/mob/abstract/ghost/observer/ghost = new(src, src) //Transfer safety to observer spawning proc.
|
||||
ghost.key = key
|
||||
ghost.mind.name = "[ghost.key] BSTech"
|
||||
ghost.name = "[ghost.key] BSTech"
|
||||
@@ -85,6 +92,11 @@
|
||||
status_flags ^= GODMODE
|
||||
to_chat(src, SPAN_NOTICE("God mode is now [status_flags & GODMODE ? "enabled" : "disabled"]"))
|
||||
|
||||
/mob/living/silicon/robot/bluespace/vv_edit_var(var_name, var_value)
|
||||
if(var_name == NAMEOF(src, original_mob))
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/mob/living/silicon/robot/purpose
|
||||
mod_type = "Purpose"
|
||||
spawn_module = /obj/item/robot_module/purpose
|
||||
|
||||
@@ -76,7 +76,7 @@
|
||||
GLOB.move_manager.stop_looping(src)
|
||||
|
||||
if(prob(2)) //spooky
|
||||
var/mob/abstract/observer/spook = locate() in range(src,5)
|
||||
var/mob/abstract/ghost/observer/spook = locate() in range(src,5)
|
||||
if(spook)
|
||||
var/turf/T = spook.loc
|
||||
var/list/visible = list()
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
if(!B.brainmob.key)
|
||||
var/ghost_can_reenter = 0
|
||||
if(B.brainmob.mind)
|
||||
for(var/mob/abstract/observer/G in GLOB.player_list)
|
||||
for(var/mob/abstract/ghost/observer/G in GLOB.player_list)
|
||||
if(G.can_reenter_corpse && G.mind == B.brainmob.mind)
|
||||
ghost_can_reenter = 1
|
||||
break
|
||||
|
||||
@@ -41,7 +41,8 @@
|
||||
|
||||
//None of these mobs can 'die' in any sense, and none of them should be able to become ghosts.
|
||||
//Ghosts are the only ones that even technically 'exist' and aren't just an abstraction using mob code for convenience
|
||||
if (istype(src, /mob/living))
|
||||
//Well, those and storytellers. This code is seriously shit and needs a rework, but who gives a fuck right now. Sue me.
|
||||
if (istype(src, /mob/living) && !isstoryteller(src))
|
||||
ghostize()
|
||||
|
||||
if (istype(src.loc, /atom/movable))
|
||||
@@ -180,7 +181,7 @@
|
||||
continue
|
||||
if (!M.client || istype(M, /mob/abstract/new_player))
|
||||
continue
|
||||
if((get_turf(M) in messageturfs) || (show_observers && isobserver(M) && (M.client.prefs.toggles & CHAT_GHOSTSIGHT)))
|
||||
if((get_turf(M) in messageturfs) || (show_observers && isghost(M) && (M.client.prefs.toggles & CHAT_GHOSTSIGHT)))
|
||||
messagemobs += M
|
||||
|
||||
for(var/o in GLOB.listening_objects)
|
||||
@@ -191,7 +192,7 @@
|
||||
|
||||
for(var/A in messagemobs)
|
||||
var/mob/M = A
|
||||
if(isobserver(M))
|
||||
if(isghost(M))
|
||||
M.show_message("[ghost_follow_link(src, M)] [message]", 1)
|
||||
continue
|
||||
if(self_message && M == src)
|
||||
|
||||
@@ -582,8 +582,8 @@ var/list/intents = list(I_HELP,I_DISARM,I_GRAB,I_HURT)
|
||||
follow = "[ghost_follow_link(subject, M)] "
|
||||
if(M.stat != DEAD && M.client.holder)
|
||||
follow = "([admin_jump_link(subject, M.client.holder)]) "
|
||||
var/mob/abstract/observer/DM
|
||||
if(istype(subject, /mob/abstract/observer))
|
||||
var/mob/abstract/ghost/observer/DM
|
||||
if(istype(subject, /mob/abstract/ghost/observer))
|
||||
DM = subject
|
||||
if(M.client.holder) // What admins see
|
||||
lname = "[keyname][(DM && DM.anonsay) ? "*" : (DM ? "" : "^")] ([name])"
|
||||
@@ -1092,7 +1092,7 @@ var/list/intents = list(I_HELP,I_DISARM,I_GRAB,I_HURT)
|
||||
if(P?.ismultitool())
|
||||
return P
|
||||
|
||||
/mob/abstract/observer/get_multitool()
|
||||
/mob/abstract/ghost/observer/get_multitool()
|
||||
return can_admin_interact() && ..(ghost_multitool)
|
||||
|
||||
/mob/living/carbon/human/get_multitool()
|
||||
|
||||
@@ -250,7 +250,7 @@
|
||||
if(mob.control_object)
|
||||
Move_object(direct)
|
||||
|
||||
if(mob.incorporeal_move && isobserver(mob))
|
||||
if(mob.incorporeal_move && isabstractmob(mob))
|
||||
Process_Incorpmove(direct, mob)
|
||||
return
|
||||
|
||||
|
||||
Reference in New Issue
Block a user