Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

port: seethrough component #6176

Open
wants to merge 23 commits into
base: master220
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions code/__DEFINES/layers.dm
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@

#define ABOVE_GAME_PLANE -2

/// Slightly above the game plane but does not catch mouse clicks. Useful for certain visuals that should be clicked through, like seethrough trees
#define SEETHROUGH_PLANE -2

#define RENDER_PLANE_GAME_WORLD -1

#define DEFAULT_PLANE 0 //Marks out the default plane, even if we don't use it
Expand Down
11 changes: 11 additions & 0 deletions code/__DEFINES/turfs.dm
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,14 @@
#define TURF_WET_ICE (1<<2)
/// Turf has lube on the floor and mobs will slip
#define TURF_WET_LUBE (1<<3)


///Returns all turfs in a zlevel
#define Z_TURFS(ZLEVEL) block(locate(1,1,ZLEVEL), locate(world.maxx, world.maxy, ZLEVEL))

///Returns all currently loaded turfs
#define ALL_TURFS(...) block(locate(1, 1, 1), locate(world.maxx, world.maxy, world.maxz))

#define TURF_FROM_COORDS_LIST(List) (locate(List[1], List[2], List[3]))


78 changes: 78 additions & 0 deletions code/__HELPERS/see_through_maps.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// For these defines, check also above for their actual shapes in-game and maybe get a better idea

/// Default shape. It's one tile above the atom
#define SEE_THROUGH_MAP_DEFAULT "default"
/// A 3x3 area 2 tiles above the atom (trees love to be this shape)
#define SEE_THROUGH_MAP_THREE_X_THREE "3x3"
/// 2 tiles above the atom
#define SEE_THROUGH_MAP_DEFAULT_TWO_TALL "default_two_tall"
/// two rows of three tiles above the atom (small but thick trees love these)
#define SEE_THROUGH_MAP_THREE_X_TWO "3x2"
/// Seethrough component for the ratvar wreck, in shape of the ratvar wreck
#define SEE_THROUGH_MAP_RATVAR_WRECK "ratvar"

/** global statics for the see_through_component coordinate maps
* For ease of use, include a comment in the shape of the coordinate map, where O is nothing, X is a hidden tile and A is the object
* List-coordinate layout is list(relative_x, relative_y, relative_z)
* Turf finding algorithm needs the z and you can totally use it, but I can't think of any reason to ever do it
* Also it'd be really cool if you could keep the list-coordinates in here represent their actual relative coords, dont use tabs though since their spacing can differ
*/
GLOBAL_LIST_INIT(see_through_maps, list(
// X
// A
SEE_THROUGH_MAP_DEFAULT = list(
/*----------------*/list(0, 1, 0),
/*----------------*/list(0, 0, 0)
),

// XXX
// XXX
// XXX
// OAO
SEE_THROUGH_MAP_THREE_X_THREE = list(
list(-1, 3, 0), list(0, 3, 0), list(1, 3, 0),
list(-1, 2, 0), list(0, 2, 0), list(1, 2, 0),
list(-1, 1, 0), list(0, 1, 0), list(1, 1, 0)
),

// X
// X
// A
SEE_THROUGH_MAP_DEFAULT_TWO_TALL = list(
/*----------------*/list(0, 2, 0),
/*----------------*/list(0, 1, 0),
/*----------------*/list(0, 0, 0)
),

// XXX
// XXX
// OAO
SEE_THROUGH_MAP_THREE_X_TWO = list(
list(-1, 2, 0), list(0, 2, 0), list(1, 2, 0),
list(-1, 1, 0), list(0, 1, 0), list(1, 1, 0)
),

/// XXX
/// AOO
SEE_THROUGH_MAP_BILLBOARD = list(
list(0, 1, 0), list(1, 1, 0), list(2, 1, 0)
),
/// XXX
/// AXX
SEE_THROUGH_MAP_SHIPPING_CONTAINER = list(
list(0, 1, 0), list(1, 1, 0), list(2, 1, 0),
list(0, 0, 0), list(1, 0, 0), list(2, 0, 0)
),
// No
SEE_THROUGH_MAP_RATVAR_WRECK = list(
list(3, 5, 0), list(4, 5, 0), list(5, 5, 0), list(6, 5, 0),
list(3, 4, 0), list(4, 4, 0), list(5, 4, 0), list(6, 4, 0), list(7, 4, 0), list(9, 4, 0),
list(3, 3, 0), list(4, 3, 0), list(5, 3, 0), list(6, 3, 0), /* the neck */ list(8, 3, 0), list(9, 3, 0),
list(0, 2, 0), list(1, 2, 0), list(2, 2, 0), list(3, 2, 0), list(4, 2, 0), list(5, 2, 0), list(6, 2, 0), list(7, 2, 0), list(8, 2, 0), list(9, 2, 0), list(10, 2, 0), list(11, 2, 0), list(12, 2, 0),
list(0, 1, 0), list(1, 1, 0), list(2, 1, 0), list(3, 1, 0), list(4, 1, 0), list(5, 1, 0), list(6, 1, 0), list(7, 1, 0), list(8, 1, 0), list(9, 1, 0), list(10, 1, 0), list(11, 1, 0), list(12, 1, 0),
list(0, 0, 0), list(1, 0, 0), list(2, 0, 0), list(3, 0, 0), list(4, 0, 0), list(5, 0, 0), list(6, 0, 0), list(7, 0, 0), list(8, 0, 0), list(9, 0, 0), list(10, 0, 0), list(11, 0, 0), list(12, 0, 0), list(13, 0, 0)
)
))



