mirror of
https://github.com/VOREStation/VOREStation.git
synced 2026-08-25 13:09:11 +01:00
Porting see down through open spaces
Ported 'see-down' open spaces from Vore, who ported it from Eris Ported talking and visible messages traveling upwards through open spaces Tested, seems to work? Does not seem to break anything, maybe. Maybe made a changelog.
This commit is contained in:
@@ -302,6 +302,21 @@ proc/get_radio_key_from_channel(var/channel)
|
||||
var/image/speech_bubble = image('icons/mob/talk.dmi',src,"[speech_type][speech_bubble_test]")
|
||||
spawn(30) qdel(speech_bubble)
|
||||
|
||||
// VOREStation Edit - Attempt Multi-Z Talking
|
||||
var/mob/above = src.shadow
|
||||
while(!QDELETED(above))
|
||||
var/turf/ST = get_turf(above)
|
||||
if(ST)
|
||||
var/list/results = get_mobs_and_objs_in_view_fast(ST, world.view)
|
||||
var/image/z_speech_bubble = image('icons/mob/talk.dmi', above, "h[speech_bubble_test]")
|
||||
spawn(30) qdel(z_speech_bubble)
|
||||
for(var/item in results["mobs"])
|
||||
if(item != above && !(item in listening))
|
||||
listening[item] = z_speech_bubble
|
||||
listening_obj |= results["objs"]
|
||||
above = above.shadow
|
||||
// VOREStation Edit End
|
||||
|
||||
//Main 'say' and 'whisper' message delivery
|
||||
for(var/mob/M in listening)
|
||||
spawn(0) //Using spawns to queue all the messages for AFTER this proc is done, and stop runtimes
|
||||
@@ -310,12 +325,12 @@ proc/get_radio_key_from_channel(var/channel)
|
||||
var/dst = get_dist(get_turf(M),get_turf(src))
|
||||
|
||||
if(dst <= message_range || (M.stat == DEAD && !forbid_seeing_deadchat)) //Inside normal message range, or dead with ears (handled in the view proc)
|
||||
M << speech_bubble
|
||||
M << (listening[M] || speech_bubble) // VOREStation Edit - Send the image attached to shadow mob if available
|
||||
M.hear_say(message, verb, speaking, alt_name, italics, src, speech_sound, sound_vol)
|
||||
|
||||
if(whispering) //Don't even bother with these unless whispering
|
||||
if(dst > message_range && dst <= w_scramble_range) //Inside whisper scramble range
|
||||
M << speech_bubble
|
||||
M << (listening[M] || speech_bubble) // VOREStation Edit - Send the image attached to shadow mob if available
|
||||
M.hear_say(stars(message), verb, speaking, alt_name, italics, src, speech_sound, sound_vol*0.2)
|
||||
if(dst > w_scramble_range && dst <= world.view) //Inside whisper 'visible' range
|
||||
M.show_message("<span class='game say'><span class='name'>[src.name]</span> [w_not_heard].</span>", 2)
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
//
|
||||
// Controller handling icon updates of open space turfs
|
||||
//
|
||||
|
||||
/var/global/open_space_initialised = FALSE
|
||||
/var/global/datum/controller/process/open_space/OS_controller = null
|
||||
/var/global/image/over_OS_darkness = image('icons/turf/open_space.dmi', "black_open")
|
||||
|
||||
/datum/controller/process/open_space
|
||||
var/list/turfs_to_process = list() // List of turfs queued for update.
|
||||
var/list/turfs_to_process_old = null // List of turfs currently being updated.
|
||||
|
||||
/datum/controller/process/open_space/setup()
|
||||
. = ..()
|
||||
name = "openspace"
|
||||
schedule_interval = world.tick_lag // every second
|
||||
start_delay = 30 SECONDS
|
||||
OS_controller = src
|
||||
over_OS_darkness.plane = OVER_OPENSPACE_PLANE
|
||||
over_OS_darkness.layer = MOB_LAYER
|
||||
initialize_open_space()
|
||||
|
||||
// Pre-process open space once once before the round starts. Wait 20 seconds so other stuff has time to finish.
|
||||
spawn(200)
|
||||
doWork(1)
|
||||
|
||||
/datum/controller/process/open_space/copyStateFrom(var/datum/controller/process/open_space/other)
|
||||
. = ..()
|
||||
OS_controller = src
|
||||
|
||||
/datum/controller/process/open_space/doWork()
|
||||
// We use a different list so any additions to the update lists during a delay from scheck()
|
||||
// don't cause things to be cut from the list without being updated.
|
||||
turfs_to_process_old = turfs_to_process
|
||||
turfs_to_process = list()
|
||||
|
||||
for(last_object in turfs_to_process_old)
|
||||
var/turf/T = last_object
|
||||
if(!QDELETED(T))
|
||||
update_turf(T)
|
||||
SCHECK
|
||||
|
||||
/datum/controller/process/open_space/proc/update_turf(var/turf/T)
|
||||
for(var/atom/movable/A in T)
|
||||
A.fall()
|
||||
T.update_icon()
|
||||
|
||||
/datum/controller/process/open_space/proc/add_turf(var/turf/T, var/recursive = 0)
|
||||
ASSERT(isturf(T))
|
||||
turfs_to_process += T
|
||||
if(recursive > 0)
|
||||
var/turf/above = GetAbove(T)
|
||||
if(above && isopenspace(above))
|
||||
add_turf(above, recursive)
|
||||
|
||||
// Do the initial updates of open space turfs when the game starts. This will lag!
|
||||
/datum/controller/process/open_space/proc/initialize_open_space()
|
||||
// Do initial setup from bottom to top.
|
||||
for(var/zlevel = 1 to world.maxz)
|
||||
for(var/turf/simulated/open/T in block(locate(1, 1, zlevel), locate(world.maxx, world.maxy, zlevel)))
|
||||
add_turf(T)
|
||||
open_space_initialised = TRUE
|
||||
|
||||
/turf/simulated/open/initialize()
|
||||
. = ..()
|
||||
if(open_space_initialised)
|
||||
// log_debug("[src] ([x],[y],[z]) queued for update for initialize()")
|
||||
OS_controller.add_turf(src)
|
||||
|
||||
/turf/Entered(atom/movable/AM)
|
||||
. = ..()
|
||||
if(open_space_initialised && !AM.invisibility && isobj(AM))
|
||||
var/turf/T = GetAbove(src)
|
||||
if(isopenspace(T))
|
||||
// log_debug("[T] ([T.x],[T.y],[T.z]) queued for update for [src].Entered([AM])")
|
||||
OS_controller.add_turf(T, 1)
|
||||
|
||||
/turf/Exited(atom/movable/AM)
|
||||
. = ..()
|
||||
if(open_space_initialised && !AM.invisibility && isobj(AM))
|
||||
var/turf/T = GetAbove(src)
|
||||
if(isopenspace(T))
|
||||
// log_debug("[T] ([T.x],[T.y],[T.z]) queued for update for [src].Exited([AM])")
|
||||
OS_controller.add_turf(T, 1)
|
||||
|
||||
/obj/update_icon()
|
||||
. = ..()
|
||||
if(open_space_initialised && !invisibility && isturf(loc))
|
||||
var/turf/T = GetAbove(src)
|
||||
if(isopenspace(T))
|
||||
// log_debug("[T] ([T.x],[T.y],[T.z]) queued for update for [src].update_icon()")
|
||||
OS_controller.add_turf(T, 1)
|
||||
|
||||
// Ouch... this is painful. But is there any other way?
|
||||
/* - No for now
|
||||
/obj/New()
|
||||
. = ..()
|
||||
if(open_space_initialised && !invisibility)
|
||||
var/turf/T = GetAbove(src)
|
||||
if(isopenspace(T))
|
||||
// log_debug("[T] ([T.x],[T.y],[T.z]) queued for update for [src]New()")
|
||||
OS_controller.add_turf(T, 1)
|
||||
*/
|
||||
|
||||
// Just as New() we probably should hook Destroy() If we can think of something more efficient, lets hear it.
|
||||
/obj/Destroy()
|
||||
if(open_space_initialised && !invisibility && isturf(loc))
|
||||
var/turf/T = GetAbove(src)
|
||||
if(isopenspace(T))
|
||||
OS_controller.add_turf(T, 1)
|
||||
. = ..() // Important that this be at the bottom, or we will have been moved to nullspace.
|
||||
+64
-21
@@ -13,13 +13,19 @@
|
||||
/turf/space/CanZPass(atom, direction)
|
||||
return 1
|
||||
|
||||
//
|
||||
// Open Space - "empty" turf that lets stuff fall thru it to the layer below
|
||||
//
|
||||
|
||||
/turf/simulated/open
|
||||
name = "open space"
|
||||
icon = 'icons/turf/space.dmi'
|
||||
icon_state = ""
|
||||
layer = 0
|
||||
desc = "\..."
|
||||
density = 0
|
||||
plane = OPENSPACE_PLANE_START
|
||||
pathweight = 100000 //Seriously, don't try and path over this one numbnuts
|
||||
dynamic_lighting = 0 // Someday lets do proper lighting z-transfer. Until then we are leaving this off so it looks nicer.
|
||||
|
||||
var/turf/below
|
||||
|
||||
@@ -42,42 +48,75 @@
|
||||
AM.fall()
|
||||
|
||||
/turf/simulated/open/proc/update()
|
||||
plane = OPENSPACE_PLANE + src.z
|
||||
below = GetBelow(src)
|
||||
turf_changed_event.register(below, src, /turf/simulated/open/update_icon)
|
||||
var/turf/simulated/T = get_step(src,NORTH)
|
||||
if(T)
|
||||
turf_changed_event.register(T, src, /turf/simulated/open/update_icon)
|
||||
levelupdate()
|
||||
for(var/atom/movable/A in src)
|
||||
A.fall()
|
||||
update_icon()
|
||||
OS_controller.add_turf(src, 1)
|
||||
|
||||
// override to make sure nothing is hidden
|
||||
/turf/simulated/open/levelupdate()
|
||||
for(var/obj/O in src)
|
||||
O.hide(0)
|
||||
|
||||
/turf/simulated/open/examine(mob/user, distance, infix, suffix)
|
||||
if(..(user, 2))
|
||||
var/depth = 1
|
||||
for(var/T = GetBelow(src); isopenspace(T); T = GetBelow(T))
|
||||
depth += 1
|
||||
to_chat(user, "It is about [depth] levels deep.")
|
||||
|
||||
/**
|
||||
* Update icon and overlays of open space to be that of the turf below, plus any visible objects on that turf.
|
||||
*/
|
||||
/turf/simulated/open/update_icon()
|
||||
overlays = list() // Edit - Overlays are being crashy when modified.
|
||||
update_icon_edge()// Add - Get grass into open spaces and whatnot.
|
||||
var/turf/below = GetBelow(src)
|
||||
if(below)
|
||||
underlays = list(image(icon = below.icon, icon_state = below.icon_state))
|
||||
underlays += below.overlays.Copy()
|
||||
var/below_is_open = isopenspace(below)
|
||||
|
||||
var/list/noverlays = list()
|
||||
if(!istype(below,/turf/space))
|
||||
noverlays += image(icon =icon, icon_state = "empty", layer = 2.2)
|
||||
if(below_is_open)
|
||||
underlays = below.underlays
|
||||
else
|
||||
var/image/bottom_turf = image(icon = below.icon, icon_state = below.icon_state, dir=below.dir, layer=below.layer)
|
||||
bottom_turf.plane = src.plane
|
||||
bottom_turf.color = below.color
|
||||
underlays = list(bottom_turf)
|
||||
// VOREStation Edit - Hack workaround to byond crash bug - Include the magic overlay holder object.
|
||||
overlays += below.overlays
|
||||
// if(below.overlay_holder)
|
||||
// overlays += (below.overlays + below.overlay_holder.overlays)
|
||||
// else
|
||||
// overlays += below.overlays
|
||||
// VOREStation Edit End
|
||||
|
||||
var/turf/simulated/T = get_step(src,NORTH)
|
||||
if(istype(T) && !istype(T,/turf/simulated/open))
|
||||
noverlays += image(icon ='icons/turf/cliff.dmi', icon_state = "metal", layer = 2.2)
|
||||
// get objects (not mobs, they are handled by /obj/zshadow)
|
||||
var/list/o_img = list()
|
||||
for(var/obj/O in below)
|
||||
if(O.invisibility) continue // Ignore objects that have any form of invisibility
|
||||
if(O.loc != below) continue // Ignore multi-turf objects not directly below
|
||||
var/image/temp2 = image(O, dir = O.dir, layer = O.layer)
|
||||
temp2.plane = src.plane
|
||||
temp2.color = O.color
|
||||
temp2.overlays += O.overlays
|
||||
// TODO Is pixelx/y needed?
|
||||
o_img += temp2
|
||||
var/overlays_pre = overlays.len
|
||||
overlays += o_img
|
||||
var/overlays_post = overlays.len
|
||||
if(overlays_post != (overlays_pre + o_img.len)) //Here we go!
|
||||
world.log << "Corrupted openspace turf at [x],[y],[z] being replaced. Pre: [overlays_pre], Post: [overlays_post]"
|
||||
new /turf/simulated/open(src)
|
||||
return //Let's get out of here.
|
||||
|
||||
var/obj/structure/stairs/S = locate() in below
|
||||
if(S && S.loc == below)
|
||||
var/image/I = image(icon = S.icon, icon_state = "below", dir = S.dir, layer = 2.2)
|
||||
I.pixel_x = S.pixel_x
|
||||
I.pixel_y = S.pixel_y
|
||||
noverlays += I
|
||||
if(!below_is_open)
|
||||
overlays += over_OS_darkness
|
||||
|
||||
overlays = noverlays
|
||||
return 0
|
||||
return PROCESS_KILL
|
||||
|
||||
// Straight copy from space.
|
||||
/turf/simulated/open/attackby(obj/item/C as obj, mob/user as mob)
|
||||
@@ -115,4 +154,8 @@
|
||||
|
||||
//Most things use is_plating to test if there is a cover tile on top (like regular floors)
|
||||
/turf/simulated/open/is_plating()
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
/turf/simulated/open/is_space()
|
||||
var/turf/below = GetBelow(src)
|
||||
return !below || below.is_space()
|
||||
@@ -0,0 +1,133 @@
|
||||
/mob // TODO: rewrite as obj.
|
||||
var/mob/zshadow/shadow
|
||||
|
||||
/mob/zshadow
|
||||
plane = OVER_OPENSPACE_PLANE
|
||||
name = "shadow"
|
||||
desc = "Z-level shadow"
|
||||
status_flags = GODMODE
|
||||
anchored = 1
|
||||
unacidable = 1
|
||||
density = 0
|
||||
opacity = 0 // Don't trigger lighting recalcs gah! TODO - consider multi-z lighting.
|
||||
auto_init = FALSE // We do not need to be initialize()d
|
||||
var/mob/owner = null // What we are a shadow of.
|
||||
|
||||
/mob/zshadow/can_fall()
|
||||
return FALSE
|
||||
|
||||
/mob/zshadow/New(var/mob/L)
|
||||
if(!istype(L))
|
||||
qdel(src)
|
||||
return
|
||||
..() // I'm cautious about this, but its the right thing to do.
|
||||
owner = L
|
||||
sync_icon(L)
|
||||
|
||||
/mob/Destroy()
|
||||
if(shadow)
|
||||
qdel(shadow)
|
||||
shadow = null
|
||||
. = ..()
|
||||
|
||||
/mob/zshadow/examine(mob/user, distance, infix, suffix)
|
||||
return owner.examine(user, distance, infix, suffix)
|
||||
|
||||
// Relay some stuff they hear
|
||||
/mob/zshadow/hear_say(var/message, var/verb = "says", var/datum/language/language = null, var/alt_name = "", var/italics = 0, var/mob/speaker = null, var/sound/speech_sound, var/sound_vol)
|
||||
if(speaker && speaker.z != src.z)
|
||||
return // Only relay speech on our acutal z, otherwise we might relay sounds that were themselves relayed up!
|
||||
if(isliving(owner))
|
||||
verb += " from above"
|
||||
return owner.hear_say(message, verb, language, alt_name, italics, speaker, speech_sound, sound_vol)
|
||||
|
||||
/mob/zshadow/proc/sync_icon(var/mob/M)
|
||||
name = M.name
|
||||
icon = M.icon
|
||||
icon_state = M.icon_state
|
||||
//color = M.color
|
||||
color = "#848484"
|
||||
overlays = M.overlays
|
||||
transform = M.transform
|
||||
dir = M.dir
|
||||
if(shadow)
|
||||
shadow.sync_icon(src)
|
||||
|
||||
/mob/living/Move()
|
||||
. = ..()
|
||||
check_shadow()
|
||||
|
||||
/mob/living/forceMove()
|
||||
. = ..()
|
||||
check_shadow()
|
||||
|
||||
/mob/living/on_mob_jump()
|
||||
// We're about to be admin-jumped.
|
||||
// Unfortuantely loc isn't set until after this proc is called. So we must spawn() so check_shadow executes with the new loc.
|
||||
. = ..()
|
||||
if(shadow)
|
||||
spawn(0)
|
||||
check_shadow()
|
||||
|
||||
/mob/living/proc/check_shadow()
|
||||
var/mob/M = src
|
||||
if(isturf(M.loc))
|
||||
var/turf/simulated/open/OS = GetAbove(src)
|
||||
while(OS && istype(OS))
|
||||
if(!M.shadow)
|
||||
M.shadow = new /mob/zshadow(M)
|
||||
M.shadow.forceMove(OS)
|
||||
M = M.shadow
|
||||
OS = GetAbove(M)
|
||||
// The topmost level does not need a shadow!
|
||||
if(M.shadow)
|
||||
qdel(M.shadow)
|
||||
M.shadow = null
|
||||
|
||||
//
|
||||
// Handle cases where the owner mob might have changed its icon or overlays.
|
||||
//
|
||||
|
||||
/mob/living/update_icons()
|
||||
. = ..()
|
||||
if(shadow)
|
||||
shadow.sync_icon(src)
|
||||
|
||||
// WARNING - the true carbon/human/update_icons does not call ..(), therefore we must sideways override this.
|
||||
// But be careful, we don't want to screw with that proc. So lets be cautious about what we do here.
|
||||
/mob/living/carbon/human/update_icons()
|
||||
. = ..()
|
||||
if(shadow)
|
||||
shadow.sync_icon(src)
|
||||
|
||||
/mob/set_dir(new_dir)
|
||||
. = ..()
|
||||
if(shadow)
|
||||
shadow.set_dir(new_dir)
|
||||
|
||||
// Transfer messages about what we are doing to upstairs
|
||||
/mob/visible_message(var/message, var/self_message, var/blind_message)
|
||||
. = ..()
|
||||
if(shadow)
|
||||
shadow.visible_message(message, self_message, blind_message)
|
||||
|
||||
// We should show the typing indicator so people above us can tell we're about to talk.
|
||||
/mob/set_typing_indicator(var/state)
|
||||
var/old_typing = src.typing
|
||||
. = ..()
|
||||
if(shadow && old_typing != src.typing)
|
||||
shadow.set_typing_indicator(state) // Okay the real proc changed something! That means we should handle things too
|
||||
|
||||
/mob/zshadow/set_typing_indicator(var/state)
|
||||
if(!typing_indicator)
|
||||
typing_indicator = new
|
||||
typing_indicator.icon = 'icons/mob/talk.dmi' //VOREStation Edit - Looks better on the right with job icons.
|
||||
typing_indicator.icon_state = "typing"
|
||||
if(state && !typing)
|
||||
overlays += typing_indicator
|
||||
typing = 1
|
||||
else if(!state && typing)
|
||||
overlays -= typing_indicator
|
||||
typing = 0
|
||||
if(shadow)
|
||||
shadow.set_typing_indicator(state)
|
||||
Reference in New Issue
Block a user