mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-10 09:42:29 +00:00
[MIRROR] Adds seethrough component [MDB IGNORE] (#16421)
* Adds seethrough component (#69642) Adds a seethrough component! Standing behind a big object with this component will make the object transparent: https://youtu.be/nnyWMJakVtE And no one else can see it: And yes you can click through it thanks to the power of plane masters! Standing behind a tree is a pretty big meme and people will have to either shift right click or bump into you to ever find you. This makes it so much better to implement big objects, since they no longer obscure the tiles behind them It's also useful for existing big objects, like billboards and the likes 🆑 qol: You can now see through big trees when you stand behind them! refactor: Adds a seethrough component to make it easier to add big stationairy objects without reducing visibility /🆑 Info This is done by sending an override overlay to the user that obscures the normal object and plays an animation. It registers an ENTERED signal on specific turfs. Those tiles in which it hides stuff is defined as a list of list coordinates, for which I made a global list with some defines. It's really crappy and I'd appreciate some feedback on that * Adds seethrough component Co-authored-by: Time-Green <timkoster1@hotmail.com>
This commit is contained in:
@@ -17,18 +17,20 @@
|
|||||||
|
|
||||||
#define OPENSPACE_LAYER 600 //Openspace layer over all
|
#define OPENSPACE_LAYER 600 //Openspace layer over all
|
||||||
|
|
||||||
#define TRANSPARENT_FLOOR_PLANE -10 //Transparent plane that shows openspace underneath the floor
|
#define TRANSPARENT_FLOOR_PLANE -11 //Transparent plane that shows openspace underneath the floor
|
||||||
#define OPENSPACE_PLANE -9 //Openspace plane below all turfs
|
#define OPENSPACE_PLANE -10 //Openspace plane below all turfs
|
||||||
#define OPENSPACE_BACKDROP_PLANE -8 //Black square just over openspace plane to guaranteed cover all in openspace turf
|
#define OPENSPACE_BACKDROP_PLANE -9 //Black square just over openspace plane to guaranteed cover all in openspace turf
|
||||||
|
|
||||||
|
|
||||||
#define FLOOR_PLANE -7
|
#define FLOOR_PLANE -8
|
||||||
|
|
||||||
#define GAME_PLANE -6
|
#define GAME_PLANE -7
|
||||||
#define GAME_PLANE_FOV_HIDDEN -5
|
#define GAME_PLANE_FOV_HIDDEN -6
|
||||||
#define GAME_PLANE_UPPER -4
|
#define GAME_PLANE_UPPER -5
|
||||||
#define GAME_PLANE_UPPER_FOV_HIDDEN -3
|
#define GAME_PLANE_UPPER_FOV_HIDDEN -4
|
||||||
|
|
||||||
|
///Slightly above the game plane but does not catch mouse clicks. Useful for certain visuals that should be clicked through, like seethrough trees
|
||||||
|
#define ABOVE_GAME_NO_MOUSE_PLANE -3
|
||||||
#define ABOVE_GAME_PLANE -2
|
#define ABOVE_GAME_PLANE -2
|
||||||
|
|
||||||
#define MOUSE_TRANSPARENT_PLANE -1 //SKYRAT EDIT ADDITION - Pollution port
|
#define MOUSE_TRANSPARENT_PLANE -1 //SKYRAT EDIT ADDITION - Pollution port
|
||||||
|
|||||||
61
code/__HELPERS/see_through_maps.dm
Normal file
61
code/__HELPERS/see_through_maps.dm
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
//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"
|
||||||
|
///One row of three tiles above the atom, but offset one tile to the left because of how billboards work
|
||||||
|
#define SEE_THROUGH_MAP_BILLBOARD "billboard"
|
||||||
|
|
||||||
|
|
||||||
|
/**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)
|
||||||
|
),
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
),
|
||||||
|
|
||||||
|
// 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
|
||||||
|
/// OAO
|
||||||
|
SEE_THROUGH_MAP_BILLBOARD = list(
|
||||||
|
list(0, 1, 0), list(1, 1, 0), list(2, 1, 0)
|
||||||
|
)
|
||||||
|
))
|
||||||
|
|
||||||
|
|
||||||
@@ -107,6 +107,15 @@
|
|||||||
appearance_flags = PLANE_MASTER //should use client color
|
appearance_flags = PLANE_MASTER //should use client color
|
||||||
blend_mode = BLEND_OVERLAY
|
blend_mode = BLEND_OVERLAY
|
||||||
|
|
||||||
|
/atom/movable/screen/plane_master/game_world_above_no_mouse
|
||||||
|
name = "above game world no mouse plane master"
|
||||||
|
plane = ABOVE_GAME_NO_MOUSE_PLANE
|
||||||
|
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||||
|
|
||||||
|
render_relay_plane = GAME_PLANE
|
||||||
|
appearance_flags = PLANE_MASTER
|
||||||
|
blend_mode = BLEND_OVERLAY
|
||||||
|
|
||||||
/atom/movable/screen/plane_master/massive_obj
|
/atom/movable/screen/plane_master/massive_obj
|
||||||
name = "massive object plane master"
|
name = "massive object plane master"
|
||||||
plane = MASSIVE_OBJ_PLANE
|
plane = MASSIVE_OBJ_PLANE
|
||||||
@@ -292,3 +301,5 @@
|
|||||||
name = "splashscreen plane"
|
name = "splashscreen plane"
|
||||||
plane = SPLASHSCREEN_PLANE
|
plane = SPLASHSCREEN_PLANE
|
||||||
render_relay_plane = RENDER_PLANE_NON_GAME
|
render_relay_plane = RENDER_PLANE_NON_GAME
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -108,6 +108,7 @@ INITIALIZE_IMMEDIATE(/atom/movable/plane_master_controller)
|
|||||||
GAME_PLANE_FOV_HIDDEN,
|
GAME_PLANE_FOV_HIDDEN,
|
||||||
GAME_PLANE_UPPER,
|
GAME_PLANE_UPPER,
|
||||||
GAME_PLANE_UPPER_FOV_HIDDEN,
|
GAME_PLANE_UPPER_FOV_HIDDEN,
|
||||||
|
ABOVE_GAME_NO_MOUSE_PLANE,
|
||||||
ABOVE_GAME_PLANE,
|
ABOVE_GAME_PLANE,
|
||||||
MASSIVE_OBJ_PLANE,
|
MASSIVE_OBJ_PLANE,
|
||||||
GHOST_PLANE,
|
GHOST_PLANE,
|
||||||
|
|||||||
147
code/datums/components/seethrough.dm
Normal file
147
code/datums/components/seethrough.dm
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
///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()
|
||||||
|
|
||||||
|
///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
|
||||||
|
|
||||||
|
///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)
|
||||||
|
. = ..()
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, .proc/dismantle_perimeter)
|
||||||
|
|
||||||
|
setup_perimeter(parent)
|
||||||
|
|
||||||
|
///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/on_entered)
|
||||||
|
RegisterSignal(target, COMSIG_ATOM_EXITED, .proc/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/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, /datum/component/seethrough/proc/clear_image, trickery_image, mob.client), animation_time)
|
||||||
|
|
||||||
|
///Apply the trickery image and animation
|
||||||
|
/datum/component/seethrough/proc/trick_mob(mob/fool)
|
||||||
|
var/image/user_overlay = new(parent)
|
||||||
|
user_overlay.loc = parent
|
||||||
|
user_overlay.override = TRUE
|
||||||
|
//Special plane so we can click through the overlay
|
||||||
|
user_overlay.plane = ABOVE_GAME_NO_MOUSE_PLANE
|
||||||
|
|
||||||
|
//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/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, /datum/component/seethrough/proc/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)
|
||||||
|
|
||||||
|
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/trick_mob)
|
||||||
@@ -3,12 +3,18 @@
|
|||||||
desc = "A blank billboard, with space for all kinds of advertising."
|
desc = "A blank billboard, with space for all kinds of advertising."
|
||||||
icon = 'icons/obj/billboard.dmi'
|
icon = 'icons/obj/billboard.dmi'
|
||||||
icon_state = "billboard_blank"
|
icon_state = "billboard_blank"
|
||||||
|
plane = ABOVE_GAME_PLANE
|
||||||
max_integrity = 1000
|
max_integrity = 1000
|
||||||
bound_width = 96
|
bound_width = 96
|
||||||
bound_height = 64
|
bound_height = 32
|
||||||
density = TRUE
|
density = TRUE
|
||||||
anchored = TRUE
|
anchored = TRUE
|
||||||
|
|
||||||
|
/obj/structure/billboard/Initialize(mapload)
|
||||||
|
. = ..()
|
||||||
|
|
||||||
|
AddComponent(/datum/component/seethrough, SEE_THROUGH_MAP_BILLBOARD)
|
||||||
|
|
||||||
/obj/structure/billboard/donk_n_go
|
/obj/structure/billboard/donk_n_go
|
||||||
name = "\improper Donk-n-Go billboard"
|
name = "\improper Donk-n-Go billboard"
|
||||||
desc = "A billboard advertising Donk-n-Go, Donk Co's ever-present and ever-unhealthy fast-food venture: GET IN, GET FED, GET GONE!"
|
desc = "A billboard advertising Donk-n-Go, Donk Co's ever-present and ever-unhealthy fast-food venture: GET IN, GET FED, GET GONE!"
|
||||||
|
|||||||
@@ -324,6 +324,15 @@ GLOBAL_LIST_EMPTY(flora_uprooting_tools_typepaths)
|
|||||||
delete_on_harvest = TRUE
|
delete_on_harvest = TRUE
|
||||||
flora_flags = FLORA_HERBAL | FLORA_WOODEN
|
flora_flags = FLORA_HERBAL | FLORA_WOODEN
|
||||||
|
|
||||||
|
/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
|
||||||
|
|
||||||
/obj/structure/flora/tree/harvest(mob/living/user)
|
/obj/structure/flora/tree/harvest(mob/living/user)
|
||||||
. = ..()
|
. = ..()
|
||||||
var/turf/my_turf = get_turf(src)
|
var/turf/my_turf = get_turf(src)
|
||||||
@@ -381,6 +390,9 @@ GLOBAL_LIST_EMPTY(flora_uprooting_tools_typepaths)
|
|||||||
pixel_x = -48
|
pixel_x = -48
|
||||||
pixel_y = -20
|
pixel_y = -20
|
||||||
|
|
||||||
|
/obj/structure/flora/tree/jungle/get_seethrough_map()
|
||||||
|
return SEE_THROUGH_MAP_THREE_X_THREE
|
||||||
|
|
||||||
/obj/structure/flora/tree/jungle/style_2
|
/obj/structure/flora/tree/jungle/style_2
|
||||||
icon_state = "tree2"
|
icon_state = "tree2"
|
||||||
/obj/structure/flora/tree/jungle/style_3
|
/obj/structure/flora/tree/jungle/style_3
|
||||||
@@ -401,6 +413,9 @@ GLOBAL_LIST_EMPTY(flora_uprooting_tools_typepaths)
|
|||||||
icon = 'icons/obj/flora/jungletreesmall.dmi'
|
icon = 'icons/obj/flora/jungletreesmall.dmi'
|
||||||
icon_state = "tree1"
|
icon_state = "tree1"
|
||||||
|
|
||||||
|
/obj/structure/flora/tree/jungle/small/get_seethrough_map()
|
||||||
|
return SEE_THROUGH_MAP_THREE_X_TWO
|
||||||
|
|
||||||
/obj/structure/flora/tree/jungle/small/style_2
|
/obj/structure/flora/tree/jungle/small/style_2
|
||||||
icon_state = "tree2"
|
icon_state = "tree2"
|
||||||
/obj/structure/flora/tree/jungle/small/style_3
|
/obj/structure/flora/tree/jungle/small/style_3
|
||||||
@@ -425,6 +440,9 @@ GLOBAL_LIST_EMPTY(flora_uprooting_tools_typepaths)
|
|||||||
icon = 'icons/obj/flora/pinetrees.dmi'
|
icon = 'icons/obj/flora/pinetrees.dmi'
|
||||||
icon_state = "pine_1"
|
icon_state = "pine_1"
|
||||||
|
|
||||||
|
/obj/structure/flora/tree/pine/get_seethrough_map()
|
||||||
|
return SEE_THROUGH_MAP_DEFAULT_TWO_TALL
|
||||||
|
|
||||||
/obj/structure/flora/tree/pine/style_2
|
/obj/structure/flora/tree/pine/style_2
|
||||||
icon_state = "pine_2"
|
icon_state = "pine_2"
|
||||||
/obj/structure/flora/tree/pine/style_3
|
/obj/structure/flora/tree/pine/style_3
|
||||||
|
|||||||
@@ -406,6 +406,7 @@
|
|||||||
#include "code\__HELPERS\roundend.dm"
|
#include "code\__HELPERS\roundend.dm"
|
||||||
#include "code\__HELPERS\sanitize_values.dm"
|
#include "code\__HELPERS\sanitize_values.dm"
|
||||||
#include "code\__HELPERS\screen_objs.dm"
|
#include "code\__HELPERS\screen_objs.dm"
|
||||||
|
#include "code\__HELPERS\see_through_maps.dm"
|
||||||
#include "code\__HELPERS\shell.dm"
|
#include "code\__HELPERS\shell.dm"
|
||||||
#include "code\__HELPERS\spatial_info.dm"
|
#include "code\__HELPERS\spatial_info.dm"
|
||||||
#include "code\__HELPERS\spawns.dm"
|
#include "code\__HELPERS\spawns.dm"
|
||||||
@@ -918,6 +919,7 @@
|
|||||||
#include "code\datums\components\rotation.dm"
|
#include "code\datums\components\rotation.dm"
|
||||||
#include "code\datums\components\scope.dm"
|
#include "code\datums\components\scope.dm"
|
||||||
#include "code\datums\components\seclight_attachable.dm"
|
#include "code\datums\components\seclight_attachable.dm"
|
||||||
|
#include "code\datums\components\seethrough.dm"
|
||||||
#include "code\datums\components\shell.dm"
|
#include "code\datums\components\shell.dm"
|
||||||
#include "code\datums\components\shielded.dm"
|
#include "code\datums\components\shielded.dm"
|
||||||
#include "code\datums\components\shrink.dm"
|
#include "code\datums\components\shrink.dm"
|
||||||
|
|||||||
Reference in New Issue
Block a user