180 changes: 180 additions & 0 deletions code/datums/components/seethrough.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
/// A component that lets you turn an object invisible when you're standing on certain relative turfs to it, like behind a tree
/datum/component/seethrough
/// List of lists that represent relative coordinates to the source atom
var/list/relative_turf_coords
/// A list of turfs on which we make ourself transparent
var/list/watched_turfs
/// Associate list, with client = trickery_image. Track which client is being tricked with which image
var/list/tricked_mobs = list()
Ravgolin marked this conversation as resolved.
Show resolved Hide resolved
/// Which alpha do we animate towards?
var/target_alpha
/// How long our fase in/out takes
var/animation_time
/// After we somehow moved (because ss13 is godless and does not respect anything), how long do we need to stand still to feel safe to setup our "behind" area again
var/perimeter_reset_timer
/// Does this object let clicks from players its transparent to pass through it
var/clickthrough

/// see_through_map is a define pointing to a specific map. It's basically defining the area which is considered behind. See see_through_maps.dm for a list of maps
/datum/component/seethrough/Initialize(
see_through_map = SEE_THROUGH_MAP_DEFAULT,
target_alpha = 100,
animation_time = 0.5 SECONDS,
perimeter_reset_timer = 2 SECONDS,
clickthrough = TRUE
)
. = ..()

relative_turf_coords = GLOB.see_through_maps[see_through_map]

if(!isatom(parent) || !LAZYLEN(relative_turf_coords))
return COMPONENT_INCOMPATIBLE

relative_turf_coords = GLOB.see_through_maps[see_through_map]
src.relative_turf_coords = relative_turf_coords
src.target_alpha = target_alpha
src.animation_time = animation_time
src.perimeter_reset_timer = perimeter_reset_timer
src.clickthrough = clickthrough

setup_perimeter(parent)

/datum/component/seethrough/Destroy(force)
LAZYNULL(relative_turf_coords)
LAZYNULL(watched_turfs)
LAZYNULL(tricked_mobs)

return ..()

/datum/component/seethrough/RegisterWithParent()
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, PROC_REF(dismantle_perimeter))

/datum/component/seethrough/UnregisterFromParent()
UnregisterSignal(parent, COMSIG_MOVABLE_MOVED)

/// Loop through a list with relative coordinate lists to mark those tiles and hide our parent when someone enters those tiles
/datum/component/seethrough/proc/setup_perimeter(atom/parent)
watched_turfs = list()

for(var/list/coordinates as anything in relative_turf_coords)
var/turf/target = TURF_FROM_COORDS_LIST(list(parent.x + coordinates[1], parent.y + coordinates[2], parent.z + coordinates[3]))

if(isnull(target))
continue

RegisterSignal(target, COMSIG_ATOM_ENTERED, PROC_REF(on_entered))
RegisterSignal(target, COMSIG_ATOM_EXITED, PROC_REF(on_exited))

watched_turfs.Add(target)

/// Someone entered one of our tiles, so sent an override overlay and a cute animation to make us fade out a bit
/datum/component/seethrough/proc/on_entered(atom/source, atom/movable/entered)
SIGNAL_HANDLER

if(!ismob(entered))
return

var/mob/mob = entered

if(!mob.client)
RegisterSignal(mob, COMSIG_MOB_LOGIN, PROC_REF(trick_mob))
return

if(mob in tricked_mobs)
return

trick_mob(mob)

/// Remove the screen object and make us appear solid to the client again
/datum/component/seethrough/proc/on_exited(atom/source, atom/movable/exited, direction)
SIGNAL_HANDLER

if(!ismob(exited))
return

var/mob/mob = exited

if(!mob.client)
UnregisterSignal(mob, COMSIG_MOB_LOGIN)
return

var/turf/moving_to = get_turf(exited)
if(moving_to in watched_turfs)
return

// Check if we're being 'tricked'
if(mob in tricked_mobs)
var/image/trickery_image = tricked_mobs[mob]
animate(trickery_image, alpha = 255, time = animation_time)
tricked_mobs.Remove(mob)
UnregisterSignal(mob, COMSIG_MOB_LOGOUT)

