diff --git a/code/__defines/misc.dm b/code/__defines/misc.dm index 5106ec1ef3..48b85e24c1 100644 --- a/code/__defines/misc.dm +++ b/code/__defines/misc.dm @@ -112,6 +112,7 @@ #define AREA_ALLOW_LARGE_SIZE 0x400 // If mob size is limited in the area. #define AREA_BLOCK_SUIT_SENSORS 0x800 // If suit sensors are blocked in the area. #define AREA_BLOCK_TRACKING 0x1000 // If camera tracking is blocked in the area. +#define AREA_BLOCK_GHOST_SIGHT 0x2000 // If an area blocks sight for ghosts // CHOMPAdd Start/area #define PHASE_SHIELDED 0x200000 // A less rough way to prevent phase shifting without blocking access diff --git a/code/__defines/visualnet.dm b/code/__defines/visualnet.dm new file mode 100644 index 0000000000..4b503bee2d --- /dev/null +++ b/code/__defines/visualnet.dm @@ -0,0 +1 @@ +#define CHUNK_SIZE 16 diff --git a/code/_helpers/global_lists.dm b/code/_helpers/global_lists.dm index ea4995b16e..40bb6c20e8 100644 --- a/code/_helpers/global_lists.dm +++ b/code/_helpers/global_lists.dm @@ -62,6 +62,7 @@ var/global/list/exclude_jobs = list(/datum/job/ai,/datum/job/cyborg) var/list/datum/visualnet/visual_nets = list() var/datum/visualnet/camera/cameranet = new() var/datum/visualnet/cult/cultnet = new() +var/datum/visualnet/ghost/ghostnet = new() // Runes var/global/list/rune_list = new() diff --git a/code/game/area/Space Station 13 areas_ch.dm b/code/game/area/Space Station 13 areas_ch.dm index ea2db10925..8f65344611 100644 --- a/code/game/area/Space Station 13 areas_ch.dm +++ b/code/game/area/Space Station 13 areas_ch.dm @@ -32,11 +32,8 @@ /area/crew_quarters/bar flags = RAD_SHIELDED -/area/crew_quarters/barrestroom - flags = RAD_SHIELDED - /area/crew_quarters/sleep - flags = RAD_SHIELDED | AREA_SOUNDPROOF | AREA_FORBID_EVENTS | AREA_ALLOW_LARGE_SIZE | AREA_BLOCK_SUIT_SENSORS | AREA_BLOCK_TRACKING + flags = RAD_SHIELDED | AREA_SOUNDPROOF | AREA_FORBID_EVENTS | AREA_ALLOW_LARGE_SIZE | AREA_BLOCK_SUIT_SENSORS | AREA_BLOCK_TRACKING | AREA_FORBID_SINGULO /area/crew_quarters/sleep/vistor_room_1 @@ -87,3 +84,105 @@ /area/maintenance/field name = "Maintenance Deck Field" + +/area/security/armoury + flags = PHASE_SHIELDED + +/area/centcom/living + flags = AREA_FLAG_IS_NOT_PERSISTENT | AREA_SOUNDPROOF | AREA_ALLOW_LARGE_SIZE | AREA_BLOCK_GHOSTS | AREA_BLOCK_TRACKING | AREA_BLOCK_SUIT_SENSORS | AREA_BLOCK_PHASE_SHIFT | AREA_BLOCK_GHOST_SIGHT + +/area/centcom/specops + flags = AREA_FLAG_IS_NOT_PERSISTENT | AREA_BLOCK_GHOSTS | AREA_BLOCK_TRACKING | AREA_BLOCK_SUIT_SENSORS | AREA_BLOCK_PHASE_SHIFT | AREA_BLOCK_GHOST_SIGHT + +/area/centcom/command + flags = AREA_FLAG_IS_NOT_PERSISTENT | AREA_BLOCK_GHOSTS | AREA_BLOCK_TRACKING | AREA_BLOCK_SUIT_SENSORS | AREA_BLOCK_PHASE_SHIFT | AREA_BLOCK_GHOST_SIGHT + +/area/centcom/creed + flags = AREA_FLAG_IS_NOT_PERSISTENT | AREA_BLOCK_GHOSTS | AREA_BLOCK_TRACKING | AREA_BLOCK_SUIT_SENSORS | AREA_BLOCK_PHASE_SHIFT | AREA_BLOCK_GHOST_SIGHT + +/area/shuttle/response_ship + flags = AREA_FLAG_IS_NOT_PERSISTENT | AREA_BLOCK_GHOSTS | AREA_BLOCK_TRACKING | AREA_BLOCK_SUIT_SENSORS | AREA_BLOCK_PHASE_SHIFT | AREA_BLOCK_GHOST_SIGHT + +/area/shuttle/administration + flags = AREA_FLAG_IS_NOT_PERSISTENT | AREA_BLOCK_GHOSTS | AREA_BLOCK_TRACKING | AREA_BLOCK_SUIT_SENSORS | AREA_BLOCK_PHASE_SHIFT | AREA_BLOCK_GHOST_SIGHT + +/area/shuttle/transport1/centcom + flags = AREA_FLAG_IS_NOT_PERSISTENT | AREA_BLOCK_GHOSTS | AREA_BLOCK_TRACKING | AREA_BLOCK_SUIT_SENSORS | AREA_BLOCK_PHASE_SHIFT | AREA_BLOCK_GHOST_SIGHT + +/area/shuttle/syndicate + flags = AREA_FLAG_IS_NOT_PERSISTENT | AREA_BLOCK_GHOSTS | AREA_BLOCK_TRACKING | AREA_BLOCK_SUIT_SENSORS | AREA_BLOCK_PHASE_SHIFT | AREA_BLOCK_GHOST_SIGHT + +/area/syndicate_station + flags = AREA_FLAG_IS_NOT_PERSISTENT | AREA_BLOCK_GHOSTS | AREA_BLOCK_TRACKING | AREA_BLOCK_SUIT_SENSORS | AREA_BLOCK_PHASE_SHIFT | AREA_BLOCK_GHOST_SIGHT + +/area/syndicate_mothership/elite_squad + flags = AREA_FLAG_IS_NOT_PERSISTENT | AREA_BLOCK_GHOSTS | AREA_BLOCK_TRACKING | AREA_BLOCK_SUIT_SENSORS | AREA_BLOCK_PHASE_SHIFT | AREA_BLOCK_GHOST_SIGHT + +/area/shuttle/syndicate_elite/mothership + flags = AREA_FLAG_IS_NOT_PERSISTENT | AREA_BLOCK_GHOSTS | AREA_BLOCK_TRACKING | AREA_BLOCK_SUIT_SENSORS | AREA_BLOCK_PHASE_SHIFT | AREA_BLOCK_GHOST_SIGHT + +/area/shuttle/skipjack + flags = AREA_FLAG_IS_NOT_PERSISTENT | AREA_BLOCK_GHOSTS | AREA_BLOCK_TRACKING | AREA_BLOCK_SUIT_SENSORS | AREA_BLOCK_PHASE_SHIFT | AREA_BLOCK_GHOST_SIGHT + +/area/skipjack_station + flags = AREA_FLAG_IS_NOT_PERSISTENT | AREA_BLOCK_GHOSTS | AREA_BLOCK_TRACKING | AREA_BLOCK_SUIT_SENSORS | AREA_BLOCK_PHASE_SHIFT | AREA_BLOCK_GHOST_SIGHT + +/area/ninja_dojo/dojo + flags = AREA_FLAG_IS_NOT_PERSISTENT | AREA_BLOCK_GHOSTS | AREA_BLOCK_TRACKING | AREA_BLOCK_SUIT_SENSORS | AREA_BLOCK_PHASE_SHIFT | AREA_BLOCK_GHOST_SIGHT + +/area/shuttle/ninja + flags = AREA_FLAG_IS_NOT_PERSISTENT | AREA_BLOCK_GHOSTS | AREA_BLOCK_TRACKING | AREA_BLOCK_SUIT_SENSORS | AREA_BLOCK_PHASE_SHIFT | AREA_BLOCK_GHOST_SIGHT + +/area/shuttle/trade + flags = AREA_FLAG_IS_NOT_PERSISTENT | AREA_BLOCK_GHOSTS | AREA_BLOCK_TRACKING | AREA_BLOCK_SUIT_SENSORS | AREA_BLOCK_PHASE_SHIFT | AREA_BLOCK_GHOST_SIGHT + +/area/shuttle/merchant + flags = AREA_FLAG_IS_NOT_PERSISTENT | AREA_BLOCK_GHOSTS | AREA_BLOCK_TRACKING | AREA_BLOCK_SUIT_SENSORS | AREA_BLOCK_PHASE_SHIFT | AREA_BLOCK_GHOST_SIGHT + +/area/wizard_station + flags = AREA_FLAG_IS_NOT_PERSISTENT | AREA_BLOCK_GHOSTS | AREA_BLOCK_TRACKING | AREA_BLOCK_SUIT_SENSORS | AREA_BLOCK_PHASE_SHIFT | AREA_BLOCK_GHOST_SIGHT + +/area/crew_quarters/heads/sc + flags = RAD_SHIELDED | AREA_FORBID_EVENTS | AREA_FORBID_SINGULO + +/area/crew_quarters/heads/sc/hop/quarters + flags = RAD_SHIELDED | AREA_FORBID_EVENTS | AREA_FORBID_SINGULO | AREA_BLOCK_TRACKING | AREA_BLOCK_SUIT_SENSORS + +/area/crew_quarters/heads/sc/hor/quarters + flags = RAD_SHIELDED | AREA_FORBID_EVENTS | AREA_FORBID_SINGULO | AREA_BLOCK_TRACKING | AREA_BLOCK_SUIT_SENSORS + +/area/crew_quarters/heads/sc/chief/quarters + flags = RAD_SHIELDED | AREA_FORBID_EVENTS | AREA_FORBID_SINGULO | AREA_BLOCK_TRACKING | AREA_BLOCK_SUIT_SENSORS + +/area/crew_quarters/heads/sc/hos/quarters + flags = RAD_SHIELDED | AREA_FORBID_EVENTS | AREA_FORBID_SINGULO | AREA_BLOCK_TRACKING | AREA_BLOCK_SUIT_SENSORS + +/area/crew_quarters/heads/sc/cmo/quarters + flags = RAD_SHIELDED | AREA_FORBID_EVENTS | AREA_FORBID_SINGULO | AREA_BLOCK_TRACKING | AREA_BLOCK_SUIT_SENSORS + +/area/crew_quarters/heads/sc/restroom + flags = RAD_SHIELDED | AREA_FORBID_EVENTS | AREA_FORBID_SINGULO | AREA_BLOCK_TRACKING | AREA_BLOCK_SUIT_SENSORS + +/area/crew_quarters/heads/sc/bs + flags = RAD_SHIELDED | AREA_FORBID_EVENTS | AREA_FORBID_SINGULO | AREA_BLOCK_TRACKING | AREA_BLOCK_SUIT_SENSORS + +/area/crew_quarters/toilet + flags = RAD_SHIELDED | AREA_FORBID_EVENTS | AREA_FORBID_SINGULO | AREA_BLOCK_TRACKING | AREA_BLOCK_SUIT_SENSORS + +/area/crew_quarters/barrestroom + flags = RAD_SHIELDED | AREA_FORBID_EVENTS | AREA_FORBID_SINGULO | AREA_BLOCK_TRACKING | AREA_BLOCK_SUIT_SENSORS + +/area/engineering/engi_restroom + flags = RAD_SHIELDED | AREA_FORBID_EVENTS | AREA_FORBID_SINGULO | AREA_BLOCK_TRACKING | AREA_BLOCK_SUIT_SENSORS + +/area/security/security_restroom + flags = RAD_SHIELDED | AREA_FORBID_EVENTS | AREA_FORBID_SINGULO | AREA_BLOCK_TRACKING | AREA_BLOCK_SUIT_SENSORS + +/area/medical/medical_restroom + flags = RAD_SHIELDED | AREA_FORBID_EVENTS | AREA_FORBID_SINGULO | AREA_BLOCK_TRACKING | AREA_BLOCK_SUIT_SENSORS + +/area/rnd/research_restroom_sc + flags = RAD_SHIELDED | AREA_FORBID_EVENTS | AREA_FORBID_SINGULO | AREA_BLOCK_TRACKING | AREA_BLOCK_SUIT_SENSORS + +/area/crew_quarters/toilet/firstdeck + flags = RAD_SHIELDED | AREA_FORBID_EVENTS | AREA_FORBID_SINGULO | AREA_BLOCK_TRACKING | AREA_BLOCK_SUIT_SENSORS diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm index ac23d3a552..5c4e903ff6 100644 --- a/code/game/area/areas.dm +++ b/code/game/area/areas.dm @@ -562,6 +562,8 @@ GLOBAL_DATUM(spoiler_obfuscation_image, /image) return if(!isliving(ourmob)) return + if(ourmob.client?.holder) + return if(isanimal(ourmob)) var/mob/living/simple_mob/shadekin/SK = ourmob if(SK.ability_flags & AB_PHASE_SHIFTED) diff --git a/code/modules/admin/admin_verb_lists_vr.dm b/code/modules/admin/admin_verb_lists_vr.dm index 2089389432..dd26754792 100644 --- a/code/modules/admin/admin_verb_lists_vr.dm +++ b/code/modules/admin/admin_verb_lists_vr.dm @@ -579,6 +579,8 @@ var/list/admin_verbs_event_manager = list( /client/proc/start_vote, /client/proc/AdminCreateVirus, /client/proc/ReleaseVirus, + /client/proc/add_hidden_area, + /client/proc/remove_hidden_area, /datum/admins/proc/quick_nif, //CHOMPStation Add, /datum/admins/proc/quick_authentic_nif, //CHOMPStation add /client/proc/reload_jobwhitelist, //ChompADD diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index eedc180a9c..9da59bae9f 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -67,14 +67,12 @@ var/mob/observer/dead/ghost if(build_mode) togglebuildmode(body) - ghost = body.ghostize(1) - ghost.admin_ghosted = 1 + ghost = body.ghostize(1, TRUE) log_and_message_admins("[key_name(src)] admin-ghosted.") // CHOMPEdit - Add logging. if(build_mode == "Yes") togglebuildmode(ghost) else - ghost = body.ghostize(1) - ghost.admin_ghosted = 1 + ghost = body.ghostize(1, TRUE) log_and_message_admins("[key_name(src)] admin-ghosted.") // CHOMPEdit - Add logging. init_verbs() if(body) @@ -361,6 +359,9 @@ message_admins("[src] re-admined themself.", 1) to_chat(src, span_filter_system(span_interface("You now have the keys to control the planet, or at least a small space station"))) remove_verb(src, /client/proc/readmin_self) + if(isobserver(mob)) + var/mob/observer/dead/our_mob = mob + our_mob.visualnet?.addVisibility(our_mob, src) /client/proc/deadmin_self() set name = "De-admin self" @@ -373,6 +374,9 @@ deadmin() to_chat(src, span_filter_system(span_interface("You are now a normal player."))) add_verb(src, /client/proc/readmin_self) + if(isobserver(mob)) + var/mob/observer/dead/our_mob = mob + our_mob.visualnet?.removeVisibility(our_mob, src) feedback_add_details("admin_verb","DAS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /client/proc/toggle_log_hrefs() @@ -552,3 +556,35 @@ B.icon_state = "bottle-1" B.reagents.add_reagent(R.id, 60) B.name = "[B.name] of [R.name]" + +/client/proc/add_hidden_area() + set name = "Add Ghostsight Block Area" + set category = "Admin.Game" + + var/list/blocked_areas = list() + for(var/area/A in world) + if(!A.flag_check(AREA_BLOCK_GHOST_SIGHT)) + blocked_areas[A.name] = A + blocked_areas = sortTim(blocked_areas, GLOBAL_PROC_REF(cmp_text_asc)) + var/selected_area = tgui_input_list(usr, "Pick an area to hide from ghost", "Select Area to hide", blocked_areas) + var/area/A = blocked_areas[selected_area] + if(!A) + return + A.flags |= AREA_BLOCK_GHOST_SIGHT + ghostnet.addArea(A) + +/client/proc/remove_hidden_area() + set name = "Remove Ghostsight Block Area" + set category = "Admin.Game" + + var/list/blocked_areas = list() + for(var/area/A in world) + if(A.flag_check(AREA_BLOCK_GHOST_SIGHT)) + blocked_areas[A.name] = A + blocked_areas = sortTim(blocked_areas, GLOBAL_PROC_REF(cmp_text_asc)) + var/selected_area = tgui_input_list(usr, "Pick a from ghost hidden area to let them see it again", "Select Hidden Area", blocked_areas) + var/area/A = blocked_areas[selected_area] + if(!A) + return + A.flags &= ~(AREA_BLOCK_GHOST_SIGHT) + ghostnet.removeArea(A) diff --git a/code/modules/admin/player_effects.dm b/code/modules/admin/player_effects.dm index d65d870c58..c5222c5b49 100644 --- a/code/modules/admin/player_effects.dm +++ b/code/modules/admin/player_effects.dm @@ -1,7 +1,7 @@ /client/proc/player_effects(var/mob/target in mob_list) set name = "Player Effects" set desc = "Modify a player character with various 'special treatments' from a list." - set category = "Fun.Event Kit" //CHOMPEdit + set category = "Fun.Event Kit" if(!check_rights(R_FUN)) return diff --git a/code/modules/env_message/env_message.dm b/code/modules/env_message/env_message.dm index 256b877492..ce4b17d41c 100644 --- a/code/modules/env_message/env_message.dm +++ b/code/modules/env_message/env_message.dm @@ -124,7 +124,7 @@ var/global/list/env_messages = list() /client/proc/create_gm_message() set name = "Map Message - Create" set desc = "Create an ooc message in the environment for other players to see." - set category = "Fun.Event Kit" //CHOMPEdit + set category = "Fun.Event Kit" if(!check_rights(R_FUN)) return @@ -154,7 +154,7 @@ var/global/list/env_messages = list() /client/proc/remove_gm_message() set name = "Map Message - Remove" set desc = "Remove any env/map message." - set category = "Fun.Event Kit" //CHOMPEdit + set category = "Fun.Event Kit" if(!istype(src) || !src.ckey) return diff --git a/code/modules/eventkit/generic_objects/generic_item.dm b/code/modules/eventkit/generic_objects/generic_item.dm index 88e0f3492e..fd1b7d9e20 100644 --- a/code/modules/eventkit/generic_objects/generic_item.dm +++ b/code/modules/eventkit/generic_objects/generic_item.dm @@ -90,7 +90,7 @@ return ..() /client/proc/generic_item() - set category = "Fun.Event Kit" //CHOMPEdit + set category = "Fun.Event Kit" set name = "Spawn Generic Item" set desc = "Spawn a customisable item with a range of different options." diff --git a/code/modules/eventkit/generic_objects/generic_structure.dm b/code/modules/eventkit/generic_objects/generic_structure.dm index 5d3de99cf9..83acb8ada0 100644 --- a/code/modules/eventkit/generic_objects/generic_structure.dm +++ b/code/modules/eventkit/generic_objects/generic_structure.dm @@ -108,7 +108,7 @@ anchored = !anchored /client/proc/generic_structure() - set category = "Fun.Event Kit" //CHOMPEdit + set category = "Fun.Event Kit" set name = "Spawn Generic Structure" set desc = "Spawn a customisable structure with a range of different options." diff --git a/code/modules/materials/materials/gems.dm b/code/modules/materials/materials/gems.dm index 3d85b3e2c5..ba3a1bd6fa 100644 --- a/code/modules/materials/materials/gems.dm +++ b/code/modules/materials/materials/gems.dm @@ -50,8 +50,8 @@ /datum/material/quartz name = MAT_QUARTZ - display_name = ORE_QUARTZ - use_name = ORE_QUARTZ + display_name = MAT_QUARTZ + use_name = MAT_QUARTZ icon_colour = "#e6d7df" stack_type = /obj/item/stack/material/quartz tableslam_noise = 'sound/effects/Glasshit.ogg' diff --git a/code/modules/mob/dead/observer/chunk.dm b/code/modules/mob/dead/observer/chunk.dm new file mode 100644 index 0000000000..5efe8fcd5b --- /dev/null +++ b/code/modules/mob/dead/observer/chunk.dm @@ -0,0 +1,113 @@ +// GHOST CHUNK +// +// A 16x16 grid of the map with a list of turfs that can be seen, are visible and are dimmed. +// Allows ghosts to see turfs of non AREA_BLOCK_GHOST_SIGHT flagged areas within these chunks. + +/datum/chunk/ghost + var/list/hidden_areas = list() + +/datum/chunk/ghost/add(mob/observer/dead/ghost, add_images = TRUE) + if(add_images) + var/client/client = ghost.client + if(client) + client.images += obscured + ghost.visibleChunks += src + visible++ + seenby += ghost + if(changed && !updating) + update() + +/datum/chunk/ghost/remove(mob/observer/dead/ghost, remove_images = TRUE) + if(remove_images) + var/client/client = ghost.client + if(client) + client.images -= obscured + ghost.visibleChunks -= src + seenby -= ghost + if(visible > 0) + visible-- + +/datum/chunk/ghost/acquireVisibleTurfs(var/list/invisible) + + for(var/area/A in hidden_areas) + + for(var/turf/T in A.contents) + invisible[T] = T + +// Don't call the parernt, we work inverted! +/datum/chunk/ghost/New(loc, x, y, z) + for(var/area/A in range(16, locate(x + 8, y + 8, z))) + if(A.flag_check(AREA_BLOCK_GHOST_SIGHT)) + hidden_areas += A + + // 0xf = 15 + x &= ~0xf + y &= ~0xf + + src.x = x + src.y = y + src.z = z + + for(var/turf/t in range(10, locate(x + 8, y + 8, z))) + if(t.x >= x && t.y >= y && t.x < x + 16 && t.y < y + 16) + turfs[t] = t + + acquireVisibleTurfs(obscuredTurfs) + + // Removes turf that isn't in turfs. + obscuredTurfs &= turfs + + visibleTurfs = turfs - obscuredTurfs + + for(var/turf/t as anything in obscuredTurfs) + LAZYINITLIST(t.obfuscations) + if(!t.obfuscations[obfuscation.type]) + var/image/ob_image = image(obfuscation.icon, t, obfuscation.icon_state, OBFUSCATION_LAYER) + ob_image.plane = PLANE_FULLSCREEN + t.obfuscations[obfuscation.type] = ob_image + obscured += t.obfuscations[obfuscation.type] + +/datum/chunk/ghost/update() + + set background = 1 + + var/list/newInvisibleTurfs = new() + acquireVisibleTurfs(newInvisibleTurfs) + + // Removes turf that isn't in turfs. + newInvisibleTurfs &= turfs + + var/list/visAdded = obscuredTurfs - newInvisibleTurfs + var/list/visRemoved = newInvisibleTurfs - obscuredTurfs + + visibleTurfs = turfs - newInvisibleTurfs + obscuredTurfs = newInvisibleTurfs + + for(var/turf/t as anything in visAdded) + if(LAZYLEN(t.obfuscations) && t.obfuscations[obfuscation.type]) + obscured -= t.obfuscations[obfuscation.type] + for(var/mob/observer/dead/m as anything in seenby) + if(!m) + continue + var/client/client = m.client + if(client) + client.images -= t.obfuscations[obfuscation.type] + + for(var/turf/t as anything in visRemoved) + if(obscuredTurfs[t]) + LAZYINITLIST(t.obfuscations) + if(!t.obfuscations[obfuscation.type]) + var/image/ob_image = image(obfuscation.icon, t, obfuscation.icon_state, OBFUSCATION_LAYER) + ob_image.plane = PLANE_FULLSCREEN + t.obfuscations[obfuscation.type] = ob_image + + obscured += t.obfuscations[obfuscation.type] + for(var/mob/observer/dead/m as anything in seenby) + if(!m) + seenby -= m + continue + if(!m.checkStatic()) + continue + var/client/client = m.client + if(client) + client.images += t.obfuscations[obfuscation.type] diff --git a/code/modules/mob/dead/observer/ghostnet.dm b/code/modules/mob/dead/observer/ghostnet.dm new file mode 100644 index 0000000000..b9e6952d19 --- /dev/null +++ b/code/modules/mob/dead/observer/ghostnet.dm @@ -0,0 +1,92 @@ +// GHOST NET +// +// The datum containing all the hidden chunks. + +/datum/visualnet/ghost + chunk_type = /datum/chunk/ghost + +/datum/visualnet/ghost/proc/addVisibility(list/moved_eyes, client/C) + if(!islist(moved_eyes)) + moved_eyes = moved_eyes ? list(moved_eyes) : list() + + var/list/chunks_pre_seen = list() + + for(var/mob/observer/dead/ghost as anything in moved_eyes) + if(C) + chunks_pre_seen |= ghost.visibleChunks + + if(C) + for(var/datum/chunk/ghost/c as anything in chunks_pre_seen) + for(var/mob/observer/dead/ghost as anything in moved_eyes) + c.remove(ghost) + +/datum/visualnet/ghost/proc/removeVisibility(list/moved_eyes, client/C) + if(!islist(moved_eyes)) + moved_eyes = moved_eyes ? list(moved_eyes) : list() + + var/list/chunks_post_seen = list() + + for(var/mob/observer/dead/ghost as anything in moved_eyes) + // 0xf = 15 + var/static_range = ghost.static_visibility_range + var/x1 = max(0, ghost.x - static_range) & ~(CHUNK_SIZE - 1) + var/y1 = max(0, ghost.y - static_range) & ~(CHUNK_SIZE - 1) + var/x2 = min(world.maxx, ghost.x + static_range) & ~(CHUNK_SIZE - 1) + var/y2 = min(world.maxy, ghost.y + static_range) & ~(CHUNK_SIZE - 1) + + var/list/visibleChunks = list() + + for(var/x = x1; x <= x2; x += CHUNK_SIZE) + for(var/y = y1; y <= y2; y += CHUNK_SIZE) + visibleChunks |= getChunk(x, y, ghost.z) + + var/list/add = visibleChunks - ghost.visibleChunks + + for(var/datum/chunk/ghost/c as anything in add) + c.add(ghost, FALSE) + + if(C) + chunks_post_seen |= ghost.visibleChunks + + if(C) + + for(var/datum/chunk/c as anything in chunks_post_seen) + C.images += c.obscured + +// Removes a area from a chunk. +/datum/visualnet/ghost/proc/removeArea(area/A) + if(!A.flag_check(AREA_BLOCK_GHOST_SIGHT)) + majorChunkChange(A, 0) + +// Add a area to a chunk. +/datum/visualnet/ghost/proc/addArea(area/A) + if(A.flag_check(AREA_BLOCK_GHOST_SIGHT)) + majorChunkChange(A, 1) + +// Used for ghost visible areas. Since portable areas can be in ANY chunk. +/datum/visualnet/ghost/proc/updateArea(area/A) + if(A.flag_check(AREA_BLOCK_GHOST_SIGHT)) + majorChunkChange(A, 1) + else + majorChunkChange(A, 0) + +/datum/visualnet/ghost/majorChunkChange(area/A, var/choice) + if(choice == 2) + return + for(var/entry in chunks) + var/datum/chunk/ghost/gchunk = chunks[entry] + for(var/turf/T in gchunk.turfs) + if(T.loc == A) + onMajorChunkChange(A, choice, gchunk) + gchunk.hasChanged(TRUE) + break + +/datum/visualnet/ghost/onMajorChunkChange(atom/c, var/choice, var/datum/chunk/ghost/chunk) +// Only add actual areas to the list of areas + if(istype(c, /area)) + if(choice == 0) + // Remove the area. + chunk.hidden_areas -= c + else if(choice == 1) + // You can't have the same area in the list twice. + chunk.hidden_areas |= c diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 9adcd8738b..566f73b82c 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -12,7 +12,10 @@ stat = DEAD canmove = 0 blinded = 0 - anchored = TRUE // don't get pushed around + anchored = TRUE // don't get pushed around + var/list/visibleChunks = list() + var/datum/visualnet/ghost/visualnet + var/static_visibility_range = 16 var/can_reenter_corpse var/datum/hud/living/carbon/hud = null // hud @@ -88,13 +91,14 @@ var/last_revive_notification = null // world.time of last notification, used to avoid spamming players from defibs or cloners. var/cleanup_timer // Refernece to a timer that will delete this mob if no client returns -/mob/observer/dead/New(mob/body) +/mob/observer/dead/New(mob/body, aghost = FALSE) appearance = body invisibility = INVISIBILITY_OBSERVER layer = BELOW_MOB_LAYER plane = PLANE_GHOSTS alpha = 127 + admin_ghosted = aghost sight |= SEE_TURFS | SEE_MOBS | SEE_OBJS | SEE_SELF see_invisible = SEE_INVISIBLE_OBSERVER @@ -140,6 +144,17 @@ animate(pixel_y = default_pixel_y, time = 10, loop = -1) observer_mob_list += src ..() + visualnet = ghostnet + +/mob/observer/dead/proc/checkStatic() + return !(check_rights(R_ADMIN|R_FUN|R_EVENT|R_SERVER, 0, src) || (client && client.buildmode) || isbelly(loc)) + +/mob/observer/dead/Moved(atom/old_loc, direction, forced) + . = ..() + if(isbelly(loc) && !isbelly(old_loc)) + visualnet.addVisibility() + if(visualnet && checkStatic()) + visualnet.visibility(src, client) /mob/observer/dead/Topic(href, href_list) if (href_list["track"]) @@ -209,14 +224,14 @@ Works together with spawning an observer, noted above. forceMove(O.loc) //RS Port #658 End -/mob/proc/ghostize(var/can_reenter_corpse = 1) +/mob/proc/ghostize(var/can_reenter_corpse = 1, var/aghost = FALSE) if(key) if(ishuman(src)) var/mob/living/carbon/human/H = src if(H.vr_holder && !can_reenter_corpse) H.exit_vr() return 0 - var/mob/observer/dead/ghost = new(src) //Transfer safety to observer spawning proc. + var/mob/observer/dead/ghost = new(src, aghost) //Transfer safety to observer spawning proc. ghost.can_reenter_corpse = can_reenter_corpse ghost.timeofdeath = src.timeofdeath //BS12 EDIT ghost.key = key @@ -574,6 +589,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp return ..() /mob/observer/dead/Destroy() + visualnet = null if(ismob(following)) var/mob/M = following M.following_mobs -= src diff --git a/code/modules/mob/freelook/visualnet.dm b/code/modules/mob/freelook/visualnet.dm index 2af7ffacd6..d153701cdd 100644 --- a/code/modules/mob/freelook/visualnet.dm +++ b/code/modules/mob/freelook/visualnet.dm @@ -2,8 +2,6 @@ // // The datum containing all the chunks. -#define CHUNK_SIZE 16 - /datum/visualnet // The chunks of the map, mapping the areas that an object can see. var/list/chunks = list() @@ -159,5 +157,3 @@ var/datum/chunk/chunk = cameranet.getCameraChunk(x, y, z) usr.client.debug_variables(chunk) */ - -#undef CHUNK_SIZE diff --git a/code/modules/mob/mob_helpers_vr.dm b/code/modules/mob/mob_helpers_vr.dm index 8443fffe05..e3ee5caf82 100644 --- a/code/modules/mob/mob_helpers_vr.dm +++ b/code/modules/mob/mob_helpers_vr.dm @@ -33,7 +33,7 @@ /mob/verb/toggle_stomach_vision() set name = "Toggle Stomach Sprites" - set category = "Preferences.Vore" //CHOMPEdit + set category = "Preferences.Vore" set desc = "Toggle the ability to see stomachs or not" var/toggle diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index 7b90f4d63b..ca0919e180 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -404,9 +404,9 @@ switch(mob.incorporeal_move) if(1) var/turf/T = get_step(mob, direct) - var/area/A = T.loc //RS Port #658 if(!T) return + var/area/A = T.loc //RS Port #658 if(mob.check_holy(T)) to_chat(mob, span_warning("You cannot get past holy grounds while you are in this plane of existence!")) return diff --git a/code/modules/power/privacy_switch.dm b/code/modules/power/privacy_switch.dm new file mode 100644 index 0000000000..c18a6a295c --- /dev/null +++ b/code/modules/power/privacy_switch.dm @@ -0,0 +1,41 @@ +/obj/structure/privacyswitch + name = "privacy switch" + desc = "A special switch to increase the room's privavy. (Blocks ghosts from seeing the area)" + icon = 'icons/obj/power_vr.dmi' + icon_state = "light0" + var/nextUse = 0 + +/obj/structure/privacyswitch/Initialize() + var/area/A = get_area(src) + if(A?.flag_check(AREA_BLOCK_GHOST_SIGHT)) + icon_state = "light1" + . = ..() + +/obj/structure/privacyswitch/attack_ai(mob/user) + attack_hand() + return + +/obj/structure/privacyswitch/attack_hand(mob/user) + if(nextUse - world.time > 0) + to_chat(user, span_warning("The area can not be altered so soon again!")) + return + var/area/A = get_area(src) + if(!A) + return + + if(tgui_alert(user, "Do you want to toggle ghost vision for this area [A.flag_check(AREA_BLOCK_GHOST_SIGHT) ? "on" : "off"]?", "Toggle ghost vision?", list("Yes", "No")) != "Yes") + return + + if(A.flag_check(AREA_BLOCK_GHOST_SIGHT)) + A.flags ^= AREA_BLOCK_GHOST_SIGHT + icon_state = "light0" + ghostnet.removeArea(A) + to_chat(user, span_notice("The area is no longer protected from ghost vison.")) + log_and_message_admins("toggled ghost vision in [A] on.", user) + else + A.flags ^= AREA_BLOCK_GHOST_SIGHT + icon_state = "light1" + ghostnet.addArea(A) + to_chat(user, span_notice("The area is now protected from ghost vison.")) + log_and_message_admins("toggled ghost vision in [A] off.", user) + nextUse = world.time + 5 MINUTES diff --git a/code/modules/vote/vote_verb.dm b/code/modules/vote/vote_verb.dm index a23f232576..12f8ae7d7f 100644 --- a/code/modules/vote/vote_verb.dm +++ b/code/modules/vote/vote_verb.dm @@ -1,5 +1,5 @@ /client/verb/vote() - set category = "OOC.Game" // CHOMPedit + set category = "OOC.Game" set name = "Vote" if(SSvote.active_vote) diff --git a/modular_chomp/maps/relic_base/relicbase_areas.dm b/modular_chomp/maps/relic_base/relicbase_areas.dm index 74721344a9..78e0f2eda3 100644 --- a/modular_chomp/maps/relic_base/relicbase_areas.dm +++ b/modular_chomp/maps/relic_base/relicbase_areas.dm @@ -1038,7 +1038,6 @@ z /area/engineering/engi_restroom name = "\improper Engineering Restroom" icon_state = "toilet" - flags = RAD_SHIELDED sound_env = SMALL_ENCLOSED /area/engineering/hallway/atmos_hallway @@ -1120,7 +1119,6 @@ z /area/medical/medical_restroom name = "\improper Medbay Restroom" icon_state = "medbay_restroom" - flags = RAD_SHIELDED sound_env = SMALL_ENCLOSED /area/security/aid_station @@ -1134,7 +1132,6 @@ z /area/security/security_restroom name = "\improper Security - Restroom" icon_state = "security_bathroom" - flags = RAD_SHIELDED sound_env = SMALL_ENCLOSED /area/storage/emergency_storage/seconddeck/ap_emergency @@ -1158,7 +1155,6 @@ z /area/rnd/research_restroom_sc name = "\improper Research Restroom" icon_state = "research_restroom" - flags = RAD_SHIELDED sound_env = SMALL_ENCLOSED /area/rnd/research_lockerroom diff --git a/modular_chomp/maps/southern_cross/southern_cross_areas.dm b/modular_chomp/maps/southern_cross/southern_cross_areas.dm index 516e90be8b..7ee8e6310f 100644 --- a/modular_chomp/maps/southern_cross/southern_cross_areas.dm +++ b/modular_chomp/maps/southern_cross/southern_cross_areas.dm @@ -448,7 +448,6 @@ /area/crew_quarters/heads/sc/ name = "\improper Command - Head Office" icon_state = "head_quarters" - flags = RAD_SHIELDED | AREA_FORBID_EVENTS | AREA_FORBID_SINGULO sound_env = MEDIUM_SOFTFLOOR /area/crew_quarters/heads/sc/hop @@ -483,7 +482,6 @@ /area/engineering/engi_restroom name = "\improper Engineering Restroom" icon_state = "toilet" - flags = RAD_SHIELDED sound_env = SMALL_ENCLOSED /area/engineering/hallway/atmos_hallway @@ -561,7 +559,6 @@ /area/medical/medical_restroom name = "\improper Medbay Restroom" icon_state = "medbay_restroom" - flags = RAD_SHIELDED sound_env = SMALL_ENCLOSED /area/security/aid_station @@ -575,7 +572,6 @@ /area/security/security_restroom name = "\improper Security - Restroom" icon_state = "security_bathroom" - flags = RAD_SHIELDED sound_env = SMALL_ENCLOSED /area/storage/emergency_storage/seconddeck/ap_emergency @@ -599,7 +595,6 @@ /area/rnd/research_restroom_sc name = "\improper Research Restroom" icon_state = "research_restroom" - flags = RAD_SHIELDED sound_env = SMALL_ENCLOSED /area/rnd/research_lockerroom @@ -822,7 +817,6 @@ name = "\improper Response Team Ship" icon_state = "shuttlered" requires_power = 0 - flags = RAD_SHIELDED ambience = AMBIENCE_HIGHSEC /* Chompstation Edit - Removing Shuttle 1 & 2 @@ -948,7 +942,6 @@ End Chompstation Edit*/ icon_state = "syndie-ship" requires_power = 0 dynamic_lighting = 0 - flags = RAD_SHIELDED ambience = AMBIENCE_HIGHSEC /area/syndicate_station @@ -956,7 +949,6 @@ End Chompstation Edit*/ icon_state = "syndie-ship" requires_power = 0 dynamic_lighting = 0 - flags = RAD_SHIELDED ambience = AMBIENCE_HIGHSEC /area/syndicate_station/start @@ -1017,7 +1009,6 @@ End Chompstation Edit*/ icon_state = "yellow" requires_power = 0 dynamic_lighting = 0 - flags = RAD_SHIELDED ambience = AMBIENCE_HIGHSEC /area/skipjack_station/transit @@ -1071,7 +1062,6 @@ End Chompstation Edit*/ name = "\improper Ninja Base" icon_state = "green" requires_power = 0 - flags = RAD_SHIELDED ambience = AMBIENCE_HIGHSEC /area/ninja_dojo/dojo diff --git a/vorestation.dme b/vorestation.dme index 4adfaaf44c..a9a749fe03 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -172,6 +172,7 @@ #include "code\__defines\unit_tests.dm" #include "code\__defines\update_icons.dm" #include "code\__defines\verb_manager.dm" +#include "code\__defines\visualnet.dm" #include "code\__defines\vore.dm" #include "code\__defines\vote.dm" #include "code\__defines\vv.dm" @@ -3115,7 +3116,9 @@ #include "code\modules\mob\dead\corpse_ch.dm" #include "code\modules\mob\dead\corpse_vr.dm" #include "code\modules\mob\dead\death.dm" +#include "code\modules\mob\dead\observer\chunk.dm" #include "code\modules\mob\dead\observer\free_vr.dm" +#include "code\modules\mob\dead\observer\ghostnet.dm" #include "code\modules\mob\dead\observer\login.dm" #include "code\modules\mob\dead\observer\logout.dm" #include "code\modules\mob\dead\observer\observer.dm" @@ -4006,6 +4009,7 @@ #include "code\modules\power\port_gen_vr.dm" #include "code\modules\power\power.dm" #include "code\modules\power\powernet.dm" +#include "code\modules\power\privacy_switch.dm" #include "code\modules\power\smes.dm" #include "code\modules\power\smes_construction.dm" #include "code\modules\power\smes_vr.dm"