Merge pull request #4039 from Woodratt/10092017_WRBreaksEverything

Porting see down through open spaces
This commit is contained in:
Anewbe
2017-10-12 22:48:19 -05:00
committed by GitHub
9 changed files with 419 additions and 23 deletions

View File

@@ -0,0 +1,54 @@
/*This file is a list of all preclaimed planes & layers
All planes & layers should be given a value here instead of using a magic/arbitrary number.
After fiddling with planes and layers for some time, I figured I may as well provide some documentation:
What are planes?
Think of Planes as a sort of layer for a layer - if plane X is a larger number than plane Y, the highest number for a layer in X will be below the lowest
number for a layer in Y.
Planes also have the added bonus of having planesmasters.
What are Planesmasters?
Planesmasters, when in the sight of a player, will have its appearance properties (for example, colour matrices, alpha, transform, etc)
applied to all the other objects in the plane. This is all client sided.
Usually you would want to add the planesmaster as an invisible image in the client's screen.
What can I do with Planesmasters?
You can: Make certain players not see an entire plane,
Make an entire plane have a certain colour matrices,
Make an entire plane transform in a certain way,
Make players see a plane which is hidden to normal players - I intend to implement this with the antag HUDs for example.
Planesmasters can be used as a neater way to deal with client images or potentially to do some neat things
How do planes work?
A plane can be any integer from -100 to 100. (If you want more, bug lummox.)
All planes above 0, the 'base plane', are visible even when your character cannot 'see' them, for example, the HUD.
All planes below 0, the 'base plane', are only visible when a character can see them.
How do I add a plane?
Think of where you want the plane to appear, look through the pre-existing planes and find where it is above and where it is below
Slot it in in that place, and change the pre-existing planes, making sure no plane shares a number.
Add a description with a comment as to what the plane does.
How do I make something a planesmaster?
Add the PLANE_MASTER appearance flag to the appearance_flags variable.
What is the naming convention for planes or layers?
Make sure to use the name of your object before the _LAYER or _PLANE, eg: [NAME_OF_YOUR_OBJECT HERE]_LAYER or [NAME_OF_YOUR_OBJECT HERE]_PLANE
Also, as it's a define, it is standard practice to use capital letters for the variable so people know this.
*/
#define DEFAULT_PLANE 0 // BYOND's default value for plane, the "base plane"
#define SPACE_PLANE -32 // Reserved for use in space/parallax
#define PARALLAX_PLANE -30 // Reserved for use in space/parallax
// OPENSPACE_PLANE reserves all planes between OPENSPACE_PLANE_START and OPENSPACE_PLANE_END inclusive
#define OPENSPACE_PLANE_START -23
#define OPENSPACE_PLANE_END -8
#define OPENSPACE_PLANE -25 // /turf/simulated/open will use OPENSPACE_PLANE + z (Valid z's being 2 thru 17)
#define OVER_OPENSPACE_PLANE -7

View File

@@ -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)

View File

@@ -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.

View File

@@ -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()

View File

@@ -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)

View File

@@ -0,0 +1,37 @@
################################
# Example Changelog File
#
# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb.
#
# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.)
# When it is, any changes listed below will disappear.
#
# Valid Prefixes:
# bugfix
# wip (For works in progress)
# tweak
# soundadd
# sounddel
# rscadd (general adding of nice things)
# rscdel (general deleting of nice things)
# imageadd
# imagedel
# maptweak
# spellcheck (typo fixes)
# experiment
#################################
# Your name.
author: Woodrat
# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again.
delete-after: True
# Any changes you've made. See valid prefix list above.
# INDENT WITH TWO SPACES. NOT TABS. SPACES.
# SCREW THIS UP AND IT WON'T WORK.
# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries.
# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog.
changes:
- rscadd: "Added 'see down' in open spaces from Vore."
- rscadd: "Added talking and visible messages upward through open space from Vore."

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

BIN
icons/turf/open_space.dmi Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 288 B

View File

@@ -18,6 +18,7 @@
#include "code\stylesheet.dm"
#include "code\world.dm"
#include "code\__defines\_compile_options.dm"
#include "code\__defines\_planes+layers.dm"
#include "code\__defines\admin.dm"
#include "code\__defines\appearance.dm"
#include "code\__defines\atmos.dm"
@@ -1835,9 +1836,11 @@
#include "code\modules\multiz\_stubs.dm"
#include "code\modules\multiz\basic.dm"
#include "code\modules\multiz\movement.dm"
#include "code\modules\multiz\open_space_controller.dm"
#include "code\modules\multiz\pipes.dm"
#include "code\modules\multiz\structures.dm"
#include "code\modules\multiz\turf.dm"
#include "code\modules\multiz\zshadow.dm"
#include "code\modules\nano\nanoexternal.dm"
#include "code\modules\nano\nanomanager.dm"
#include "code\modules\nano\nanomapgen.dm"