// after playing the fade-in animation, remove the screen obj
addtimer(CALLBACK(src, TYPE_PROC_REF(/datum/component/seethrough, clear_image), trickery_image, mob.client), animation_time)

/// Apply the trickery image and animation
/datum/component/seethrough/proc/trick_mob(mob/fool)
var/datum/hud/our_hud = fool.hud_used
for(var/atom/movable/screen/plane_master/seethrough in our_hud.get_true_plane_masters(SEETHROUGH_PLANE))
seethrough.unhide_plane(fool)

var/atom/atom_parent = parent
var/image/user_overlay = new(atom_parent)
user_overlay.loc = atom_parent
user_overlay.override = TRUE

if(clickthrough)
// Special plane so we can click through the overlay
SET_PLANE_EXPLICIT(user_overlay, SEETHROUGH_PLANE, atom_parent)

// These are inherited, but we already use the atom's loc so we end up at double the pixel offset
user_overlay.pixel_x = 0
user_overlay.pixel_y = 0

fool.client.images += user_overlay

animate(user_overlay, alpha = target_alpha, time = animation_time)

tricked_mobs[fool] = user_overlay
RegisterSignal(fool, COMSIG_MOB_LOGOUT, PROC_REF(on_client_disconnect))


/// Unrout ourselves after we somehow moved, and start a timer so we can re-restablish our behind area after standing still for a bit
/datum/component/seethrough/proc/dismantle_perimeter()
SIGNAL_HANDLER

for(var/turf in watched_turfs)
UnregisterSignal(turf, list(COMSIG_ATOM_ENTERED, COMSIG_ATOM_EXITED))

watched_turfs = null
clear_all_images()

// Timer override, so if our atom keeps moving the timer is reset until they stop for X time
addtimer(CALLBACK(src, TYPE_PROC_REF(/datum/component/seethrough, setup_perimeter), parent), perimeter_reset_timer, TIMER_OVERRIDE | TIMER_UNIQUE)

/// Remove a screen image from a client
/datum/component/seethrough/proc/clear_image(image/removee, client/remove_from)
remove_from?.images -= removee // player could've logged out during the animation, so check just in case

/datum/component/seethrough/proc/clear_all_images()
for(var/mob/fool in tricked_mobs)
var/image/trickery_image = tricked_mobs[fool]
fool.client?.images -= trickery_image
UnregisterSignal(fool, COMSIG_MOB_LOGOUT)
var/datum/hud/our_hud = fool.hud_used

for(var/atom/movable/screen/plane_master/seethrough in our_hud.get_true_plane_masters(SEETHROUGH_PLANE))
seethrough.hide_plane(fool)

tricked_mobs.Cut()

/// Image is removed when they log out because client gets deleted, so drop the mob reference
/datum/component/seethrough/proc/on_client_disconnect(mob/fool)
SIGNAL_HANDLER

tricked_mobs.Remove(fool)
UnregisterSignal(fool, COMSIG_MOB_LOGOUT)
RegisterSignal(fool, COMSIG_MOB_LOGIN, PROC_REF(trick_mob))
var/datum/hud/our_hud = fool.hud_used
for(var/atom/movable/screen/plane_master/seethrough in our_hud.get_true_plane_masters(SEETHROUGH_PLANE))
seethrough.hide_plane(fool)
15 changes: 15 additions & 0 deletions code/game/objects/structures/flora.dm
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,21 @@
pixel_x = -16
layer = 9

/obj/structure/flora/tree/Initialize(mapload)
. = ..()
AddComponent(/datum/component/seethrough, get_seethrough_map())

/// Return a see_through_map, examples in seethrough.dm
/obj/structure/flora/tree/proc/get_seethrough_map()
return SEE_THROUGH_MAP_DEFAULT

//trees cant see through
/obj/structure/flora/tree/ComponentInitialize()
AddComponent(/datum/component/seethrough, get_seethrough_map())

/obj/structure/flora/tree/cant_see_through/ComponentInitialize()
return

/obj/structure/flora/tree/pine
name = "pine tree"
icon = 'icons/obj/flora/pinetrees.dmi'
Expand Down
2 changes: 2 additions & 0 deletions paradise.dme
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@
#include "code\__HELPERS\reagents_helpers.dm"
#include "code\__HELPERS\russian.dm"
#include "code\__HELPERS\sanitize_values.dm"
#include "code\__HELPERS\see_through_maps.dm"
#include "code\__HELPERS\shell.dm"
#include "code\__HELPERS\stat_tracking.dm"
#include "code\__HELPERS\string_assoc_lists.dm"
Expand Down Expand Up @@ -465,6 +466,7 @@
#include "code\datums\components\proximity_monitor.dm"
#include "code\datums\components\radioactivity.dm"
#include "code\datums\components\ritual_object.dm"
#include "code\datums\components\seethrough.dm"
#include "code\datums\components\shielded.dm"
#include "code\datums\components\slippery.dm"
#include "code\datums\components\spawner.dm"
Expand Down
Loading