mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-09 16:05:07 +00:00
[MIRROR] Multiz Rework: Human Suffering Edition (Contains PLANE CUBE) [MDB IGNORE] (#16472)
* Multiz Rework: Human Suffering Edition (Contains PLANE CUBE) * skyrat changes * bodyparts merge * unres door floorlight fix * Future upstream fix for blindness * upcoming upstream airlock fix * fix button emissive * Fix FOV markings? Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com> Co-authored-by: tastyfish <crazychris32@gmail.com>
This commit is contained in:
650
.github/guides/VISUALS.md
vendored
Normal file
650
.github/guides/VISUALS.md
vendored
Normal file
@@ -0,0 +1,650 @@
|
||||
# Visuals in /tg/station 13
|
||||
|
||||
Welcome to a breakdown of visuals and visual effects in our codebase, and in BYOND.
|
||||
|
||||
I will be describing all of the existing systems we use, alongside explaining and providing references to BYOND's ref for each tool.
|
||||
|
||||
Note, I will not be covering things that are trivial to understand, and which we don't mess with much.
|
||||
For a complete list of byond ref stuff relevant to this topic, see [here](https://www.byond.com/docs/ref/#/atom/var/appearance).
|
||||
|
||||
This is to some extent a collation of the BYOND ref, alongside a description of how we actually use these tools.
|
||||
My hope is after reading this you'll be able to understand and implement different visual effects in our codebase.
|
||||
|
||||
Also please see the ref entry on the [renderer](https://www.byond.com/docs/ref/#/{notes}/renderer).
|
||||
|
||||
We do a LOT, so this document might run on for a bit. Forgive me.
|
||||
|
||||
You'll find links to the relevant reference entries at the heading of each entry, alongside a hook back to the head of this document.
|
||||
|
||||
### Table of Contents
|
||||
|
||||
- [Appearances](#appearances-in-byond)
|
||||
- [Overlays](#overlays)
|
||||
- [Visual contents](#visual-contents)
|
||||
- [Images](#images)
|
||||
- [Client images](#client-images)
|
||||
- [View](#view)
|
||||
- [Eye](#eye)
|
||||
- [Client screen](#client-screen)
|
||||
- [Blend mode](#client-screen)
|
||||
- [Appearance flags](#appearance-flags)
|
||||
- [Gliding](#gliding)
|
||||
- [Sight](#sight)
|
||||
- [BYOND lighting](#byond-lighting)
|
||||
- [Luminosity](#luminosity)
|
||||
- [See in dark](#see-in-dark)
|
||||
- [Infrared](#infrared)
|
||||
- [Invisibility](#invisibility)
|
||||
- [Layers](#layers)
|
||||
- [Planes](#planes)
|
||||
- [Render target/source](#render-targetsource)
|
||||
- [Multiz](#multiz)
|
||||
- [Mouse opacity](#mouse-opacity)
|
||||
- [Filters](#filters)
|
||||
- [Particles](#particles)
|
||||
- [Pixel offsets](#pixel-offsets)
|
||||
- [Color](#color)
|
||||
- [Transform](#transform)
|
||||
- [Lighting](#lighting)
|
||||
- [Animate()](#animate())
|
||||
- [GAGS](#gags)
|
||||
|
||||
## Appearances in BYOND
|
||||
|
||||
- [Table of Contents](#table-of-contents)
|
||||
- [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/appearance)
|
||||
|
||||
Everything that is displayed on the map has an appearance variable that describes exactly how it should be rendered.
|
||||
To be clear, it doesn't contain EVERYTHING, [plane masters](#planes) exist separately and so do many other factors.
|
||||
But it sets out a sort of recipe of everything that could effect rendering.
|
||||
|
||||
Appearances have a few quirks that can be helpful or frustrating depending on what you're trying to do.
|
||||
|
||||
To start off with, appearances are static. You can't directly edit an appearance "datum", it will throw a runtime or just yell at you.
|
||||
|
||||
The way to edit them most of the time is to just modify the corresponding variable on the thing the appearance represents.
|
||||
|
||||
This doesn't mean it's impossible to modify them directly however. While appearances are static,
|
||||
their cousins mutable appearances [(Ref Entry)](https://www.byond.com/docs/ref/info.html#/mutable_appearance) **are**.
|
||||
|
||||
What we can do is create a new mutable appearance, set its appearance to be a copy of the static one (remember all appearance variables are static),
|
||||
edit it, and then set the desired thing's appearance var to the appearance var of the mutable.
|
||||
|
||||
Somewhat like this
|
||||
|
||||
```byond
|
||||
// NOTE: we do not actually have access to a raw appearance type, so we will often
|
||||
// Lie to the compiler, and pretend we are using a mutable appearance
|
||||
// This lets us access vars as expected. Be careful with it tho
|
||||
/proc/mutate_icon_state(mutable_appearance/thing)
|
||||
var/mutable_appearance/temporary_lad = new()
|
||||
temporary_lad.appearance = thing
|
||||
temporary_lad.icon_state += "haha_owned"
|
||||
return temporary_lad.appearance
|
||||
```
|
||||
|
||||
> **Warning:** BYOND has been observed to have issues with appearance corruption, it's something to be weary of when "realizing" appearances in this manner.
|
||||
|
||||
## Overlays
|
||||
|
||||
- [Table of Contents](#table-of-contents)
|
||||
- [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/overlays) (Also see [rendering](https://www.byond.com/docs/ref/#/{notes}/renderer))
|
||||
|
||||
Overlays are a list of static [appearances](#appearances-in-byond) that we render on top of ourselves.
|
||||
Said appearances can be edited via the realizing method mentioned above.
|
||||
|
||||
Their rendering order is determined by [layer](#layers) and [plane](#planes), but conflicts are resolved based off order of appearance inside the list.
|
||||
|
||||
While overlays are stored as static appearances they can be created using icon states to draw from the overlay'd thing icon, or using `/icon` objects.
|
||||
|
||||
Also of note: overlays have a cost on addition, which is why as we will discuss we cache modifications to the list.
|
||||
|
||||
It's not significant, but it is there, and something to be aware of.
|
||||
|
||||
### Our Implementation
|
||||
|
||||
We use overlays as our primary method of overlaying visuals.
|
||||
However, since overlays are COPIES of a thing's appearance, ensuring that they can be cleared is semi troublesome.
|
||||
|
||||
To solve this problem, we manage most overlays using `update_overlays()`.
|
||||
|
||||
This proc is called whenever an atom's appearance is updated with `update_appearance()`
|
||||
(essentially just a way to tell an object to rerender anything static about it, like icon state or name),
|
||||
which will often call `update_icon()`.
|
||||
|
||||
`update_icon()` handles querying the object for its desired icon, and also manages its overlays, by calling `update_overlays()`.
|
||||
|
||||
Said proc returns a list of things to turn into static appearances, which are then passed into `add_overlay()`,
|
||||
which makes them static with `build_appearance_list()` before queuing an overlay compile.
|
||||
|
||||
This list of static appearances is then queued inside a list called `managed_overlays` on `/atom`.
|
||||
This is so we can clear old overlays out before running an update.
|
||||
|
||||
We actually compile queued overlay builds once every tick using a dedicated subsystem.
|
||||
This is done to avoid adding/removing/adding again to the overlays list in cases like humans where it's mutated a lot.
|
||||
|
||||
You can bypass this managed overlays system if you'd like, using `add_overlay()` and `cut_overlay()`,
|
||||
but this is semi dangerous because you don't by default have a way to "clear" the overlay.
|
||||
Be careful of this.
|
||||
|
||||
## Visual Contents
|
||||
|
||||
- [Table of Contents](#table-of-contents)
|
||||
- [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/vis_contents)
|
||||
|
||||
The `vis_contents` list allows you to essentially say "Hey, render this thing ON me".
|
||||
|
||||
The definition of "ON" varies significantly with the `vis_flags` value of the *thing* being relayed.
|
||||
See the ref [here](https://www.byond.com/docs/ref/#/atom/var/vis_flags).
|
||||
|
||||
Some flags of interest:
|
||||
- `VIS_INHERIT_ID`: This allows you to link the object DIRECTLY to the thing it's drawn on,
|
||||
so clicking on the `vis_contents`'d object is just like clicking on the thing
|
||||
- `VIS_INHERIT_PLANE`: We will discuss [planes](#planes) more in future, but we use them to both effect rendering order and apply effects as a group.
|
||||
This flag changes the plane of any `vis_contents`'d object (while displayed on the source object) to the source's.
|
||||
This is occasionally useful, but should be used with care as it breaks any effects that rely on plane.
|
||||
|
||||
Anything inside a `vis_contents` list will have its loc stored in its `vis_locs` variable.
|
||||
We very rarely use this, primarily just for clearing references from `vis_contents`.
|
||||
|
||||
`vis_contents`, unlike `overlays` is a reference, not a copy. So you can update a `vis_contents`'d thing and have it mirror properly.
|
||||
This is how we do multiz by the by, with uh, some more hell discussed under [multiz](#multiz).
|
||||
|
||||
To pay for this additional behavior however, vis_contents has additional cost in maptick.
|
||||
Because it's not a copy, we need to constantly check if it's changed at all, which leads to cost scaling with player count.
|
||||
Careful how much you use it.
|
||||
|
||||
## Images
|
||||
|
||||
|
||||
- [Table of Contents](#table-of-contents)
|
||||
- [Reference Entry](https://www.byond.com/docs/ref/#/image)
|
||||
|
||||
Images are technically parents of [mutable appearances](#appearances-in-byond).
|
||||
We don't often use them, mostly because we can accomplish their behavior with just MAs.
|
||||
|
||||
Images exist both to be used in overlays, and to display things to only select clients on the map.
|
||||
See [/client/var/images](#client-images)
|
||||
|
||||
> Note: the inheritance between the two is essentially for engine convenience. Don't rely on it.
|
||||
|
||||
## Client Images
|
||||
|
||||
- [Table of Contents](#table-of-contents)
|
||||
- [Reference Entry](https://www.byond.com/docs/ref/#/client/var/images)
|
||||
|
||||
`/client/var/images` is a list of image objects to display to JUST that particular client.
|
||||
|
||||
The image objects are displayed at their loc variable, and can be shown to more then one user at once.
|
||||
|
||||
### Our Implementation
|
||||
|
||||
We use client images in a few ways. Often they will be used just as intended, to modify the view of just one user.
|
||||
Think tray scanner or technically ai static.
|
||||
|
||||
However, we often want to show a set of images to the same GROUP of people, but in a limited manner.
|
||||
For this, we use the `/datum/atom_hud` (hereafter hud) system.
|
||||
|
||||
This is different from `/datum/hud`, which I will discuss later.
|
||||
|
||||
HUDs are datums that represent categories of images to display to users.
|
||||
They are most often global, but can be created on an atom to atom bases in rare cases.
|
||||
|
||||
They store a list of images to display (sorted by source z level to reduce lag) and a list of clients to display to.
|
||||
|
||||
We then mirror this group of images into/out of the client's images list, based on what HUDs they're able to see.
|
||||
This is the pattern we use for things like the medihud, or robot trails.
|
||||
|
||||
## View
|
||||
- [Table of Contents](#table-of-contents)
|
||||
- [Reference Entry](https://www.byond.com/docs/ref/#/client/var/view)
|
||||
|
||||
`/client/var/view` is actually a pretty simple topic,
|
||||
but I'm gonna take this chance to discuss the other things we do to manage pixel sizing and such since there isn't a better place for it,
|
||||
and they're handled in the same place by us.
|
||||
|
||||
Alright then, view. This is pretty simple, but it basically just lets us define the tile bound we want to show to our client.
|
||||
|
||||
This can either be a number for an X by X square, or a string in the form "XxY" for more control.
|
||||
|
||||
We use `/datum/view_data` to manage and track view changes, so zoom effects can work without canceling or being canceled by anything else.
|
||||
|
||||
### Client Rendering Modes
|
||||
|
||||
- [Zoom Ref](https://www.byond.com/docs/ref/#/{skin}/param/zoom) / [Zoom Mode Ref](https://www.byond.com/docs/ref/#/{skin}/param/zoom-mode)
|
||||
|
||||
Clients get some choice in literally how they want the game to be rendered to them.
|
||||
|
||||
The two I'm gonna discuss here are `zoom`, and `zoom-mode` mode, both of which are skin params (basically just variables that live on the client)
|
||||
|
||||
`zoom` decides how the client wants to display the turfs shown to it.
|
||||
It can have two types of values.
|
||||
If it's equal to 0 it will stretch the tiles sent to the client to fix the size of the map-window.
|
||||
Otherwise, any other numbers will lead to pixels being scaled by some multiple.
|
||||
This effect can only really result in nice clean edges if you pass in whole numbers which is why most of the constant scaling we give players are whole numbers.
|
||||
|
||||
`zoom-mode` controls how a pixel will be up-scaled, if it needs to be.
|
||||
See the ref for more details, but `normal` is gonna have the sharpest output, `distort` uses nearest neighbor,
|
||||
which causes some blur, and `blur` uses bilinear sampling, which causes a LOT of blur.
|
||||
|
||||
## Eye
|
||||
- [Table of Contents](#table-of-contents)
|
||||
- [Reference Entry](https://www.byond.com/docs/ref/#/client/var/eye)
|
||||
|
||||
`/client/var/eye` is the atom or mob at which our view should be centered.
|
||||
Any screen objects we display will show "off" this, as will our actual well eye position.
|
||||
|
||||
It is by default `/client/var/mob` but it can be modified.
|
||||
This is how we accomplish ai eyes and ventcrawling, alongside most other effects that involve a player getting "into" something.
|
||||
|
||||
## Client Screen
|
||||
- [Table of Contents](#table-of-contents)
|
||||
- [Reference Entry](https://www.byond.com/docs/ref/#/{notes}/HUD)
|
||||
|
||||
Similar to client images but not *quite* the same, we can also insert objects onto our client's literal screen
|
||||
|
||||
This is done by giving it an appropriate `screen_loc` value, and inserting it into the client's `screen` list.
|
||||
|
||||
Note: we use screen for other things too, I'll get to that eventually.
|
||||
|
||||
`screen` is actually rather uninteresting, but `screen_loc` has a LOT more nuance.
|
||||
|
||||
To start with, the format.
|
||||
The classic `screen_loc` format looks something like this (keeping in mind it counts from the top left):
|
||||
`x:px,y:py`
|
||||
|
||||
The pixel offsets can be discarded as optional, but crucially the x and y values do not NEED to be absolute.
|
||||
|
||||
We can use cardinal keywords like `NORTH` to anchor screen objects to the view size of the client (a topic that will be discussed soon).
|
||||
You can also use directional keywords like `TOP` to anchor to the actual visible map-window, which prevents any accidental out of bounds.
|
||||
Oh yeah you can use absolute offsets to position screen objects out of the view range, which will cause the map-window to forcefully expand,
|
||||
exposing the parts of the map byond uses to ahead of time render border things so moving is smooth.
|
||||
|
||||
### Secondary Maps
|
||||
|
||||
While we're here, this is a bit of a side topic but you can have more then one map-window on a client's screen at once.
|
||||
|
||||
This gets into dmf fuckery but you can use [window ids](https://www.byond.com/docs/ref/#/{skin}/param/id) to tell a screen object to render to a secondary map.
|
||||
Useful for creating popup windows and such.
|
||||
|
||||
## Blend Mode
|
||||
- [Table of Contents](#table-of-contents)
|
||||
- [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/blend_mode)
|
||||
|
||||
`/atom/var/blend_mode` defines how an atom well, renders onto the map.
|
||||
|
||||
There's a whole bunch of options but really the only one you need to know offhand is `BLEND_MULTIPLY`, which multiplies the thing being drawn "on" by us.
|
||||
|
||||
This is how we do lighting effects, since the lighting [plane](#planes) can be used to multiply just normal coloring. If it's all black, the full screen goes black.
|
||||
|
||||
## Appearance Flags
|
||||
- [Table of Contents](#table-of-contents)
|
||||
- [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/appearance_flags)
|
||||
|
||||
`/atom/var/appearance_flags` is a catch all for toggles that apply to visual elements of an atom.
|
||||
I won't go over all of them, but I will discuss a few.
|
||||
|
||||
Flags of interest:
|
||||
- `LONG_GLIDE`: without this, diagonal movements will automatically take sqrt(2) more time, to account for the greater distance. We do this calculus automatically, and so want this flipped to disable the behavior.
|
||||
- `KEEP_TOGETHER`: this allows us to force overlays to render in the same manner as the thing they're overlaid on. Most useful for humans to make alpha changes effect all overlays.
|
||||
- `PLANE_MASTER`: I will get into this later, but this allows us to use the [plane](#planes) var to relay renders onto screen objects, so we can apply visual effects and masks and such.
|
||||
- `TILE_BOUND`: By default if something is part in one tile and part in another it will display if either is visible. With this set it'll go off its loc value only.
|
||||
|
||||
## Gliding
|
||||
- [Table of Contents](#table-of-contents)
|
||||
- [Reference Entry](https://www.byond.com/docs/ref/#/{notes}/gliding)
|
||||
|
||||
You may have noticed that moving between tiles is smooth, or at least as close as we can get it.
|
||||
Moving at 0.2 or 10 tiles per second will be smooth. This is because we have control over the speed at which atoms animate between moves.
|
||||
|
||||
This is done using two patterns. One is how we handle input, the other is BYOND's gliding.
|
||||
|
||||
We can edit `/atom/movable/var/glide_size` to set the amount of pixels our mob should move per SERVER tick (Our server tick rate is 20 times a second, or 0.5 deciseconds).
|
||||
This is done using `/atom/movable/proc/set_glide_size`, which will inform anything we are "carrying" to match our rate.
|
||||
|
||||
Glide size is often set in the context of some rate of movement. Either the movement delay of a mob, set in `/client/Move()`, or the delay of a movement subsystem.
|
||||
|
||||
We use defines to turn delays into pixels per tick.
|
||||
Client moves will be limited by `DELAY_TO_GLIDE_SIZE` which will allow at most 32 pixels a tick.
|
||||
Subsystems and other niche uses use `MOVEMENT_ADJUSTED_GLIDE_SIZE`.
|
||||
We will also occasionally use glide size as a way to force a transition between different movement types, like space-drift into normal walking.
|
||||
There's extra cruft here.
|
||||
|
||||
> Something you should know: Our gliding system attempts to account for time dilation when setting move rates.
|
||||
This is done in a very simplistic way however, so a spike in td will lead to jumping around as glide rate is outpaced by mob movement rate.
|
||||
|
||||
On that note, it is VERY important that glide rate is the same or near the same as actual move rate.
|
||||
Otherwise you will get strange jumping and jitter.
|
||||
This can also lead to stupid shit where people somehow manage to intentionally shorten a movement delay to jump around. Dumb.
|
||||
|
||||
Related to the above, we are not always able to maintain sync between glide rate and mob move rate.
|
||||
This is because mob move rate is a function of the initial move delay and a bunch of slowdown/speedup modifiers.
|
||||
In order to maintain sync we would need to issue a move command the MOMENT a delay is up, and if delays are not cleanly divisible by our tick rate (0.5 deciseconds) this is impossible.
|
||||
This is why you'll sometime see a stutter in your step when slowed
|
||||
|
||||
Just so you know, client movement works off `/client/var/move_delay` which sets the next time an input will be accepted. It's typically glide rate, but is in some cases just 1 tick.
|
||||
|
||||
## Sight
|
||||
- [Table of Contents](#table-of-contents)
|
||||
- [Reference Entry](https://www.byond.com/docs/ref/#/mob/var/sight)
|
||||
|
||||
`/mob/var/sight` is a set of bitflags that *mostly* set what HAS to render on your screen. Be that mobs, turfs, etc.
|
||||
That said, there is some nuance here so I'ma get into that.
|
||||
|
||||
- `SEE_INFRA`: I'll get into this later, but infrared is essentially a copy of BYOND darkness, it's not something we currently use.
|
||||
- `SEE_BLACKNESS`: This relates heavily to [planes](#planes), essentially typically the "blackness" (that darkness that masks things that you can't see)
|
||||
is rendered separately, out of our control as "users".
|
||||
However, if the `SEE_BLACKNESS` flag is set, it will instead render on plane 0, the default BYOND plane.
|
||||
This allows us to capture it, and say, blur it, or redraw it elsewhere. Very very powerful, we always have this flag set.
|
||||
|
||||
## BYOND Lighting
|
||||
|
||||
- [Table of Contents](#table-of-contents)
|
||||
|
||||
Alongside OUR lighting implementation, which is discussed in with color matrixes, BYOND has its own lighting system.
|
||||
|
||||
It's very basic. Essentially, a tile is either "lit" or it's not.
|
||||
|
||||
If a tile is not lit, and it matches some other preconditions, it and all its contents will be hidden from the user,
|
||||
sort of like if there was a wall between them. This hiding uses BYOND darkness, and is thus controllable.
|
||||
|
||||
I'll use this section to discuss all the little bits that contribute to this behavior
|
||||
|
||||
### Luminosity
|
||||
- [Table of Contents](#table-of-contents)
|
||||
- [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/luminosity)
|
||||
|
||||
`/atom/var/luminosity` is a variable that lets us inject light into BYOND's lighting system.
|
||||
It's real simple, just a range of tiles that will be lit, respecting sight-lines and such of course.
|
||||
|
||||
> This "light" is how `/proc/view()` knows if something is in view or not. Oh by the by `view()` respects lighting.
|
||||
You can actually force it to use a particular mob's sight to avoid aspects of this, this is what `dview()` is
|
||||
|
||||
### See in Dark
|
||||
- [Table of Contents](#table-of-contents)
|
||||
- [Reference Entry](https://www.byond.com/docs/ref/#/mob/var/see_in_dark)
|
||||
|
||||
`/mob/var/see_in_dark` sets the radius of a square around the mob that cuts out BYOND darkness.
|
||||
|
||||
This is why when you stand in darkness you can see yourself, and why you can see a line of objects appear when you use mesons (horrible effect btw).
|
||||
It's quite simple, but worth describing.
|
||||
|
||||
### Infrared
|
||||
- [Table of Contents](#table-of-contents)
|
||||
- [Reference Entry](https://www.byond.com/docs/ref/#/mob/var/see_infrared)
|
||||
|
||||
Infrared vision can be thought of as a hidden copy of standard BYOND darkness.
|
||||
It's not something we actually use, but I think you should know about it, because the whole thing is real confusing without context.
|
||||
|
||||
## Invisibility
|
||||
- [Table of Contents](#table-of-contents)
|
||||
- [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/invisibility)
|
||||
|
||||
`/atom/var/invisibility` is a rudimentary way of hiding things from select groups of users. Think of it like [planes](#planes), or [client images](#client-images) but more limited.
|
||||
We use this to hide ghosts, ghost visible things, and in the past we used it to hide/show backdrops for the lighting plane, which is semi redundant now.
|
||||
|
||||
It's also used to hide some more then ghost invisible things, like some timers and countdowns. It scales from 0 to 101.
|
||||
|
||||
`/mob/var/see_invisible` is the catcher of invisibility. If a mob's see_invisible is higher then a target/s invisibility, it'll be shown. Really basic stuff.
|
||||
|
||||
## Layers
|
||||
- [Table of Contents](#table-of-contents)
|
||||
- [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/layer)
|
||||
|
||||
`/atom/var/layer` is the first bit of logic that decides the order in which things on the map render.
|
||||
Rendering order depends a LOT on the [map format](https://www.byond.com/docs/ref/#/world/var/map_format),
|
||||
which I will not get into in this document because it is not yet relevant.
|
||||
All you really need to know is for our current format,
|
||||
the objects that appear first in something's contents will draw first, and render lowest.
|
||||
Think of it like stacking little paper cutouts.
|
||||
|
||||
Layer has a bit more nuance then just being lowest to highest, tho it's not a lot.
|
||||
There are a few snowflake layers that can be used to accomplish niche goals, alongside floating layers, which are essentially just any layer that is negative.
|
||||
|
||||
Floating layers will float "up" the chain of things they're being drawn onto, until they find a real layer. They'll then offset off of that.
|
||||
|
||||
This allows us to keep relative layer differences while not needing to make all sources static. Often very useful.
|
||||
|
||||
## Planes
|
||||
- [Table of Contents](#table-of-contents)
|
||||
- [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/plane)
|
||||
|
||||
Allllright `/atom/var/plane`s. Let's talk about em.
|
||||
|
||||
They serve two purposes. The first is really simple, and basically just a copy of [layers](#layers).
|
||||
Higher planes will (**normally**) render over lower ones. Very clearcut.
|
||||
|
||||
Similarly to [layers](#layers), planes also support "floating" with `FLOAT_PLANE`. See above for an explanation of that.
|
||||
|
||||
However, they can be used for more complex and... fun things too!
|
||||
If a client has an atom with the `PLANE_MASTER` [appearance flag](#appearance-flags) in their [screen](#client-screen),
|
||||
then rather then being all rendered normally, anything in the client's view is instead first rendered onto the plane master.
|
||||
|
||||
This is VERY powerful, because it lets us [hide](https://www.byond.com/docs/ref/#/atom/var/alpha), [color](#color),
|
||||
and [distort](#filters) whole classes of objects, among other things.
|
||||
I cannot emphasize enough how useful this is. It does have some downsides however.
|
||||
|
||||
Because planes are tied to both grouping and rendering order, there are some effects that require splitting a plane into bits.
|
||||
It's also possible for some effects, especially things relating to [map format](https://www.byond.com/docs/ref/#/world/var/map_format),
|
||||
to just be straight up impossible, or conflict with each other.
|
||||
It's dumb, but it's what we've got brother so we're gonna use it like it's a free ticket to the bahamas.
|
||||
|
||||
We have a system that allows for arbitrary grouping of plane masters for the purposes of [filter effects](#filters)
|
||||
called `/atom/movable/plane_master_controller`.
|
||||
This is somewhat outmoded by our use of [render relays](#render-targetsource), but it's still valid and occasionally useful.
|
||||
|
||||
> Something you should know: Plane masters effect ONLY the map their screen_loc is on.
|
||||
For this reason, we are forced to generate whole copies of the set of plane masters with the proper screen_loc to make subviews look right
|
||||
|
||||
> Warning: Planes have some restrictions on valid values. They NEED to be whole integers, and they NEED to have an absolute value of `10000`.
|
||||
This is to support `FLOAT_PLANE`, which lives out at the very edge of the 32 bit int range.
|
||||
|
||||
## Render Target/Source
|
||||
- [Table of Contents](#table-of-contents)
|
||||
- [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/render_target)
|
||||
|
||||
Render targets are a way of rendering one thing onto another. Not like vis_contents but in a literal sense ONTO.
|
||||
The target object is given a `/atom/var/render_target` value, and anything that wishes to "take" it sets its `/atom/var/render_source` var to match.
|
||||
|
||||
When I say render onto, I mean it literally. It is like adding a second step in the rendering process.
|
||||
|
||||
You can even prepend * to the render target value to disable the initial render, and JUST render via the render source.
|
||||
|
||||
### Our Implementation
|
||||
|
||||
We use render targets to create "render relays" which can be used to link [plane masters](#planes) together and accomplish more advanced effects.
|
||||
See [the renderer documentation](../../code/_onclick/hud/rendering/_render_readme.md) for visualizations for this.
|
||||
|
||||
> Of note: this linking behavior is accomplished by adding a screen object to link onto with a plane value of the desired PM we want to relay onto.
|
||||
Layer is VERY important here, and will be set based off the layer of the last plane master.
|
||||
This means plane order is not always the absolute order in which different plane masters render. Be careful of this.
|
||||
|
||||
> To edit and display planes and plane connections in game, run the `Edit/Debug Planes` command.
|
||||
It will open a ui that allows you to view relay connections, plane master descriptions, and edit their values and effects.
|
||||
|
||||
## Multiz
|
||||
- [Table of Contents](#table-of-contents)
|
||||
- Reference: Hell of our own creation
|
||||
|
||||
I'm gonna explain how our multiz system works. But first I need to explain how it used to work.
|
||||
|
||||
What we used to do was take an openspace turf above, insert the turf below into its [vis_contents](#visual-contents), and call it a day.
|
||||
This worked because everything on the map had the `VIS_INHERIT_PLANE` flag, and openspace had a plane master below most everything.
|
||||
|
||||
This meant the turf below looked as if it was offset, and everything was good.
|
||||
|
||||
Except not, for 2 reasons. One more annoying then the other.
|
||||
|
||||
- 1: It looked like dog doo-doo. This pattern destroyed the old planes of everything vis_contents'd, so effects/lighting/dropshadows broke bad.
|
||||
- 2: I alluded to this earlier, but it totally breaks the `side_map` [map format](https://www.byond.com/docs/ref/#/world/var/map_format)
|
||||
which I need for a massive resprite I'm helping with. This is because `side_map` changes how rendering order works,
|
||||
going off "distance" from the front of the frame.
|
||||
The issue here is it of course needs a way to group things that are even allowed to overlap, so it uses plane.
|
||||
So when you squish everything down onto one plane, this of course breaks horribly and fucks you.
|
||||
|
||||
Ok then, old way's not workable. What will we do instead?
|
||||
|
||||
There's two problems here. The first is that all our plane masters come pre-ordered. We need a way to have lower and upper plane masters.
|
||||
|
||||
This is well... not trivial but not hard either. We essentially duplicate all our plane masters out like a tree, and link the head of the master rendering plate
|
||||
to the openspace plane master one level up. More then doable.
|
||||
|
||||
SECOND problem. How do we get everything below to "land" on the right plane?
|
||||
|
||||
The answer to this is depressing but still true. We manually offset every single object on the map's plane based off its "z layer".
|
||||
This includes any `overlays` or `vis_contents` with a unique plane value.
|
||||
|
||||
Mostly we require anything that sets the plane var to pass in a source of context, like a turf or something that can be used to derive a turf.
|
||||
There are a few edge cases where we need to work in explicitly offsets, but those are much rarer.
|
||||
|
||||
This is stupid, but it's makable, and what we do.
|
||||
|
||||
## Mouse Opacity
|
||||
- [Table of Contents](#table-of-contents)
|
||||
- [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/mouse_opacity)
|
||||
|
||||
`/atom/var/mouse_opacity` tells clients how to treat mousing over the atom in question.
|
||||
|
||||
A value of 0 means it is completely ignored, no matter what.
|
||||
A value of 1 means it is transparent/opaque based off the alpha of the icon at any particular part.
|
||||
A value of 2 means it will count as opaque across ALL of the icon-state. All 32x32 (or whatever) of it.
|
||||
|
||||
We will on occasion use mouse opacity to expand hitboxes, but more often this is done with [vis_contents](#visual-contents),
|
||||
or just low alpha pixels on the sprite.
|
||||
|
||||
> Note: Mouse opacity will only matter if the atom is being rendered on its own. [Overlays](#overlays)(and [images](#images))
|
||||
will NOT work as expected with this.
|
||||
However, you can still have totally transparent overlays. If you render them onto a [plane master](#planes) with the desired mouse opacity value
|
||||
it will work as expected. This is because as a step of the rendering pipeline the overlay is rendered ONTO the plane master, and then the plane
|
||||
master's effects are applied.
|
||||
|
||||
## Filters
|
||||
- [Table of Contents](#table-of-contents)
|
||||
- [Reference Entry](https://www.byond.com/docs/ref/#/{notes}/filters)
|
||||
|
||||
Filters are a general purpose system for applying a limited set of shaders to a render.
|
||||
These shaders run on the client's machine. This has upsides and downsides.
|
||||
Upside: Very cheap for the server. Downside: Potentially quite laggy for the client.
|
||||
Take care with these
|
||||
|
||||
Like I said, they're quite general purpose. There's a LOT of different effects, and many things you can do with them.
|
||||
|
||||
There's two things I want you to know about them, partly to put across their usefulness, and partially so you know their limitations.
|
||||
|
||||
On Usefulness. There are filters for alpha masking. They accept render sources as params, which means we can use say, one plane master
|
||||
to mask out another. This + some fucking bullshit is how emissive lighting works.
|
||||
|
||||
Similarly there are filters for distortions. This is how we accomplish the grav anomaly effect, as it too accepts a render source as a param.
|
||||
|
||||
On limitations: Filters, like many things in BYOND, are stored in a snowflake list on `/atom`. This means if we want to manage them,
|
||||
we will need our own management system. This is why we, unlike byond, use a wrapper around filters to set priorities and manage addition/removal.
|
||||
This system has the potential to break animations and other such things. Take care.
|
||||
|
||||
> We have a debug tool for filters, called filterrific. You can access it in-game by vving an atom, going to the dropdown, and hitting `Edit Filters`
|
||||
It'll let you add and tweak *most* of the filters in BYOND.
|
||||
|
||||
## Particles
|
||||
- [Table of Contents](#table-of-contents)
|
||||
- [Reference Entry](https://www.byond.com/docs/ref/#/{notes}/particles)
|
||||
|
||||
Particles are a system that allows you to attach "generators" to atoms on the world, and have them spit out little visual effects.
|
||||
This is done by creating a subtype of the `/particles` type, and giving it the values you want.
|
||||
|
||||
At base BYOND only allows you to attach one particle emitter to any one `/atom`. We get around this using an atom inserted into the loc of some parent atom to follow.
|
||||
The type is `/obj/effect/abstract/particle_holder`. Interacting with it's real simple, you just pass in the location to mirror, and the type to use.
|
||||
It'll do the rest.
|
||||
|
||||
## Pixel Offsets
|
||||
- [Table of Contents](#table-of-contents)
|
||||
- [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/pixel_x)
|
||||
|
||||
This is a real simple idea and I normally wouldn't mention it, but I have something else I wanna discuss related to it, so I'ma take this chance.
|
||||
|
||||
`/atom/var/pixel_x/y/w/z` are variables that allow us to offset the DISPLAY position of an atom. This doesn't effect its position on the map mind,
|
||||
just where it APPEARS to be. This is useful for many little effects, and some larger ones.
|
||||
|
||||
Anyway, onto why I'm mentioning this.
|
||||
|
||||
There are two "types" of each direction offset. There's the "real" offset (x/y) and the "fake" offset (w,z).
|
||||
Real offsets will change both the visual position (IE: where it renders) and also the positional position (IE: where the renderer thinks they are).
|
||||
Fake offsets only effect visual position.
|
||||
|
||||
This doesn't really matter for our current map format, but for anything that takes position into account when layering, like `side_map` or `isometric_map`
|
||||
it matters a whole ton. It's kinda a hard idea to get across, but I hope you have at least some idea.
|
||||
|
||||
## Color
|
||||
- [Table of Contents](#table-of-contents)
|
||||
- [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/color)
|
||||
|
||||
`/atom/var/color` is another one like [pixel offsets](#pixel-offsets) where its most common use is really uninteresting, but it has an interesting
|
||||
edge case I think is fun to discuss/important to know.
|
||||
|
||||
So let's get the base case out of the way shall we?
|
||||
|
||||
At base, you can set an atom's color to some `rrggbbaa` string (see [here](https://www.byond.com/docs/ref/#/{{appendix}}/html-colors)). This will shade every pixel on that atom to said color, and override its [`/atom/var/alpha`](https://www.byond.com/docs/ref/#/atom/var/alpha) value.
|
||||
See [appearance flags](#appearance-flags) for how this effect can carry into overlays and such.
|
||||
|
||||
That's the boring stuff, now the fun shit.
|
||||
|
||||
> Before we get into this. `rr` is read as "red to red". `ag` is read as "alpha to green", etc. `c` is read as constant, and always has a value of 255
|
||||
|
||||
You can use the color variable to not just shade, but shift the colors of the atom.
|
||||
It accepts a list (functionally a matrix if you know those) in the format `list(rr,br,gr,ar, rb,bb,gb,ab, rg,bg,gg,ag, ra,ba,ga,aa, cr,cb,cg,ca)`
|
||||
This allows us to essentially multiply the color of each pixel by some other other. The values inserted in each multiple are not really bounded.
|
||||
|
||||
You can accomplish some really fun effects with this trick, it gives you a LOT of control over the color of a sprite or say, a [plane master](#planes)
|
||||
and leads to some fun vfx.
|
||||
|
||||
> We have a debug tool for color matrixes. Just VV an atom, go to the VV dropdown and look for the `Edit Color as Matrix` entry.
|
||||
It'll help visualize this process quite well. Play around with it, it's fun.
|
||||
|
||||
## Transform
|
||||
- [Table of Contents](#table-of-contents)
|
||||
- [Reference Entry](https://www.byond.com/docs/ref/#/atom/var/transform)
|
||||
|
||||
`/atom/var/transform` allows you to shift, contort, rotate and scale atoms visually.
|
||||
This is done using a matrix, similarly to color matrixes. You will likely never need to use it manually however, since there are
|
||||
helper procs for pretty much everything it can do.
|
||||
|
||||
> Note: the transform var is COPIED whenever you read it. So if you want to modify it, you will need to reset the atom var back to your changes.
|
||||
|
||||
It's not totally without explanation, and I figured you might wanna know about it. Not a whole lot more to say tho. Neat tool.
|
||||
|
||||
## Lighting
|
||||
- [Table of Contents](#table-of-contents)
|
||||
- Reference: Hell of our own creation
|
||||
|
||||
I wanted to take this chance to briefly explain the essentials of how our lighting system works.
|
||||
Essentially, each tile has a lighting [overlay](#overlays) (technically an [underlay](https://www.byond.com/docs/ref/#/atom/var/underlays)
|
||||
which is just overlays but drawn under).
|
||||
Anyway, each underlay is a color gradient, with red green and blue and alpha in each corner.
|
||||
Every "corner" (we call them lighting corners) on the map impacts the 4 colors that touch it.
|
||||
This is done with color matrixes. This allows us to apply color and lighting in a smooth way, while only needing 1 overlay per tile.
|
||||
|
||||
There's a lot of nuance here, like how color is calculated and stored, and our overlay lighting system which is a whole other beast.
|
||||
But it covers the core idea, the rest should be derivable, and you're more qualified to do so then me, assuming some bastard will come along to change it
|
||||
and forget to update this file.
|
||||
|
||||
## Animate()
|
||||
- [Table of Contents](#table-of-contents)
|
||||
- [Reference Entry](https://www.byond.com/docs/ref/#/proc/animate)
|
||||
|
||||
The animate proc allows us to VISUALLY transition between different values on an appearance on clients, while in actuality
|
||||
setting the values instantly on the servers.
|
||||
|
||||
This is quite powerful, and lets us do many things, like slow fades, shakes, hell even parallax using matrixes.
|
||||
|
||||
It doesn't support everything, and it can be quite temperamental especially if you use things like the flag that makes it work in
|
||||
parallel. It's got a lot of nuance to it, but it's real useful. Works on filters and their variables too, which is AGGRESSIVELY useful.
|
||||
|
||||
Lets you give radiation glow a warm pulse, that sort of thing.
|
||||
|
||||
## GAGS
|
||||
- [Table of Contents](#table-of-contents)
|
||||
- Reference: Hell of our own creation
|
||||
|
||||
GAGS is a system of our own design built to support runtime creation of icons from split components.
|
||||
|
||||
This means recoloring is trivial, and bits of sprites can be combined and split easily. Very useful.
|
||||
|
||||
I won't go into much detail here, check out the [starter guide](https://hackmd.io/@tgstation/GAGS-Walkthrough) for more info if you're interested.
|
||||
@@ -47,16 +47,20 @@
|
||||
|
||||
GLOBAL_LIST_INIT(nonoverlaying_gases, typecache_of_gases_with_no_overlays())
|
||||
///Returns a list of overlays of every gas in the mixture
|
||||
#define GAS_OVERLAYS(gases, out_var)\
|
||||
out_var = list();\
|
||||
for(var/_ID in gases){\
|
||||
if(GLOB.nonoverlaying_gases[_ID]) continue;\
|
||||
var/_GAS = gases[_ID];\
|
||||
var/_GAS_META = _GAS[GAS_META];\
|
||||
if(_GAS[MOLES] <= _GAS_META[META_GAS_MOLES_VISIBLE]) continue;\
|
||||
var/_GAS_OVERLAY = _GAS_META[META_GAS_OVERLAY];\
|
||||
out_var += _GAS_OVERLAY[min(TOTAL_VISIBLE_STATES, CEILING(_GAS[MOLES] / MOLES_GAS_VISIBLE_STEP, 1))];\
|
||||
}
|
||||
#define GAS_OVERLAYS(gases, out_var, z_layer_turf)\
|
||||
do { \
|
||||
out_var = list();\
|
||||
var/offset = GET_TURF_PLANE_OFFSET(z_layer_turf);\
|
||||
for(var/_ID in gases){\
|
||||
if(GLOB.nonoverlaying_gases[_ID]) continue;\
|
||||
var/_GAS = gases[_ID];\
|
||||
var/_GAS_META = _GAS[GAS_META];\
|
||||
if(_GAS[MOLES] <= _GAS_META[META_GAS_MOLES_VISIBLE]) continue;\
|
||||
var/_GAS_OVERLAY = _GAS_META[META_GAS_OVERLAY][offset + 1];\
|
||||
out_var += _GAS_OVERLAY[min(TOTAL_VISIBLE_STATES, CEILING(_GAS[MOLES] / MOLES_GAS_VISIBLE_STEP, 1))];\
|
||||
} \
|
||||
}\
|
||||
while (FALSE)
|
||||
|
||||
#ifdef TESTING
|
||||
GLOBAL_LIST_INIT(atmos_adjacent_savings, list(0,0))
|
||||
@@ -79,7 +83,7 @@ GLOBAL_LIST_INIT(atmos_adjacent_savings, list(0,0))
|
||||
*
|
||||
* To equalize two gas mixtures, we simply pool the energy and divide it by the pooled heat capacity.
|
||||
* T' = (W1+W2) / (C1+C2)
|
||||
* But if we want to moderate this conduction, maybe we can calculate the energy transferred
|
||||
* But if we want to moderate this conduction, maybe we can calculate the energy transferred
|
||||
* and multiply a coefficient to it instead.
|
||||
* This is the energy transferred:
|
||||
* W = T' * C1 - W1
|
||||
@@ -91,20 +95,20 @@ GLOBAL_LIST_INIT(atmos_adjacent_savings, list(0,0))
|
||||
* W = (W2C1 - W1C2) / (C1+C2)
|
||||
* W = (T2*C2*C1 - T1*C1*C2) / (C1+C2)
|
||||
* W = (C1*C2) * (T2-T1) / (C1+C2)
|
||||
*
|
||||
*
|
||||
* W: Energy involved in the operation
|
||||
* T': Combined temperature
|
||||
* T1, C1, W1: Temp, heat cap, and thermal energy of the first gas mixture
|
||||
* T2, C2, W2: Temp, heat cap, and thermal energy of the second gas mixture
|
||||
*
|
||||
* Not immediately obvious, but saves us operation time.
|
||||
*
|
||||
* We put a lot of parentheses here because the numbers get really really big.
|
||||
*
|
||||
* We put a lot of parentheses here because the numbers get really really big.
|
||||
* By prioritizing the division we try to tone the number down so we dont get overflows.
|
||||
*
|
||||
*
|
||||
* Arguments:
|
||||
* * temperature_delta: T2 - T1. [/datum/gas_mixture/var/temperature]
|
||||
* If you have any moderating (less than 1) coefficients and are dealing with very big numbers
|
||||
* If you have any moderating (less than 1) coefficients and are dealing with very big numbers
|
||||
* multiply the temperature_delta by it first before passing so we get even more breathing room.
|
||||
* * heat_capacity_one: gasmix one's [/datum/gas_mixture/proc/heat_capacity]
|
||||
* * heat_capacity_two: gasmix two's [/datum/gas_mixture/proc/heat_capacity]
|
||||
|
||||
36
code/__DEFINES/blend_modes.dm
Normal file
36
code/__DEFINES/blend_modes.dm
Normal file
@@ -0,0 +1,36 @@
|
||||
|
||||
// Taken from https://www.byond.com/docs/ref/#/atom/var/blend_mode
|
||||
// I want you to be able to get these values without using global.vars manually yourself.
|
||||
// The suggestions here are from the ref, and therefore are NOT ALWAYS ACCURATE TO SS13
|
||||
|
||||
// Controls the way the atom's icon is blended onto the icons behind it.
|
||||
// The blend mode used by an atom is inherited by any attached overlays, unless they override it.
|
||||
// BLEND_DEFAULT will use the main atom's blend mode; for the atom itself, it's the same as BLEND_OVERLAY.
|
||||
// #define BLEND_DEFAULT 0
|
||||
|
||||
// BLEND_OVERLAY will draw an icon the normal way.
|
||||
// #define BLEND_OVERLAY 1
|
||||
|
||||
// BLEND_ADD will do additive blending, so that the colors in the icon are added to whatever is behind it.
|
||||
// Light effects like explosions will tend to look better in this mode.
|
||||
// #define BLEND_ADD 2
|
||||
|
||||
// BLEND_SUBTRACT is for subtractive blending. This may be useful for special effects.
|
||||
// #define BLEND_SUBTRACT 3
|
||||
|
||||
// BLEND_MULTIPLY will multiply the icon's colors by whatever is behind it.
|
||||
// This is typically only useful for applying a colored light effect; for simply darkening, using a translucent black icon with normal overlay blending is a better option.
|
||||
// #define BLEND_MULTIPLY 4
|
||||
|
||||
// BLEND_INSET_OVERLAY overlays the icon, but masks it by the image being drawn on.
|
||||
// This is pretty much not at all useful directly on the map, but can be very useful for an overlay for an atom that uses KEEP_TOGETHER (see appearance_flags), or for the layering filter.
|
||||
// #define BLEND_INSET_OVERLAY 5
|
||||
|
||||
GLOBAL_LIST_INIT(blend_names, list(
|
||||
"0" = "BLEND_DEFAULT",
|
||||
"1" = "BLEND_OVERLAY",
|
||||
"2" = "BLEND_ADD",
|
||||
"3" = "BLEND_SUBTRACT",
|
||||
"4" = "BLEND_MULTIPLY",
|
||||
"5" = "BLEND_INSET_OVERLAY",
|
||||
))
|
||||
2
code/__DEFINES/dcs/signals/mapping.dm
Normal file
2
code/__DEFINES/dcs/signals/mapping.dm
Normal file
@@ -0,0 +1,2 @@
|
||||
// Sent when the max plane offset changes : (old_max_offset, new_max_offset)
|
||||
#define COMSIG_PLANE_OFFSET_INCREASE "plane_offset_increase"
|
||||
@@ -45,7 +45,7 @@
|
||||
#define COMSIG_MOVABLE_POST_THROW "movable_post_throw"
|
||||
///from base of datum/thrownthing/finalize(): (obj/thrown_object, datum/thrownthing) used for when a throw is finished
|
||||
#define COMSIG_MOVABLE_THROW_LANDED "movable_throw_landed"
|
||||
///from base of atom/movable/on_changed_z_level(): (turf/old_turf, turf/new_turf)
|
||||
///from base of atom/movable/on_changed_z_level(): (turf/old_turf, turf/new_turf, same_z_layer)
|
||||
#define COMSIG_MOVABLE_Z_CHANGED "movable_ztransit"
|
||||
///called when the movable is placed in an unaccessible area, used for stationloving: ()
|
||||
#define COMSIG_MOVABLE_SECLUDED_LOCATION "movable_secluded"
|
||||
|
||||
@@ -2,3 +2,6 @@
|
||||
|
||||
// from /client/proc/change_view() : (new_size)
|
||||
#define COMSIG_VIEW_SET "view_set"
|
||||
|
||||
// from /client/proc/handle_popup_close() : (window_id)
|
||||
#define COMSIG_POPUP_CLEARED "popup_cleared"
|
||||
|
||||
2
code/__DEFINES/dcs/signals/signals_hud.dm
Normal file
2
code/__DEFINES/dcs/signals/signals_hud.dm
Normal file
@@ -0,0 +1,2 @@
|
||||
/// Sent from /datum/hud/proc/eye_z_changed() : (old_offset, new_offset)
|
||||
#define COMSIG_HUD_OFFSET_CHANGED "hud_offset_changed"
|
||||
@@ -42,8 +42,11 @@
|
||||
#define COMSIG_MOB_CLIENT_MOVED "mob_client_moved"
|
||||
/// From base of /client/proc/change_view() (mob/source, new_size)
|
||||
#define COMSIG_MOB_CLIENT_CHANGE_VIEW "mob_client_change_view"
|
||||
/// From base of /mob/proc/reset_perspective() (mob/source)
|
||||
/// From base of /mob/proc/reset_perspective() : ()
|
||||
#define COMSIG_MOB_RESET_PERSPECTIVE "mob_reset_perspective"
|
||||
/// from base of /client/proc/set_eye() : (atom/old_eye, atom/new_eye)
|
||||
#define COMSIG_CLIENT_SET_EYE "client_set_eye"
|
||||
|
||||
|
||||
///from mind/transfer_to. Sent to the receiving mob.
|
||||
#define COMSIG_MOB_MIND_TRANSFERRED_INTO "mob_mind_transferred_into"
|
||||
@@ -62,6 +65,16 @@
|
||||
|
||||
///from base of mob/create_mob_hud(): ()
|
||||
#define COMSIG_MOB_HUD_CREATED "mob_hud_created"
|
||||
///from base of hud/show_to(): (datum/hud/hud_source)
|
||||
#define COMSIG_MOB_HUD_REFRESHED "mob_hud_refreshed"
|
||||
|
||||
///from base of mob/set_sight(): (new_sight, old_sight)
|
||||
#define COMSIG_MOB_SIGHT_CHANGE "mob_sight_changed"
|
||||
///from base of mob/set_invis_see(): (new_invis, old_invis)
|
||||
#define COMSIG_MOB_SEE_INVIS_CHANGE "mob_see_invis_change"
|
||||
///from base of mob/set_see_in_dark(): (new_range, old_range)
|
||||
#define COMSIG_MOB_SEE_IN_DARK_CHANGE "mob_see_in_dark_change"
|
||||
|
||||
|
||||
///from base of /mob/living/proc/apply_damage(): (damage, damagetype, def_zone)
|
||||
#define COMSIG_MOB_APPLY_DAMAGE "mob_apply_damage"
|
||||
|
||||
@@ -211,9 +211,14 @@
|
||||
#define SCRN_OBJ_IN_LIST "list"
|
||||
/// In the collapseable palette
|
||||
#define SCRN_OBJ_IN_PALETTE "palette"
|
||||
|
||||
///Inserted first in the list
|
||||
#define SCRN_OBJ_INSERT_FIRST "first"
|
||||
|
||||
// Plane group keys, used to group swaths of plane masters that need to appear in subwindows
|
||||
/// The primary group, holds everything on the main window
|
||||
#define PLANE_GROUP_MAIN "main"
|
||||
/// A secondary group, used when a client views a generic window
|
||||
#define PLANE_GROUP_POPUP_WINDOW(screen) "popup-[REF(screen)]"
|
||||
|
||||
/// The filter name for the hover outline
|
||||
#define HOVER_OUTLINE_FILTER "hover_outline"
|
||||
|
||||
@@ -2,23 +2,20 @@
|
||||
//KEEP THESE IN A NICE ACSCENDING ORDER, PLEASE
|
||||
|
||||
//NEVER HAVE ANYTHING BELOW THIS PLANE ADJUST IF YOU NEED MORE SPACE
|
||||
#define LOWEST_EVER_PLANE -200
|
||||
#define LOWEST_EVER_PLANE -100
|
||||
|
||||
#define FIELD_OF_VISION_BLOCKER_PLANE -199
|
||||
#define FIELD_OF_VISION_BLOCKER_PLANE -90
|
||||
#define FIELD_OF_VISION_BLOCKER_RENDER_TARGET "*FIELD_OF_VISION_BLOCKER_RENDER_TARGET"
|
||||
|
||||
#define CLICKCATCHER_PLANE -99
|
||||
#define CLICKCATCHER_PLANE -80
|
||||
|
||||
#define PLANE_SPACE -95
|
||||
#define PLANE_SPACE_PARALLAX -90
|
||||
#define PLANE_SPACE -25
|
||||
#define PLANE_SPACE_PARALLAX -20
|
||||
|
||||
#define GRAVITY_PULSE_PLANE -12
|
||||
#define GRAVITY_PULSE_RENDER_TARGET "*GRAVPULSE_RENDER_TARGET"
|
||||
|
||||
#define TRANSPARENT_FLOOR_PLANE -11 //Transparent plane that shows openspace underneath the floor
|
||||
#define OPENSPACE_PLANE -10 //Openspace plane below all turfs
|
||||
#define OPENSPACE_BACKDROP_PLANE -9 //Black square just over openspace plane to guaranteed cover all in openspace turf
|
||||
|
||||
#define RENDER_PLANE_TRANSPARENT -9 //Transparent plane that shows openspace underneath the floor
|
||||
|
||||
#define FLOOR_PLANE -8
|
||||
|
||||
@@ -28,15 +25,82 @@
|
||||
#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 SEETHROUGH_PLANE -3
|
||||
#define ABOVE_GAME_PLANE -2
|
||||
|
||||
#define MOUSE_TRANSPARENT_PLANE -1 //SKYRAT EDIT ADDITION - Pollution port
|
||||
#define RENDER_PLANE_GAME_WORLD -1
|
||||
|
||||
#define BLACKNESS_PLANE 0 //To keep from conflicts with SEE_BLACKNESS internals
|
||||
|
||||
#define AREA_PLANE 2
|
||||
#define MASSIVE_OBJ_PLANE 3
|
||||
#define GHOST_PLANE 4
|
||||
#define POINT_PLANE 5
|
||||
|
||||
//---------- LIGHTING -------------
|
||||
///Normal 1 per turf dynamic lighting underlays
|
||||
#define LIGHTING_PLANE 10
|
||||
|
||||
///Lighting objects that are "free floating"
|
||||
#define O_LIGHTING_VISUAL_PLANE 11
|
||||
#define O_LIGHTING_VISUAL_RENDER_TARGET "O_LIGHT_VISUAL_PLANE"
|
||||
|
||||
///Things that should render ignoring lighting
|
||||
#define ABOVE_LIGHTING_PLANE 12
|
||||
|
||||
/// This plane masks out lighting to create an "emissive" effect, ie for glowing lights in otherwise dark areas.
|
||||
#define EMISSIVE_PLANE 14
|
||||
|
||||
#define RENDER_PLANE_LIGHTING 15
|
||||
|
||||
///---------------- MISC -----------------------
|
||||
|
||||
///Pipecrawling images
|
||||
#define PIPECRAWL_IMAGES_PLANE 20
|
||||
|
||||
///AI Camera Static
|
||||
#define CAMERA_STATIC_PLANE 21
|
||||
|
||||
///Anything that wants to be part of the game plane, but also wants to draw above literally everything else
|
||||
#define HIGH_GAME_PLANE 22
|
||||
|
||||
#define FULLSCREEN_PLANE 23
|
||||
|
||||
///Visuals that represent sounds happening, and can be seen while blind.
|
||||
#define SOUND_EFFECT_VISUAL_PLANE 25
|
||||
|
||||
///--------------- FULLSCREEN RUNECHAT BUBBLES ------------
|
||||
|
||||
///Popup Chat Messages
|
||||
#define RUNECHAT_PLANE 30
|
||||
/// Plane for balloon text (text that fades up)
|
||||
#define BALLOON_CHAT_PLANE 31
|
||||
|
||||
//-------------------- HUD ---------------------
|
||||
//HUD layer defines
|
||||
#define HUD_PLANE 40
|
||||
#define ABOVE_HUD_PLANE 41
|
||||
|
||||
///Plane of the "splash" icon used that shows on the lobby screen. only render plate planes should be above this
|
||||
#define SPLASHSCREEN_PLANE 50
|
||||
|
||||
//-------------------- Rendering ---------------------
|
||||
#define RENDER_PLANE_GAME 100
|
||||
#define RENDER_PLANE_NON_GAME 101
|
||||
#define RENDER_PLANE_MASTER 102
|
||||
|
||||
// Lummox I swear to god I will find you
|
||||
// NOTE! You can only ever have planes greater then -10000, if you add too many with large offsets you will brick multiz
|
||||
// Same can be said for large multiz maps. Tread carefully mappers
|
||||
#define HIGHEST_EVER_PLANE RENDER_PLANE_MASTER
|
||||
/// The range unique planes can be in
|
||||
#define PLANE_RANGE (HIGHEST_EVER_PLANE - LOWEST_EVER_PLANE)
|
||||
|
||||
// PLANE_SPACE layer(s)
|
||||
#define SPACE_LAYER 1.8
|
||||
|
||||
//#define TURF_LAYER 2 //For easy recordkeeping; this is a byond define. Most floors (FLOOR_PLANE) and walls (GAME_PLANE) use this.
|
||||
#define OPENSPACE_LAYER 600 //Openspace layer over all turfs
|
||||
|
||||
// GAME_PLANE layers
|
||||
#define CULT_OVERLAY_LAYER 2.01
|
||||
@@ -60,7 +124,7 @@
|
||||
#define GAS_PUMP_LAYER 2.49
|
||||
#define PLUMBING_PIPE_VISIBILE_LAYER 2.495//layer = initial(layer) + ducting_layer / 3333 in atmospherics/handle_layer() to determine order of duct overlap
|
||||
#define LOW_OBJ_LAYER 2.5
|
||||
///catwalk overlay of /turf/open/floor/catwalk_floor
|
||||
///catwalk overlay of /turf/open/floor/plating/catwalk_floor
|
||||
#define CATWALK_LAYER 2.51
|
||||
#define LOW_SIGIL_LAYER 2.52
|
||||
#define SIGIL_LAYER 2.53
|
||||
@@ -122,81 +186,37 @@
|
||||
#define GASFIRE_LAYER 5.05
|
||||
#define RIPPLE_LAYER 5.1
|
||||
|
||||
#define OPENSPACE_LAYER 600 //Openspace layer over all
|
||||
|
||||
#define BLACKNESS_PLANE 0 //To keep from conflicts with SEE_BLACKNESS internals
|
||||
|
||||
#define AREA_PLANE 60
|
||||
#define MASSIVE_OBJ_PLANE 70
|
||||
#define GHOST_PLANE 80
|
||||
#define POINT_PLANE 90
|
||||
|
||||
//---------- LIGHTING -------------
|
||||
///Normal 1 per turf dynamic lighting underlays
|
||||
#define LIGHTING_PLANE 100
|
||||
|
||||
///Lighting objects that are "free floating"
|
||||
#define O_LIGHTING_VISUAL_PLANE 110
|
||||
#define O_LIGHTING_VISUAL_RENDER_TARGET "O_LIGHT_VISUAL_PLANE"
|
||||
|
||||
///Things that should render ignoring lighting
|
||||
#define ABOVE_LIGHTING_PLANE 120
|
||||
|
||||
#define LIGHTING_PRIMARY_LAYER 15 //The layer for the main lights of the station
|
||||
#define LIGHTING_PRIMARY_DIMMER_LAYER 15.1 //The layer that dims the main lights of the station
|
||||
#define LIGHTING_SECONDARY_LAYER 16 //The colourful, usually small lights that go on top
|
||||
|
||||
|
||||
///visibility + hiding of things outside of light source range
|
||||
#define BYOND_LIGHTING_PLANE 130
|
||||
|
||||
|
||||
//---------- EMISSIVES -------------
|
||||
//Layering order of these is not particularly meaningful.
|
||||
//Important part is the seperation of the planes for control via plane_master
|
||||
|
||||
/// This plane masks out lighting to create an "emissive" effect, ie for glowing lights in otherwise dark areas.
|
||||
#define EMISSIVE_PLANE 150
|
||||
/// The render target used by the emissive layer.
|
||||
#define EMISSIVE_RENDER_TARGET "*EMISSIVE_PLANE"
|
||||
/// The layer you should use if you _really_ don't want an emissive overlay to be blocked.
|
||||
#define EMISSIVE_LAYER_UNBLOCKABLE 9999
|
||||
|
||||
///---------------- MISC -----------------------
|
||||
|
||||
///Pipecrawling images
|
||||
#define PIPECRAWL_IMAGES_PLANE 180
|
||||
|
||||
///AI Camera Static
|
||||
#define CAMERA_STATIC_PLANE 200
|
||||
|
||||
///Debug Atmos Overlays
|
||||
#define ATMOS_GROUP_PLANE 450
|
||||
|
||||
///--------------- FULLSCREEN IMAGES ------------
|
||||
|
||||
#define FULLSCREEN_PLANE 500
|
||||
#define FLASH_LAYER 1
|
||||
#define FULLSCREEN_LAYER 2
|
||||
#define UI_DAMAGE_LAYER 3
|
||||
#define BLIND_LAYER 4
|
||||
#define CRIT_LAYER 5
|
||||
#define CURSE_LAYER 6
|
||||
#define FOV_EFFECTS_LAYER 10000 //Blindness effects are not layer 4, they lie to you
|
||||
|
||||
///--------------- FULLSCREEN RUNECHAT BUBBLES ------------
|
||||
|
||||
///Popup Chat Messages
|
||||
#define RUNECHAT_PLANE 501
|
||||
/// Plane for balloon text (text that fades up)
|
||||
#define BALLOON_CHAT_PLANE 502
|
||||
///--------------- SOUND EFFECT VISUALS ------------
|
||||
/// Bubble for typing indicators
|
||||
#define TYPING_LAYER 500
|
||||
|
||||
//-------------------- HUD ---------------------
|
||||
//HUD layer defines
|
||||
#define HUD_PLANE 1000
|
||||
#define ABOVE_HUD_PLANE 1100
|
||||
#define TYPING_LAYER 1
|
||||
#define FOV_EFFECTS_LAYER 2 //Blindness effects are not layer 4, they lie to you
|
||||
|
||||
#define RADIAL_BACKGROUND_LAYER 0
|
||||
///1000 is an unimportant number, it's just to normalize copied layers
|
||||
@@ -207,14 +227,6 @@
|
||||
///Layer for screentips
|
||||
#define SCREENTIP_LAYER 4
|
||||
|
||||
///Plane of the "splash" icon used that shows on the lobby screen. only render plate planes should be above this
|
||||
#define SPLASHSCREEN_PLANE 9900
|
||||
|
||||
//-------------------- Rendering ---------------------
|
||||
#define RENDER_PLANE_GAME 9990
|
||||
#define RENDER_PLANE_NON_GAME 9995
|
||||
#define RENDER_PLANE_MASTER 9999
|
||||
//----------------------------------------------------
|
||||
|
||||
#define LOBBY_BACKGROUND_LAYER 3
|
||||
#define LOBBY_BUTTON_LAYER 4
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
/// This shouldn't be higher than the icon size, and generally you shouldn't be changing this, but it's here just in case.
|
||||
#define MAX_GLIDE_SIZE 32
|
||||
|
||||
/// Compensating for time dialation
|
||||
/// Compensating for time dilation
|
||||
GLOBAL_VAR_INIT(glide_size_multiplier, 1.0)
|
||||
|
||||
///Broken down, here's what this does:
|
||||
|
||||
@@ -30,3 +30,30 @@
|
||||
#define VISOR_VISIONFLAGS (1<<2) //all following flags only matter for glasses
|
||||
#define VISOR_DARKNESSVIEW (1<<3)
|
||||
#define VISOR_INVISVIEW (1<<4)
|
||||
|
||||
// BYOND internal values for the sight flags
|
||||
// See [https://www.byond.com/docs/ref/#/mob/var/sight]
|
||||
/// can't see anything
|
||||
//#define BLIND (1<<0)
|
||||
/// can see all mobs, no matter what
|
||||
//#define SEE_MOBS (1<<2)
|
||||
/// can see all objs, no matter what
|
||||
//#define SEE_OBJS (1<<3)
|
||||
// can see all turfs (and areas), no matter what
|
||||
//#define SEE_TURFS (1<<4)
|
||||
/// can see self, no matter what
|
||||
//#define SEE_SELF (1<<5)
|
||||
/// can see infra-red objects (different sort of luminosity, essentially a copy of it, one we do not use)
|
||||
//#define SEE_INFRA (1<<6)
|
||||
/// if an object is located on an unlit area, but some of its pixels are
|
||||
/// in a lit area (via pixel_x,y or smooth movement), can see those pixels
|
||||
//#define SEE_PIXELS (1<<8)
|
||||
/// can see through opaque objects
|
||||
//#define SEE_THRU (1<<9)
|
||||
/// render dark tiles as blackness (Note, this basically means we draw dark tiles to plane 0)
|
||||
/// we can then hijack that plane with a plane master, and start drawing it anywhere we want
|
||||
//#define SEE_BLACKNESS (1<<10)
|
||||
|
||||
/// Bitfield of sight flags that show things "inside" the blackness plane
|
||||
/// We've gotta alpha it down if we get this, cause otherwise the sight flag won't work
|
||||
#define BLACKNESS_CUTTING (SEE_MOBS|SEE_OBJS|SEE_TURFS|SEE_TURFS|SEE_TURFS)
|
||||
|
||||
@@ -121,6 +121,7 @@
|
||||
#define VV_HK_DIRECT_CONTROL "direct_control"
|
||||
#define VV_HK_GIVE_DIRECT_CONTROL "give_direct_control"
|
||||
#define VV_HK_OFFER_GHOSTS "offer_ghosts"
|
||||
#define VV_HK_VIEW_PLANES "view_planes"
|
||||
|
||||
// /mob/living
|
||||
#define VV_HK_GIVE_SPEECH_IMPEDIMENT "impede_speech"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/// Creates a mutable appearance glued to the EMISSIVE_PLAN, using the values from a mutable appearance
|
||||
/proc/emissive_appearance_copy(mutable_appearance/to_use, appearance_flags = (RESET_COLOR|KEEP_APART))
|
||||
var/mutable_appearance/appearance = mutable_appearance(to_use.icon, to_use.icon_state, to_use.layer, EMISSIVE_PLANE, to_use.alpha, to_use.appearance_flags | appearance_flags)
|
||||
/proc/emissive_appearance_copy(mutable_appearance/to_use, atom/offset_spokesman, appearance_flags = (RESET_COLOR|KEEP_APART))
|
||||
var/mutable_appearance/appearance = mutable_appearance(to_use.icon, to_use.icon_state, to_use.layer, offset_spokesman, EMISSIVE_PLANE, to_use.alpha, to_use.appearance_flags | appearance_flags)
|
||||
appearance.color = GLOB.emissive_color
|
||||
appearance.pixel_x = to_use.pixel_x
|
||||
appearance.pixel_y = to_use.pixel_y
|
||||
|
||||
78
code/__HELPERS/_planes.dm
Normal file
78
code/__HELPERS/_planes.dm
Normal file
@@ -0,0 +1,78 @@
|
||||
// This file contains helper macros for plane operations
|
||||
// See the planes section of Visuals.md for more detail, but essentially
|
||||
// When we render multiz, we do it by placing all atoms on lower levels on well, lower planes
|
||||
// This is done with stacks of plane masters (things we use to apply effects to planes)
|
||||
// These macros exist to facilitate working with this system, and other associated small bits
|
||||
|
||||
/// Takes an atom to change the plane of, a new plane value, and something that can be used as a reference to a z level as input
|
||||
/// Modifies the new value to match the plane we actually want. Note, if you pass in an already offset plane the offsets will add up
|
||||
/// Use PLANE_TO_TRUE() to avoid this
|
||||
#define SET_PLANE(thing, new_value, z_reference) (thing.plane = MUTATE_PLANE(new_value, z_reference))
|
||||
|
||||
/// Takes a plane and a z reference, and offsets the plane by the mutation
|
||||
/// The SSmapping.max_plane_offset bit here is technically redundant, but saves a bit of work in the base case
|
||||
/// And the base case is important to me. Non multiz shouldn't get hit too bad by this code
|
||||
#define MUTATE_PLANE(new_value, z_reference) ((SSmapping.max_plane_offset) ? GET_NEW_PLANE(new_value, GET_TURF_PLANE_OFFSET(z_reference)) : (new_value))
|
||||
|
||||
/// Takes a z reference that we are unsure of, sanity checks it
|
||||
/// Returns either its offset, or 0 if it's not a valid ref
|
||||
#define GET_TURF_PLANE_OFFSET(z_reference) ((SSmapping.max_plane_offset && isatom(z_reference)) ? GET_Z_PLANE_OFFSET(z_reference.z) : 0)
|
||||
/// Essentially just an unsafe version of GET_TURF_PLANE_OFFSET()
|
||||
/// Takes a z value we returns its offset with a list lookup
|
||||
/// Will runtime during parts of init. Be careful :)
|
||||
#define GET_Z_PLANE_OFFSET(z) (SSmapping.z_level_to_plane_offset[z])
|
||||
|
||||
/// Takes a plane to offset, and the multiplier to use, and well, does the offsetting
|
||||
/// Respects a blacklist we use to remove redundant plane masters, such as hud objects
|
||||
#define GET_NEW_PLANE(new_value, multiplier) (SSmapping.plane_offset_blacklist?["[new_value]"] ? new_value : (new_value) - (PLANE_RANGE * (multiplier)))
|
||||
|
||||
// Now for the more niche things
|
||||
|
||||
/// Takes an object, new plane, and multipler, and offsets the plane
|
||||
/// This is for cases where you have a multipler precalculated, and just want to use it
|
||||
/// Often an optimization, sometimes a necessity
|
||||
#define SET_PLANE_W_SCALAR(thing, new_value, multiplier) (thing.plane = GET_NEW_PLANE(new_value, multiplier))
|
||||
|
||||
|
||||
/// Implicit plane set. We take the turf from the object we're changing the plane of, and use ITS z as a spokesperson for our plane value
|
||||
#define SET_PLANE_IMPLICIT(thing, new_value) SET_PLANE_EXPLICIT(thing, new_value, thing)
|
||||
|
||||
// This is an unrolled and optimized version of SET_PLANE, for use anywhere where you are unsure of a source's "turfness"
|
||||
// The plane is cached to allow for fancy stuff to be eval'd once, rather then often
|
||||
#define SET_PLANE_EXPLICIT(thing, new_value, source) \
|
||||
do {\
|
||||
if(SSmapping.max_plane_offset) {\
|
||||
var/_cached_plane = new_value;\
|
||||
var/turf/_our_turf = get_turf(source);\
|
||||
if(_our_turf){\
|
||||
thing.plane = GET_NEW_PLANE(_cached_plane, GET_Z_PLANE_OFFSET(_our_turf.z));\
|
||||
}\
|
||||
}\
|
||||
else {\
|
||||
thing.plane = new_value;\
|
||||
}\
|
||||
}\
|
||||
while (FALSE)
|
||||
|
||||
// Now for macros that exist to get info from SSmapping
|
||||
// Mostly about details of planes, or z levels
|
||||
|
||||
/// Takes a z level, gets the lowest plane offset in its "stack"
|
||||
#define GET_LOWEST_STACK_OFFSET(z) ((SSmapping.max_plane_offset) ? SSmapping.z_level_to_lowest_plane_offset[z] : 0)
|
||||
/// Takes a plane, returns the canonical, unoffset plane it represents
|
||||
#define PLANE_TO_TRUE(plane) ((SSmapping.plane_offset_to_true) ? SSmapping.plane_offset_to_true["[plane]"] : plane)
|
||||
/// Takes a plane, returns the offset it uses
|
||||
#define PLANE_TO_OFFSET(plane) ((SSmapping.plane_to_offset) ? SSmapping.plane_to_offset["[plane]"] : plane)
|
||||
/// Takes a true plane, returns the offset planes that would canonically represent it
|
||||
#define TRUE_PLANE_TO_OFFSETS(plane) ((SSmapping.true_to_offset_planes) ? SSmapping.true_to_offset_planes["[plane]"] : list(plane))
|
||||
/// Takes a render target and an offset, returns a canonical render target string for it
|
||||
#define OFFSET_RENDER_TARGET(render_target, offset) (_OFFSET_RENDER_TARGET(render_target, SSmapping.render_offset_blacklist?["[render_target]"] ? 0 : offset))
|
||||
/// Helper macro for the above
|
||||
/// Honestly just exists to make the pattern of render target strings more readable
|
||||
#define _OFFSET_RENDER_TARGET(render_target, offset) ("[(render_target)] #[(offset)]")
|
||||
|
||||
// Known issues:
|
||||
// Potentially too much client load? Hard to tell due to not having a potato pc to hand.
|
||||
// This is solvable with lowspec preferences, which would not be hard to implement
|
||||
// Player popups will now render their effects, like overlay lights. this is fixable, but I've not gotten to it
|
||||
// I think overlay lights can render on the wrong z layer. s fucked
|
||||
@@ -379,7 +379,7 @@ DEFINE_BITFIELD(smoothing_junction, list(
|
||||
var/junction_dir = reverse_ndir(smoothing_junction)
|
||||
var/turned_adjacency = REVERSE_DIR(junction_dir)
|
||||
var/turf/neighbor_turf = get_step(src, turned_adjacency & (NORTH|SOUTH))
|
||||
var/mutable_appearance/underlay_appearance = mutable_appearance(layer = TURF_LAYER, plane = FLOOR_PLANE)
|
||||
var/mutable_appearance/underlay_appearance = mutable_appearance(layer = TURF_LAYER, offset_spokesman = src, plane = FLOOR_PLANE)
|
||||
if(!neighbor_turf.get_smooth_underlay_icon(underlay_appearance, src, turned_adjacency))
|
||||
neighbor_turf = get_step(src, turned_adjacency & (EAST|WEST))
|
||||
|
||||
|
||||
@@ -1312,9 +1312,8 @@ GLOBAL_LIST_EMPTY(transformation_animation_objects)
|
||||
* result_appearance - End result appearance/atom/image
|
||||
* time - Animation duration
|
||||
* transform_overlay - Appearance/atom/image of effect that moves along the animation - should be horizonatally centered
|
||||
* reset_after - If FALSE, filters won't be reset and helper vis_objects will not be removed after animation duration expires. Cleanup must be handled by the caller!
|
||||
*/
|
||||
/atom/movable/proc/transformation_animation(result_appearance,time = 3 SECONDS,transform_overlay,reset_after=TRUE)
|
||||
/atom/movable/proc/transformation_animation(result_appearance,time = 3 SECONDS,transform_overlay)
|
||||
var/list/transformation_objects = GLOB.transformation_animation_objects[src] || list()
|
||||
//Disappearing part
|
||||
var/top_part_filter = filter(type="alpha",icon=icon('icons/effects/alphacolors.dmi',"white"),y=0)
|
||||
@@ -1343,8 +1342,7 @@ GLOBAL_LIST_EMPTY(transformation_animation_objects)
|
||||
GLOB.transformation_animation_objects[src] = transformation_objects
|
||||
for(var/A in transformation_objects)
|
||||
vis_contents += A
|
||||
if(reset_after)
|
||||
addtimer(CALLBACK(src,.proc/_reset_transformation_animation,filter_index),time)
|
||||
addtimer(CALLBACK(src,.proc/_reset_transformation_animation,filter_index),time)
|
||||
|
||||
/*
|
||||
* Resets filters and removes transformation animations helper objects from vis contents.
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
/// Produces a mutable appearance glued to the [EMISSIVE_PLANE] dyed to be the [EMISSIVE_COLOR].
|
||||
/proc/emissive_appearance(icon, icon_state = "", layer = FLOAT_LAYER, alpha = 255, appearance_flags = NONE)
|
||||
var/mutable_appearance/appearance = mutable_appearance(icon, icon_state, layer, EMISSIVE_PLANE, alpha, appearance_flags | EMISSIVE_APPEARANCE_FLAGS)
|
||||
/proc/emissive_appearance(icon, icon_state = "", atom/offset_spokesman, layer = FLOAT_LAYER, alpha = 255, appearance_flags = NONE, offset_const)
|
||||
var/mutable_appearance/appearance = mutable_appearance(icon, icon_state, layer, offset_spokesman, EMISSIVE_PLANE, alpha, appearance_flags | EMISSIVE_APPEARANCE_FLAGS, offset_const)
|
||||
appearance.color = GLOB.emissive_color
|
||||
return appearance
|
||||
|
||||
/// Produces a mutable appearance glued to the [EMISSIVE_PLANE] dyed to be the [EM_BLOCK_COLOR].
|
||||
/proc/emissive_blocker(icon, icon_state = "", layer = FLOAT_LAYER, alpha = 255, appearance_flags = NONE)
|
||||
/proc/emissive_blocker(icon, icon_state = "", atom/offset_spokesman, layer = FLOAT_LAYER, alpha = 255, appearance_flags = NONE, offset_const)
|
||||
// Note: alpha doesn't "do" anything, since it's overriden by the color set shortly after
|
||||
// Consider removing it someday?
|
||||
var/mutable_appearance/appearance = mutable_appearance(icon, icon_state, layer, EMISSIVE_PLANE, alpha, appearance_flags | EMISSIVE_APPEARANCE_FLAGS)
|
||||
var/mutable_appearance/appearance = mutable_appearance(icon, icon_state, layer, offset_spokesman, EMISSIVE_PLANE, alpha, appearance_flags | EMISSIVE_APPEARANCE_FLAGS, offset_const)
|
||||
appearance.color = GLOB.em_block_color
|
||||
return appearance
|
||||
|
||||
|
||||
@@ -891,7 +891,7 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
|
||||
|
||||
GLOB.dview_mob.loc = center
|
||||
|
||||
GLOB.dview_mob.see_invisible = invis_flags
|
||||
GLOB.dview_mob.set_invis_see(invis_flags)
|
||||
|
||||
. = view(range, GLOB.dview_mob)
|
||||
GLOB.dview_mob.loc = null
|
||||
@@ -925,7 +925,7 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
|
||||
|
||||
#define FOR_DVIEW(type, range, center, invis_flags) \
|
||||
GLOB.dview_mob.loc = center; \
|
||||
GLOB.dview_mob.see_invisible = invis_flags; \
|
||||
GLOB.dview_mob.set_invis_see(invis_flags); \
|
||||
for(type in view(range, GLOB.dview_mob))
|
||||
|
||||
#define FOR_DVIEW_END GLOB.dview_mob.loc = null
|
||||
|
||||
@@ -530,6 +530,16 @@
|
||||
M.Scale(px/sx, py/sy)
|
||||
transform = M
|
||||
|
||||
/atom/movable/screen/click_catcher/Initialize(mapload)
|
||||
. = ..()
|
||||
RegisterSignal(SSmapping, COMSIG_PLANE_OFFSET_INCREASE, .proc/offset_increased)
|
||||
offset_increased(SSmapping, 0, SSmapping.max_plane_offset)
|
||||
|
||||
// Draw to the lowest plane level offered
|
||||
/atom/movable/screen/click_catcher/proc/offset_increased(datum/source, old_offset, new_offset)
|
||||
SIGNAL_HANDLER
|
||||
SET_PLANE_W_SCALAR(src, initial(plane), new_offset)
|
||||
|
||||
/atom/movable/screen/click_catcher/Click(location, control, params)
|
||||
var/list/modifiers = params2list(params)
|
||||
if(LAZYACCESS(modifiers, MIDDLE_CLICK) && iscarbon(usr))
|
||||
|
||||
@@ -163,7 +163,7 @@
|
||||
blobpwrdisplay.icon_state = "block"
|
||||
blobpwrdisplay.screen_loc = ui_health
|
||||
blobpwrdisplay.mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
blobpwrdisplay.plane = ABOVE_HUD_PLANE
|
||||
SET_PLANE_EXPLICIT(blobpwrdisplay, ABOVE_HUD_PLANE, owner)
|
||||
blobpwrdisplay.hud = src
|
||||
infodisplay += blobpwrdisplay
|
||||
|
||||
|
||||
@@ -56,6 +56,19 @@
|
||||
else
|
||||
client.screen -= screen
|
||||
|
||||
/mob/on_changed_z_level(turf/old_turf, turf/new_turf, same_z_layer, notify_contents)
|
||||
. = ..()
|
||||
if(!same_z_layer)
|
||||
relayer_fullscreens()
|
||||
|
||||
/mob/proc/relayer_fullscreens()
|
||||
var/turf/our_lad = get_turf(src)
|
||||
var/offset = GET_TURF_PLANE_OFFSET(our_lad)
|
||||
var/atom/movable/screen/fullscreen/screen
|
||||
for(var/category in screens)
|
||||
screen = screens[category]
|
||||
screen.plane = GET_NEW_PLANE(initial(screen.plane), offset)
|
||||
|
||||
/atom/movable/screen/fullscreen
|
||||
icon = 'icons/hud/screen_full.dmi'
|
||||
icon_state = "default"
|
||||
|
||||
@@ -70,10 +70,18 @@ GLOBAL_LIST_INIT(available_erp_ui_styles, list(
|
||||
var/list/screenoverlays = list() //the screen objects used as whole screen overlays (flash, damageoverlay, etc...)
|
||||
var/list/inv_slots[SLOTS_AMT] // /atom/movable/screen/inventory objects, ordered by their slot ID.
|
||||
var/list/hand_slots // /atom/movable/screen/inventory/hand objects, assoc list of "[held_index]" = object
|
||||
var/list/atom/movable/screen/plane_master/plane_masters = list() // see "appearance_flags" in the ref, assoc list of "[plane]" = object
|
||||
|
||||
/// Assoc list of key => "plane master groups"
|
||||
/// This is normally just the main window, but it'll occasionally contain things like spyglasses windows
|
||||
var/list/datum/plane_master_group/master_groups = list()
|
||||
///Assoc list of controller groups, associated with key string group name with value of the plane master controller ref
|
||||
var/list/atom/movable/plane_master_controller/plane_master_controllers = list()
|
||||
|
||||
/// Think of multiz as a stack of z levels. Each index in that stack has its own group of plane masters
|
||||
/// This variable is the plane offset our mob/client is currently "on"
|
||||
/// We use it to track what we should show/not show
|
||||
/// Goes from 0 to the max (z level stack size - 1)
|
||||
var/current_plane_offset = 0
|
||||
|
||||
///UI for screentips that appear when you mouse over things
|
||||
var/atom/movable/screen/screentip/screentip_text
|
||||
@@ -83,6 +91,8 @@ GLOBAL_LIST_INIT(available_erp_ui_styles, list(
|
||||
/// had with a proc call, especially on one of the hottest procs in the
|
||||
/// game (MouseEntered).
|
||||
var/screentips_enabled = SCREENTIP_PREFERENCE_ENABLED
|
||||
/// If this client is being shown atmos debug overlays or not
|
||||
var/atmos_debug_overlays = FALSE
|
||||
|
||||
/// The color to use for the screentips.
|
||||
/// This is updated by the preference for cheaper reads than would be
|
||||
@@ -123,10 +133,8 @@ GLOBAL_LIST_INIT(available_erp_ui_styles, list(
|
||||
|
||||
hand_slots = list()
|
||||
|
||||
for(var/mytype in subtypesof(/atom/movable/screen/plane_master)- /atom/movable/screen/plane_master/rendering_plate)
|
||||
var/atom/movable/screen/plane_master/instance = new mytype()
|
||||
plane_masters["[instance.plane]"] = instance
|
||||
instance.backdrop(mymob)
|
||||
var/datum/plane_master_group/main/main_group = new(PLANE_GROUP_MAIN)
|
||||
main_group.attach_to(src)
|
||||
|
||||
var/datum/preferences/preferences = owner?.client?.prefs
|
||||
screentip_color = preferences?.read_preference(/datum/preference/color/screentip_color)
|
||||
@@ -141,6 +149,59 @@ GLOBAL_LIST_INIT(available_erp_ui_styles, list(
|
||||
owner.overlay_fullscreen("see_through_darkness", /atom/movable/screen/fullscreen/see_through_darkness)
|
||||
|
||||
AddComponent(/datum/component/zparallax, owner.client)
|
||||
RegisterSignal(SSmapping, COMSIG_PLANE_OFFSET_INCREASE, .proc/on_plane_increase)
|
||||
RegisterSignal(mymob, COMSIG_MOB_LOGIN, .proc/client_refresh)
|
||||
RegisterSignal(mymob, COMSIG_MOB_LOGOUT, .proc/clear_client)
|
||||
RegisterSignal(mymob, COMSIG_MOB_SIGHT_CHANGE, .proc/update_sightflags)
|
||||
update_sightflags(mymob, mymob.sight, NONE)
|
||||
|
||||
/datum/hud/proc/client_refresh(datum/source)
|
||||
RegisterSignal(mymob.client, COMSIG_CLIENT_SET_EYE, .proc/on_eye_change)
|
||||
on_eye_change(null, null, mymob.client.eye)
|
||||
|
||||
/datum/hud/proc/clear_client(datum/source)
|
||||
if(mymob.canon_client)
|
||||
UnregisterSignal(mymob.canon_client, COMSIG_CLIENT_SET_EYE)
|
||||
|
||||
/datum/hud/proc/on_eye_change(datum/source, atom/old_eye, atom/new_eye)
|
||||
SIGNAL_HANDLER
|
||||
if(old_eye)
|
||||
UnregisterSignal(old_eye, COMSIG_MOVABLE_Z_CHANGED)
|
||||
if(new_eye)
|
||||
// By the time logout runs, the client's eye has already changed
|
||||
// There's just no log of the old eye, so we need to override
|
||||
// :sadkirby:
|
||||
RegisterSignal(new_eye, COMSIG_MOVABLE_Z_CHANGED, .proc/eye_z_changed, override = TRUE)
|
||||
eye_z_changed(new_eye)
|
||||
|
||||
/datum/hud/proc/update_sightflags(datum/source, new_sight, old_sight)
|
||||
// If neither the old and new flags can see turfs but not objects, don't transform the turfs
|
||||
// This is to ensure parallax works when you can't see holder objects
|
||||
if(should_sight_scale(new_sight) == should_sight_scale(old_sight))
|
||||
return
|
||||
|
||||
var/datum/plane_master_group/group = get_plane_group(PLANE_GROUP_MAIN)
|
||||
group.transform_lower_turfs(src, current_plane_offset)
|
||||
|
||||
/datum/hud/proc/should_use_scale()
|
||||
return should_sight_scale(mymob.sight)
|
||||
|
||||
/datum/hud/proc/should_sight_scale(sight_flags)
|
||||
return (sight_flags & (SEE_TURFS | SEE_OBJS)) != SEE_TURFS
|
||||
|
||||
/datum/hud/proc/eye_z_changed(atom/eye)
|
||||
SIGNAL_HANDLER
|
||||
var/turf/eye_turf = get_turf(eye)
|
||||
var/new_offset = GET_TURF_PLANE_OFFSET(eye_turf)
|
||||
if(current_plane_offset == new_offset)
|
||||
return
|
||||
var/old_offset = current_plane_offset
|
||||
current_plane_offset = new_offset
|
||||
|
||||
SEND_SIGNAL(src, COMSIG_HUD_OFFSET_CHANGED, old_offset, new_offset)
|
||||
var/datum/plane_master_group/group = get_plane_group(PLANE_GROUP_MAIN)
|
||||
if(group && should_use_scale())
|
||||
group.transform_lower_turfs(src, new_offset)
|
||||
|
||||
/datum/hud/Destroy()
|
||||
if(mymob.hud_used == src)
|
||||
@@ -182,7 +243,7 @@ GLOBAL_LIST_INIT(available_erp_ui_styles, list(
|
||||
wanted_lvl = null
|
||||
// SKYRAT EDIT END - SKYRAT HUD
|
||||
|
||||
QDEL_LIST_ASSOC_VAL(plane_masters)
|
||||
QDEL_LIST_ASSOC_VAL(master_groups)
|
||||
QDEL_LIST_ASSOC_VAL(plane_master_controllers)
|
||||
QDEL_LIST(screenoverlays)
|
||||
mymob = null
|
||||
@@ -191,6 +252,38 @@ GLOBAL_LIST_INIT(available_erp_ui_styles, list(
|
||||
|
||||
return ..()
|
||||
|
||||
/datum/hud/proc/on_plane_increase(datum/source, old_max_offset, new_max_offset)
|
||||
SIGNAL_HANDLER
|
||||
build_plane_groups(old_max_offset + 1, new_max_offset)
|
||||
|
||||
/// Creates the required plane masters to fill out new z layers (because each "level" of multiz gets its own plane master set)
|
||||
/datum/hud/proc/build_plane_groups(starting_offset, ending_offset)
|
||||
for(var/group_key in master_groups)
|
||||
var/datum/plane_master_group/group = master_groups[group_key]
|
||||
group.build_plane_masters(starting_offset, ending_offset)
|
||||
|
||||
/// Returns the plane master that matches the input plane from the passed in group
|
||||
/datum/hud/proc/get_plane_master(plane, group_key = PLANE_GROUP_MAIN)
|
||||
var/plane_key = "[plane]"
|
||||
var/datum/plane_master_group/group = master_groups[group_key]
|
||||
return group.plane_masters[plane_key]
|
||||
|
||||
/// Returns a list of all plane masters that match the input true plane, drawn from the passed in group (ignores z layer offsets)
|
||||
/datum/hud/proc/get_true_plane_masters(true_plane, group_key = PLANE_GROUP_MAIN)
|
||||
var/list/atom/movable/screen/plane_master/masters = list()
|
||||
for(var/plane in TRUE_PLANE_TO_OFFSETS(true_plane))
|
||||
masters += get_plane_master(plane, group_key)
|
||||
return masters
|
||||
|
||||
/// Returns all the planes belonging to the passed in group key
|
||||
/datum/hud/proc/get_planes_from(group_key)
|
||||
var/datum/plane_master_group/group = master_groups[group_key]
|
||||
return group.plane_masters
|
||||
|
||||
/// Returns the corresponding plane group datum if one exists
|
||||
/datum/hud/proc/get_plane_group(key)
|
||||
return master_groups[key]
|
||||
|
||||
/mob/proc/create_mob_hud()
|
||||
if(!client || hud_used)
|
||||
return
|
||||
@@ -296,14 +389,14 @@ GLOBAL_LIST_INIT(available_erp_ui_styles, list(
|
||||
else if (viewmob.hud_used)
|
||||
viewmob.hud_used.plane_masters_update()
|
||||
|
||||
SEND_SIGNAL(screenmob, COMSIG_MOB_HUD_REFRESHED, src)
|
||||
return TRUE
|
||||
|
||||
/datum/hud/proc/plane_masters_update()
|
||||
// Plane masters are always shown to OUR mob, never to observers
|
||||
for(var/thing in plane_masters)
|
||||
var/atom/movable/screen/plane_master/PM = plane_masters[thing]
|
||||
PM.backdrop(mymob)
|
||||
mymob.client.screen += PM
|
||||
for(var/group_key in master_groups)
|
||||
var/datum/plane_master_group/group = master_groups[group_key]
|
||||
// Plane masters are always shown to OUR mob, never to observers
|
||||
group.refresh_hud()
|
||||
|
||||
/datum/hud/human/show_hud(version = 0,mob/viewmob)
|
||||
. = ..()
|
||||
|
||||
@@ -1,12 +1,3 @@
|
||||
/**
|
||||
* A screen object, which acts as a container for turfs and other things
|
||||
* you want to show on the map, which you usually attach to "vis_contents".
|
||||
*/
|
||||
/atom/movable/screen/map_view
|
||||
// Map view has to be on the lowest plane to enable proper lighting
|
||||
layer = GAME_PLANE
|
||||
plane = GAME_PLANE
|
||||
|
||||
/**
|
||||
* A generic background object.
|
||||
* It is also implicitly used to allocate a rectangle on the map, which will
|
||||
@@ -84,9 +75,10 @@
|
||||
*
|
||||
* Returns a map name.
|
||||
*/
|
||||
/client/proc/create_popup(name, ratiox = 100, ratioy = 100)
|
||||
/client/proc/create_popup(name, title, ratiox = 100, ratioy = 100)
|
||||
winclone(src, "popupwindow", name)
|
||||
var/list/winparams = list()
|
||||
winparams["title"] = title
|
||||
winparams["size"] = "[ratiox]x[ratioy]"
|
||||
winparams["on-close"] = "handle-popup-close [name]"
|
||||
winset(src, "[name]", list2params(winparams))
|
||||
@@ -109,13 +101,13 @@
|
||||
* Width and height are multiplied by 64 by default.
|
||||
*/
|
||||
/client/proc/setup_popup(popup_name, width = 9, height = 9, \
|
||||
tilesize = 2, bg_icon)
|
||||
tilesize = 2, title, bg_icon)
|
||||
if(!popup_name)
|
||||
return
|
||||
clear_map("[popup_name]_map")
|
||||
var/x_value = world.icon_size * tilesize * width
|
||||
var/y_value = world.icon_size * tilesize * height
|
||||
var/map_name = create_popup(popup_name, x_value, y_value)
|
||||
var/map_name = create_popup(popup_name, title, x_value, y_value)
|
||||
|
||||
var/atom/movable/screen/background/background = new
|
||||
background.assigned_map = map_name
|
||||
@@ -139,3 +131,4 @@
|
||||
/client/verb/handle_popup_close(window_id as text)
|
||||
set hidden = TRUE
|
||||
clear_map("[window_id]_map")
|
||||
SEND_SIGNAL(src, COMSIG_POPUP_CLEARED, window_id)
|
||||
|
||||
69
code/_onclick/hud/map_view.dm
Normal file
69
code/_onclick/hud/map_view.dm
Normal file
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* A screen object, which acts as a container for turfs and other things
|
||||
* you want to show on the map, which you usually attach to "vis_contents".
|
||||
* Additionally manages the plane masters required to display said container contents
|
||||
*/
|
||||
INITIALIZE_IMMEDIATE(/atom/movable/screen/map_view)
|
||||
/atom/movable/screen/map_view
|
||||
name = "screen"
|
||||
// Map view has to be on the lowest plane to enable proper lighting
|
||||
layer = GAME_PLANE
|
||||
plane = GAME_PLANE
|
||||
del_on_map_removal = FALSE
|
||||
|
||||
// Weakrefs of all our hud viewers -> a weakref to the hud datum they last used
|
||||
var/list/datum/weakref/viewers_to_huds = list()
|
||||
|
||||
/atom/movable/screen/map_view/Destroy()
|
||||
for(var/datum/weakref/client_ref in viewers_to_huds)
|
||||
var/client/our_client = client_ref.resolve()
|
||||
if(!our_client)
|
||||
continue
|
||||
hide_from(our_client.mob)
|
||||
|
||||
return ..()
|
||||
|
||||
/atom/movable/screen/map_view/proc/generate_view(map_key)
|
||||
// Map keys have to start and end with an A-Z character,
|
||||
// and definitely NOT with a square bracket or even a number.
|
||||
// I wasted 6 hours on this. :agony:
|
||||
// -- Stylemistake
|
||||
assigned_map = map_key
|
||||
set_position(1, 1)
|
||||
|
||||
/atom/movable/screen/map_view/proc/display_to(mob/show_to)
|
||||
show_to.client.register_map_obj(src)
|
||||
// We need to add planesmasters to the popup, otherwise
|
||||
// blending fucks up massively. Any planesmaster on the main screen does
|
||||
// NOT apply to map popups. If there's ever a way to make planesmasters
|
||||
// omnipresent, then this wouldn't be needed.
|
||||
// We lazy load this because there's no point creating all these if none's gonna see em
|
||||
|
||||
// Store this info in a client -> hud pattern, so ghosts closing the window nukes the right group
|
||||
var/datum/weakref/client_ref = WEAKREF(show_to.client)
|
||||
|
||||
var/datum/weakref/hud_ref = viewers_to_huds[client_ref]
|
||||
var/datum/hud/our_hud = hud_ref?.resolve()
|
||||
if(our_hud)
|
||||
return our_hud.get_plane_group(PLANE_GROUP_POPUP_WINDOW(src))
|
||||
|
||||
// Generate a new plane group for this case
|
||||
var/datum/plane_master_group/popup/pop_planes = new(PLANE_GROUP_POPUP_WINDOW(src), assigned_map)
|
||||
viewers_to_huds[client_ref] = WEAKREF(show_to.hud_used)
|
||||
pop_planes.attach_to(show_to.hud_used)
|
||||
|
||||
return pop_planes
|
||||
|
||||
/atom/movable/screen/map_view/proc/hide_from(mob/hide_from)
|
||||
hide_from?.canon_client.clear_map(assigned_map)
|
||||
var/client_ref = WEAKREF(hide_from?.canon_client)
|
||||
|
||||
// Make sure we clear the *right* hud
|
||||
var/datum/weakref/hud_ref = viewers_to_huds[client_ref]
|
||||
viewers_to_huds -= client_ref
|
||||
var/datum/hud/clear_from = hud_ref?.resolve()
|
||||
if(!clear_from)
|
||||
return
|
||||
|
||||
var/datum/plane_master_group/popup/pop_planes = clear_from.get_plane_group(PLANE_GROUP_POPUP_WINDOW(src))
|
||||
qdel(pop_planes)
|
||||
@@ -20,28 +20,30 @@
|
||||
C.parallax_layers.len = C.parallax_layers_max
|
||||
|
||||
C.screen |= (C.parallax_layers)
|
||||
var/atom/movable/screen/plane_master/PM = screenmob.hud_used.plane_masters["[PLANE_SPACE]"]
|
||||
if(screenmob != mymob)
|
||||
C.screen -= locate(/atom/movable/screen/plane_master/parallax_white) in C.screen
|
||||
C.screen += PM
|
||||
PM.color = list(
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
1, 1, 1, 1,
|
||||
0, 0, 0, 0
|
||||
)
|
||||
|
||||
// We could do not do parallax for anything except the main plane group
|
||||
// This could be changed, but it would require refactoring this whole thing
|
||||
// And adding non client particular hooks for all the inputs, and I do not have the time I'm sorry :(
|
||||
for(var/atom/movable/screen/plane_master/plane_master in screenmob.hud_used.get_true_plane_masters(PLANE_SPACE))
|
||||
if(screenmob != mymob)
|
||||
C.screen -= locate(/atom/movable/screen/plane_master/parallax_white) in C.screen
|
||||
C.screen += plane_master
|
||||
plane_master.color = list(
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
1, 1, 1, 1,
|
||||
0, 0, 0, 0
|
||||
)
|
||||
|
||||
/datum/hud/proc/remove_parallax(mob/viewmob)
|
||||
var/mob/screenmob = viewmob || mymob
|
||||
var/client/C = screenmob.client
|
||||
C.screen -= (C.parallax_layers_cached)
|
||||
var/atom/movable/screen/plane_master/PM = screenmob.hud_used.plane_masters["[PLANE_SPACE]"]
|
||||
if(screenmob != mymob)
|
||||
C.screen -= locate(/atom/movable/screen/plane_master/parallax_white) in C.screen
|
||||
C.screen += PM
|
||||
PM.color = initial(PM.color)
|
||||
for(var/atom/movable/screen/plane_master/plane_master in screenmob.hud_used.get_true_plane_masters(PLANE_SPACE))
|
||||
if(screenmob != mymob)
|
||||
C.screen -= locate(/atom/movable/screen/plane_master/parallax_white) in C.screen
|
||||
C.screen += plane_master
|
||||
plane_master.color = initial(plane_master.color)
|
||||
C.parallax_layers = null
|
||||
|
||||
/datum/hud/proc/apply_parallax_pref(mob/viewmob)
|
||||
@@ -247,7 +249,6 @@ INITIALIZE_IMMEDIATE(/atom/movable/screen/parallax_layer)
|
||||
var/speed = 1
|
||||
var/offset_x = 0
|
||||
var/offset_y = 0
|
||||
var/view_sized
|
||||
var/absolute = FALSE
|
||||
blend_mode = BLEND_ADD
|
||||
plane = PLANE_SPACE_PARALLAX
|
||||
@@ -289,7 +290,6 @@ INITIALIZE_IMMEDIATE(/atom/movable/screen/parallax_layer)
|
||||
new_overlays += texture_overlay
|
||||
cut_overlays()
|
||||
add_overlay(new_overlays)
|
||||
view_sized = view
|
||||
|
||||
/atom/movable/screen/parallax_layer/layer_1
|
||||
icon_state = "layer1"
|
||||
|
||||
@@ -16,6 +16,12 @@
|
||||
/atom/movable/screen/movable/pic_in_pic/Initialize(mapload)
|
||||
. = ..()
|
||||
make_backgrounds()
|
||||
RegisterSignal(SSmapping, COMSIG_PLANE_OFFSET_INCREASE, .proc/multiz_offset_increase)
|
||||
multiz_offset_increase(SSmapping)
|
||||
|
||||
/atom/movable/screen/movable/pic_in_pic/proc/multiz_offset_increase(datum/source)
|
||||
SIGNAL_HANDLER
|
||||
SET_PLANE_W_SCALAR(src, initial(plane), SSmapping.max_plane_offset)
|
||||
|
||||
/atom/movable/screen/movable/pic_in_pic/Destroy()
|
||||
for(var/C in shown_to)
|
||||
|
||||
@@ -6,6 +6,7 @@ GLOBAL_LIST_EMPTY(radial_menus)
|
||||
/atom/movable/screen/radial
|
||||
icon = 'icons/hud/radial.dmi'
|
||||
plane = ABOVE_HUD_PLANE
|
||||
vis_flags = VIS_INHERIT_PLANE
|
||||
var/datum/radial_menu/parent
|
||||
|
||||
/atom/movable/screen/radial/proc/set_parent(new_value)
|
||||
@@ -251,7 +252,7 @@ GLOBAL_LIST_EMPTY(radial_menus)
|
||||
E.add_overlay(choices_icons[choice_id])
|
||||
if (choice_datum?.info)
|
||||
var/obj/effect/abstract/info/info_button = new(E, choice_datum.info)
|
||||
info_button.plane = ABOVE_HUD_PLANE
|
||||
SET_PLANE_EXPLICIT(info_button, ABOVE_HUD_PLANE, anchor)
|
||||
info_button.layer = RADIAL_CONTENT_LAYER
|
||||
E.vis_contents += info_button
|
||||
|
||||
@@ -295,7 +296,7 @@ GLOBAL_LIST_EMPTY(radial_menus)
|
||||
|
||||
var/mutable_appearance/MA = new /mutable_appearance(to_extract_from)
|
||||
if(MA)
|
||||
MA.plane = ABOVE_HUD_PLANE
|
||||
SET_PLANE_EXPLICIT(MA, ABOVE_HUD_PLANE, anchor)
|
||||
MA.layer = RADIAL_CONTENT_LAYER
|
||||
MA.appearance_flags |= RESET_TRANSFORM
|
||||
return MA
|
||||
@@ -314,7 +315,7 @@ GLOBAL_LIST_EMPTY(radial_menus)
|
||||
current_user = M.client
|
||||
//Blank
|
||||
menu_holder = image(icon='icons/effects/effects.dmi',loc=anchor,icon_state="nothing", layer = RADIAL_BACKGROUND_LAYER)
|
||||
menu_holder.plane = ABOVE_HUD_PLANE
|
||||
SET_PLANE_EXPLICIT(menu_holder, ABOVE_HUD_PLANE, M)
|
||||
menu_holder.appearance_flags |= KEEP_APART|RESET_ALPHA|RESET_COLOR|RESET_TRANSFORM
|
||||
menu_holder.vis_contents += elements + close_button
|
||||
current_user.images += menu_holder
|
||||
|
||||
@@ -1,218 +1,460 @@
|
||||
// I hate this place
|
||||
INITIALIZE_IMMEDIATE(/atom/movable/screen/plane_master)
|
||||
/atom/movable/screen/plane_master
|
||||
screen_loc = "CENTER"
|
||||
icon_state = "blank"
|
||||
appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR
|
||||
appearance_flags = PLANE_MASTER
|
||||
blend_mode = BLEND_OVERLAY
|
||||
plane = LOWEST_EVER_PLANE
|
||||
var/show_alpha = 255
|
||||
var/hide_alpha = 0
|
||||
/// Will be sent to the debug ui as a description for each plane
|
||||
/// Also useful as a place to explain to coders how/why your plane works, and what it's meant to do
|
||||
/// Plaintext and basic html are fine to use here.
|
||||
/// I'll bonk you if I find you putting "lmao stuff" in here, make this useful.
|
||||
var/documentation = ""
|
||||
/// Our real alpha value, so alpha can persist through being hidden/shown
|
||||
var/true_alpha = 255
|
||||
/// Tracks if we're using our true alpha, or being manipulated in some other way
|
||||
var/alpha_enabled = TRUE
|
||||
|
||||
/// The plane master group we're a member of, our "home"
|
||||
var/datum/plane_master_group/home
|
||||
|
||||
/// If our plane master allows for offsetting
|
||||
/// Mostly used for planes that really don't need to be duplicated, like the hud planes
|
||||
var/allows_offsetting = TRUE
|
||||
/// Our offset from our "true" plane, see below
|
||||
var/offset
|
||||
/// When rendering multiz, lower levels get their own set of plane masters
|
||||
/// Real plane here represents the "true" plane value of something, ignoring the offset required to handle lower levels
|
||||
var/real_plane
|
||||
|
||||
//--rendering relay vars--
|
||||
///integer: what plane we will relay this planes render to
|
||||
var/render_relay_plane = RENDER_PLANE_GAME
|
||||
///bool: Whether this plane should get a render target automatically generated
|
||||
var/generate_render_target = TRUE
|
||||
///integer: blend mode to apply to the render relay in case you dont want to use the plane_masters blend_mode
|
||||
/// list of planes we will relay this plane's render to
|
||||
var/list/render_relay_planes = list(RENDER_PLANE_GAME)
|
||||
/// blend mode to apply to the render relay in case you dont want to use the plane_masters blend_mode
|
||||
var/blend_mode_override
|
||||
///reference: current relay this plane is utilizing to render
|
||||
var/atom/movable/render_plane_relay/relay
|
||||
/// list of current relays this plane is utilizing to render
|
||||
var/list/atom/movable/render_plane_relay/relays = list()
|
||||
/// if render relays have already be generated
|
||||
var/relays_generated = FALSE
|
||||
|
||||
/atom/movable/screen/plane_master/proc/Show(override)
|
||||
alpha = override || show_alpha
|
||||
/// If this plane master should be hidden from the player at roundstart
|
||||
/// We do this so PMs can opt into being temporary, to reduce load on clients
|
||||
var/start_hidden = FALSE
|
||||
/// If this plane master is being forced to hide.
|
||||
/// Hidden PMs will dump ANYTHING relayed or drawn onto them. Be careful with this
|
||||
/// Remember: a hidden plane master will dump anything drawn directly to it onto the output render. It does NOT hide its contents
|
||||
/// Use alpha for that
|
||||
var/force_hidden = FALSE
|
||||
|
||||
/atom/movable/screen/plane_master/proc/Hide(override)
|
||||
alpha = override || hide_alpha
|
||||
/// If this plane should be scaled by multiz
|
||||
/// Planes with this set should NEVER be relay'd into each other, as that will cause visual fuck
|
||||
var/multiz_scaled = TRUE
|
||||
|
||||
//Why do plane masters need a backdrop sometimes? Read https://secure.byond.com/forum/?post=2141928
|
||||
//Trust me, you need one. Period. If you don't think you do, you're doing something extremely wrong.
|
||||
/atom/movable/screen/plane_master/proc/backdrop(mob/mymob)
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
if(!isnull(render_relay_plane))
|
||||
relay_render_to_plane(mymob, render_relay_plane)
|
||||
|
||||
///Things rendered on "openspace"; holes in multi-z
|
||||
/atom/movable/screen/plane_master/openspace_backdrop
|
||||
name = "open space backdrop plane master"
|
||||
plane = OPENSPACE_BACKDROP_PLANE
|
||||
appearance_flags = PLANE_MASTER
|
||||
blend_mode = BLEND_MULTIPLY
|
||||
alpha = 255
|
||||
|
||||
/atom/movable/screen/plane_master/openspace
|
||||
name = "open space plane master"
|
||||
plane = OPENSPACE_PLANE
|
||||
appearance_flags = PLANE_MASTER
|
||||
|
||||
/atom/movable/screen/plane_master/openspace/Initialize(mapload)
|
||||
/atom/movable/screen/plane_master/Initialize(mapload, datum/plane_master_group/home, offset = 0)
|
||||
. = ..()
|
||||
add_filter("first_stage_openspace", 1, drop_shadow_filter(color = "#04080FAA", size = -10))
|
||||
add_filter("second_stage_openspace", 2, drop_shadow_filter(color = "#04080FAA", size = -15))
|
||||
add_filter("third_stage_openspace", 3, drop_shadow_filter(color = "#04080FAA", size = -20))
|
||||
src.offset = offset
|
||||
true_alpha = alpha
|
||||
real_plane = plane
|
||||
|
||||
///For any transparent multi-z tiles we want to render
|
||||
/atom/movable/screen/plane_master/transparent
|
||||
name = "transparent plane master"
|
||||
plane = TRANSPARENT_FLOOR_PLANE
|
||||
appearance_flags = PLANE_MASTER
|
||||
if(!set_home(home))
|
||||
return INITIALIZE_HINT_QDEL
|
||||
update_offset()
|
||||
if(!documentation && !(istype(src, /atom/movable/screen/plane_master) || istype(src, /atom/movable/screen/plane_master/rendering_plate)))
|
||||
stack_trace("Plane master created without a description. Document how your thing works so people will know in future, and we can display it in the debug menu")
|
||||
if(start_hidden)
|
||||
hide_plane(home.our_hud?.mymob)
|
||||
generate_render_relays()
|
||||
|
||||
/atom/movable/screen/plane_master/Destroy()
|
||||
if(home)
|
||||
// NOTE! We do not clear ourselves from client screens
|
||||
// We relay on whoever qdel'd us to reset our hud, and properly purge us
|
||||
home.plane_masters -= "[plane]"
|
||||
home = null
|
||||
. = ..()
|
||||
QDEL_LIST(relays)
|
||||
|
||||
/// Sets the plane group that owns us, it also determines what screen we render to
|
||||
/// Returns FALSE if the set_home fails, TRUE otherwise
|
||||
/atom/movable/screen/plane_master/proc/set_home(datum/plane_master_group/home)
|
||||
if(!istype(home, /datum/plane_master_group))
|
||||
return FALSE
|
||||
src.home = home
|
||||
if(home.map)
|
||||
screen_loc = "[home.map]:[screen_loc]"
|
||||
assigned_map = home.map
|
||||
return TRUE
|
||||
|
||||
/// Updates our "offset", basically what layer of multiz we're meant to render
|
||||
/// Top is 0, goes up as you go down
|
||||
/// It's taken into account by render targets and relays, so we gotta make sure they're on the same page
|
||||
/atom/movable/screen/plane_master/proc/update_offset()
|
||||
name = "[initial(name)] #[offset]"
|
||||
SET_PLANE_W_SCALAR(src, real_plane, offset)
|
||||
for(var/i in 1 to length(render_relay_planes))
|
||||
render_relay_planes[i] = GET_NEW_PLANE(render_relay_planes[i], offset)
|
||||
if(initial(render_target))
|
||||
render_target = OFFSET_RENDER_TARGET(initial(render_target), offset)
|
||||
|
||||
/atom/movable/screen/plane_master/proc/set_alpha(new_alpha)
|
||||
true_alpha = new_alpha
|
||||
if(!alpha_enabled)
|
||||
return
|
||||
alpha = new_alpha
|
||||
|
||||
/atom/movable/screen/plane_master/proc/disable_alpha()
|
||||
alpha_enabled = FALSE
|
||||
alpha = 0
|
||||
|
||||
/atom/movable/screen/plane_master/proc/enable_alpha()
|
||||
alpha_enabled = TRUE
|
||||
alpha = true_alpha
|
||||
|
||||
/// Shows a plane master to the passed in mob
|
||||
/// Override this to apply unique effects and such
|
||||
/// Returns TRUE if the call is allowed, FALSE otherwise
|
||||
/atom/movable/screen/plane_master/proc/show_to(mob/mymob)
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
if(force_hidden)
|
||||
return FALSE
|
||||
|
||||
var/client/our_client = mymob?.client
|
||||
if(!our_client)
|
||||
return TRUE
|
||||
|
||||
our_client.screen += src
|
||||
our_client.screen += relays
|
||||
return TRUE
|
||||
|
||||
/// Hides a plane master from the passeed in mob
|
||||
/// Do your effect cleanup here
|
||||
/atom/movable/screen/plane_master/proc/hide_from(mob/oldmob)
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
var/client/their_client = oldmob?.client
|
||||
if(!their_client)
|
||||
return
|
||||
their_client.screen -= src
|
||||
their_client.screen -= relays
|
||||
|
||||
|
||||
/// Forces this plane master to hide, until unhide_plane is called
|
||||
/// This allows us to disable unused PMs without breaking anything else
|
||||
/atom/movable/screen/plane_master/proc/hide_plane(mob/cast_away)
|
||||
force_hidden = TRUE
|
||||
hide_from(cast_away)
|
||||
|
||||
/// Disables any forced hiding, allows the plane master to be used as normal
|
||||
/atom/movable/screen/plane_master/proc/unhide_plane(mob/enfold)
|
||||
force_hidden = FALSE
|
||||
show_to(enfold)
|
||||
|
||||
/// Mirrors our force hidden state to the hidden state of the plane that came before, assuming it's valid
|
||||
/// This allows us to mirror any hidden sets from before we were created, no matter how low that chance is
|
||||
/atom/movable/screen/plane_master/proc/mirror_parent_hidden()
|
||||
var/mob/our_mob = home?.our_hud?.mymob
|
||||
var/atom/movable/screen/plane_master/true_plane = our_mob?.hud_used.get_plane_master(plane)
|
||||
if(true_plane == src || !true_plane)
|
||||
return
|
||||
|
||||
if(true_plane.force_hidden == force_hidden)
|
||||
return
|
||||
|
||||
// If one of us already exists and it's not hidden, unhide ourselves
|
||||
if(true_plane.force_hidden)
|
||||
hide_plane(our_mob)
|
||||
else
|
||||
unhide_plane(our_mob)
|
||||
|
||||
/atom/movable/screen/plane_master/clickcatcher
|
||||
name = "Click Catcher"
|
||||
documentation = "Contains the screen object we use as a backdrop to catch clicks on portions of the screen that would otherwise contain nothing else. \
|
||||
<br>Will always be below almost everything else"
|
||||
plane = CLICKCATCHER_PLANE
|
||||
appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR
|
||||
multiz_scaled = FALSE
|
||||
|
||||
/atom/movable/screen/plane_master/clickcatcher/Initialize(mapload, datum/plane_master_group/home, offset)
|
||||
. = ..()
|
||||
RegisterSignal(SSmapping, COMSIG_PLANE_OFFSET_INCREASE, .proc/offset_increased)
|
||||
offset_increased(SSmapping, 0, SSmapping.max_plane_offset)
|
||||
|
||||
/atom/movable/screen/plane_master/clickcatcher/proc/offset_increased(datum/source, old_off, new_off)
|
||||
SIGNAL_HANDLER
|
||||
// We only want need the lowest level
|
||||
// If my system better supported changing PM plane values mid op I'd do that, but I do NOT so
|
||||
if(new_off > offset)
|
||||
hide_plane(home?.our_hud?.mymob)
|
||||
|
||||
/atom/movable/screen/plane_master/parallax_white
|
||||
name = "Parallax whitifier"
|
||||
documentation = "Essentially a backdrop for the parallax plane. We're rendered just below it, so we'll be multiplied by its well, parallax.\
|
||||
<br>If you want something to look as if it has parallax on it, draw it to this plane."
|
||||
plane = PLANE_SPACE
|
||||
appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR
|
||||
|
||||
///Contains space parallax
|
||||
/atom/movable/screen/plane_master/parallax
|
||||
name = "Parallax"
|
||||
documentation = "Contains parallax, or to be more exact the screen objects that hold parallax.\
|
||||
<br>Note the BLEND_MULTIPLY. The trick here is how low our plane value is. Because of that, we draw below almost everything in the game.\
|
||||
<br>We abuse this to ensure we multiply against the Parallax whitifier plane, or space's plane. It's set to full white, so when you do the multiply you just get parallax out where it well, makes sense to be.\
|
||||
<br>Also notice that the parent parallax plane is mirrored down to all children. We want to support viewing parallax across all z levels at once."
|
||||
plane = PLANE_SPACE_PARALLAX
|
||||
appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR
|
||||
blend_mode = BLEND_MULTIPLY
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
multiz_scaled = FALSE
|
||||
|
||||
/atom/movable/screen/plane_master/parallax/Initialize(mapload, datum/plane_master_group/home, offset)
|
||||
. = ..()
|
||||
if(offset != 0)
|
||||
// You aren't the source? don't change yourself
|
||||
return
|
||||
RegisterSignal(SSmapping, COMSIG_PLANE_OFFSET_INCREASE, .proc/on_offset_increase)
|
||||
offset_increase(0, SSmapping.max_plane_offset)
|
||||
|
||||
/atom/movable/screen/plane_master/parallax/proc/on_offset_increase(datum/source, old_offset, new_offset)
|
||||
SIGNAL_HANDLER
|
||||
offset_increase(old_offset, new_offset)
|
||||
|
||||
/atom/movable/screen/plane_master/parallax/proc/offset_increase(old_offset, new_offset)
|
||||
// Parallax will be mirrored down to any new planes that are added, so it will properly render across mirage borders
|
||||
for(var/offset in old_offset to new_offset)
|
||||
if(offset != 0)
|
||||
// Overlay so we don't multiply twice, and thus fuck up our rendering
|
||||
add_relay_to(GET_NEW_PLANE(plane, offset), BLEND_OVERLAY)
|
||||
|
||||
/atom/movable/screen/plane_master/gravpulse
|
||||
name = "Gravpulse"
|
||||
documentation = "Ok so this one's fun. Basically, we want to be able to distort the game plane when a grav annom is around.\
|
||||
<br>So we draw the pattern we want to use to this plane, and it's then used as a render target by a distortion filter on the game plane.\
|
||||
<br>Note the blend mode and lack of relay targets. This plane exists only to distort, it's never rendered anywhere."
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
plane = GRAVITY_PULSE_PLANE
|
||||
appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR
|
||||
blend_mode = BLEND_ADD
|
||||
render_target = GRAVITY_PULSE_RENDER_TARGET
|
||||
render_relay_planes = list()
|
||||
|
||||
///Contains just the floor
|
||||
/atom/movable/screen/plane_master/floor
|
||||
name = "floor plane master"
|
||||
name = "Floor"
|
||||
documentation = "The well, floor. This is mostly used as a sorting mechanism, but it also lets us create a \"border\" around the game world plane, so its drop shadow will actually work."
|
||||
plane = FLOOR_PLANE
|
||||
appearance_flags = PLANE_MASTER
|
||||
blend_mode = BLEND_OVERLAY
|
||||
|
||||
///Contains most things in the game world
|
||||
/atom/movable/screen/plane_master/game_world
|
||||
name = "game world plane master"
|
||||
/atom/movable/screen/plane_master/game
|
||||
name = "Lower game world"
|
||||
documentation = "Exists mostly because of FOV shit. Basically, if you've just got a normal not ABOVE fov thing, and you don't want it masked, stick it here yeah?"
|
||||
plane = GAME_PLANE
|
||||
appearance_flags = PLANE_MASTER //should use client color
|
||||
blend_mode = BLEND_OVERLAY
|
||||
|
||||
/atom/movable/screen/plane_master/game_world/backdrop(mob/mymob)
|
||||
. = ..()
|
||||
remove_filter("AO")
|
||||
if(istype(mymob) && mymob.client?.prefs?.read_preference(/datum/preference/toggle/ambient_occlusion))
|
||||
add_filter("AO", 1, drop_shadow_filter(x = 0, y = -2, size = 4, color = "#04080FAA"))
|
||||
render_relay_planes = list(RENDER_PLANE_GAME_WORLD)
|
||||
|
||||
/atom/movable/screen/plane_master/game_world_fov_hidden
|
||||
name = "game world fov hidden plane master"
|
||||
name = "lower game world fov hidden"
|
||||
documentation = "If you want something to be hidden by fov, stick it on this plane. We're masked by the fov blocker plane, so the items on us can actually well, disappear."
|
||||
plane = GAME_PLANE_FOV_HIDDEN
|
||||
render_relay_plane = GAME_PLANE
|
||||
appearance_flags = PLANE_MASTER //should use client color
|
||||
blend_mode = BLEND_OVERLAY
|
||||
render_relay_planes = list(RENDER_PLANE_GAME_WORLD)
|
||||
|
||||
/atom/movable/screen/plane_master/game_world_fov_hidden/Initialize(mapload)
|
||||
. = ..()
|
||||
add_filter("vision_cone", 1, alpha_mask_filter(render_source = FIELD_OF_VISION_BLOCKER_RENDER_TARGET, flags = MASK_INVERSE))
|
||||
add_filter("vision_cone", 1, alpha_mask_filter(render_source = OFFSET_RENDER_TARGET(FIELD_OF_VISION_BLOCKER_RENDER_TARGET, offset), flags = MASK_INVERSE))
|
||||
|
||||
/atom/movable/screen/plane_master/field_of_vision_blocker
|
||||
name = "Field of vision blocker"
|
||||
documentation = "This is one of those planes that's only used as a filter. It masks out things that want to be hidden by fov.\
|
||||
<br>Literally just contains FOV images, or masks."
|
||||
plane = FIELD_OF_VISION_BLOCKER_PLANE
|
||||
appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR
|
||||
render_target = FIELD_OF_VISION_BLOCKER_RENDER_TARGET
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
render_relay_planes = list()
|
||||
// We do NOT allow offsetting, because there's no case where you would want to block only one layer, at least currently
|
||||
allows_offsetting = FALSE
|
||||
start_hidden = TRUE
|
||||
// We mark as multiz_scaled FALSE so transforms don't effect us, and we draw to the planes below us as if they were us.
|
||||
// This is safe because we will ALWAYS be on the top z layer, so it DON'T MATTER
|
||||
multiz_scaled = FALSE
|
||||
|
||||
/atom/movable/screen/plane_master/field_of_vision_blocker/Initialize(mapload, datum/plane_master_group/home, offset)
|
||||
. = ..()
|
||||
mirror_parent_hidden()
|
||||
|
||||
/atom/movable/screen/plane_master/game_world_upper
|
||||
name = "upper game world plane master"
|
||||
name = "Upper game world"
|
||||
documentation = "Ok so fov is kinda fucky, because planes in byond serve both as effect groupings and as rendering orderers. Since that's true, we need a plane that we can stick stuff that draws above fov blocked stuff on."
|
||||
plane = GAME_PLANE_UPPER
|
||||
render_relay_plane = GAME_PLANE
|
||||
appearance_flags = PLANE_MASTER //should use client color
|
||||
blend_mode = BLEND_OVERLAY
|
||||
render_relay_planes = list(RENDER_PLANE_GAME_WORLD)
|
||||
|
||||
/atom/movable/screen/plane_master/game_world_upper_fov_hidden
|
||||
name = "upper game world fov hidden plane master"
|
||||
name = "Upper game world fov hidden"
|
||||
documentation = "Just as we need a place to draw things \"above\" the hidden fov plane, we also need to be able to hide stuff that draws over the upper game plane."
|
||||
plane = GAME_PLANE_UPPER_FOV_HIDDEN
|
||||
render_relay_plane = GAME_PLANE_FOV_HIDDEN
|
||||
appearance_flags = PLANE_MASTER //should use client color
|
||||
blend_mode = BLEND_OVERLAY
|
||||
render_relay_planes = list(RENDER_PLANE_GAME_WORLD)
|
||||
|
||||
/atom/movable/screen/plane_master/game_world_upper_fov_hidden/Initialize()
|
||||
. = ..()
|
||||
// Dupe of the other hidden plane
|
||||
add_filter("vision_cone", 1, alpha_mask_filter(render_source = OFFSET_RENDER_TARGET(FIELD_OF_VISION_BLOCKER_RENDER_TARGET, offset), flags = MASK_INVERSE))
|
||||
|
||||
/atom/movable/screen/plane_master/seethrough
|
||||
name = "Seethrough"
|
||||
documentation = "Holds the seethrough versions (done using image overrides) of large objects. Mouse transparent, so you can click through them."
|
||||
plane = SEETHROUGH_PLANE
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
render_relay_planes = list(GAME_PLANE)
|
||||
start_hidden = TRUE
|
||||
|
||||
/atom/movable/screen/plane_master/game_world_above
|
||||
name = "above game world plane master"
|
||||
name = "Above game world"
|
||||
documentation = "We need a place that's unmasked by fov that also draws above the upper game world fov hidden plane. I told you fov was hacky man."
|
||||
plane = ABOVE_GAME_PLANE
|
||||
render_relay_plane = GAME_PLANE
|
||||
appearance_flags = PLANE_MASTER //should use client color
|
||||
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
|
||||
name = "massive object plane master"
|
||||
plane = MASSIVE_OBJ_PLANE
|
||||
appearance_flags = PLANE_MASTER //should use client color
|
||||
blend_mode = BLEND_OVERLAY
|
||||
|
||||
/atom/movable/screen/plane_master/ghost
|
||||
name = "ghost plane master"
|
||||
plane = GHOST_PLANE
|
||||
appearance_flags = PLANE_MASTER //should use client color
|
||||
blend_mode = BLEND_OVERLAY
|
||||
render_relay_plane = RENDER_PLANE_NON_GAME
|
||||
|
||||
/atom/movable/screen/plane_master/point
|
||||
name = "point plane master"
|
||||
plane = POINT_PLANE
|
||||
appearance_flags = PLANE_MASTER //should use client color
|
||||
blend_mode = BLEND_OVERLAY
|
||||
render_relay_planes = list(RENDER_PLANE_GAME_WORLD)
|
||||
|
||||
/**
|
||||
* Plane master handling byond internal blackness
|
||||
* vars are set as to replicate behavior when rendering to other planes
|
||||
* do not touch this unless you know what you are doing
|
||||
*/
|
||||
// Blackness renders weird when you view down openspace, because of transforms and borders and such
|
||||
// This is a consequence of not using lummy's grouped transparency, but I couldn't get that to work without totally fucking up
|
||||
// Sight flags, and shooting vis_contents usage to the moon. So we're doin it different.
|
||||
// Look into lessening this, maybe mirror down all the time? idk
|
||||
// Part of the issue is it isn't actually the blackness plane, it's just normal blackness
|
||||
// (If image vis contents worked (it should in 515), and we were ok with a maptick cost (wait for threaded maptick)) this could be fixed
|
||||
/atom/movable/screen/plane_master/blackness
|
||||
name = "darkness plane master"
|
||||
name = "Darkness"
|
||||
documentation = "This is quite fiddly, so bear with me. By default (in byond) everything in the game is rendered onto plane 0. It's the default plane. \
|
||||
<br>But, because we've moved everything we control off plane 0, all that's left is stuff byond internally renders. \
|
||||
<br>What we're doing here is using plane 0 to capture \"Blackness\", or the mask that hides tiles. Note, this only works if our mob has the SEE_PIXELS or SEE_BLACKNESS sight flags.\
|
||||
<br>We relay this plane master (on plane 0) down to other copies of itself, depending on the layer your mob is on at the moment.\
|
||||
<br>Of note: plane master blackness, and the blackness that comes from having nothing to display look similar, but are not the same thing,\
|
||||
mind yourself when you're working with this plane, you might have accidentially been trying to work with the wrong thing."
|
||||
plane = BLACKNESS_PLANE
|
||||
appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR
|
||||
// Note: we don't set this to blend multiply because it just dies when its alpha is modified, because of fun byond bugs
|
||||
// Marked as multiz_scaled = FALSE because it should not scale, scaling lets you see "through" the floor
|
||||
multiz_scaled = FALSE
|
||||
|
||||
/atom/movable/screen/plane_master/blackness/show_to(mob/mymob)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
if(offset != 0)
|
||||
// You aren't the source? don't change yourself
|
||||
return
|
||||
RegisterSignal(mymob, COMSIG_MOB_SIGHT_CHANGE, .proc/handle_sight_value)
|
||||
handle_sight_value(mymob, mymob.sight, 0)
|
||||
var/datum/hud/hud = home.our_hud
|
||||
if(hud)
|
||||
RegisterSignal(hud, COMSIG_HUD_OFFSET_CHANGED, .proc/on_offset_change)
|
||||
offset_change(0, hud.current_plane_offset)
|
||||
|
||||
/atom/movable/screen/plane_master/blackness/hide_from(mob/oldmob)
|
||||
. = ..()
|
||||
if(offset != 0)
|
||||
return
|
||||
UnregisterSignal(oldmob, COMSIG_MOB_SIGHT_CHANGE)
|
||||
var/datum/hud/hud = home.our_hud
|
||||
if(hud)
|
||||
UnregisterSignal(hud, COMSIG_HUD_OFFSET_CHANGED, .proc/on_offset_change)
|
||||
|
||||
/// Reacts to some new plane master value
|
||||
/atom/movable/screen/plane_master/blackness/proc/handle_sight_value(datum/source, new_sight, old_sight)
|
||||
SIGNAL_HANDLER
|
||||
// Tryin to set a sight flag that cuts blackness eh?
|
||||
if(new_sight & BLACKNESS_CUTTING)
|
||||
// Better set alpha then, so it'll actually work
|
||||
// We just get the one because there is only one blackness PM, it's just mirrored around
|
||||
disable_alpha()
|
||||
else
|
||||
enable_alpha()
|
||||
|
||||
/atom/movable/screen/plane_master/blackness/proc/on_offset_change(datum/source, old_offset, new_offset)
|
||||
SIGNAL_HANDLER
|
||||
offset_change(old_offset, new_offset)
|
||||
|
||||
/atom/movable/screen/plane_master/blackness/proc/offset_change(old_offset, new_offset)
|
||||
// Basically, the rule here is the blackness we harvest from the mob using the SEE_BLACKNESS flag will be relayed to the darkness
|
||||
// Plane that we're actually on
|
||||
if(old_offset != 0) // If our old target wasn't just ourselves
|
||||
remove_relay_from(GET_NEW_PLANE(plane, old_offset))
|
||||
|
||||
if(new_offset != 0)
|
||||
add_relay_to(GET_NEW_PLANE(plane, new_offset))
|
||||
|
||||
/atom/movable/screen/plane_master/area
|
||||
name = "Area"
|
||||
documentation = "Holds the areas themselves, which ends up meaning it holds any overlays/effects we apply to areas. NOT snow or rad storms, those go on above lighting"
|
||||
plane = AREA_PLANE
|
||||
|
||||
/atom/movable/screen/plane_master/massive_obj
|
||||
name = "Massive object"
|
||||
documentation = "Huge objects need to render above everything else on the game plane, otherwise they'd well, get clipped and look not that huge. This does that."
|
||||
plane = MASSIVE_OBJ_PLANE
|
||||
|
||||
/atom/movable/screen/plane_master/point
|
||||
name = "Point"
|
||||
documentation = "I mean like, what do you want me to say? Points draw over pretty much everything else, so they get their own plane. Remember we layer render relays to draw planes in their proper order on render plates."
|
||||
plane = POINT_PLANE
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
|
||||
///Contains all turf lighting
|
||||
/atom/movable/screen/plane_master/turf_lighting
|
||||
name = "Turf Lighting"
|
||||
documentation = "Contains all lighting drawn to turfs. Not so complex, draws directly onto the lighting plate."
|
||||
plane = LIGHTING_PLANE
|
||||
appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR
|
||||
render_relay_planes = list(RENDER_PLANE_LIGHTING)
|
||||
blend_mode_override = BLEND_ADD
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
|
||||
/// This will not work through multiz, because of a byond bug with BLEND_MULTIPLY
|
||||
/// Bug report is up, waiting on a fix
|
||||
/atom/movable/screen/plane_master/o_light_visual
|
||||
name = "Overlight light visual"
|
||||
documentation = "Holds overlay lighting objects, or the sort of lighting that's a well, overlay stuck to something.\
|
||||
<br>Exists because lighting updating is really slow, and movement needs to feel smooth.\
|
||||
<br>We draw to the game plane, and mask out space for ourselves on the lighting plane so any color we have has the chance to display."
|
||||
plane = O_LIGHTING_VISUAL_PLANE
|
||||
appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR
|
||||
render_target = O_LIGHTING_VISUAL_RENDER_TARGET
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
blend_mode = BLEND_MULTIPLY
|
||||
appearance_flags = PLANE_MASTER | NO_CLIENT_COLOR | PIXEL_SCALE
|
||||
//byond internal end
|
||||
|
||||
///Contains all lighting objects
|
||||
/atom/movable/screen/plane_master/lighting
|
||||
name = "lighting plane master"
|
||||
plane = LIGHTING_PLANE
|
||||
blend_mode_override = BLEND_MULTIPLY
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
|
||||
|
||||
/atom/movable/screen/plane_master/lighting/backdrop(mob/mymob)
|
||||
. = ..()
|
||||
mymob.overlay_fullscreen("lighting_backdrop_lit", /atom/movable/screen/fullscreen/lighting_backdrop/lit)
|
||||
mymob.overlay_fullscreen("lighting_backdrop_unlit", /atom/movable/screen/fullscreen/lighting_backdrop/unlit)
|
||||
|
||||
/*!
|
||||
* This system works by exploiting BYONDs color matrix filter to use layers to handle emissive blockers.
|
||||
*
|
||||
* Emissive overlays are pasted with an atom color that converts them to be entirely some specific color.
|
||||
* Emissive blockers are pasted with an atom color that converts them to be entirely some different color.
|
||||
* Emissive overlays and emissive blockers are put onto the same plane.
|
||||
* The layers for the emissive overlays and emissive blockers cause them to mask eachother similar to normal BYOND objects.
|
||||
* A color matrix filter is applied to the emissive plane to mask out anything that isn't whatever the emissive color is.
|
||||
* This is then used to alpha mask the lighting plane.
|
||||
*/
|
||||
/atom/movable/screen/plane_master/lighting/Initialize(mapload)
|
||||
. = ..()
|
||||
add_filter("emissives", 1, alpha_mask_filter(render_source = EMISSIVE_RENDER_TARGET, flags = MASK_INVERSE))
|
||||
add_filter("object_lighting", 2, alpha_mask_filter(render_source = O_LIGHTING_VISUAL_RENDER_TARGET, flags = MASK_INVERSE))
|
||||
|
||||
/atom/movable/screen/plane_master/above_lighting
|
||||
name = "Above lighting"
|
||||
plane = ABOVE_LIGHTING_PLANE
|
||||
documentation = "Anything on the game plane that needs a space to draw on that will be above the lighting plane.\
|
||||
<br>Mostly little alerts and effects, also sometimes contains things that are meant to look as if they glow."
|
||||
|
||||
/**
|
||||
* Handles emissive overlays and emissive blockers.
|
||||
*/
|
||||
/atom/movable/screen/plane_master/emissive
|
||||
name = "emissive plane master"
|
||||
name = "Emissive"
|
||||
documentation = "This system works by exploiting BYONDs color matrix filter to use layers to handle emissive blockers.\
|
||||
<br>Emissive overlays are pasted with an atom color that converts them to be entirely some specific color.\
|
||||
<br>Emissive blockers are pasted with an atom color that converts them to be entirely some different color.\
|
||||
<br>Emissive overlays and emissive blockers are put onto the same plane (This one).\
|
||||
<br>The layers for the emissive overlays and emissive blockers cause them to mask eachother similar to normal BYOND objects.\
|
||||
<br>A color matrix filter is applied to the emissive plane to mask out anything that isn't whatever the emissive color is.\
|
||||
<br>This is then used to alpha mask the lighting plane."
|
||||
plane = EMISSIVE_PLANE
|
||||
appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
render_target = EMISSIVE_RENDER_TARGET
|
||||
render_relay_plane = null
|
||||
render_relay_planes = list()
|
||||
|
||||
/atom/movable/screen/plane_master/emissive/Initialize(mapload)
|
||||
. = ..()
|
||||
add_filter("em_block_masking", 1, color_matrix_filter(GLOB.em_mask_matrix))
|
||||
|
||||
/atom/movable/screen/plane_master/above_lighting
|
||||
name = "above lighting plane master"
|
||||
plane = ABOVE_LIGHTING_PLANE
|
||||
appearance_flags = PLANE_MASTER //should use client color
|
||||
blend_mode = BLEND_OVERLAY
|
||||
|
||||
///Contains space parallax
|
||||
/atom/movable/screen/plane_master/parallax
|
||||
name = "parallax plane master"
|
||||
plane = PLANE_SPACE_PARALLAX
|
||||
blend_mode = BLEND_MULTIPLY
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
|
||||
/atom/movable/screen/plane_master/parallax_white
|
||||
name = "parallax whitifier plane master"
|
||||
plane = PLANE_SPACE
|
||||
|
||||
/atom/movable/screen/plane_master/pipecrawl
|
||||
name = "pipecrawl plane master"
|
||||
name = "Pipecrawl"
|
||||
documentation = "Holds pipecrawl images generated during well, pipecrawling.\
|
||||
<br>Has a few effects and a funky color matrix designed to make things a bit more visually readable."
|
||||
plane = PIPECRAWL_IMAGES_PLANE
|
||||
appearance_flags = PLANE_MASTER
|
||||
blend_mode = BLEND_OVERLAY
|
||||
start_hidden = TRUE
|
||||
|
||||
/atom/movable/screen/plane_master/pipecrawl/Initialize(mapload)
|
||||
. = ..()
|
||||
@@ -221,85 +463,99 @@
|
||||
color = list(1.2,0,0,0, 0,1.2,0,0, 0,0,1.2,0, 0,0,0,1, 0,0,0,0)
|
||||
// This serves a similar purpose, I want the pipes to pop
|
||||
add_filter("pipe_dropshadow", 1, drop_shadow_filter(x = -1, y= -1, size = 1, color = "#0000007A"))
|
||||
mirror_parent_hidden()
|
||||
|
||||
/atom/movable/screen/plane_master/camera_static
|
||||
name = "camera static plane master"
|
||||
name = "Camera static"
|
||||
documentation = "Holds camera static images. Usually only visible to people who can well, see static.\
|
||||
<br>We use images rather then vis contents because they're lighter on maptick, and maptick sucks butt."
|
||||
plane = CAMERA_STATIC_PLANE
|
||||
appearance_flags = PLANE_MASTER
|
||||
blend_mode = BLEND_OVERLAY
|
||||
start_hidden = TRUE
|
||||
|
||||
/atom/movable/screen/plane_master/excited_turfs
|
||||
name = "atmos excited turfs"
|
||||
plane = ATMOS_GROUP_PLANE
|
||||
appearance_flags = PLANE_MASTER
|
||||
blend_mode = BLEND_OVERLAY
|
||||
alpha = 0
|
||||
/atom/movable/screen/plane_master/camera_static/show_to(mob/mymob)
|
||||
// If we aren't an AI, we have no need for this plane master (most of the time, ai eyes are weird and annoying)
|
||||
if(force_hidden && isAI(mymob))
|
||||
unhide_plane(mymob)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
if(isAI(mymob))
|
||||
return
|
||||
return FALSE
|
||||
|
||||
/atom/movable/screen/plane_master/o_light_visual
|
||||
name = "overlight light visual plane master"
|
||||
plane = O_LIGHTING_VISUAL_PLANE
|
||||
render_target = O_LIGHTING_VISUAL_RENDER_TARGET
|
||||
/atom/movable/screen/plane_master/high_game
|
||||
name = "High Game"
|
||||
documentation = "Holds anything that wants to be displayed above the rest of the game plane, and doesn't want to be clickable. \
|
||||
<br>This includes atmos debug overlays, blind sound images, and mining scanners. \
|
||||
<br>Really only exists for its layering potential, we don't use this for any vfx"
|
||||
plane = HIGH_GAME_PLANE
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
|
||||
/atom/movable/screen/plane_master/ghost
|
||||
name = "Ghost"
|
||||
documentation = "Ghosts draw here, so they don't get mixed up in the visuals of the game world. Note, this is not not how we HIDE ghosts from people, that's done with invisible and see_invisible."
|
||||
plane = GHOST_PLANE
|
||||
render_relay_planes = list(RENDER_PLANE_NON_GAME)
|
||||
|
||||
/atom/movable/screen/plane_master/fullscreen
|
||||
name = "Fullscreen"
|
||||
documentation = "Holds anything that applies to or above the full screen. \
|
||||
<br>Note, it's still rendered underneath hud objects, but this lets us control the order that things like death/damage effects render in."
|
||||
plane = FULLSCREEN_PLANE
|
||||
appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR
|
||||
render_relay_planes = list(RENDER_PLANE_NON_GAME)
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
allows_offsetting = FALSE
|
||||
|
||||
/atom/movable/screen/plane_master/sound_effect_visual
|
||||
name = "Sound Effect Visuals"
|
||||
documentation = "Holds anything that is a game visual, but is displayed over fullscreen effects. \
|
||||
<br>Displayed over fullscreen effects, but still under runechat and the HUD."
|
||||
plane = SOUND_EFFECT_VISUAL_PLANE
|
||||
render_relay_planes = list(RENDER_PLANE_NON_GAME)
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
blend_mode = BLEND_MULTIPLY
|
||||
blend_mode_override = BLEND_MULTIPLY
|
||||
|
||||
/atom/movable/screen/plane_master/runechat
|
||||
name = "runechat plane master"
|
||||
name = "Runechat"
|
||||
documentation = "Holds runechat images, that text that pops up when someone say something. Uses a dropshadow to well, look nice."
|
||||
plane = RUNECHAT_PLANE
|
||||
appearance_flags = PLANE_MASTER
|
||||
blend_mode = BLEND_OVERLAY
|
||||
render_relay_plane = RENDER_PLANE_NON_GAME
|
||||
render_relay_planes = list(RENDER_PLANE_NON_GAME)
|
||||
|
||||
/atom/movable/screen/plane_master/runechat/backdrop(mob/mymob)
|
||||
/atom/movable/screen/plane_master/runechat/show_to(mob/mymob)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
remove_filter("AO")
|
||||
if(istype(mymob) && mymob.client?.prefs?.read_preference(/datum/preference/toggle/ambient_occlusion))
|
||||
add_filter("AO", 1, drop_shadow_filter(x = 0, y = -2, size = 4, color = "#04080FAA"))
|
||||
|
||||
/atom/movable/screen/plane_master/gravpulse
|
||||
name = "gravpulse plane"
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
plane = GRAVITY_PULSE_PLANE
|
||||
blend_mode = BLEND_ADD
|
||||
blend_mode_override = BLEND_ADD
|
||||
render_target = GRAVITY_PULSE_RENDER_TARGET
|
||||
render_relay_plane = null
|
||||
|
||||
/atom/movable/screen/plane_master/area
|
||||
name = "area plane"
|
||||
plane = AREA_PLANE
|
||||
|
||||
/atom/movable/screen/plane_master/balloon_chat
|
||||
name = "balloon alert plane"
|
||||
name = "Balloon chat"
|
||||
documentation = "Holds ballon chat images, those little text bars that pop up for a second when you do some things. NOT runechat."
|
||||
plane = BALLOON_CHAT_PLANE
|
||||
render_relay_plane = RENDER_PLANE_NON_GAME
|
||||
|
||||
/atom/movable/screen/plane_master/fullscreen
|
||||
name = "fullscreen alert plane"
|
||||
plane = FULLSCREEN_PLANE
|
||||
render_relay_plane = RENDER_PLANE_NON_GAME
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
|
||||
/atom/movable/screen/plane_master/field_of_vision_blocker
|
||||
name = "field of vision blocker plane master"
|
||||
plane = FIELD_OF_VISION_BLOCKER_PLANE
|
||||
render_target = FIELD_OF_VISION_BLOCKER_RENDER_TARGET
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
render_relay_plane = null
|
||||
appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR
|
||||
render_relay_planes = list(RENDER_PLANE_NON_GAME)
|
||||
|
||||
/atom/movable/screen/plane_master/hud
|
||||
name = "HUD plane"
|
||||
name = "HUD"
|
||||
documentation = "Contains anything that want to be rendered on the hud. Typically is just screen elements."
|
||||
plane = HUD_PLANE
|
||||
render_relay_plane = RENDER_PLANE_NON_GAME
|
||||
appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR
|
||||
render_relay_planes = list(RENDER_PLANE_NON_GAME)
|
||||
allows_offsetting = FALSE
|
||||
|
||||
/atom/movable/screen/plane_master/above_hud
|
||||
name = "above HUD plane"
|
||||
name = "Above HUD"
|
||||
documentation = "Anything that wants to be drawn ABOVE the rest of the hud. Typically close buttons and other elements that need to be always visible. Think preventing draggable action button memes."
|
||||
plane = ABOVE_HUD_PLANE
|
||||
render_relay_plane = RENDER_PLANE_NON_GAME
|
||||
appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR
|
||||
render_relay_planes = list(RENDER_PLANE_NON_GAME)
|
||||
allows_offsetting = FALSE
|
||||
|
||||
/atom/movable/screen/plane_master/splashscreen
|
||||
name = "splashscreen plane"
|
||||
name = "Splashscreen"
|
||||
documentation = "Anything that's drawn above LITERALLY everything else. Think cinimatics and the well, spashscreen."
|
||||
plane = SPLASHSCREEN_PLANE
|
||||
render_relay_plane = RENDER_PLANE_NON_GAME
|
||||
|
||||
|
||||
appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR
|
||||
render_relay_planes = list(RENDER_PLANE_NON_GAME)
|
||||
allows_offsetting = FALSE
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
///Atom that manages and controls multiple planes. It's an atom so we can hook into add_filter etc. Multiple controllers can control one plane.
|
||||
/atom/movable/plane_master_controller
|
||||
///List of planes in this controllers control. Initially this is a normal list, but becomes an assoc list of plane numbers as strings | plane instance
|
||||
///List of planes as defines in this controllers control
|
||||
var/list/controlled_planes = list()
|
||||
///hud that owns this controller
|
||||
var/datum/hud/owner_hud
|
||||
@@ -12,71 +12,68 @@ INITIALIZE_IMMEDIATE(/atom/movable/plane_master_controller)
|
||||
. = ..()
|
||||
if(!istype(hud))
|
||||
return
|
||||
|
||||
owner_hud = hud
|
||||
var/assoc_controlled_planes = list()
|
||||
for(var/i in controlled_planes)
|
||||
var/atom/movable/screen/plane_master/instance = owner_hud.plane_masters["[i]"]
|
||||
if(!instance) //If we looked for a hud that isn't instanced, just keep going
|
||||
stack_trace("[i] isn't a valid plane master layer for [owner_hud.type], are you sure it exists in the first place?")
|
||||
continue
|
||||
assoc_controlled_planes["[i]"] = instance
|
||||
controlled_planes = assoc_controlled_planes
|
||||
|
||||
/atom/movable/plane_master_controller/proc/get_planes()
|
||||
var/returned_planes = list()
|
||||
for(var/true_plane in controlled_planes)
|
||||
returned_planes += get_true_plane(true_plane)
|
||||
return returned_planes
|
||||
|
||||
/atom/movable/plane_master_controller/proc/get_true_plane(true_plane)
|
||||
var/list/returned_planes = owner_hud.get_true_plane_masters(true_plane)
|
||||
if(!length(returned_planes)) //If we looked for a hud that isn't instanced, just keep going
|
||||
stack_trace("[plane] isn't a valid plane master layer for [owner_hud.type], are you sure it exists in the first place?")
|
||||
return
|
||||
|
||||
return returned_planes
|
||||
|
||||
///Full override so we can just use filterrific
|
||||
/atom/movable/plane_master_controller/add_filter(name, priority, list/params)
|
||||
. = ..()
|
||||
for(var/i in controlled_planes)
|
||||
var/atom/movable/screen/plane_master/pm_iterator = controlled_planes[i]
|
||||
for(var/atom/movable/screen/plane_master/pm_iterator as anything in get_planes())
|
||||
pm_iterator.add_filter(name, priority, params)
|
||||
|
||||
///Full override so we can just use filterrific
|
||||
/atom/movable/plane_master_controller/remove_filter(name_or_names)
|
||||
. = ..()
|
||||
for(var/i in controlled_planes)
|
||||
var/atom/movable/screen/plane_master/pm_iterator = controlled_planes[i]
|
||||
for(var/atom/movable/screen/plane_master/pm_iterator as anything in get_planes())
|
||||
pm_iterator.remove_filter(name_or_names)
|
||||
|
||||
/atom/movable/plane_master_controller/update_filters()
|
||||
. = ..()
|
||||
for(var/i in controlled_planes)
|
||||
var/atom/movable/screen/plane_master/pm_iterator = controlled_planes[i]
|
||||
for(var/atom/movable/screen/plane_master/pm_iterator as anything in get_planes())
|
||||
pm_iterator.update_filters()
|
||||
|
||||
///Gets all filters for this controllers plane masters
|
||||
/atom/movable/plane_master_controller/proc/get_filters(name)
|
||||
. = list()
|
||||
for(var/i in controlled_planes)
|
||||
var/atom/movable/screen/plane_master/pm_iterator = controlled_planes[i]
|
||||
for(var/atom/movable/screen/plane_master/pm_iterator as anything in get_planes())
|
||||
. += pm_iterator.get_filter(name)
|
||||
|
||||
///Transitions all filters owned by this plane master controller
|
||||
/atom/movable/plane_master_controller/transition_filter(name, time, list/new_params, easing, loop)
|
||||
. = ..()
|
||||
for(var/i in controlled_planes)
|
||||
var/atom/movable/screen/plane_master/pm_iterator = controlled_planes[i]
|
||||
for(var/atom/movable/screen/plane_master/pm_iterator as anything in get_planes())
|
||||
pm_iterator.transition_filter(name, time, new_params, easing, loop)
|
||||
|
||||
///Full override so we can just use filterrific
|
||||
/atom/movable/plane_master_controller/add_atom_colour(coloration, colour_priority)
|
||||
. = ..()
|
||||
for(var/i in controlled_planes)
|
||||
var/atom/movable/screen/plane_master/pm_iterator = controlled_planes[i]
|
||||
for(var/atom/movable/screen/plane_master/pm_iterator as anything in get_planes())
|
||||
pm_iterator.add_atom_colour(coloration, colour_priority)
|
||||
|
||||
|
||||
///Removes an instance of colour_type from the atom's atom_colours list
|
||||
/atom/movable/plane_master_controller/remove_atom_colour(colour_priority, coloration)
|
||||
. = ..()
|
||||
for(var/i in controlled_planes)
|
||||
var/atom/movable/screen/plane_master/pm_iterator = controlled_planes[i]
|
||||
for(var/atom/movable/screen/plane_master/pm_iterator as anything in get_planes())
|
||||
pm_iterator.remove_atom_colour(colour_priority, coloration)
|
||||
|
||||
|
||||
///Resets the atom's color to null, and then sets it to the highest priority colour available
|
||||
/atom/movable/plane_master_controller/update_atom_colour()
|
||||
for(var/i in controlled_planes)
|
||||
var/atom/movable/screen/plane_master/pm_iterator = controlled_planes[i]
|
||||
for(var/atom/movable/screen/plane_master/pm_iterator as anything in get_planes())
|
||||
pm_iterator.update_atom_colour()
|
||||
|
||||
|
||||
@@ -84,7 +81,7 @@ INITIALIZE_IMMEDIATE(/atom/movable/plane_master_controller)
|
||||
name = PLANE_MASTERS_GAME
|
||||
controlled_planes = list(
|
||||
FLOOR_PLANE,
|
||||
TRANSPARENT_FLOOR_PLANE,
|
||||
RENDER_PLANE_TRANSPARENT,
|
||||
GAME_PLANE,
|
||||
GAME_PLANE_FOV_HIDDEN,
|
||||
GAME_PLANE_UPPER,
|
||||
@@ -108,7 +105,7 @@ INITIALIZE_IMMEDIATE(/atom/movable/plane_master_controller)
|
||||
GAME_PLANE_FOV_HIDDEN,
|
||||
GAME_PLANE_UPPER,
|
||||
GAME_PLANE_UPPER_FOV_HIDDEN,
|
||||
ABOVE_GAME_NO_MOUSE_PLANE,
|
||||
SEETHROUGH_PLANE,
|
||||
ABOVE_GAME_PLANE,
|
||||
MASSIVE_OBJ_PLANE,
|
||||
GHOST_PLANE,
|
||||
@@ -118,8 +115,9 @@ INITIALIZE_IMMEDIATE(/atom/movable/plane_master_controller)
|
||||
ABOVE_LIGHTING_PLANE,
|
||||
CAMERA_STATIC_PLANE,
|
||||
PIPECRAWL_IMAGES_PLANE,
|
||||
ATMOS_GROUP_PLANE,
|
||||
HIGH_GAME_PLANE,
|
||||
FULLSCREEN_PLANE,
|
||||
SOUND_EFFECT_VISUAL_PLANE,
|
||||
RUNECHAT_PLANE,
|
||||
HUD_PLANE,
|
||||
ABOVE_HUD_PLANE,
|
||||
|
||||
153
code/_onclick/hud/rendering/plane_master_group.dm
Normal file
153
code/_onclick/hud/rendering/plane_master_group.dm
Normal file
@@ -0,0 +1,153 @@
|
||||
/// Datum that represents one "group" of plane masters
|
||||
/// So all the main window planes would be in one, all the spyglass planes in another
|
||||
/// Etc
|
||||
/datum/plane_master_group
|
||||
/// Our key in the group list on /datum/hud
|
||||
/// Should be unique for any group of plane masters in the world
|
||||
var/key
|
||||
/// Our parent hud
|
||||
var/datum/hud/our_hud
|
||||
/// List in the form "[plane]" = object, the plane masters we own
|
||||
var/list/atom/movable/screen/plane_master/plane_masters = list()
|
||||
/// The visual offset we are currently using
|
||||
var/active_offset = 0
|
||||
|
||||
/// What, if any, submap we render onto
|
||||
var/map = ""
|
||||
|
||||
/datum/plane_master_group/New(key, map = "")
|
||||
. = ..()
|
||||
src.key = key
|
||||
src.map = map
|
||||
build_plane_masters(0, SSmapping.max_plane_offset)
|
||||
|
||||
/datum/plane_master_group/Destroy()
|
||||
orphan_hud()
|
||||
QDEL_LIST_ASSOC_VAL(plane_masters)
|
||||
return ..()
|
||||
|
||||
/// Display a plane master group to some viewer, so show all our planes to it
|
||||
/datum/plane_master_group/proc/attach_to(datum/hud/viewing_hud)
|
||||
if(viewing_hud.master_groups[key])
|
||||
stack_trace("Hey brother, our key [key] is already in use by a plane master group on the passed in hud, belonging to [viewing_hud.mymob]. Ya fucked up, why are there dupes")
|
||||
return
|
||||
|
||||
our_hud = viewing_hud
|
||||
our_hud.master_groups[key] = src
|
||||
show_hud()
|
||||
transform_lower_turfs(our_hud, active_offset)
|
||||
|
||||
/// Hide the plane master from its current hud, fully clear it out
|
||||
/datum/plane_master_group/proc/orphan_hud()
|
||||
if(our_hud)
|
||||
our_hud.master_groups -= key
|
||||
hide_hud()
|
||||
our_hud = null
|
||||
|
||||
/// Well, refresh our group, mostly useful for plane specific updates
|
||||
/datum/plane_master_group/proc/refresh_hud()
|
||||
hide_hud()
|
||||
show_hud()
|
||||
|
||||
/// Fully regenerate our group, resetting our planes to their compile time values
|
||||
/datum/plane_master_group/proc/rebuild_hud()
|
||||
hide_hud()
|
||||
QDEL_LIST_ASSOC_VAL(plane_masters)
|
||||
build_plane_masters(0, SSmapping.max_plane_offset)
|
||||
show_hud()
|
||||
transform_lower_turfs(our_hud, active_offset)
|
||||
|
||||
/datum/plane_master_group/proc/hide_hud()
|
||||
for(var/thing in plane_masters)
|
||||
var/atom/movable/screen/plane_master/plane = plane_masters[thing]
|
||||
plane.hide_from(our_hud.mymob)
|
||||
|
||||
/datum/plane_master_group/proc/show_hud()
|
||||
for(var/thing in plane_masters)
|
||||
var/atom/movable/screen/plane_master/plane = plane_masters[thing]
|
||||
show_plane(plane)
|
||||
|
||||
/// This is mostly a proc so it can be overriden by popups, since they have unique behavior they want to do
|
||||
/datum/plane_master_group/proc/show_plane(atom/movable/screen/plane_master/plane)
|
||||
plane.show_to(our_hud.mymob)
|
||||
|
||||
/// Returns a list of all the plane master types we want to create
|
||||
/datum/plane_master_group/proc/get_plane_types()
|
||||
return subtypesof(/atom/movable/screen/plane_master) - /atom/movable/screen/plane_master/rendering_plate
|
||||
|
||||
/// Actually generate our plane masters, in some offset range (where offset is the z layers to render to, because each "layer" in a multiz stack gets its own plane master cube)
|
||||
/datum/plane_master_group/proc/build_plane_masters(starting_offset, ending_offset)
|
||||
for(var/atom/movable/screen/plane_master/mytype as anything in get_plane_types())
|
||||
for(var/plane_offset in starting_offset to ending_offset)
|
||||
if(plane_offset != 0 && !initial(mytype.allows_offsetting))
|
||||
continue
|
||||
var/atom/movable/screen/plane_master/instance = new mytype(null, src, plane_offset)
|
||||
plane_masters["[instance.plane]"] = instance
|
||||
prep_plane_instance(instance)
|
||||
|
||||
/// Similarly, exists so subtypes can do unique behavior to planes on creation
|
||||
/datum/plane_master_group/proc/prep_plane_instance(atom/movable/screen/plane_master/instance)
|
||||
return
|
||||
|
||||
// It would be nice to setup parallaxing for stairs and things when doing this
|
||||
// So they look nicer. if you can't it's all good, if you think you can sanely look at monster's work
|
||||
// It's hard, and potentially expensive. be careful
|
||||
/datum/plane_master_group/proc/transform_lower_turfs(datum/hud/source, new_offset, use_scale = TRUE)
|
||||
// No offset? piss off
|
||||
if(!SSmapping.max_plane_offset)
|
||||
return
|
||||
active_offset = new_offset
|
||||
// Each time we go "down" a visual z level, we'll reduce the scale by this amount
|
||||
// Chosen because mothblocks liked it, didn't cause motion sickness while also giving a sense of height
|
||||
var/scale_by = 0.965
|
||||
// If our mob can see through walls
|
||||
if(!use_scale)
|
||||
// This is a workaround for two things
|
||||
// First of all, if a mob can see objects but not turfs, they will not be shown the holder objects we use for
|
||||
// What I'd like to do is revert to images if this case throws, but image vis_contents is broken
|
||||
// https://www.byond.com/forum/post/2821969
|
||||
// If that's ever fixed, please just use that. thanks :)
|
||||
scale_by = 1
|
||||
|
||||
var/list/offsets = list()
|
||||
// We accept negatives so going down "zooms" away the drop above as it goes
|
||||
for(var/offset in -SSmapping.max_plane_offset to SSmapping.max_plane_offset)
|
||||
// No transformations if we're landing ON you
|
||||
if(offset == 0)
|
||||
offsets += null
|
||||
continue
|
||||
var/scale = scale_by ** (offset)
|
||||
var/matrix/multiz_shrink = matrix()
|
||||
multiz_shrink.Scale(scale)
|
||||
offsets += multiz_shrink
|
||||
|
||||
// So we can talk in 1 -> max_offset * 2 + 1, rather then -max_offset -> max_offset
|
||||
var/offset_offset = SSmapping.max_plane_offset + 1
|
||||
|
||||
for(var/plane_key in plane_masters)
|
||||
var/atom/movable/screen/plane_master/plane = plane_masters[plane_key]
|
||||
if(!plane.multiz_scaled || !plane.allows_offsetting)
|
||||
continue
|
||||
var/visual_offset = plane.offset - new_offset
|
||||
if(plane.force_hidden || visual_offset < 0)
|
||||
// We don't animate here because it should be invisble, but we do mark because it'll look nice
|
||||
plane.transform = offsets[visual_offset + offset_offset]
|
||||
continue
|
||||
animate(plane, transform = offsets[visual_offset + offset_offset], 0.05 SECONDS, easing = LINEAR_EASING)
|
||||
|
||||
/// Holds plane masters for popups, like camera windows
|
||||
/// Note: We do not scale this plane, even though we could
|
||||
/// This is because it's annoying to get turfs to position inside it correctly
|
||||
/// If you wanna try someday feel free, but I can't manage it
|
||||
/datum/plane_master_group/popup
|
||||
|
||||
/datum/plane_master_group/popup/transform_lower_turfs(datum/hud/source, new_offset, use_scale = TRUE)
|
||||
return ..(source, new_offset, FALSE)
|
||||
|
||||
/// Holds the main plane master
|
||||
/datum/plane_master_group/main
|
||||
|
||||
/datum/plane_master_group/main/transform_lower_turfs(datum/hud/source, new_offset, use_scale = TRUE)
|
||||
if(use_scale)
|
||||
return ..(source, new_offset, source.should_use_scale())
|
||||
return ..()
|
||||
@@ -24,61 +24,264 @@
|
||||
* remember that once planes are unified on a render plate you cant change the layering of them!
|
||||
*/
|
||||
/atom/movable/screen/plane_master/rendering_plate
|
||||
name = "default rendering plate"
|
||||
|
||||
name = "Default rendering plate"
|
||||
multiz_scaled = FALSE
|
||||
|
||||
///this plate renders the final screen to show to the player
|
||||
/atom/movable/screen/plane_master/rendering_plate/master
|
||||
name = "master rendering plate"
|
||||
name = "Master rendering plate"
|
||||
documentation = "The endpoint of all plane masters, you can think of this as the final \"view\" we draw.\
|
||||
<br>If offset is not 0 this will be drawn to the transparent plane of the floor above, but otherwise this is drawn to nothing, or shown to the player."
|
||||
plane = RENDER_PLANE_MASTER
|
||||
render_relay_plane = null
|
||||
generate_render_target = FALSE
|
||||
render_relay_planes = list()
|
||||
|
||||
/atom/movable/screen/plane_master/rendering_plate/master/show_to(mob/mymob)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
if(offset == 0)
|
||||
return
|
||||
// Non 0 offset render plates will relay up to the transparent plane above them, assuming they're not on the same z level as their target of course
|
||||
var/datum/hud/hud = home.our_hud
|
||||
if(hud)
|
||||
RegisterSignal(hud, COMSIG_HUD_OFFSET_CHANGED, .proc/on_offset_change)
|
||||
offset_change(hud.current_plane_offset)
|
||||
|
||||
/atom/movable/screen/plane_master/rendering_plate/master/hide_from(mob/oldmob)
|
||||
. = ..()
|
||||
if(offset == 0)
|
||||
return
|
||||
var/datum/hud/hud = home.our_hud
|
||||
if(hud)
|
||||
UnregisterSignal(hud, COMSIG_HUD_OFFSET_CHANGED, .proc/on_offset_change)
|
||||
|
||||
/atom/movable/screen/plane_master/rendering_plate/master/proc/on_offset_change(datum/source, old_offset, new_offset)
|
||||
SIGNAL_HANDLER
|
||||
offset_change(new_offset)
|
||||
|
||||
/atom/movable/screen/plane_master/rendering_plate/master/proc/offset_change(new_offset)
|
||||
if(new_offset == offset) // If we're on our own z layer, relay to nothing, just draw
|
||||
remove_relay_from(GET_NEW_PLANE(RENDER_PLANE_TRANSPARENT, offset - 1))
|
||||
else // Otherwise, regenerate the relay
|
||||
add_relay_to(GET_NEW_PLANE(RENDER_PLANE_TRANSPARENT, offset - 1))
|
||||
|
||||
///renders general in charachter game objects
|
||||
/atom/movable/screen/plane_master/rendering_plate/game_world
|
||||
name = "game rendering plate"
|
||||
/atom/movable/screen/plane_master/rendering_plate/game_plate
|
||||
name = "Game rendering plate"
|
||||
documentation = "Holds all objects that are ahhh, in character? is maybe the best way to describe it.\
|
||||
<br>We apply a displacement effect from the gravity pulse plane too, so we can warp the game world."
|
||||
plane = RENDER_PLANE_GAME
|
||||
render_relay_plane = RENDER_PLANE_MASTER
|
||||
render_relay_planes = list(RENDER_PLANE_MASTER)
|
||||
|
||||
/atom/movable/screen/plane_master/rendering_plate/game_world/Initialize(mapload)
|
||||
/atom/movable/screen/plane_master/rendering_plate/game_plate/Initialize(mapload)
|
||||
. = ..()
|
||||
add_filter("displacer", 1, displacement_map_filter(render_source = GRAVITY_PULSE_RENDER_TARGET, size = 10))
|
||||
add_filter("displacer", 1, displacement_map_filter(render_source = OFFSET_RENDER_TARGET(GRAVITY_PULSE_RENDER_TARGET, offset), size = 10))
|
||||
|
||||
/atom/movable/screen/plane_master/rendering_plate/transparent
|
||||
name = "Transparent plate"
|
||||
documentation = "The master rendering plate from the offset below ours will be mirrored onto this plane. That way we achive a \"stack\" effect.\
|
||||
<br>This plane exists to uplayer the master rendering plate to the correct spot in our z layer's rendering order"
|
||||
plane = RENDER_PLANE_TRANSPARENT
|
||||
appearance_flags = PLANE_MASTER
|
||||
|
||||
/atom/movable/screen/plane_master/rendering_plate/transparent/Initialize(mapload, datum/plane_master_group/home, offset)
|
||||
. = ..()
|
||||
// Don't display us if we're below everything else yeah?
|
||||
AddComponent(/datum/component/plane_hide_highest_offset)
|
||||
color = list(0.9,0,0,0, 0,0.9,0,0, 0,0,0.9,0, 0,0,0,1, 0,0,0,0)
|
||||
|
||||
///Contains most things in the game world
|
||||
/atom/movable/screen/plane_master/rendering_plate/game_world
|
||||
name = "Game world plate"
|
||||
documentation = "Contains most of the objects in the world. Mobs, machines, etc. Note the drop shadow, it gives a very nice depth effect."
|
||||
plane = RENDER_PLANE_GAME_WORLD
|
||||
appearance_flags = PLANE_MASTER //should use client color
|
||||
blend_mode = BLEND_OVERLAY
|
||||
|
||||
/atom/movable/screen/plane_master/rendering_plate/game_world/show_to(mob/mymob)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
remove_filter("AO")
|
||||
if(istype(mymob) && mymob.client?.prefs?.read_preference(/datum/preference/toggle/ambient_occlusion))
|
||||
add_filter("AO", 1, drop_shadow_filter(x = 0, y = -2, size = 4, color = "#04080FAA"))
|
||||
|
||||
///Contains all lighting objects
|
||||
/atom/movable/screen/plane_master/rendering_plate/lighting
|
||||
name = "Lighting plate"
|
||||
documentation = "Anything on this plane will be <b>multiplied</b> with the plane it's rendered onto (typically the game plane).\
|
||||
<br>That's how lighting functions at base. Because it uses BLEND_MULTIPLY and occasionally color matrixes, it needs a backdrop of blackness.\
|
||||
<br>See <a href=\"https://secure.byond.com/forum/?post=2141928\">This byond post</a>\
|
||||
<br>Lemme see uh, we're masked by the emissive plane so it can actually function (IE: make things glow in the dark).\
|
||||
<br>We're also masked by the overlay lighting plane, which contains all the movable lights in the game. It draws to us and also the game plane.\
|
||||
<br>Masks us out so it has the breathing room to apply its effect.\
|
||||
<br>Oh and we quite often have our alpha changed to achive night vision effects, or things of that sort."
|
||||
plane = RENDER_PLANE_LIGHTING
|
||||
blend_mode_override = BLEND_MULTIPLY
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
|
||||
/atom/movable/screen/plane_master/rendering_plate/lighting/show_to(mob/mymob)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
// This applies a backdrop to our lighting plane
|
||||
// Why do plane masters need a backdrop sometimes? Read https://secure.byond.com/forum/?post=2141928
|
||||
// Basically, we need something to brighten
|
||||
// unlit is perhaps less needed rn, it exists to provide a fullbright for things that can't see the lighting plane
|
||||
// but we don't actually use invisibility to hide the lighting plane anymore, so it's pointless
|
||||
mymob.overlay_fullscreen("lighting_backdrop_lit", /atom/movable/screen/fullscreen/lighting_backdrop/lit)
|
||||
mymob.overlay_fullscreen("lighting_backdrop_unlit", /atom/movable/screen/fullscreen/lighting_backdrop/unlit)
|
||||
|
||||
// Sorry, this is a bit annoying
|
||||
// Basically, we only want the lighting plane we can actually see to attempt to render
|
||||
// If we don't our lower plane gets totally overriden by the black void of the upper plane
|
||||
var/datum/hud/hud = home.our_hud
|
||||
if(hud)
|
||||
RegisterSignal(hud, COMSIG_HUD_OFFSET_CHANGED, .proc/on_offset_change)
|
||||
offset_change(hud.current_plane_offset)
|
||||
set_alpha(mymob.lighting_alpha)
|
||||
|
||||
|
||||
/atom/movable/screen/plane_master/rendering_plate/lighting/hide_from(mob/oldmob)
|
||||
. = ..()
|
||||
oldmob.clear_fullscreen("lighting_backdrop_lit")
|
||||
oldmob.clear_fullscreen("lighting_backdrop_unlit")
|
||||
var/datum/hud/hud = home.our_hud
|
||||
if(hud)
|
||||
UnregisterSignal(hud, COMSIG_HUD_OFFSET_CHANGED, .proc/on_offset_change)
|
||||
|
||||
/atom/movable/screen/plane_master/rendering_plate/lighting/proc/on_offset_change(datum/source, old_offset, new_offset)
|
||||
SIGNAL_HANDLER
|
||||
offset_change(new_offset)
|
||||
|
||||
/atom/movable/screen/plane_master/rendering_plate/lighting/proc/offset_change(mob_offset)
|
||||
// Offsets stack down remember. This implies that we're above the mob's view plane, and shouldn't render
|
||||
if(offset < mob_offset)
|
||||
disable_alpha()
|
||||
else
|
||||
enable_alpha()
|
||||
|
||||
/*!
|
||||
* This system works by exploiting BYONDs color matrix filter to use layers to handle emissive blockers.
|
||||
*
|
||||
* Emissive overlays are pasted with an atom color that converts them to be entirely some specific color.
|
||||
* Emissive blockers are pasted with an atom color that converts them to be entirely some different color.
|
||||
* Emissive overlays and emissive blockers are put onto the same plane.
|
||||
* The layers for the emissive overlays and emissive blockers cause them to mask eachother similar to normal BYOND objects.
|
||||
* A color matrix filter is applied to the emissive plane to mask out anything that isn't whatever the emissive color is.
|
||||
* This is then used to alpha mask the lighting plane.
|
||||
*/
|
||||
/atom/movable/screen/plane_master/rendering_plate/lighting/Initialize(mapload)
|
||||
. = ..()
|
||||
add_filter("emissives", 1, alpha_mask_filter(render_source = OFFSET_RENDER_TARGET(EMISSIVE_RENDER_TARGET, offset), flags = MASK_INVERSE))
|
||||
add_filter("object_lighting", 2, alpha_mask_filter(render_source = OFFSET_RENDER_TARGET(O_LIGHTING_VISUAL_RENDER_TARGET, offset), flags = MASK_INVERSE))
|
||||
|
||||
///render plate for OOC stuff like ghosts, hud-screen effects, etc
|
||||
/atom/movable/screen/plane_master/rendering_plate/non_game
|
||||
name = "non-game rendering plate"
|
||||
name = "Non-Game rendering plate"
|
||||
documentation = "Renders anything that's out of character. Mostly useful as a converse to the game rendering plate."
|
||||
plane = RENDER_PLANE_NON_GAME
|
||||
render_relay_plane = RENDER_PLANE_MASTER
|
||||
render_relay_planes = list(RENDER_PLANE_MASTER)
|
||||
|
||||
|
||||
/**
|
||||
* Plane master proc called in backdrop() that creates a relay object, sets it as needed and then adds it to the clients screen
|
||||
* Plane master proc called in Initialize() that creates relay objects, and sets them uo as needed
|
||||
* Sets:
|
||||
* * layer from plane to avoid z-fighting
|
||||
* * plane to relay the render to
|
||||
* * render_source so that the plane will render on this object
|
||||
* * planes to relay the render to
|
||||
* * render_source so that the plane will render on these objects
|
||||
* * mouse opacity to ensure proper mouse hit tracking
|
||||
* * name for debugging purposes
|
||||
* Other vars such as alpha will automatically be applied with the render source
|
||||
* Arguments:
|
||||
* * mymob: mob whose plane is being backdropped
|
||||
* * relay_plane: plane we are relaying this plane master to
|
||||
*/
|
||||
/atom/movable/screen/plane_master/proc/relay_render_to_plane(mob/mymob, relay_plane)
|
||||
if(relay in mymob.client.screen) //backdrop can be called multiple times
|
||||
return
|
||||
if(!render_target && generate_render_target)
|
||||
render_target = "*[name]: AUTOGENERATED RENDER TGT"
|
||||
relay = new()
|
||||
relay.render_source = render_target
|
||||
relay.plane = relay_plane
|
||||
relay.layer = (plane + abs(LOWEST_EVER_PLANE))*0.5 //layer must be positive but can be a decimal
|
||||
if(blend_mode_override)
|
||||
relay.blend_mode = blend_mode_override
|
||||
else
|
||||
relay.blend_mode = blend_mode
|
||||
relay.mouse_opacity = mouse_opacity
|
||||
relay.name = render_target
|
||||
mymob.client.screen += relay
|
||||
/atom/movable/screen/plane_master/proc/generate_render_relays()
|
||||
var/relay_loc = "CENTER"
|
||||
// If we're using a submap (say for a popup window) make sure we draw onto it
|
||||
if(home?.map)
|
||||
relay_loc = "[home.map]:[relay_loc]"
|
||||
|
||||
var/list/generated_planes = list()
|
||||
for(var/atom/movable/render_plane_relay/relay as anything in relays)
|
||||
generated_planes += relay.plane
|
||||
|
||||
for(var/relay_plane in (render_relay_planes - generated_planes))
|
||||
generate_relay_to(relay_plane, relay_loc)
|
||||
|
||||
if(blend_mode != BLEND_MULTIPLY)
|
||||
blend_mode = BLEND_DEFAULT
|
||||
relays_generated = TRUE
|
||||
|
||||
/// Creates a connection between this plane master and the passed in plane
|
||||
/// Helper for out of system code, shouldn't be used in this file
|
||||
/// Build system to differenchiate between generated and non generated render relays
|
||||
/atom/movable/screen/plane_master/proc/add_relay_to(target_plane, blend_override)
|
||||
if(get_relay_to(target_plane))
|
||||
return
|
||||
render_relay_planes += target_plane
|
||||
if(!relays_generated && isnull(blend_override))
|
||||
return
|
||||
var/client/display_lad = home?.our_hud?.mymob?.client
|
||||
generate_relay_to(target_plane, show_to = display_lad, blend_override = blend_override)
|
||||
|
||||
/proc/get_plane_master_render_base(name)
|
||||
return "*[name]: AUTOGENERATED RENDER TGT"
|
||||
|
||||
/atom/movable/screen/plane_master/proc/generate_relay_to(target_plane, relay_loc, client/show_to, blend_override)
|
||||
if(!length(relays) && !initial(render_target))
|
||||
render_target = OFFSET_RENDER_TARGET(get_plane_master_render_base(name), offset)
|
||||
if(!relay_loc)
|
||||
relay_loc = "CENTER"
|
||||
// If we're using a submap (say for a popup window) make sure we draw onto it
|
||||
if(home?.map)
|
||||
relay_loc = "[home.map]:[relay_loc]"
|
||||
var/blend_to_use = blend_override
|
||||
if(isnull(blend_to_use))
|
||||
blend_to_use = blend_mode_override || initial(blend_mode)
|
||||
|
||||
var/atom/movable/render_plane_relay/relay = new()
|
||||
relay.render_source = render_target
|
||||
relay.plane = target_plane
|
||||
relay.screen_loc = relay_loc
|
||||
// There are two rules here
|
||||
// 1: layer needs to be positive (negative layers are treated as float layers)
|
||||
// 2: lower planes (including offset ones) need to be layered below higher ones (because otherwise they'll render fucky)
|
||||
// By multiplying LOWEST_EVER_PLANE by 30, we give 30 offsets worth of room to planes before they start going negative
|
||||
// Bet
|
||||
relay.layer = (plane + abs(LOWEST_EVER_PLANE * 30)) //layer must be positive but can be a decimal
|
||||
relay.blend_mode = blend_to_use
|
||||
relay.mouse_opacity = mouse_opacity
|
||||
relay.name = render_target
|
||||
relays += relay
|
||||
// Relays are sometimes generated early, before huds have a mob to display stuff to
|
||||
// That's what this is for
|
||||
if(show_to)
|
||||
show_to.screen += relay
|
||||
return relay
|
||||
|
||||
/// Breaks a connection between this plane master, and the passed in place
|
||||
/atom/movable/screen/plane_master/proc/remove_relay_from(target_plane)
|
||||
render_relay_planes -= target_plane
|
||||
var/atom/movable/render_plane_relay/existing_relay = get_relay_to(target_plane)
|
||||
if(!existing_relay)
|
||||
return
|
||||
relays -= existing_relay
|
||||
if(!length(relays) && !initial(render_target))
|
||||
render_target = null
|
||||
var/client/lad = home?.our_hud?.mymob?.client
|
||||
if(lad)
|
||||
lad.screen -= existing_relay
|
||||
|
||||
/// Gets the relay atom we're using to connect to the target plane, if one exists
|
||||
/atom/movable/screen/plane_master/proc/get_relay_to(target_plane)
|
||||
for(var/atom/movable/render_plane_relay/relay in relays)
|
||||
if(relay.plane == target_plane)
|
||||
return relay
|
||||
|
||||
return null
|
||||
|
||||
/// Basically, trigger a full hud rebuild so our relays will be added to the screen
|
||||
/// I hate hud code
|
||||
/atom/movable/screen/plane_master/proc/rebuild_relays()
|
||||
relays = list()
|
||||
var/datum/hud/hud = home.our_hud
|
||||
hud.show_hud(hud.hud_version)
|
||||
|
||||
@@ -136,6 +136,8 @@
|
||||
static_inventory += using
|
||||
robit.interfaceButton = using
|
||||
if(robit.modularInterface)
|
||||
// Just trust me
|
||||
robit.modularInterface.vis_flags |= VIS_INHERIT_PLANE
|
||||
using.vis_contents += robit.modularInterface
|
||||
var/atom/movable/screen/robot/modpc/tabletbutton = using
|
||||
tabletbutton.robot = robit
|
||||
@@ -230,7 +232,7 @@
|
||||
A.screen_loc = "CENTER[x]:16,SOUTH+[y]:7"
|
||||
else
|
||||
A.screen_loc = "CENTER+[x]:16,SOUTH+[y]:7"
|
||||
A.plane = ABOVE_HUD_PLANE
|
||||
SET_PLANE_IMPLICIT(A, ABOVE_HUD_PLANE)
|
||||
|
||||
x++
|
||||
if(x == 4)
|
||||
|
||||
@@ -9,10 +9,11 @@
|
||||
/atom/movable/screen
|
||||
name = ""
|
||||
icon = 'icons/hud/screen_gen.dmi'
|
||||
// NOTE: screen objects do NOT change their plane to match the z layer of their owner
|
||||
// You shouldn't need this, but if you ever do and it's widespread, reconsider what you're doing.
|
||||
plane = HUD_PLANE
|
||||
animate_movement = SLIDE_STEPS
|
||||
speech_span = SPAN_ROBOT
|
||||
vis_flags = VIS_INHERIT_PLANE
|
||||
appearance_flags = APPEARANCE_UI
|
||||
/// A reference to the object in the slot. Grabs or items, generally.
|
||||
var/obj/master = null
|
||||
@@ -455,6 +456,7 @@
|
||||
vis_contents -= hover_overlays_cache[hovering]
|
||||
hovering = choice
|
||||
|
||||
// Don't need to account for turf cause we're on the hud babyyy
|
||||
var/obj/effect/overlay/zone_sel/overlay_object = hover_overlays_cache[choice]
|
||||
if(!overlay_object)
|
||||
overlay_object = new
|
||||
|
||||
@@ -282,7 +282,7 @@
|
||||
|
||||
var/mutable_appearance/focus_overlay = new(focus)
|
||||
focus_overlay.layer = layer + 0.01
|
||||
focus_overlay.plane = ABOVE_HUD_PLANE
|
||||
SET_PLANE_EXPLICIT(focus_overlay, ABOVE_HUD_PLANE, focus)
|
||||
. += focus_overlay
|
||||
|
||||
/obj/item/tk_grab/suicide_act(mob/user)
|
||||
|
||||
@@ -627,12 +627,16 @@ GLOBAL_LIST_EMPTY(colored_turfs)
|
||||
GLOBAL_LIST_EMPTY(colored_images)
|
||||
/datum/controller/subsystem/air/proc/setup_turf_visuals()
|
||||
for(var/sharp_color in GLOB.contrast_colors)
|
||||
var/obj/effect/overlay/atmos_excited/suger_high = new()
|
||||
GLOB.colored_turfs += suger_high
|
||||
var/image/shiny = new('icons/effects/effects.dmi', suger_high, "atmos_top")
|
||||
shiny.plane = ATMOS_GROUP_PLANE
|
||||
shiny.color = sharp_color
|
||||
GLOB.colored_images += shiny
|
||||
var/list/add_to = list()
|
||||
GLOB.colored_turfs += list(add_to)
|
||||
for(var/offset in 0 to SSmapping.max_plane_offset)
|
||||
var/obj/effect/overlay/atmos_excited/suger_high = new()
|
||||
SET_PLANE_W_SCALAR(suger_high, HIGH_GAME_PLANE, offset)
|
||||
add_to += suger_high
|
||||
var/image/shiny = new('icons/effects/effects.dmi', suger_high, "atmos_top")
|
||||
SET_PLANE_W_SCALAR(shiny, HIGH_GAME_PLANE, offset)
|
||||
shiny.color = sharp_color
|
||||
GLOB.colored_images += shiny
|
||||
|
||||
/datum/controller/subsystem/air/proc/setup_template_machinery(list/atmos_machines)
|
||||
var/obj/machinery/atmospherics/AM
|
||||
@@ -788,8 +792,7 @@ GLOBAL_LIST_EMPTY(colored_images)
|
||||
#else
|
||||
data["display_max"] = FALSE
|
||||
#endif
|
||||
var/atom/movable/screen/plane_master/plane = user.hud_used.plane_masters["[ATMOS_GROUP_PLANE]"]
|
||||
data["showing_user"] = (plane.alpha == 255)
|
||||
data["showing_user"] = user.hud_used.atmos_debug_overlays
|
||||
return data
|
||||
|
||||
/datum/controller/subsystem/air/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
|
||||
@@ -827,13 +830,10 @@ GLOBAL_LIST_EMPTY(colored_images)
|
||||
group.hide_turfs()
|
||||
return TRUE
|
||||
if("toggle_user_display")
|
||||
var/atom/movable/screen/plane_master/plane = ui.user.hud_used.plane_masters["[ATMOS_GROUP_PLANE]"]
|
||||
if(!plane.alpha)
|
||||
if(ui.user.client)
|
||||
ui.user.client.images += GLOB.colored_images
|
||||
plane.alpha = 255
|
||||
var/mob/user = ui.user
|
||||
user.hud_used.atmos_debug_overlays = !user.hud_used.atmos_debug_overlays
|
||||
if(user.hud_used.atmos_debug_overlays)
|
||||
user.client.images += GLOB.colored_images
|
||||
else
|
||||
if(ui.user.client)
|
||||
ui.user.client.images -= GLOB.colored_images
|
||||
plane.alpha = 0
|
||||
user.client.images -= GLOB.colored_images
|
||||
return TRUE
|
||||
|
||||
@@ -30,6 +30,25 @@ SUBSYSTEM_DEF(mapping)
|
||||
var/list/holodeck_templates = list()
|
||||
|
||||
var/list/areas_in_z = list()
|
||||
/// List of z level (as number) -> plane offset of that z level
|
||||
/// Used to maintain the plane cube
|
||||
var/list/z_level_to_plane_offset = list()
|
||||
/// List of z level (as number) -> The lowest plane offset in that z stack
|
||||
var/list/z_level_to_lowest_plane_offset = list()
|
||||
// This pair allows for easy conversion between an offset plane, and its true representation
|
||||
// Both are in the form "input plane" -> output plane(s)
|
||||
/// Assoc list of string plane values to their true, non offset representation
|
||||
var/list/plane_offset_to_true
|
||||
/// Assoc list of true string plane values to a list of all potential offset planess
|
||||
var/list/true_to_offset_planes
|
||||
/// Assoc list of string plane to the plane's offset value
|
||||
var/list/plane_to_offset
|
||||
/// List of planes that do not allow for offsetting
|
||||
var/list/plane_offset_blacklist
|
||||
/// List of render targets that do not allow for offsetting
|
||||
var/list/render_offset_blacklist
|
||||
/// The largest plane offset we've generated so far
|
||||
var/max_plane_offset = 0
|
||||
|
||||
var/loading_ruins = FALSE
|
||||
var/list/turf/unused_turfs = list() //Not actually unused turfs they're unused but reserved for use for whatever requests them. "[zlevel_of_turf]" = list(turfs)
|
||||
@@ -80,6 +99,17 @@ SUBSYSTEM_DEF(mapping)
|
||||
if(!config || config.defaulted)
|
||||
to_chat(world, span_boldannounce("Unable to load next or default map config, defaulting to Meta Station."))
|
||||
config = old_config
|
||||
plane_offset_to_true = list()
|
||||
true_to_offset_planes = list()
|
||||
plane_to_offset = list()
|
||||
// VERY special cases for FLOAT_PLANE, so it will be treated as expected by plane management logic
|
||||
// Sorry :(
|
||||
plane_offset_to_true["[FLOAT_PLANE]"] = FLOAT_PLANE
|
||||
true_to_offset_planes["[FLOAT_PLANE]"] = list(FLOAT_PLANE)
|
||||
plane_to_offset["[FLOAT_PLANE]"] = 0
|
||||
plane_offset_blacklist = list()
|
||||
render_offset_blacklist = list()
|
||||
create_plane_offsets(0, 0)
|
||||
initialize_biomes()
|
||||
loadWorld()
|
||||
determine_fake_sale()
|
||||
@@ -678,3 +708,108 @@ GLOBAL_LIST_EMPTY(the_station_areas)
|
||||
isolated_ruins_z = add_new_zlevel("Isolated Ruins/Reserved", list(ZTRAIT_RESERVED = TRUE, ZTRAIT_ISOLATED_RUINS = TRUE))
|
||||
initialize_reserved_level(isolated_ruins_z.z_value)
|
||||
return isolated_ruins_z.z_value
|
||||
|
||||
/// Takes a z level datum, and tells the mapping subsystem to manage it
|
||||
/// Also handles things like plane offset generation, and other things that happen on a z level to z level basis
|
||||
/datum/controller/subsystem/mapping/proc/manage_z_level(datum/space_level/new_z)
|
||||
// First, add the z
|
||||
z_list += new_z
|
||||
|
||||
// Then we build our lookup lists
|
||||
var/z_value = new_z.z_value
|
||||
// We are guarenteed that we'll always grow bottom up
|
||||
// Suck it jannies
|
||||
z_level_to_plane_offset.len += 1
|
||||
z_level_to_lowest_plane_offset += 1
|
||||
// 0's the default value, we'll update it later if required
|
||||
z_level_to_plane_offset[z_value] = 0
|
||||
z_level_to_lowest_plane_offset[z_value] = 0
|
||||
|
||||
// Now we check if this plane is offset or not
|
||||
var/below_offset = new_z.traits[ZTRAIT_DOWN]
|
||||
if(below_offset)
|
||||
update_plane_tracking(new_z)
|
||||
|
||||
// And finally, misc global generation
|
||||
|
||||
// We'll have to update this if offsets change, because we load lowest z to highest z
|
||||
generate_lighting_appearance_by_z(z_value)
|
||||
|
||||
/datum/controller/subsystem/mapping/proc/update_plane_tracking(datum/space_level/update_with)
|
||||
// We're essentially going to walk down the stack of connected z levels, and set their plane offset as we go
|
||||
// Yes this will cause infinite loops if our templating is fucked. Fuck off
|
||||
var/below_offset = 0
|
||||
// I'm sorry, it needs to start at 0
|
||||
var/current_level = -1
|
||||
var/current_z = update_with.z_value
|
||||
var/list/datum/space_level/levels_checked = list()
|
||||
do
|
||||
current_level += 1
|
||||
current_z += below_offset
|
||||
z_level_to_plane_offset[current_z] = current_level
|
||||
var/datum/space_level/next_level = z_list[current_z]
|
||||
below_offset = next_level.traits[ZTRAIT_DOWN]
|
||||
levels_checked += next_level
|
||||
while(below_offset)
|
||||
|
||||
/// Updates the lowest offset value
|
||||
for(var/datum/space_level/level_to_update in levels_checked)
|
||||
z_level_to_lowest_plane_offset[level_to_update.z_value] = current_level
|
||||
|
||||
// This can be affected by offsets, so we need to update it
|
||||
// PAIN
|
||||
for(var/i in 1 to length(z_list))
|
||||
generate_lighting_appearance_by_z(i)
|
||||
|
||||
var/old_max = max_plane_offset
|
||||
max_plane_offset = max(max_plane_offset, current_level)
|
||||
if(max_plane_offset == old_max)
|
||||
return
|
||||
|
||||
generate_offset_lists(old_max + 1, max_plane_offset)
|
||||
SEND_SIGNAL(src, COMSIG_PLANE_OFFSET_INCREASE, old_max, max_plane_offset)
|
||||
|
||||
/// Takes an offset to generate misc lists to, and a base to start from
|
||||
/// Use this to react globally to maintain parity with plane offsets
|
||||
/datum/controller/subsystem/mapping/proc/generate_offset_lists(gen_from, new_offset)
|
||||
create_plane_offsets(gen_from, new_offset)
|
||||
for(var/offset in gen_from to new_offset)
|
||||
GLOB.fullbright_overlays += create_fullbright_overlay(offset)
|
||||
GLOB.cryo_overlays_cover_on += create_cryo_overlay(offset, "cover-on")
|
||||
GLOB.cryo_overlays_cover_off += create_cryo_overlay(offset, "cover-off")
|
||||
|
||||
for(var/datum/gas/gas_type as anything in GLOB.meta_gas_info)
|
||||
var/list/gas_info = GLOB.meta_gas_info[gas_type]
|
||||
if(initial(gas_type.moles_visible) != null)
|
||||
gas_info[META_GAS_OVERLAY] += generate_gas_overlays(gen_from, new_offset, gas_type)
|
||||
|
||||
/datum/controller/subsystem/mapping/proc/create_plane_offsets(gen_from, new_offset)
|
||||
for(var/plane_offset in gen_from to new_offset)
|
||||
for(var/atom/movable/screen/plane_master/master_type as anything in subtypesof(/atom/movable/screen/plane_master) - /atom/movable/screen/plane_master/rendering_plate)
|
||||
var/plane_to_use = initial(master_type.plane)
|
||||
var/string_real = "[plane_to_use]"
|
||||
|
||||
var/offset_plane = GET_NEW_PLANE(plane_to_use, plane_offset)
|
||||
var/string_plane = "[offset_plane]"
|
||||
|
||||
if(!initial(master_type.allows_offsetting))
|
||||
plane_offset_blacklist[string_plane] = TRUE
|
||||
var/render_target = initial(master_type.render_target)
|
||||
if(!render_target)
|
||||
render_target = get_plane_master_render_base(initial(master_type.name))
|
||||
render_offset_blacklist[render_target] = TRUE
|
||||
if(plane_offset != 0)
|
||||
continue
|
||||
|
||||
plane_offset_to_true[string_plane] = plane_to_use
|
||||
plane_to_offset[string_plane] = plane_offset
|
||||
|
||||
if(!true_to_offset_planes[string_real])
|
||||
true_to_offset_planes[string_real] = list()
|
||||
|
||||
true_to_offset_planes[string_real] |= offset_plane
|
||||
|
||||
/proc/generate_lighting_appearance_by_z(z_level)
|
||||
if(length(GLOB.default_lighting_underlays_by_z) < z_level)
|
||||
GLOB.default_lighting_underlays_by_z.len = z_level
|
||||
GLOB.default_lighting_underlays_by_z[z_level] = mutable_appearance(LIGHTING_ICON, "transparent", z_level, null, LIGHTING_PLANE, 255, RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM, offset_const = GET_Z_PLANE_OFFSET(z_level))
|
||||
|
||||
@@ -131,3 +131,104 @@ SUBSYSTEM_DEF(overlays)
|
||||
overlays |= cached_other
|
||||
else if(cut_old)
|
||||
cut_overlays()
|
||||
|
||||
// Debug procs
|
||||
|
||||
/atom
|
||||
/// List of overlay "keys" (info about the appearance) -> mutable versions of static appearances
|
||||
/// Drawn from the overlays list
|
||||
var/list/realized_overlays
|
||||
|
||||
/image
|
||||
/// List of overlay "keys" (info about the appearance) -> mutable versions of static appearances
|
||||
/// Drawn from the overlays list
|
||||
var/list/realized_overlays
|
||||
|
||||
/// Takes the atoms's existing overlays, and makes them mutable so they can be properly vv'd in the realized_overlays list
|
||||
/atom/proc/realize_overlays()
|
||||
realized_overlays = list()
|
||||
var/list/queue = overlays.Copy()
|
||||
var/queue_index = 0
|
||||
while(queue_index < length(queue))
|
||||
queue_index++
|
||||
// If it's not a command, we assert that it's an appearance
|
||||
var/mutable_appearance/appearance = queue[queue_index]
|
||||
if(!appearance) // Who fucking adds nulls to their sublists god you people are the worst
|
||||
continue
|
||||
|
||||
var/mutable_appearance/new_appearance = new /mutable_appearance()
|
||||
new_appearance.appearance = appearance
|
||||
var/key = "[appearance.icon]-[appearance.icon_state]-[appearance.plane]-[appearance.layer]-[appearance.dir]-[appearance.color]"
|
||||
var/tmp_key = key
|
||||
var/overlay_indx = 1
|
||||
while(realized_overlays[tmp_key])
|
||||
tmp_key = "[key]-[overlay_indx]"
|
||||
overlay_indx++
|
||||
|
||||
realized_overlays[tmp_key] = new_appearance
|
||||
// Now check its children
|
||||
for(var/mutable_appearance/child_appearance as anything in appearance.overlays)
|
||||
queue += child_appearance
|
||||
|
||||
/// Takes the image's existing overlays, and makes them mutable so they can be properly vv'd in the realized_overlays list
|
||||
/image/proc/realize_overlays()
|
||||
realized_overlays = list()
|
||||
var/list/queue = overlays.Copy()
|
||||
var/queue_index = 0
|
||||
while(queue_index < length(queue))
|
||||
queue_index++
|
||||
// If it's not a command, we assert that it's an appearance
|
||||
var/mutable_appearance/appearance = queue[queue_index]
|
||||
if(!appearance) // Who fucking adds nulls to their sublists god you people are the worst
|
||||
continue
|
||||
|
||||
var/mutable_appearance/new_appearance = new /mutable_appearance()
|
||||
new_appearance.appearance = appearance
|
||||
var/key = "[appearance.icon]-[appearance.icon_state]-[appearance.plane]-[appearance.layer]-[appearance.dir]-[appearance.color]"
|
||||
var/tmp_key = key
|
||||
var/overlay_indx = 1
|
||||
while(realized_overlays[tmp_key])
|
||||
tmp_key = "[key]-[overlay_indx]"
|
||||
overlay_indx++
|
||||
|
||||
realized_overlays[tmp_key] = new_appearance
|
||||
// Now check its children
|
||||
for(var/mutable_appearance/child_appearance as anything in appearance.overlays)
|
||||
queue += child_appearance
|
||||
|
||||
/// Takes two appearances as args, prints out, logs, and returns a text representation of their differences
|
||||
/// Including suboverlays
|
||||
/proc/diff_appearances(mutable_appearance/first, mutable_appearance/second, iter = 0)
|
||||
var/list/diffs = list()
|
||||
var/list/firstdeet = first.vars
|
||||
var/list/seconddeet = second.vars
|
||||
var/diff_found = FALSE
|
||||
for(var/name in first.vars)
|
||||
var/firstv = firstdeet[name]
|
||||
var/secondv = seconddeet[name]
|
||||
if(firstv ~= secondv)
|
||||
continue
|
||||
if((islist(firstv) || islist(secondv)) && length(firstv) == 0 && length(secondv) == 0)
|
||||
continue
|
||||
if(name == "vars") // Go away
|
||||
continue
|
||||
if(name == "comp_lookup") // This is just gonna happen with marked datums, don't care
|
||||
continue
|
||||
if(name == "overlays")
|
||||
first.realize_overlays()
|
||||
second.realize_overlays()
|
||||
var/overlays_differ = FALSE
|
||||
for(var/i in 1 to length(first.realized_overlays))
|
||||
if(diff_appearances(first.realized_overlays[i], second.realized_overlays[i], iter + 1))
|
||||
overlays_differ = TRUE
|
||||
|
||||
if(!overlays_differ)
|
||||
continue
|
||||
|
||||
diff_found = TRUE
|
||||
diffs += "Diffs detected at [name]: First ([firstv]), Second ([secondv])"
|
||||
|
||||
var/text = "Depth of: [iter]\n\t[diffs.Join("\n\t")]"
|
||||
message_admins(text)
|
||||
log_world(text)
|
||||
return diff_found
|
||||
|
||||
@@ -63,6 +63,7 @@
|
||||
visuals.icon_state = icon_state
|
||||
visuals.color = beam_color
|
||||
visuals.layer = ABOVE_ALL_MOB_LAYER
|
||||
visuals.vis_flags = VIS_INHERIT_PLANE
|
||||
visuals.update_appearance()
|
||||
Draw()
|
||||
RegisterSignal(origin, COMSIG_MOVABLE_MOVED, .proc/redrawing)
|
||||
@@ -170,7 +171,7 @@
|
||||
|
||||
/obj/effect/ebeam/update_overlays()
|
||||
. = ..()
|
||||
var/mutable_appearance/emmisive = emissive_appearance(icon, icon_state)
|
||||
var/mutable_appearance/emmisive = emissive_appearance(icon, icon_state, src)
|
||||
emmisive.transform = transform
|
||||
. += emmisive
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
desc = "A wonderful yet fake friend."
|
||||
see_in_dark = 0
|
||||
lighting_alpha = LIGHTING_PLANE_ALPHA_VISIBLE
|
||||
sight = NONE
|
||||
sight = SEE_BLACKNESS
|
||||
mouse_opacity = MOUSE_OPACITY_ICON
|
||||
see_invisible = SEE_INVISIBLE_LIVING
|
||||
invisibility = INVISIBILITY_MAXIMUM
|
||||
@@ -215,14 +215,19 @@
|
||||
//speech bubble
|
||||
if(owner.client)
|
||||
var/mutable_appearance/MA = mutable_appearance('icons/mob/effects/talk.dmi', src, "default[say_test(message)]", FLY_LAYER)
|
||||
MA.plane = ABOVE_GAME_PLANE
|
||||
SET_PLANE_EXPLICIT(MA, ABOVE_GAME_PLANE, src)
|
||||
MA.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA
|
||||
INVOKE_ASYNC(GLOBAL_PROC, /proc/flick_overlay, MA, list(owner.client), 30)
|
||||
LAZYADD(update_on_z, MA)
|
||||
addtimer(CALLBACK(src, .proc/clear_saypopup, MA), 3.5 SECONDS)
|
||||
|
||||
for(var/mob/M in GLOB.dead_mob_list)
|
||||
var/link = FOLLOW_LINK(M, owner)
|
||||
to_chat(M, "[link] [dead_rendered]")
|
||||
|
||||
/mob/camera/imaginary_friend/proc/clear_saypopup(image/say_popup)
|
||||
LAZYREMOVE(update_on_z, say_popup)
|
||||
|
||||
/mob/camera/imaginary_friend/Move(NewLoc, Dir = 0)
|
||||
if(world.time < move_delay)
|
||||
return FALSE
|
||||
|
||||
@@ -198,7 +198,7 @@
|
||||
|
||||
// Build message image
|
||||
message = image(loc = message_loc, layer = CHAT_LAYER + CHAT_LAYER_Z_STEP * current_z_idx++)
|
||||
message.plane = RUNECHAT_PLANE
|
||||
SET_PLANE(message, RUNECHAT_PLANE, message_loc)
|
||||
message.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA | KEEP_APART
|
||||
message.alpha = 0
|
||||
message.pixel_y = target.maptext_height
|
||||
@@ -212,6 +212,7 @@
|
||||
LAZYADDASSOCLIST(owned_by.seen_messages, message_loc, src)
|
||||
owned_by.images |= message
|
||||
animate(message, alpha = 255, time = CHAT_MESSAGE_SPAWN_TIME)
|
||||
RegisterSignal(message_loc, COMSIG_MOVABLE_Z_CHANGED, .proc/loc_z_changed)
|
||||
|
||||
// Register with the runechat SS to handle EOL and destruction
|
||||
var/duration = lifespan - CHAT_MESSAGE_EOL_FADE
|
||||
@@ -229,6 +230,10 @@
|
||||
animate(message, alpha = 0, time = fadetime, flags = ANIMATION_PARALLEL)
|
||||
addtimer(CALLBACK(GLOBAL_PROC, /proc/qdel, src), fadetime, TIMER_DELETE_ME, SSrunechat)
|
||||
|
||||
/datum/chatmessage/proc/loc_z_changed(datum/source, turf/old_turf, turf/new_turf, same_z_layer)
|
||||
SIGNAL_HANDLER
|
||||
SET_PLANE(message, RUNECHAT_PLANE, new_turf)
|
||||
|
||||
/**
|
||||
* Creates a message overlay at a defined location for a given speaker
|
||||
*
|
||||
|
||||
@@ -22,6 +22,9 @@
|
||||
qdel(src) //no QDEL hint for components, and we dont want this to print a warning regarding bad component application
|
||||
return
|
||||
|
||||
for(var/atom/movable/screen/plane_master/plane_master in mob_parent.hud_used.get_true_plane_masters(FIELD_OF_VISION_BLOCKER_PLANE))
|
||||
plane_master.unhide_plane(mob_parent)
|
||||
|
||||
blocker_mask = new
|
||||
visual_shadow = new
|
||||
//visual_shadow.alpha = parent_client?.prefs.read_preference(/datum/preference/numeric/fov_darkness) //SKYRAT EDIT REMOVAL
|
||||
@@ -32,6 +35,10 @@
|
||||
update_mask()
|
||||
|
||||
/datum/component/fov_handler/Destroy()
|
||||
var/mob/living/mob_parent = parent
|
||||
for(var/atom/movable/screen/plane_master/plane_master in mob_parent.hud_used.get_true_plane_masters(FIELD_OF_VISION_BLOCKER_PLANE))
|
||||
plane_master.hide_plane(mob_parent)
|
||||
|
||||
if(applied_mask)
|
||||
remove_mask()
|
||||
if(blocker_mask) // In a case of early deletion due to volatile client
|
||||
|
||||
24
code/datums/components/hide_highest_offset.dm
Normal file
24
code/datums/components/hide_highest_offset.dm
Normal file
@@ -0,0 +1,24 @@
|
||||
/// Component that takes a plane master, and will hide it if it's the highest offset of its kind
|
||||
/// This allows us to not show PMs to clients if they're not actively doing anything
|
||||
/datum/component/plane_hide_highest_offset
|
||||
|
||||
/datum/component/plane_hide_highest_offset/Initialize()
|
||||
if(!istype(parent, /atom/movable/screen/plane_master))
|
||||
return
|
||||
RegisterSignal(SSmapping, COMSIG_PLANE_OFFSET_INCREASE, .proc/on_offset_increase)
|
||||
offset_increase(SSmapping.max_plane_offset)
|
||||
|
||||
/datum/component/plane_hide_highest_offset/proc/on_offset_increase(datum/source, old_offset, new_offset)
|
||||
SIGNAL_HANDLER
|
||||
offset_increase(new_offset)
|
||||
|
||||
/datum/component/plane_hide_highest_offset/proc/offset_increase(new_offset)
|
||||
var/atom/movable/screen/plane_master/plane_parent = parent
|
||||
var/mob/our_mob = plane_parent.home?.our_hud?.mymob
|
||||
var/our_offset = plane_parent.offset
|
||||
if(!our_mob)
|
||||
return
|
||||
if(our_offset == new_offset)
|
||||
plane_parent.hide_plane(our_mob)
|
||||
else if(plane_parent.force_hidden)
|
||||
plane_parent.unhide_plane(our_mob)
|
||||
@@ -36,7 +36,9 @@
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
holder.forceMove(parent)
|
||||
|
||||
INITIALIZE_IMMEDIATE(/obj/effect/abstract/mirage_holder)
|
||||
/obj/effect/abstract/mirage_holder
|
||||
name = "Mirage holder"
|
||||
anchored = TRUE
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
|
||||
|
||||
@@ -83,13 +83,13 @@
|
||||
. = ..()
|
||||
|
||||
visible_mask = image('icons/effects/light_overlays/light_32.dmi', icon_state = "light")
|
||||
visible_mask.plane = O_LIGHTING_VISUAL_PLANE
|
||||
SET_PLANE_EXPLICIT(visible_mask, O_LIGHTING_VISUAL_PLANE, movable_parent)
|
||||
visible_mask.appearance_flags = RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM
|
||||
visible_mask.alpha = 0
|
||||
if(is_directional)
|
||||
directional = TRUE
|
||||
cone = image('icons/effects/light_overlays/light_cone.dmi', icon_state = "light")
|
||||
cone.plane = O_LIGHTING_VISUAL_PLANE
|
||||
SET_PLANE_EXPLICIT(cone, O_LIGHTING_VISUAL_PLANE, movable_parent)
|
||||
cone.appearance_flags = RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM
|
||||
cone.alpha = 110
|
||||
cone.transform = cone.transform.Translate(-32, -32)
|
||||
@@ -119,6 +119,7 @@
|
||||
RegisterSignal(parent, COMSIG_ATOM_USED_IN_CRAFT, .proc/on_parent_crafted)
|
||||
RegisterSignal(parent, COMSIG_LIGHT_EATER_QUEUE, .proc/on_light_eater)
|
||||
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, .proc/on_parent_moved)
|
||||
RegisterSignal(parent, COMSIG_MOVABLE_Z_CHANGED, .proc/on_z_move)
|
||||
var/atom/movable/movable_parent = parent
|
||||
if(movable_parent.light_flags & LIGHT_ATTACHED)
|
||||
overlay_lighting_flags |= LIGHTING_ATTACHED
|
||||
@@ -300,6 +301,17 @@
|
||||
return
|
||||
make_luminosity_update()
|
||||
|
||||
/datum/component/overlay_lighting/proc/on_z_move(atom/source)
|
||||
SIGNAL_HANDLER
|
||||
if(current_holder && overlay_lighting_flags & LIGHTING_ON)
|
||||
current_holder.underlays -= visible_mask
|
||||
current_holder.underlays -= cone
|
||||
SET_PLANE_EXPLICIT(visible_mask, O_LIGHTING_VISUAL_PLANE, source)
|
||||
if(cone)
|
||||
SET_PLANE_EXPLICIT(cone, O_LIGHTING_VISUAL_PLANE, source)
|
||||
if(current_holder && overlay_lighting_flags & LIGHTING_ON)
|
||||
current_holder.underlays += visible_mask
|
||||
current_holder.underlays += cone
|
||||
|
||||
///Called when the current_holder is qdeleted, to remove the light effect.
|
||||
/datum/component/overlay_lighting/proc/on_parent_attached_to_qdel(atom/movable/source, force)
|
||||
|
||||
@@ -95,11 +95,15 @@
|
||||
|
||||
///Apply the trickery image and animation
|
||||
/datum/component/seethrough/proc/trick_mob(mob/fool)
|
||||
var/datum/hud/our_hud = fool.hud_used
|
||||
var/atom/movable/screen/plane_master/seethrough = our_hud.get_plane_master(SEETHROUGH_PLANE)
|
||||
seethrough.unhide_plane(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
|
||||
SET_PLANE_EXPLICIT(user_overlay, SEETHROUGH_PLANE, 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
|
||||
@@ -135,6 +139,9 @@
|
||||
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
|
||||
var/atom/movable/screen/plane_master/seethrough = our_hud.get_plane_master(SEETHROUGH_PLANE)
|
||||
seethrough.hide_plane(fool)
|
||||
|
||||
tricked_mobs.Cut()
|
||||
|
||||
@@ -145,3 +152,6 @@
|
||||
tricked_mobs.Remove(fool)
|
||||
UnregisterSignal(fool, COMSIG_MOB_LOGOUT)
|
||||
RegisterSignal(fool, COMSIG_MOB_LOGIN, .proc/trick_mob)
|
||||
var/datum/hud/our_hud = fool.hud_used
|
||||
var/atom/movable/screen/plane_master/seethrough = our_hud.get_plane_master(SEETHROUGH_PLANE)
|
||||
seethrough.hide_plane(fool)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/datum/component/tactical
|
||||
var/allowed_slot
|
||||
var/current_slot
|
||||
|
||||
/datum/component/tactical/Initialize(allowed_slot)
|
||||
if(!isitem(parent))
|
||||
@@ -19,6 +20,15 @@
|
||||
unmodify()
|
||||
return ..()
|
||||
|
||||
/datum/component/tactical/proc/on_z_move(datum/source)
|
||||
SIGNAL_HANDLER
|
||||
var/obj/item/master = parent
|
||||
if(!ismob(master.loc))
|
||||
return
|
||||
var/old_slot = current_slot
|
||||
unmodify(master, master.loc)
|
||||
modify(master, master.loc, old_slot)
|
||||
|
||||
/datum/component/tactical/proc/modify(obj/item/source, mob/user, slot)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
@@ -26,13 +36,16 @@
|
||||
unmodify()
|
||||
return
|
||||
|
||||
current_slot = slot
|
||||
|
||||
var/obj/item/master = parent
|
||||
var/image/I = image(icon = master.icon, icon_state = master.icon_state, loc = user)
|
||||
I.plane = GAME_PLANE_FOV_HIDDEN
|
||||
SET_PLANE_EXPLICIT(I, GAME_PLANE_FOV_HIDDEN, master)
|
||||
I.copy_overlays(master)
|
||||
I.override = TRUE
|
||||
source.add_alt_appearance(/datum/atom_hud/alternate_appearance/basic/everyone, "sneaking_mission", I)
|
||||
I.layer = ABOVE_MOB_LAYER
|
||||
RegisterSignal(parent, COMSIG_MOVABLE_Z_CHANGED, .proc/on_z_move)
|
||||
|
||||
/datum/component/tactical/proc/unmodify(obj/item/source, mob/user)
|
||||
SIGNAL_HANDLER
|
||||
@@ -44,3 +57,5 @@
|
||||
user = master.loc
|
||||
|
||||
user.remove_alt_appearance("sneaking_mission")
|
||||
current_slot = null
|
||||
UnregisterSignal(parent, COMSIG_MOVABLE_Z_CHANGED)
|
||||
|
||||
@@ -1,9 +1,180 @@
|
||||
/// List of z pillars (datums placed in the bottom left of XbyX squares that control transparency in that space)
|
||||
/// The pillars are stored in triple depth lists indexed by (world_size % pillar_size) + 1
|
||||
/// They are created at transparent turf request, and deleted when no turfs remain
|
||||
GLOBAL_LIST_EMPTY(pillars_by_z)
|
||||
#define Z_PILLAR_RADIUS 20
|
||||
// Takes a position, transforms it into a z pillar key
|
||||
#define Z_PILLAR_TRANSFORM(pos) (ROUND_UP(pos / Z_PILLAR_RADIUS))
|
||||
// Takes a z pillar key, hands back the actual posiiton it represents
|
||||
// A key of 1 becomes 1, a key of 2 becomes Z_PILLAR_RADIUS + 1, etc.
|
||||
#define Z_KEY_TO_POSITION(key) (((key - 1) * Z_PILLAR_RADIUS) + 1)
|
||||
|
||||
/// Returns a z pillar to insert turfs into
|
||||
/proc/request_z_pillar(x, y, z)
|
||||
var/list/pillars_by_z = GLOB.pillars_by_z
|
||||
if(length(pillars_by_z) < z)
|
||||
pillars_by_z.len = z
|
||||
var/list/our_z = pillars_by_z[z]
|
||||
if(!our_z)
|
||||
our_z = list()
|
||||
pillars_by_z[z] = our_z
|
||||
|
||||
//Now that we've got the z layer sorted, we're gonna check the X line
|
||||
var/x_key = Z_PILLAR_TRANSFORM(x)
|
||||
if(length(our_z) < x_key)
|
||||
our_z.len = x_key
|
||||
var/list/our_x = our_z[x_key]
|
||||
if(!our_x)
|
||||
our_x = list()
|
||||
our_z[x_key] = our_x
|
||||
|
||||
//And now the y layer
|
||||
var/y_key = Z_PILLAR_TRANSFORM(y)
|
||||
if(length(our_x) < y_key)
|
||||
our_x.len = y_key
|
||||
var/datum/z_pillar/our_lad = our_x[y_key]
|
||||
if(!our_lad)
|
||||
our_lad = new(x_key, y_key, z)
|
||||
our_x[y_key] = our_lad
|
||||
return our_lad
|
||||
|
||||
/// Exists to be placed on the turf of walls and such to hold the vis_contents of the tile below
|
||||
/// Otherwise the lower turf might get shifted around, which is dumb. do this instead.
|
||||
/obj/effect/abstract/z_holder
|
||||
var/datum/z_pillar/pillar
|
||||
var/turf/show_for
|
||||
appearance_flags = PIXEL_SCALE
|
||||
plane = HUD_PLANE
|
||||
anchored = TRUE
|
||||
move_resist = INFINITY
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
|
||||
/obj/effect/abstract/z_holder/Destroy()
|
||||
if(pillar)
|
||||
pillar.drawing_object -= show_for
|
||||
pillar = null
|
||||
show_for = null
|
||||
return ..()
|
||||
|
||||
/obj/effect/abstract/z_holder/proc/display(turf/display, datum/z_pillar/behalf_of)
|
||||
if(pillar)
|
||||
CRASH("We attempted to use a z holder to display when it was already in use, what'd you do")
|
||||
|
||||
pillar = behalf_of
|
||||
show_for = display
|
||||
vis_contents += display
|
||||
behalf_of.drawing_object[display] = src
|
||||
|
||||
/// Grouping datum that manages transparency for a block of space
|
||||
/// Setup to ease debugging, and to make add/remove operations cheaper
|
||||
/datum/z_pillar
|
||||
var/x_pos
|
||||
var/y_pos
|
||||
var/z_pos
|
||||
/// Assoc list in the form displayed turf -> list of sources
|
||||
var/list/turf_sources = list()
|
||||
/// Assoc list of turfs using z holders in the form displayed turf -> z holder
|
||||
var/list/drawing_object = list()
|
||||
|
||||
/datum/z_pillar/New(x_pos, y_pos, z_pos)
|
||||
. = ..()
|
||||
src.x_pos = x_pos
|
||||
src.y_pos = y_pos
|
||||
src.z_pos = z_pos
|
||||
|
||||
/datum/z_pillar/Destroy()
|
||||
GLOB.pillars_by_z[z_pos][x_pos][y_pos] = null
|
||||
// Just to be totally clear, this is code that exists to
|
||||
// A: make sure cleanup is actually possible for this datum, just in case someone goes insane
|
||||
// B: allow for easier debugging and making sure everything behaves as expected when fully removed
|
||||
// It is not meant to be relied on, please don't actually it's not very fast
|
||||
for(var/turf/displaying in turf_sources)
|
||||
for(var/turf/displaying_for in turf_sources[displaying])
|
||||
hide_turf(displaying, displaying_for)
|
||||
return ..()
|
||||
|
||||
/// Displays a turf from the z level below us on our level
|
||||
/datum/z_pillar/proc/display_turf(turf/to_display, turf/source)
|
||||
var/list/sources = turf_sources[to_display]
|
||||
if(!sources)
|
||||
sources = list()
|
||||
turf_sources[to_display] = sources
|
||||
sources |= source
|
||||
|
||||
if(length(sources) != 1) // If we aren't the first to request this turf, return
|
||||
var/obj/effect/abstract/z_holder/holding = drawing_object[to_display]
|
||||
if(!holding)
|
||||
return
|
||||
|
||||
var/turf/visual_target = to_display.above()
|
||||
/// Basically, if we used to be under a non transparent turf, but are no longer in that position
|
||||
/// Then we add to the transparent turf we're now under, and nuke the old object
|
||||
if(!istransparentturf(visual_target))
|
||||
return
|
||||
|
||||
holding.vis_contents -= to_display
|
||||
qdel(holding)
|
||||
drawing_object -= to_display
|
||||
visual_target.vis_contents += to_display
|
||||
return
|
||||
|
||||
var/turf/visual_target = to_display.above()
|
||||
if(istransparentturf(visual_target) || isopenspaceturf(visual_target))
|
||||
visual_target.vis_contents += to_display
|
||||
else
|
||||
var/obj/effect/abstract/z_holder/hold_this = new(visual_target)
|
||||
hold_this.display(to_display, src)
|
||||
|
||||
/// Hides an existing turf from our vis_contents, or the vis_contents of the source if applicable
|
||||
/datum/z_pillar/proc/hide_turf(turf/to_hide, turf/source)
|
||||
var/list/sources = turf_sources[to_hide]
|
||||
if(!sources)
|
||||
return
|
||||
sources -= source
|
||||
// More sources remain
|
||||
if(length(sources))
|
||||
return
|
||||
|
||||
turf_sources -= to_hide
|
||||
var/obj/effect/abstract/z_holder/holding = drawing_object[to_hide]
|
||||
if(holding)
|
||||
qdel(holding)
|
||||
else
|
||||
var/turf/visual_target = to_hide.above()
|
||||
visual_target.vis_contents -= to_hide
|
||||
|
||||
if(!length(turf_sources) && !QDELETED(src))
|
||||
qdel(src)
|
||||
|
||||
/// Called when a transparent turf is cleared. We wait a tick, then check to see what
|
||||
/// Kind of turf replaced our former holder, and resetup our visuals as desired
|
||||
/// We do not need to do this for non transparent holders, because they will have their abstract object cleared
|
||||
/// When a transparent holder comes back.
|
||||
/datum/z_pillar/proc/parent_cleared(turf/visual, turf/current_holder)
|
||||
addtimer(CALLBACK(src, .proc/refresh_orphan, visual, current_holder))
|
||||
|
||||
/// Runs the actual refresh of some formerly orphaned via vis_loc deletiong turf
|
||||
/// We'll only reup if we either have no souece, or if the source is a transparent turf
|
||||
/datum/z_pillar/proc/refresh_orphan(turf/orphan, turf/parent)
|
||||
var/list/sources = turf_sources[orphan]
|
||||
if(!length(sources))
|
||||
return
|
||||
|
||||
var/obj/effect/abstract/z_holder/holding = drawing_object[orphan]
|
||||
if(holding)
|
||||
return
|
||||
|
||||
if(istransparentturf(parent) || isopenspaceturf(parent))
|
||||
parent.vis_contents += orphan
|
||||
else
|
||||
var/obj/effect/abstract/z_holder/hold_this = new(parent)
|
||||
hold_this.display(orphan, src)
|
||||
|
||||
/datum/element/turf_z_transparency
|
||||
element_flags = ELEMENT_DETACH
|
||||
|
||||
///This proc sets up the signals to handle updating viscontents when turfs above/below update. Handle plane and layer here too so that they don't cover other obs/turfs in Dream Maker
|
||||
/datum/element/turf_z_transparency/Attach(datum/target, is_openspace = FALSE)
|
||||
/datum/element/turf_z_transparency/Attach(datum/target, mapload)
|
||||
. = ..()
|
||||
if(!isturf(target))
|
||||
return ELEMENT_INCOMPATIBLE
|
||||
@@ -11,43 +182,71 @@
|
||||
var/turf/our_turf = target
|
||||
|
||||
our_turf.layer = OPENSPACE_LAYER
|
||||
if(is_openspace) // openspace and windows have different visual effects but both share this component.
|
||||
our_turf.plane = OPENSPACE_PLANE
|
||||
else
|
||||
our_turf.plane = TRANSPARENT_FLOOR_PLANE
|
||||
|
||||
RegisterSignal(target, COMSIG_TURF_MULTIZ_DEL, .proc/on_multiz_turf_del)
|
||||
RegisterSignal(target, COMSIG_TURF_MULTIZ_NEW, .proc/on_multiz_turf_new)
|
||||
|
||||
ADD_TRAIT(our_turf, TURF_Z_TRANSPARENT_TRAIT, ELEMENT_TRAIT(type))
|
||||
|
||||
update_multi_z(our_turf)
|
||||
if(!mapload)
|
||||
update_multi_z(our_turf)
|
||||
|
||||
/datum/element/turf_z_transparency/Detach(datum/source)
|
||||
. = ..()
|
||||
var/turf/our_turf = source
|
||||
our_turf.vis_contents.len = 0
|
||||
clear_multiz(our_turf)
|
||||
|
||||
UnregisterSignal(our_turf, list(COMSIG_TURF_MULTIZ_NEW, COMSIG_TURF_MULTIZ_DEL))
|
||||
REMOVE_TRAIT(our_turf, TURF_Z_TRANSPARENT_TRAIT, ELEMENT_TRAIT(type))
|
||||
|
||||
///Updates the viscontents or underlays below this tile.
|
||||
/datum/element/turf_z_transparency/proc/update_multi_z(turf/our_turf)
|
||||
var/turf/below_turf = our_turf.below()
|
||||
if(below_turf) // If we actually have somethign below us, display it.
|
||||
our_turf.vis_contents += below_turf
|
||||
if(below_turf) // If we actually have something below us, display it.
|
||||
for(var/turf/partner in range(1, below_turf))
|
||||
// We use our z here to ensure the pillar is actually on our level
|
||||
var/datum/z_pillar/z_boss = request_z_pillar(partner.x, partner.y, our_turf.z)
|
||||
z_boss.display_turf(partner, our_turf)
|
||||
else
|
||||
our_turf.vis_contents.len = 0 // Nuke the list
|
||||
add_baseturf_underlay(our_turf)
|
||||
our_turf.underlays += get_baseturf_underlay(our_turf)
|
||||
|
||||
// This shit is stupid
|
||||
// z transparency is for making something SHOW WHAT'S BENEATH it, or if nothing is, show
|
||||
// the appropriate underlay
|
||||
// IT IS NOT FOR MAKING YOUR CLOSED TURF SEETHROUGH
|
||||
// these are different concerns, and should not be HANDLED TOGETHER
|
||||
// similarly, if you rip this out, rework diagonal closed turfs to work with this system
|
||||
// it will make them look significantly nicer, and should let you tie into their logic more easily
|
||||
// Just please don't break behavior yeah? thanks, I love you <3
|
||||
if(isclosedturf(our_turf)) //Show girders below closed turfs
|
||||
var/mutable_appearance/girder_underlay = mutable_appearance('icons/obj/structures.dmi', "girder", layer = TURF_LAYER-0.01)
|
||||
girder_underlay.appearance_flags = RESET_ALPHA | RESET_COLOR
|
||||
our_turf.underlays += girder_underlay
|
||||
var/mutable_appearance/plating_underlay = mutable_appearance('icons/turf/floors.dmi', "plating", layer = TURF_LAYER-0.02)
|
||||
plating_underlay = RESET_ALPHA | RESET_COLOR
|
||||
plating_underlay.appearance_flags = RESET_ALPHA | RESET_COLOR
|
||||
our_turf.underlays += plating_underlay
|
||||
return TRUE
|
||||
|
||||
/datum/element/turf_z_transparency/proc/clear_multiz(turf/our_turf)
|
||||
var/turf/below_turf = our_turf.below()
|
||||
if(below_turf) // If we actually have something below us, we need to clear ourselves from it
|
||||
for(var/turf/partner in range(1, below_turf))
|
||||
// We use our z here to ensure the pillar is actually on our level
|
||||
var/datum/z_pillar/z_boss = request_z_pillar(partner.x, partner.y, our_turf.z)
|
||||
z_boss.hide_turf(partner, our_turf)
|
||||
if(partner == below_turf)
|
||||
z_boss.parent_cleared(below_turf, our_turf)
|
||||
else
|
||||
our_turf.underlays -= get_baseturf_underlay(our_turf)
|
||||
|
||||
if(isclosedturf(our_turf)) //Show girders below closed turfs
|
||||
var/mutable_appearance/girder_underlay = mutable_appearance('icons/obj/structures.dmi', "girder", layer = TURF_LAYER-0.01)
|
||||
girder_underlay.appearance_flags = RESET_ALPHA | RESET_COLOR
|
||||
our_turf.underlays -= girder_underlay
|
||||
var/mutable_appearance/plating_underlay = mutable_appearance('icons/turf/floors.dmi', "plating", layer = TURF_LAYER-0.02)
|
||||
plating_underlay.appearance_flags = RESET_ALPHA | RESET_COLOR
|
||||
our_turf.underlays -= plating_underlay
|
||||
|
||||
/datum/element/turf_z_transparency/proc/on_multiz_turf_del(turf/our_turf, turf/below_turf, dir)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
@@ -65,13 +264,13 @@
|
||||
update_multi_z(our_turf)
|
||||
|
||||
///Called when there is no real turf below this turf
|
||||
/datum/element/turf_z_transparency/proc/add_baseturf_underlay(turf/our_turf)
|
||||
/datum/element/turf_z_transparency/proc/get_baseturf_underlay(turf/our_turf)
|
||||
var/turf/path = SSmapping.level_trait(our_turf.z, ZTRAIT_BASETURF) || /turf/open/space
|
||||
if(!ispath(path))
|
||||
path = text2path(path)
|
||||
if(!ispath(path))
|
||||
warning("Z-level [our_turf.z] has invalid baseturf '[SSmapping.level_trait(our_turf.z, ZTRAIT_BASETURF)]'")
|
||||
path = /turf/open/space
|
||||
var/mutable_appearance/underlay_appearance = mutable_appearance(initial(path.icon), initial(path.icon_state), layer = TURF_LAYER-0.02, plane = PLANE_SPACE)
|
||||
var/mutable_appearance/underlay_appearance = mutable_appearance(initial(path.icon), initial(path.icon_state), layer = TURF_LAYER-0.02, offset_spokesman = our_turf, plane = PLANE_SPACE)
|
||||
underlay_appearance.appearance_flags = RESET_ALPHA | RESET_COLOR
|
||||
our_turf.underlays += underlay_appearance
|
||||
return underlay_appearance
|
||||
|
||||
@@ -12,7 +12,20 @@
|
||||
plane = FLOAT_PLANE
|
||||
|
||||
/// Helper similar to image()
|
||||
/proc/mutable_appearance(icon, icon_state = "", layer = FLOAT_LAYER, plane = FLOAT_PLANE, alpha = 255, appearance_flags = NONE)
|
||||
/proc/mutable_appearance(icon, icon_state = "", layer = FLOAT_LAYER, atom/offset_spokesman, plane = FLOAT_PLANE, alpha = 255, appearance_flags = NONE, offset_const)
|
||||
if(plane != FLOAT_PLANE)
|
||||
// Essentially, we allow users that only want one static offset to pass one in
|
||||
if(!isnull(offset_const))
|
||||
plane = GET_NEW_PLANE(plane, offset_const)
|
||||
// That, or you need to pass in some non null object to reference
|
||||
else if(!isnull(offset_spokesman))
|
||||
// Note, we are ok with null turfs, that's not an error condition we'll just default to 0, the error would be
|
||||
// Not passing ANYTHING in, key difference
|
||||
var/turf/our_turf = get_turf(offset_spokesman)
|
||||
plane = MUTATE_PLANE(plane, our_turf)
|
||||
// otherwise if you're setting plane you better have the guts to back it up
|
||||
else
|
||||
stack_trace("No plane offset passed in as context for a non floating mutable appearance, ya done fucked up")
|
||||
var/mutable_appearance/MA = new()
|
||||
MA.icon = icon
|
||||
MA.icon_state = icon_state
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
goal = goal_number
|
||||
bar_loc = target
|
||||
bar = image('icons/effects/progessbar.dmi', bar_loc, "prog_bar_0")
|
||||
bar.plane = ABOVE_HUD_PLANE
|
||||
SET_PLANE_EXPLICIT(bar, ABOVE_HUD_PLANE, User)
|
||||
bar.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA
|
||||
user = User
|
||||
|
||||
|
||||
@@ -45,9 +45,12 @@
|
||||
effect.icon_state = overlay.icon_state
|
||||
effect.mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
effect.layer = ABOVE_ALL_MOB_LAYER
|
||||
effect.plane = ABOVE_GAME_PLANE
|
||||
SET_PLANE(effect, ABOVE_GAME_PLANE, target)
|
||||
LAZYSET(edgeturf_effects, target, effect)
|
||||
|
||||
/datum/proximity_monitor/advanced/projectile_dampener/on_z_change(datum/source)
|
||||
recalculate_field()
|
||||
|
||||
/datum/proximity_monitor/advanced/projectile_dampener/cleanup_edge_turf(turf/target)
|
||||
. = ..()
|
||||
var/obj/effect/abstract/effect = LAZYACCESS(edgeturf_effects, target)
|
||||
|
||||
@@ -34,9 +34,10 @@
|
||||
hasprox_receiver = new_host
|
||||
host = new_host
|
||||
RegisterSignal(new_host, COMSIG_PARENT_QDELETING, .proc/on_host_or_receiver_del)
|
||||
var/static/list/containers_connections = list(COMSIG_MOVABLE_MOVED = .proc/on_moved)
|
||||
var/static/list/containers_connections = list(COMSIG_MOVABLE_MOVED = .proc/on_moved, COMSIG_MOVABLE_Z_CHANGED = .proc/on_z_change)
|
||||
AddComponent(/datum/component/connect_containers, host, containers_connections)
|
||||
RegisterSignal(host, COMSIG_MOVABLE_MOVED, .proc/on_moved)
|
||||
RegisterSignal(host, COMSIG_MOVABLE_Z_CHANGED, .proc/on_z_change)
|
||||
set_range(current_range, TRUE)
|
||||
|
||||
/datum/proximity_monitor/proc/on_host_or_receiver_del(datum/source)
|
||||
@@ -62,6 +63,10 @@
|
||||
if(source == host)
|
||||
hasprox_receiver?.HasProximity(host)
|
||||
|
||||
/datum/proximity_monitor/proc/on_z_change()
|
||||
SIGNAL_HANDLER
|
||||
return
|
||||
|
||||
/datum/proximity_monitor/proc/set_ignore_if_not_on_turf(does_ignore = TRUE)
|
||||
if(ignore_if_not_on_turf == does_ignore)
|
||||
return
|
||||
|
||||
@@ -339,8 +339,8 @@
|
||||
alert_type = null
|
||||
|
||||
/datum/status_effect/cultghost/on_apply()
|
||||
owner.see_invisible = SEE_INVISIBLE_OBSERVER
|
||||
owner.see_in_dark = 2
|
||||
owner.set_invis_see(SEE_INVISIBLE_OBSERVER)
|
||||
owner.set_see_in_dark(2)
|
||||
|
||||
/datum/status_effect/cultghost/tick()
|
||||
if(owner.reagents)
|
||||
|
||||
@@ -290,7 +290,7 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches)
|
||||
/// Refreshes and item to be put back into the real world, out of storage.
|
||||
/datum/storage/proc/reset_item(obj/item/thing)
|
||||
thing.layer = initial(thing.layer)
|
||||
thing.plane = initial(thing.plane)
|
||||
SET_PLANE_IMPLICIT(thing, initial(thing.plane))
|
||||
thing.mouse_opacity = initial(thing.mouse_opacity)
|
||||
thing.screen_loc = null
|
||||
if(thing.maptext)
|
||||
@@ -860,15 +860,17 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches)
|
||||
boxes.screen_loc = "[screen_start_x]:[screen_pixel_x],[screen_start_y]:[screen_pixel_y] to [screen_start_x+cols-1]:[screen_pixel_x],[screen_start_y+rows-1]:[screen_pixel_y]"
|
||||
var/current_x = screen_start_x
|
||||
var/current_y = screen_start_y
|
||||
var/turf/our_turf = get_turf(resolve_location)
|
||||
|
||||
if(islist(numerical_display_contents))
|
||||
for(var/type in numerical_display_contents)
|
||||
var/datum/numbered_display/numberdisplay = numerical_display_contents[type]
|
||||
|
||||
numberdisplay.sample_object.mouse_opacity = MOUSE_OPACITY_OPAQUE
|
||||
numberdisplay.sample_object.screen_loc = "[current_x]:[screen_pixel_x],[current_y]:[screen_pixel_y]"
|
||||
numberdisplay.sample_object.maptext = MAPTEXT("<font color='white'>[(numberdisplay.number > 1)? "[numberdisplay.number]" : ""]</font>")
|
||||
numberdisplay.sample_object.plane = ABOVE_HUD_PLANE
|
||||
var/obj/item/display_sample = numberdisplay.sample_object
|
||||
display_sample.mouse_opacity = MOUSE_OPACITY_OPAQUE
|
||||
display_sample.screen_loc = "[current_x]:[screen_pixel_x],[current_y]:[screen_pixel_y]"
|
||||
display_sample.maptext = MAPTEXT("<font color='white'>[(numberdisplay.number > 1)? "[numberdisplay.number]" : ""]</font>")
|
||||
SET_PLANE(display_sample, ABOVE_HUD_PLANE, our_turf)
|
||||
|
||||
current_x++
|
||||
|
||||
@@ -885,6 +887,7 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches)
|
||||
item.screen_loc = "[current_x]:[screen_pixel_x],[current_y]:[screen_pixel_y]"
|
||||
item.maptext = ""
|
||||
item.plane = ABOVE_HUD_PLANE
|
||||
SET_PLANE(item, ABOVE_HUD_PLANE, our_turf)
|
||||
|
||||
current_x++
|
||||
|
||||
|
||||
158
code/datums/visual_data.dm
Normal file
158
code/datums/visual_data.dm
Normal file
@@ -0,0 +1,158 @@
|
||||
// Allows for linking one mob's view to another
|
||||
// Exists to make debugging stuff on live easier, please do not build gameplay around this it's not stable
|
||||
// Mostly because we don't have setters for everything (like ui elements IE: client.screen)
|
||||
|
||||
// DEBUG ONLY, THIS IS N O T STABLE ENOUGH FOR PLAYERS
|
||||
// Should potentially support images, might be too hard tho since there's no default "refresh" tool
|
||||
|
||||
// Convenience datum, not for use outside of this ui
|
||||
/datum/visual_data
|
||||
/// Sight flags
|
||||
var/sight = NONE
|
||||
/// see_invisible values
|
||||
var/see_invis
|
||||
/// see_in_dark values
|
||||
var/see_dark
|
||||
/// What the client is seeing "out of", client.eye
|
||||
var/datum/weakref/client_eye
|
||||
/// Weakref to the mob we're mirroring off
|
||||
var/datum/weakref/mirroring_off_ref
|
||||
|
||||
var/do_updates = FALSE
|
||||
|
||||
// Note: we do not attempt to mirror all of screen, instead confining ourselves to mirroring
|
||||
// Plane master and parralax stuff and such
|
||||
// Again, this isn't stable
|
||||
|
||||
/datum/visual_data/proc/shadow(mob/mirror_off)
|
||||
do_updates = FALSE
|
||||
mirroring_off_ref = WEAKREF(mirror_off)
|
||||
RegisterSignal(mirror_off, COMSIG_MOB_SIGHT_CHANGE, .proc/sight_changed)
|
||||
sight_changed(mirror_off)
|
||||
RegisterSignal(mirror_off, COMSIG_MOB_SEE_INVIS_CHANGE, .proc/invis_changed)
|
||||
invis_changed(mirror_off)
|
||||
RegisterSignal(mirror_off, COMSIG_MOB_SEE_IN_DARK_CHANGE, .proc/in_dark_changed)
|
||||
in_dark_changed(mirror_off)
|
||||
RegisterSignal(mirror_off, COMSIG_MOB_LOGIN, .proc/on_login)
|
||||
RegisterSignal(mirror_off, COMSIG_MOB_LOGOUT, .proc/on_logout)
|
||||
if(mirror_off.client)
|
||||
on_login(mirror_off)
|
||||
do_updates = TRUE
|
||||
|
||||
/datum/visual_data/proc/paint_onto(mob/paint_to)
|
||||
// Note: we explicitly do NOT use setters here, since it would break the behavior
|
||||
paint_to.sight = sight
|
||||
paint_to.see_invisible = see_invis
|
||||
paint_to.see_in_dark = see_dark
|
||||
if(paint_to.client)
|
||||
var/atom/eye = client_eye?.resolve()
|
||||
if(eye)
|
||||
paint_to.client.eye = eye
|
||||
// This is hacky I know, I don't have a way to update just
|
||||
/// Plane masters. I'm sorry
|
||||
var/mob/mirroring_off = mirroring_off_ref?.resolve()
|
||||
if(mirroring_off?.client && paint_to != mirroring_off)
|
||||
paint_to.client.screen = mirroring_off.client.screen
|
||||
|
||||
/datum/visual_data/proc/on_update()
|
||||
return
|
||||
|
||||
/datum/visual_data/proc/sight_changed(mob/source)
|
||||
SIGNAL_HANDLER
|
||||
sight = source.sight
|
||||
on_update()
|
||||
|
||||
/datum/visual_data/proc/invis_changed(mob/source)
|
||||
SIGNAL_HANDLER
|
||||
see_invis = source.see_invisible
|
||||
on_update()
|
||||
|
||||
/datum/visual_data/proc/in_dark_changed(mob/source)
|
||||
SIGNAL_HANDLER
|
||||
see_dark = source.see_in_dark
|
||||
on_update()
|
||||
|
||||
/datum/visual_data/proc/on_login(mob/source)
|
||||
SIGNAL_HANDLER
|
||||
// visual data can be created off login, so conflicts here are inevitable
|
||||
// Best to just override
|
||||
RegisterSignal(source.client, COMSIG_CLIENT_SET_EYE, .proc/eye_change, override = TRUE)
|
||||
set_eye(source.client.eye)
|
||||
|
||||
/datum/visual_data/proc/on_logout(mob/source)
|
||||
SIGNAL_HANDLER
|
||||
// Canon here because it'll be gone come the logout signal
|
||||
UnregisterSignal(source.canon_client, COMSIG_CLIENT_SET_EYE)
|
||||
// We do NOT unset the eye, because it's still valid even if the mob ain't logged in
|
||||
|
||||
/datum/visual_data/proc/eye_change(client/source)
|
||||
SIGNAL_HANDLER
|
||||
set_eye(source.eye)
|
||||
|
||||
/datum/visual_data/proc/set_eye(atom/new_eye)
|
||||
var/atom/old_eye = client_eye?.resolve()
|
||||
if(old_eye)
|
||||
UnregisterSignal(old_eye, COMSIG_PARENT_QDELETING)
|
||||
if(new_eye)
|
||||
// Need to update any party's client.eyes
|
||||
RegisterSignal(new_eye, COMSIG_PARENT_QDELETING, .proc/eye_deleted)
|
||||
client_eye = WEAKREF(new_eye)
|
||||
on_update()
|
||||
|
||||
/datum/visual_data/proc/eye_deleted(datum/source)
|
||||
SIGNAL_HANDLER
|
||||
set_eye(null)
|
||||
|
||||
/// Tracks but does not relay updates to someone's visual data
|
||||
/// Accepts a second visual data datum to use as a source of truth for the mob's values
|
||||
/datum/visual_data/tracking
|
||||
/// Weakref to the visual data datum to reset our mob to
|
||||
var/datum/weakref/default_to_ref
|
||||
|
||||
/datum/visual_data/tracking/Destroy()
|
||||
var/mob/our_lad = mirroring_off_ref?.resolve()
|
||||
if(our_lad)
|
||||
// Reset our mob to his proper visuals
|
||||
paint_onto(our_lad)
|
||||
return ..()
|
||||
|
||||
/datum/visual_data/tracking/proc/set_truth(datum/visual_data/truth)
|
||||
default_to_ref = WEAKREF(truth)
|
||||
on_update()
|
||||
|
||||
/datum/visual_data/tracking/paint_onto(mob/paint_onto)
|
||||
. = ..()
|
||||
// Rebuild the passed in mob's screen, since we can't track it currently
|
||||
paint_onto.hud_used?.show_hud(paint_onto.hud_used.hud_version)
|
||||
|
||||
/datum/visual_data/tracking/on_update()
|
||||
var/mob/updated = mirroring_off_ref?.resolve()
|
||||
var/datum/visual_data/mirror = default_to_ref?.resolve()
|
||||
if(!updated || !mirror)
|
||||
return
|
||||
mirror.paint_onto(updated)
|
||||
|
||||
/// Tracks and updates another mob with our mob's visual data
|
||||
/datum/visual_data/mirroring
|
||||
/// Weakref to what mob, if any, we should mirror our changes onto
|
||||
var/datum/weakref/mirror_onto_ref
|
||||
|
||||
/datum/visual_data/mirroring/proc/set_mirror_target(mob/target)
|
||||
var/mob/old_target = mirror_onto_ref?.resolve()
|
||||
if(old_target)
|
||||
UnregisterSignal(old_target, COMSIG_MOB_HUD_REFRESHED)
|
||||
mirror_onto_ref = WEAKREF(target)
|
||||
if(target)
|
||||
RegisterSignal(target, COMSIG_MOB_HUD_REFRESHED, .proc/push_ontod_hud_refreshed)
|
||||
|
||||
/datum/visual_data/mirroring/proc/push_ontod_hud_refreshed(mob/source)
|
||||
SIGNAL_HANDLER
|
||||
// Our mob refreshed its hud, so we're gonna reset it to our screen
|
||||
// I hate that I don't have a signal for this, hhhh
|
||||
paint_onto(source)
|
||||
|
||||
/datum/visual_data/mirroring/on_update()
|
||||
var/mob/draw_onto = mirror_onto_ref?.resolve()
|
||||
if(!draw_onto)
|
||||
return
|
||||
paint_onto(draw_onto)
|
||||
@@ -67,7 +67,7 @@
|
||||
/// If this bit of weather should also draw an overlay that's uneffected by lighting onto the area
|
||||
/// Taken from weather_glow.dmi
|
||||
var/use_glow = TRUE
|
||||
var/mutable_appearance/current_glow
|
||||
var/list/offsets_to_overlays
|
||||
|
||||
/// The stage of the weather, from 1-4
|
||||
var/stage = END_STAGE
|
||||
@@ -239,26 +239,51 @@
|
||||
if(END_STAGE)
|
||||
using_icon_state = ""
|
||||
|
||||
var/mutable_appearance/glow_overlay = mutable_appearance('icons/effects/glow_weather.dmi', using_icon_state, overlay_layer, ABOVE_LIGHTING_PLANE, 100)
|
||||
// Note: what we do here is effectively apply two overlays to each area, for every unique multiz layer they inhabit
|
||||
// One is the base, which will be masked by lighting. the other is "glowing", and provides a nice contrast
|
||||
// This method of applying one overlay per z layer has some minor downsides, in that it could lead to improperly doubled effects if some have alpha
|
||||
// I prefer it to creating 2 extra plane masters however, so it's a cost I'm willing to pay
|
||||
// LU
|
||||
var/list/new_offsets_to_overlays = list()
|
||||
for(var/V in impacted_areas)
|
||||
var/area/N = V
|
||||
if(current_glow)
|
||||
N.overlays -= current_glow
|
||||
if(stage == END_STAGE)
|
||||
N.color = null
|
||||
N.icon_state = using_icon_state
|
||||
N.icon = 'icons/area/areas_misc.dmi'
|
||||
N.layer = initial(N.layer)
|
||||
N.plane = initial(N.plane)
|
||||
N.set_opacity(FALSE)
|
||||
else
|
||||
N.layer = overlay_layer
|
||||
N.plane = overlay_plane
|
||||
N.icon = 'icons/effects/weather_effects.dmi'
|
||||
N.icon_state = using_icon_state
|
||||
N.color = weather_color
|
||||
if(use_glow)
|
||||
N.overlays += glow_overlay
|
||||
|
||||
current_glow = glow_overlay
|
||||
// List of overlays this area uses
|
||||
var/list/mutable_appearance/overlays = list()
|
||||
// Use all possible offsets
|
||||
// Yes this is a bit annoying, but it's too slow to calculate and store these, and it shouldn't (I hope) look weird
|
||||
for(var/offset in 0 to SSmapping.max_plane_offset)
|
||||
var/keyd_offset = offset + 1
|
||||
if(length(new_offsets_to_overlays) < keyd_offset)
|
||||
new_offsets_to_overlays.len = keyd_offset
|
||||
var/list/mutable_appearance/existing_appearances = new_offsets_to_overlays[keyd_offset]
|
||||
if(existing_appearances)
|
||||
overlays += existing_appearances
|
||||
continue
|
||||
|
||||
var/list/offset_overlays = list()
|
||||
var/mutable_appearance/glow_overlay = mutable_appearance('icons/effects/glow_weather.dmi', using_icon_state, overlay_layer, N, ABOVE_LIGHTING_PLANE, 100, offset_const = offset)
|
||||
glow_overlay.color = weather_color
|
||||
offset_overlays += glow_overlay
|
||||
|
||||
if(stage != END_STAGE)
|
||||
var/mutable_appearance/weather_overlay = mutable_appearance('icons/effects/weather_effects.dmi', using_icon_state, overlay_layer, plane = overlay_plane, offset_const = offset)
|
||||
weather_overlay.color = weather_color
|
||||
offset_overlays += weather_overlay
|
||||
|
||||
new_offsets_to_overlays[keyd_offset] = offset_overlays
|
||||
overlays += offset_overlays
|
||||
|
||||
var/list/mutable_appearance/old_glows = list()
|
||||
// Offset (ha) by 1 to match the key
|
||||
for(var/offset in 1 to SSmapping.max_plane_offset + 1)
|
||||
if(length(offsets_to_overlays) >= offset)
|
||||
old_glows += offsets_to_overlays[offset]
|
||||
|
||||
if(length(old_glows))
|
||||
N.overlays -= old_glows
|
||||
if(length(overlays))
|
||||
N.overlays += overlays
|
||||
|
||||
offsets_to_overlays = new_offsets_to_overlays
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ GLOBAL_LIST_EMPTY(active_alternate_appearances)
|
||||
var/atom/target
|
||||
var/image/image
|
||||
var/add_ghost_version = FALSE
|
||||
var/ghost_appearance
|
||||
var/datum/atom_hud/alternate_appearance/basic/observers/ghost_appearance
|
||||
uses_global_hud_category = FALSE
|
||||
|
||||
/datum/atom_hud/alternate_appearance/basic/New(key, image/I, options = AA_TARGET_SEE_APPEARANCE)
|
||||
@@ -73,6 +73,7 @@ GLOBAL_LIST_EMPTY(active_alternate_appearances)
|
||||
transfer_overlays = options & AA_MATCH_TARGET_OVERLAYS
|
||||
image = I
|
||||
target = I.loc
|
||||
LAZYADD(target.update_on_z, image)
|
||||
if(transfer_overlays)
|
||||
I.copy_overlays(target)
|
||||
|
||||
@@ -89,6 +90,7 @@ GLOBAL_LIST_EMPTY(active_alternate_appearances)
|
||||
|
||||
/datum/atom_hud/alternate_appearance/basic/Destroy()
|
||||
. = ..()
|
||||
LAZYREMOVE(target.update_on_z, image)
|
||||
QDEL_NULL(image)
|
||||
target = null
|
||||
if(ghost_appearance)
|
||||
@@ -101,7 +103,7 @@ GLOBAL_LIST_EMPTY(active_alternate_appearances)
|
||||
|
||||
/datum/atom_hud/alternate_appearance/basic/remove_atom_from_hud(atom/A)
|
||||
. = ..()
|
||||
A.hud_list -= appearance_key
|
||||
LAZYREMOVE(A.hud_list, appearance_key)
|
||||
A.set_hud_image_inactive(appearance_key)
|
||||
if(. && !QDELETED(src))
|
||||
qdel(src)
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
requires_power = TRUE
|
||||
always_unpowered = TRUE
|
||||
static_lighting = FALSE
|
||||
area_has_base_lighting = FALSE
|
||||
|
||||
base_lighting_alpha = 255
|
||||
power_light = FALSE
|
||||
power_equip = FALSE
|
||||
power_environ = FALSE
|
||||
@@ -17,11 +17,6 @@
|
||||
sound_environment = SOUND_AREA_SPACE
|
||||
ambient_buzz = null //Space is deafeningly quiet
|
||||
|
||||
/area/space/Initialize(mapload)
|
||||
. = ..()
|
||||
|
||||
add_overlay(GLOB.fullbright_overlay)
|
||||
|
||||
/area/space/nearstation
|
||||
icon_state = "space_near"
|
||||
area_flags = UNIQUE_AREA | NO_ALERTS | AREA_USES_STARLIGHT
|
||||
|
||||
@@ -60,6 +60,10 @@
|
||||
///overlays managed by [update_overlays][/atom/proc/update_overlays] to prevent removing overlays that weren't added by the same proc. Single items are stored on their own, not in a list.
|
||||
var/list/managed_overlays
|
||||
|
||||
/// Lazylist of all images (hopefully attached to us) to update when we change z levels
|
||||
/// You will need to manage adding/removing from this yourself, but I'll do the updating for you
|
||||
var/list/image/update_on_z
|
||||
|
||||
///Cooldown tick timer for buckle messages
|
||||
var/buckle_message_cooldown = 0
|
||||
///Last fingerprints to touch this atom
|
||||
@@ -235,6 +239,8 @@
|
||||
if(loc)
|
||||
SEND_SIGNAL(loc, COMSIG_ATOM_INITIALIZED_ON, src) /// Sends a signal that the new atom `src`, has been created at `loc`
|
||||
|
||||
SET_PLANE_IMPLICIT(src, plane)
|
||||
|
||||
if(greyscale_config && greyscale_colors)
|
||||
update_greyscale()
|
||||
|
||||
|
||||
@@ -102,7 +102,6 @@
|
||||
/mutable_appearance/emissive_blocker/New()
|
||||
. = ..()
|
||||
// Need to do this here because it's overriden by the parent call
|
||||
plane = EMISSIVE_PLANE
|
||||
color = EM_BLOCK_COLOR
|
||||
appearance_flags = EMISSIVE_APPEARANCE_FLAGS
|
||||
|
||||
@@ -115,6 +114,7 @@
|
||||
blocker.icon_state = icon_state
|
||||
blocker.dir = dir
|
||||
blocker.appearance_flags |= appearance_flags
|
||||
blocker.plane = GET_NEW_PLANE(EMISSIVE_PLANE, PLANE_TO_OFFSET(plane))
|
||||
// Ok so this is really cursed, but I want to set with this blocker cheaply while
|
||||
// Still allowing it to be removed from the overlays list later
|
||||
// So I'm gonna flatten it, then insert the flattened overlay into overlays AND the managed overlays list, directly
|
||||
@@ -139,7 +139,6 @@
|
||||
managed_overlays = list(managed_overlays, em_block)
|
||||
else
|
||||
managed_overlays = em_block
|
||||
|
||||
if(opacity)
|
||||
AddElement(/datum/element/light_blocking)
|
||||
switch(light_system)
|
||||
@@ -205,7 +204,7 @@
|
||||
if(!blocks_emissive)
|
||||
return
|
||||
else if (blocks_emissive == EMISSIVE_BLOCK_GENERIC)
|
||||
var/mutable_appearance/gen_emissive_blocker = emissive_blocker(icon, icon_state, alpha = src.alpha, appearance_flags = src.appearance_flags)
|
||||
var/mutable_appearance/gen_emissive_blocker = emissive_blocker(icon, icon_state, src, alpha = src.alpha, appearance_flags = src.appearance_flags)
|
||||
gen_emissive_blocker.dir = dir
|
||||
return gen_emissive_blocker
|
||||
else if(blocks_emissive == EMISSIVE_BLOCK_UNIQUE)
|
||||
@@ -717,7 +716,8 @@
|
||||
var/turf/new_turf = get_turf(src)
|
||||
|
||||
if (old_turf?.z != new_turf?.z)
|
||||
on_changed_z_level(old_turf, new_turf)
|
||||
var/same_z_layer = (GET_TURF_PLANE_OFFSET(old_turf) == GET_TURF_PLANE_OFFSET(new_turf))
|
||||
on_changed_z_level(old_turf, new_turf, same_z_layer)
|
||||
|
||||
if(HAS_SPATIAL_GRID_CONTENTS(src))
|
||||
if(old_turf && new_turf && (old_turf.z != new_turf.z \
|
||||
@@ -1034,17 +1034,31 @@
|
||||
* Called when a movable changes z-levels.
|
||||
*
|
||||
* Arguments:
|
||||
* * old_z - The previous z-level they were on before.
|
||||
* * notify_contents - Whether or not to notify the movable's contents that their z-level has changed.
|
||||
* * old_turf - The previous turf they were on before.
|
||||
* * new_turf - The turf they have now entered.
|
||||
* * same_z_layer - If their old and new z levels are on the same level of plane offsets or not
|
||||
* * notify_contents - Whether or not to notify the movable's contents that their z-level has changed. NOTE, IF YOU SET THIS, YOU NEED TO MANUALLY SET PLANE OF THE CONTENTS LATER
|
||||
*/
|
||||
/atom/movable/proc/on_changed_z_level(turf/old_turf, turf/new_turf, notify_contents = TRUE)
|
||||
SEND_SIGNAL(src, COMSIG_MOVABLE_Z_CHANGED, old_turf, new_turf)
|
||||
/atom/movable/proc/on_changed_z_level(turf/old_turf, turf/new_turf, same_z_layer, notify_contents = TRUE)
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
SEND_SIGNAL(src, COMSIG_MOVABLE_Z_CHANGED, old_turf, new_turf, same_z_layer)
|
||||
|
||||
// If our turfs are on different z "layers", recalc our planes
|
||||
if(!same_z_layer && !QDELETED(src))
|
||||
SET_PLANE(src, PLANE_TO_TRUE(src.plane), new_turf)
|
||||
// a TON of overlays use planes, and thus require offsets
|
||||
// so we do this. sucks to suck
|
||||
update_appearance()
|
||||
|
||||
// I so much wish this could be somewhere else. alas, no.
|
||||
for(var/image/update in update_on_z)
|
||||
SET_PLANE(update, PLANE_TO_TRUE(update.plane), new_turf)
|
||||
|
||||
if(!notify_contents)
|
||||
return
|
||||
|
||||
for (var/atom/movable/content as anything in src) // Notify contents of Z-transition.
|
||||
content.on_changed_z_level(old_turf, new_turf)
|
||||
content.on_changed_z_level(old_turf, new_turf, same_z_layer)
|
||||
|
||||
/**
|
||||
* Called whenever an object moves and by mobs when they attempt to move themselves through space
|
||||
|
||||
@@ -488,7 +488,9 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/camera/xray, 0)
|
||||
GLOB.cameranet.removeCamera(src)
|
||||
if (isarea(myarea))
|
||||
LAZYREMOVE(myarea.cameras, src)
|
||||
GLOB.cameranet.updateChunk(x, y, z)
|
||||
// We are not guarenteed that the camera will be on a turf. account for that
|
||||
var/turf/our_turf = get_turf(src)
|
||||
GLOB.cameranet.updateChunk(our_turf.x, our_turf.y, our_turf.z)
|
||||
var/change_msg = "deactivates"
|
||||
if(status)
|
||||
change_msg = "reactivates"
|
||||
@@ -532,10 +534,32 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/camera/xray, 0)
|
||||
/obj/machinery/camera/proc/can_see()
|
||||
var/list/see = null
|
||||
var/turf/pos = get_turf(src)
|
||||
var/check_lower = pos != get_lowest_turf(pos)
|
||||
var/check_higher = pos != get_highest_turf(pos)
|
||||
|
||||
if(isXRay())
|
||||
see = range(view_range, pos)
|
||||
else
|
||||
see = get_hear(view_range, pos)
|
||||
if(check_lower || check_higher)
|
||||
// Haha datum var access KILL ME
|
||||
var/datum/controller/subsystem/mapping/local_mapping = SSmapping
|
||||
for(var/turf/seen in see)
|
||||
if(check_lower)
|
||||
var/turf/visible = seen
|
||||
while(visible && istransparentturf(visible))
|
||||
var/turf/below = local_mapping.get_turf_below(visible)
|
||||
for(var/turf/adjacent in range(1, below))
|
||||
see += adjacent
|
||||
see += adjacent.contents
|
||||
visible = below
|
||||
if(check_higher)
|
||||
var/turf/above = local_mapping.get_turf_above(seen)
|
||||
while(above && istransparentturf(above))
|
||||
for(var/turf/adjacent in range(1, above))
|
||||
see += adjacent
|
||||
see += adjacent.contents
|
||||
above = local_mapping.get_turf_above(above)
|
||||
return see
|
||||
|
||||
/obj/machinery/camera/proc/Togglelight(on=0)
|
||||
@@ -553,11 +577,12 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/camera/xray, 0)
|
||||
user.overlay_fullscreen("remote_view", /atom/movable/screen/fullscreen/impaired, 2)
|
||||
|
||||
/obj/machinery/camera/update_remote_sight(mob/living/user)
|
||||
user.see_invisible = SEE_INVISIBLE_LIVING //can't see ghosts through cameras
|
||||
user.set_invis_see(SEE_INVISIBLE_LIVING) //can't see ghosts through cameras
|
||||
if(isXRay())
|
||||
user.sight |= (SEE_TURFS|SEE_MOBS|SEE_OBJS)
|
||||
user.see_in_dark = max(user.see_in_dark, 8)
|
||||
user.add_sight(SEE_TURFS|SEE_MOBS|SEE_OBJS)
|
||||
user.set_see_in_dark(max(user.see_in_dark, 8))
|
||||
else
|
||||
user.clear_sight(SEE_TURFS|SEE_MOBS|SEE_OBJS)
|
||||
user.sight = 0
|
||||
user.see_in_dark = 2
|
||||
user.set_see_in_dark(2)
|
||||
return 1
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
return
|
||||
|
||||
. += mutable_appearance(icon, icon_screen)
|
||||
. += emissive_appearance(icon, icon_screen)
|
||||
. += emissive_appearance(icon, icon_screen, src)
|
||||
*/
|
||||
|
||||
/obj/machinery/computer/power_change()
|
||||
|
||||
@@ -15,10 +15,8 @@
|
||||
var/list/concurrent_users = list()
|
||||
|
||||
// Stuff needed to render the map
|
||||
var/map_name
|
||||
var/atom/movable/screen/map_view/cam_screen
|
||||
/// All the plane masters that need to be applied.
|
||||
var/list/cam_plane_masters
|
||||
var/atom/movable/screen/background/cam_background
|
||||
|
||||
interaction_flags_machine = INTERACT_MACHINE_ALLOW_SILICON|INTERACT_MACHINE_SET_MACHINE|INTERACT_MACHINE_REQUIRES_SIGHT
|
||||
@@ -28,33 +26,20 @@
|
||||
// Map name has to start and end with an A-Z character,
|
||||
// and definitely NOT with a square bracket or even a number.
|
||||
// I wasted 6 hours on this. :agony:
|
||||
map_name = "camera_console_[REF(src)]_map"
|
||||
var/map_name = "camera_console_[REF(src)]_map"
|
||||
// Convert networks to lowercase
|
||||
for(var/i in network)
|
||||
network -= i
|
||||
network += lowertext(i)
|
||||
// Initialize map objects
|
||||
cam_screen = new
|
||||
cam_screen.name = "screen"
|
||||
cam_screen.assigned_map = map_name
|
||||
cam_screen.del_on_map_removal = FALSE
|
||||
cam_screen.screen_loc = "[map_name]:1,1"
|
||||
cam_plane_masters = list()
|
||||
for(var/plane in subtypesof(/atom/movable/screen/plane_master) - /atom/movable/screen/plane_master/blackness)
|
||||
var/atom/movable/screen/plane_master/instance = new plane()
|
||||
if(instance.blend_mode_override)
|
||||
instance.blend_mode = instance.blend_mode_override
|
||||
instance.assigned_map = map_name
|
||||
instance.del_on_map_removal = FALSE
|
||||
instance.screen_loc = "[map_name]:CENTER"
|
||||
cam_plane_masters += instance
|
||||
cam_screen.generate_view(map_name)
|
||||
cam_background = new
|
||||
cam_background.assigned_map = map_name
|
||||
cam_background.del_on_map_removal = FALSE
|
||||
|
||||
/obj/machinery/computer/security/Destroy()
|
||||
QDEL_NULL(cam_screen)
|
||||
QDEL_LIST(cam_plane_masters)
|
||||
QDEL_NULL(cam_background)
|
||||
return ..()
|
||||
|
||||
@@ -83,9 +68,7 @@
|
||||
playsound(src, 'sound/machines/terminal_on.ogg', 25, FALSE)
|
||||
use_power(active_power_usage)
|
||||
// Register map objects
|
||||
user.client.register_map_obj(cam_screen)
|
||||
for(var/plane in cam_plane_masters)
|
||||
user.client.register_map_obj(plane)
|
||||
cam_screen.display_to(user)
|
||||
user.client.register_map_obj(cam_background)
|
||||
// Open UI
|
||||
ui = new(user, src, "CameraConsole", name)
|
||||
@@ -110,7 +93,7 @@
|
||||
|
||||
/obj/machinery/computer/security/ui_static_data()
|
||||
var/list/data = list()
|
||||
data["mapRef"] = map_name
|
||||
data["mapRef"] = cam_screen.assigned_map
|
||||
var/list/cameras = get_available_cameras()
|
||||
data["cameras"] = list()
|
||||
for(var/i in cameras)
|
||||
@@ -181,7 +164,7 @@
|
||||
// Living creature or not, we remove you anyway.
|
||||
concurrent_users -= user_ref
|
||||
// Unregister map objects
|
||||
user.client.clear_map(map_name)
|
||||
cam_screen.hide_from(user)
|
||||
// Turn off the console
|
||||
if(length(concurrent_users) == 0 && is_living)
|
||||
active_camera = null
|
||||
|
||||
@@ -92,6 +92,9 @@
|
||||
user.remote_control = null
|
||||
current_user = null
|
||||
user.unset_machine()
|
||||
var/atom/movable/screen/plane_master/plane_static = user.hud_used?.get_plane_master(CAMERA_STATIC_PLANE)
|
||||
if(plane_static)
|
||||
plane_static.hide_plane(user)
|
||||
playsound(src, 'sound/machines/terminal_off.ogg', 25, FALSE)
|
||||
|
||||
/obj/machinery/computer/camera_advanced/check_eye(mob/user)
|
||||
@@ -174,8 +177,12 @@
|
||||
user.remote_control = eyeobj
|
||||
user.reset_perspective(eyeobj)
|
||||
eyeobj.setLoc(eyeobj.loc)
|
||||
if(should_supress_view_changes )
|
||||
if(should_supress_view_changes)
|
||||
user.client.view_size.supress()
|
||||
// Who passes control like this god I hate static code
|
||||
var/atom/movable/screen/plane_master/plane_static = user.hud_used?.get_plane_master(CAMERA_STATIC_PLANE)
|
||||
if(plane_static)
|
||||
plane_static.unhide_plane(user)
|
||||
|
||||
/mob/camera/ai_eye/remote
|
||||
name = "Inactive Camera Eye"
|
||||
@@ -190,9 +197,9 @@
|
||||
var/image/user_image = null
|
||||
|
||||
/mob/camera/ai_eye/remote/update_remote_sight(mob/living/user)
|
||||
user.see_invisible = SEE_INVISIBLE_LIVING //can't see ghosts through cameras
|
||||
user.sight = SEE_TURFS | SEE_BLACKNESS
|
||||
user.see_in_dark = 2
|
||||
user.set_invis_see(SEE_INVISIBLE_LIVING) //can't see ghosts through cameras
|
||||
user.set_sight(SEE_TURFS)
|
||||
user.set_see_in_dark(2)
|
||||
return TRUE
|
||||
|
||||
/mob/camera/ai_eye/remote/Destroy()
|
||||
@@ -224,7 +231,7 @@
|
||||
if(eye_user.client)
|
||||
eye_user.client.images -= user_image
|
||||
user_image = image(icon,loc,icon_state, FLY_LAYER)
|
||||
user_image.plane = ABOVE_GAME_PLANE
|
||||
SET_PLANE(user_image, ABOVE_GAME_PLANE, destination)
|
||||
eye_user.client.images += user_image
|
||||
|
||||
/mob/camera/ai_eye/remote/relaymove(mob/living/user, direction)
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
/// Someone, for the love of god, profile this. Is there a reason to cache mutable_appearance
|
||||
/// if so, why are we JUST doing the airlocks when we can put this in mutable_appearance.dm for
|
||||
/// everything
|
||||
/proc/get_airlock_overlay(icon_state, icon_file, em_block)
|
||||
/proc/get_airlock_overlay(icon_state, icon_file, atom/offset_spokesman, em_block)
|
||||
var/static/list/airlock_overlays = list()
|
||||
|
||||
var/base_icon_key = "[icon_state][REF(icon_file)]"
|
||||
@@ -31,10 +31,12 @@
|
||||
if(isnull(em_block))
|
||||
return
|
||||
|
||||
var/em_block_key = "[base_icon_key][em_block]"
|
||||
var/turf/our_turf = get_turf(offset_spokesman)
|
||||
|
||||
var/em_block_key = "[base_icon_key][em_block][GET_TURF_PLANE_OFFSET(our_turf)]"
|
||||
var/mutable_appearance/em_blocker = airlock_overlays[em_block_key]
|
||||
if(!em_blocker)
|
||||
em_blocker = airlock_overlays[em_block_key] = mutable_appearance(icon_file, icon_state, plane = EMISSIVE_PLANE, appearance_flags = EMISSIVE_APPEARANCE_FLAGS)
|
||||
em_blocker = airlock_overlays[em_block_key] = mutable_appearance(icon_file, icon_state, offset_spokesman = offset_spokesman, plane = EMISSIVE_PLANE, appearance_flags = EMISSIVE_APPEARANCE_FLAGS)
|
||||
em_blocker.color = em_block ? GLOB.em_block_color : GLOB.emissive_color
|
||||
|
||||
return list(., em_blocker)
|
||||
@@ -150,23 +152,10 @@
|
||||
rad_insulation = RAD_MEDIUM_INSULATION
|
||||
|
||||
/obj/machinery/door/airlock/Initialize(mapload)
|
||||
//SKYRAT EDIT ADDITION BEGIN - Door aesthetic overhaul
|
||||
vis_overlay1 = new()
|
||||
vis_overlay1.icon = overlays_file
|
||||
vis_overlay2 = new()
|
||||
vis_overlay2.icon = overlays_file
|
||||
vis_overlay2.layer = layer
|
||||
vis_overlay2.plane = 1
|
||||
vis_contents += vis_overlay1
|
||||
vis_contents += vis_overlay2
|
||||
//SKYRAT EDIT END
|
||||
. = ..()
|
||||
//SKYRAT EDIT ADDITION BEGIN - Door aesthetic overhaul
|
||||
if(multi_tile)
|
||||
SetBounds()
|
||||
if(multi_tile)
|
||||
vis_overlay1.dir = src.dir
|
||||
vis_overlay2.dir = src.dir
|
||||
update_overlays()
|
||||
//SKYRAT EDIT END
|
||||
init_network_id(NETWORK_DOOR_AIRLOCKS)
|
||||
@@ -519,45 +508,44 @@
|
||||
frame_state = AIRLOCK_FRAME_OPENING
|
||||
light_state = AIRLOCK_LIGHT_OPENING
|
||||
|
||||
. += get_airlock_overlay(frame_state, icon, em_block = TRUE)
|
||||
. += get_airlock_overlay(frame_state, icon, src, em_block = TRUE)
|
||||
if(airlock_material)
|
||||
. += get_airlock_overlay("[airlock_material]_[frame_state]", overlays_file, em_block = TRUE)
|
||||
. += get_airlock_overlay("[airlock_material]_[frame_state]", overlays_file, src, em_block = TRUE)
|
||||
else
|
||||
. += get_airlock_overlay("fill_[frame_state]", icon, em_block = TRUE)
|
||||
. += get_airlock_overlay("fill_[frame_state]", icon, src, em_block = TRUE)
|
||||
|
||||
if(lights && hasPower())
|
||||
. += get_airlock_overlay("lights_[light_state]", overlays_file, em_block = FALSE)
|
||||
. += get_airlock_overlay("lights_[light_state]", overlays_file, src, em_block = FALSE)
|
||||
|
||||
if(panel_open)
|
||||
. += get_airlock_overlay("panel_[frame_state][security_level ? "_protected" : null]", overlays_file, em_block = TRUE)
|
||||
. += get_airlock_overlay("panel_[frame_state][security_level ? "_protected" : null]", overlays_file, src, em_block = TRUE)
|
||||
if(frame_state == AIRLOCK_FRAME_CLOSED && welded)
|
||||
. += get_airlock_overlay("welded", overlays_file, em_block = TRUE)
|
||||
. += get_airlock_overlay("welded", overlays_file, src, em_block = TRUE)
|
||||
|
||||
if(airlock_state == AIRLOCK_EMAG)
|
||||
. += get_airlock_overlay("sparks", overlays_file, em_block = FALSE)
|
||||
. += get_airlock_overlay("sparks", overlays_file, src, em_block = FALSE)
|
||||
|
||||
if(hasPower())
|
||||
if(frame_state == AIRLOCK_FRAME_CLOSED)
|
||||
if(atom_integrity < integrity_failure * max_integrity)
|
||||
. += get_airlock_overlay("sparks_broken", overlays_file, em_block = FALSE)
|
||||
. += get_airlock_overlay("sparks_broken", overlays_file, src, em_block = FALSE)
|
||||
else if(atom_integrity < (0.75 * max_integrity))
|
||||
. += get_airlock_overlay("sparks_damaged", overlays_file, em_block = FALSE)
|
||||
. += get_airlock_overlay("sparks_damaged", overlays_file, src, em_block = FALSE)
|
||||
else if(frame_state == AIRLOCK_FRAME_OPEN)
|
||||
if(atom_integrity < (0.75 * max_integrity))
|
||||
. += get_airlock_overlay("sparks_open", overlays_file, em_block = FALSE)
|
||||
. += get_airlock_overlay("sparks_open", overlays_file, src, em_block = FALSE)
|
||||
|
||||
if(note)
|
||||
. += get_airlock_overlay(get_note_state(frame_state), note_overlay_file, em_block = TRUE)
|
||||
. += get_airlock_overlay(get_note_state(frame_state), note_overlay_file, src, em_block = TRUE)
|
||||
|
||||
if(frame_state == AIRLOCK_FRAME_CLOSED && seal)
|
||||
. += get_airlock_overlay("sealed", overlays_file, em_block = TRUE)
|
||||
. += get_airlock_overlay("sealed", overlays_file, src, em_block = TRUE)
|
||||
|
||||
if(hasPower() && unres_sides)
|
||||
for(var/heading in list(NORTH,SOUTH,EAST,WEST))
|
||||
if(!(unres_sides & heading))
|
||||
continue
|
||||
var/image/floorlight = image(icon='icons/obj/doors/airlocks/station/overlays.dmi', icon_state="unres_[heading]")
|
||||
floorlight.plane = ABOVE_LIGHTING_PLANE
|
||||
var/mutable_appearance/floorlight = mutable_appearance('icons/obj/doors/airlocks/station/overlays.dmi', "unres_[heading]", FLOAT_LAYER, src, ABOVE_LIGHTING_PLANE)
|
||||
switch (heading)
|
||||
if (NORTH)
|
||||
floorlight.pixel_x = 0
|
||||
|
||||
@@ -601,7 +601,7 @@
|
||||
hazards.pixel_x = light_xoffset
|
||||
hazards.pixel_y = light_yoffset
|
||||
. += hazards
|
||||
hazards = emissive_appearance(icon, "[(obj_flags & EMAGGED) ? "firelock_alarm_type_emag" : alarm_type]", alpha = src.alpha)
|
||||
hazards = emissive_appearance(icon, "[(obj_flags & EMAGGED) ? "firelock_alarm_type_emag" : alarm_type]", src, alpha = src.alpha)
|
||||
hazards.pixel_x = light_xoffset
|
||||
hazards.pixel_y = light_yoffset
|
||||
. += hazards
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
/obj/machinery/ecto_sniffer/update_overlays()
|
||||
. = ..()
|
||||
if(is_operational && on)
|
||||
. += emissive_appearance(icon, "[initial(icon_state)]-light-mask", alpha = src.alpha)
|
||||
. += emissive_appearance(icon, "[initial(icon_state)]-light-mask", src, alpha = src.alpha)
|
||||
|
||||
/obj/machinery/ecto_sniffer/wrench_act(mob/living/user, obj/item/tool)
|
||||
tool.play_tool_sound(src, 15)
|
||||
|
||||
@@ -129,25 +129,25 @@
|
||||
. += mutable_appearance(icon, "fire_overlay")
|
||||
if(is_station_level(z))
|
||||
. += mutable_appearance(icon, "fire_[SSsecurity_level.get_current_level_as_number()]")
|
||||
. += emissive_appearance(icon, "fire_[SSsecurity_level.get_current_level_as_number()]", alpha = src.alpha)
|
||||
. += emissive_appearance(icon, "fire_[SSsecurity_level.get_current_level_as_number()]", src, alpha = src.alpha)
|
||||
else
|
||||
. += mutable_appearance(icon, "fire_[SEC_LEVEL_GREEN]")
|
||||
. += emissive_appearance(icon, "fire_[SEC_LEVEL_GREEN]", alpha = src.alpha)
|
||||
. += emissive_appearance(icon, "fire_[SEC_LEVEL_GREEN]", src, alpha = src.alpha)
|
||||
|
||||
if(!(my_area?.fire || LAZYLEN(my_area?.active_firelocks)))
|
||||
if(my_area?.fire_detect) //If this is false, leave the green light missing. A good hint to anyone paying attention.
|
||||
. += mutable_appearance(icon, "fire_off")
|
||||
. += emissive_appearance(icon, "fire_off", alpha = src.alpha)
|
||||
. += emissive_appearance(icon, "fire_off", src, alpha = src.alpha)
|
||||
else if(obj_flags & EMAGGED)
|
||||
. += mutable_appearance(icon, "fire_emagged")
|
||||
. += emissive_appearance(icon, "fire_emagged", alpha = src.alpha)
|
||||
. += emissive_appearance(icon, "fire_emagged", src, alpha = src.alpha)
|
||||
else
|
||||
. += mutable_appearance(icon, "fire_on")
|
||||
. += emissive_appearance(icon, "fire_on", alpha = src.alpha)
|
||||
. += emissive_appearance(icon, "fire_on", src, alpha = src.alpha)
|
||||
|
||||
if(!panel_open && my_area?.fire_detect && my_area?.fire) //It just looks horrible with the panel open
|
||||
. += mutable_appearance(icon, "fire_detected")
|
||||
. += emissive_appearance(icon, "fire_detected", alpha = src.alpha) //Pain
|
||||
. += emissive_appearance(icon, "fire_detected", src, alpha = src.alpha) //Pain
|
||||
|
||||
/obj/machinery/firealarm/emp_act(severity)
|
||||
. = ..()
|
||||
|
||||
@@ -90,8 +90,8 @@ Possible to do for anyone motivated enough:
|
||||
/obj/machinery/holopad/Initialize(mapload)
|
||||
. = ..()
|
||||
/// We set the plane on mapload such that we can see the holopad render over atmospherics pipe and cabling in a map editor (without initialization), but so it gets that "inset" look in the floor in-game.
|
||||
plane = FLOOR_PLANE
|
||||
update_overlays()
|
||||
SET_PLANE_IMPLICIT(src, FLOOR_PLANE)
|
||||
update_appearance()
|
||||
|
||||
/obj/machinery/holopad/secure
|
||||
name = "secure holopad"
|
||||
@@ -554,7 +554,7 @@ Possible to do for anyone motivated enough:
|
||||
|
||||
Hologram.mouse_opacity = MOUSE_OPACITY_TRANSPARENT//So you can't click on it.
|
||||
Hologram.layer = FLY_LAYER //Above all the other objects/mobs. Or the vast majority of them.
|
||||
Hologram.plane = ABOVE_GAME_PLANE
|
||||
SET_PLANE_EXPLICIT(Hologram, ABOVE_GAME_PLANE, src)
|
||||
Hologram.set_anchored(TRUE)//So space wind cannot drag it.
|
||||
Hologram.name = "[user.name] (Hologram)"//If someone decides to right click.
|
||||
Hologram.set_light(2) //hologram lighting
|
||||
@@ -704,6 +704,7 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
|
||||
transfered = TRUE
|
||||
//All is good.
|
||||
holo.abstract_move(new_turf)
|
||||
SET_PLANE(holo, ABOVE_GAME_PLANE, new_turf)
|
||||
if(!transfered)
|
||||
update_holoray(user,new_turf)
|
||||
return TRUE
|
||||
@@ -744,7 +745,7 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
|
||||
holder.selected_language = record.language
|
||||
Hologram.mouse_opacity = MOUSE_OPACITY_TRANSPARENT//So you can't click on it.
|
||||
Hologram.layer = FLY_LAYER//Above all the other objects/mobs. Or the vast majority of them.
|
||||
Hologram.plane = ABOVE_GAME_PLANE
|
||||
SET_PLANE_EXPLICIT(Hologram, ABOVE_GAME_PLANE, src)
|
||||
Hologram.set_anchored(TRUE)//So space wind cannot drag it.
|
||||
Hologram.name = "[record.caller_name] (Hologram)"//If someone decides to right click.
|
||||
Hologram.set_light(2) //hologram lighting
|
||||
|
||||
@@ -37,13 +37,17 @@
|
||||
for(var/datum/atom_hud/data/diagnostic/diag_hud in GLOB.huds)
|
||||
diag_hud.add_atom_to_hud(src)
|
||||
|
||||
update_hud()
|
||||
|
||||
/obj/machinery/launchpad/on_changed_z_level(turf/old_turf, turf/new_turf, same_z_layer, notify_contents)
|
||||
if(same_z_layer && !QDELETED(src))
|
||||
update_hud()
|
||||
return ..()
|
||||
|
||||
/obj/machinery/launchpad/proc/update_hud()
|
||||
var/image/holder = hud_list[DIAG_LAUNCHPAD_HUD]
|
||||
var/mutable_appearance/MA = new /mutable_appearance()
|
||||
MA.icon = 'icons/effects/effects.dmi'
|
||||
MA.icon_state = "launchpad_target"
|
||||
MA.layer = ABOVE_OPEN_TURF_LAYER
|
||||
MA.plane = GAME_PLANE
|
||||
holder.appearance = MA
|
||||
var/mutable_appearance/target = mutable_appearance('icons/effects/effects.dmi', "launchpad_target", ABOVE_OPEN_TURF_LAYER, src, GAME_PLANE)
|
||||
holder.appearance = target
|
||||
|
||||
update_indicator()
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/light_switch, 26)
|
||||
. = ..()
|
||||
if(machine_stat & NOPOWER)
|
||||
return ..()
|
||||
. += emissive_appearance(icon, "[base_icon_state]-emissive[area.lightswitch ? "-on" : "-off"]", alpha = src.alpha)
|
||||
. += emissive_appearance(icon, "[base_icon_state]-emissive[area.lightswitch ? "-on" : "-off"]", src, alpha = src.alpha)
|
||||
|
||||
/obj/machinery/light_switch/examine(mob/user)
|
||||
. = ..()
|
||||
|
||||
@@ -34,12 +34,12 @@
|
||||
glob_lists_deregister()
|
||||
return ..()
|
||||
|
||||
/obj/machinery/navbeacon/on_changed_z_level(turf/old_turf, turf/new_turf)
|
||||
/obj/machinery/navbeacon/on_changed_z_level(turf/old_turf, turf/new_turf, same_z_layer, notify_contents)
|
||||
if (GLOB.navbeacons["[old_turf?.z]"])
|
||||
GLOB.navbeacons["[old_turf?.z]"] -= src
|
||||
if (GLOB.navbeacons["[new_turf?.z]"])
|
||||
GLOB.navbeacons["[new_turf?.z]"] += src
|
||||
..()
|
||||
return ..()
|
||||
|
||||
// set the transponder codes assoc list from codes_txt
|
||||
/obj/machinery/navbeacon/proc/set_codes()
|
||||
|
||||
@@ -85,14 +85,15 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/newscaster, 30)
|
||||
/obj/machinery/newscaster/update_overlays()
|
||||
. = ..()
|
||||
|
||||
|
||||
if(!(machine_stat & (NOPOWER|BROKEN)))
|
||||
var/state = "[base_icon_state]_[GLOB.news_network.wanted_issue.active ? "wanted" : "normal"]"
|
||||
. += mutable_appearance(icon, state)
|
||||
. += emissive_appearance(icon, state, alpha = src.alpha)
|
||||
. += emissive_appearance(icon, state, src, alpha = src.alpha)
|
||||
|
||||
if(GLOB.news_network.wanted_issue.active && alert)
|
||||
. += mutable_appearance(icon, "[base_icon_state]_alert")
|
||||
. += emissive_appearance(icon, "[base_icon_state]_alert", alpha = src.alpha)
|
||||
. += emissive_appearance(icon, "[base_icon_state]_alert", src, alpha = src.alpha,)
|
||||
|
||||
var/hp_percent = atom_integrity * 100 / max_integrity
|
||||
switch(hp_percent)
|
||||
@@ -100,13 +101,13 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/newscaster, 30)
|
||||
return
|
||||
if(50 to 75)
|
||||
. += "crack1"
|
||||
. += emissive_blocker(icon, "crack1", alpha = src.alpha)
|
||||
. += emissive_blocker(icon, "crack1", src, alpha = src.alpha)
|
||||
if(25 to 50)
|
||||
. += "crack2"
|
||||
. += emissive_blocker(icon, "crack2", alpha = src.alpha)
|
||||
. += emissive_blocker(icon, "crack2", src, alpha = src.alpha)
|
||||
else
|
||||
. += "crack3"
|
||||
. += emissive_blocker(icon, "crack3", alpha = src.alpha)
|
||||
. += emissive_blocker(icon, "crack3", src, alpha = src.alpha)
|
||||
|
||||
/obj/machinery/newscaster/ui_interact(mob/user, datum/tgui/ui)
|
||||
. = ..()
|
||||
|
||||
@@ -204,13 +204,13 @@
|
||||
|
||||
if(!charging)
|
||||
. += mutable_appearance(icon, "[base_icon_state]-empty", alpha = src.alpha)
|
||||
. += emissive_appearance(icon, "[base_icon_state]-empty", alpha = src.alpha)
|
||||
. += emissive_appearance(icon, "[base_icon_state]-empty", src, alpha = src.alpha)
|
||||
return
|
||||
|
||||
if(using_power)
|
||||
. += mutable_appearance(icon, "[base_icon_state]-charging", alpha = src.alpha)
|
||||
. += emissive_appearance(icon, "[base_icon_state]-charging", alpha = src.alpha)
|
||||
. += emissive_appearance(icon, "[base_icon_state]-charging", src, alpha = src.alpha)
|
||||
return
|
||||
|
||||
. += mutable_appearance(icon, "[base_icon_state]-full", alpha = src.alpha)
|
||||
. += emissive_appearance(icon, "[base_icon_state]-full", alpha = src.alpha)
|
||||
. += emissive_appearance(icon, "[base_icon_state]-full", src, alpha = src.alpha)
|
||||
|
||||
@@ -109,7 +109,7 @@ GLOBAL_LIST_EMPTY(req_console_ckey_departments)
|
||||
screen_state = "[base_icon_state]0"
|
||||
|
||||
. += mutable_appearance(icon, screen_state)
|
||||
. += emissive_appearance(icon, screen_state, alpha = src.alpha)
|
||||
. += emissive_appearance(icon, screen_state, src, alpha = src.alpha)
|
||||
|
||||
/obj/machinery/requests_console/Initialize(mapload)
|
||||
. = ..()
|
||||
|
||||
@@ -88,6 +88,11 @@
|
||||
var/easing_direction = _running ? EASE_OUT : EASE_IN
|
||||
animate(mattress_on, alpha = new_alpha, time = 50, easing = CUBIC_EASING|easing_direction)
|
||||
|
||||
/obj/machinery/stasis/on_changed_z_level(turf/old_turf, turf/new_turf, same_z_layer, notify_contents)
|
||||
if(same_z_layer)
|
||||
return ..()
|
||||
SET_PLANE(mattress_on, PLANE_TO_TRUE(mattress_on.plane), new_turf)
|
||||
return ..()
|
||||
|
||||
/obj/machinery/stasis/atom_break(damage_flag)
|
||||
. = ..()
|
||||
|
||||
@@ -174,7 +174,7 @@
|
||||
if(message1 == "" && message2 == "")
|
||||
return
|
||||
|
||||
. += emissive_appearance(icon, "outline", alpha = src.alpha)
|
||||
. += emissive_appearance(icon, "outline", src, alpha = src.alpha)
|
||||
|
||||
// Timed process - performs nothing in the base class
|
||||
/obj/machinery/status_display/process()
|
||||
|
||||
@@ -131,6 +131,12 @@
|
||||
warp = null
|
||||
return ..()
|
||||
|
||||
/obj/effect/anomaly/grav/on_changed_z_level(turf/old_turf, turf/new_turf, same_z_layer, notify_contents)
|
||||
. = ..()
|
||||
if(same_z_layer)
|
||||
return
|
||||
SET_PLANE(warp, PLANE_TO_TRUE(warp.plane), new_turf)
|
||||
|
||||
/obj/effect/anomaly/grav/anomalyEffect(delta_time)
|
||||
..()
|
||||
boing = 1
|
||||
@@ -219,7 +225,7 @@
|
||||
|
||||
/obj/effect/anomaly/flux/update_overlays()
|
||||
. = ..()
|
||||
. += emissive_appearance(icon, icon_state, alpha=src.alpha)
|
||||
. += emissive_appearance(icon, icon_state, src, alpha=src.alpha)
|
||||
|
||||
/obj/effect/anomaly/flux/proc/on_entered(datum/source, atom/movable/AM)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
@@ -72,6 +72,7 @@
|
||||
/obj/effect/decal/cleanable/blood/splatter/over_window // special layer/plane set to appear on windows
|
||||
layer = ABOVE_WINDOW_LAYER
|
||||
plane = GAME_PLANE
|
||||
vis_flags = VIS_INHERIT_PLANE
|
||||
turf_loc_check = FALSE
|
||||
alpha = 180
|
||||
|
||||
|
||||
@@ -321,6 +321,8 @@
|
||||
/obj/effect/decal/cleanable/ants/update_icon_state()
|
||||
if(istype(src, /obj/effect/decal/cleanable/ants/fire)) //i fucking hate this but you're forced to call parent in update_icon_state()
|
||||
return ..()
|
||||
if(!(flags_1 & INITIALIZED_1))
|
||||
return ..()
|
||||
|
||||
var/datum/component/caltrop/caltrop_comp = GetComponent(/datum/component/caltrop)
|
||||
if(!caltrop_comp)
|
||||
@@ -339,7 +341,7 @@
|
||||
|
||||
/obj/effect/decal/cleanable/ants/update_overlays()
|
||||
. = ..()
|
||||
. += emissive_appearance(icon, "[icon_state]_light", alpha = src.alpha)
|
||||
. += emissive_appearance(icon, "[icon_state]_light", src, alpha = src.alpha)
|
||||
|
||||
/obj/effect/decal/cleanable/ants/fire_act(exposed_temperature, exposed_volume)
|
||||
var/obj/effect/decal/cleanable/ants/fire/fire_ants = new(loc)
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF | FREEZE_PROOF
|
||||
move_resist = INFINITY
|
||||
obj_flags = NONE
|
||||
vis_flags = VIS_INHERIT_PLANE
|
||||
blocks_emissive = EMISSIVE_BLOCK_GENERIC
|
||||
|
||||
/obj/effect/attackby(obj/item/weapon, mob/user, params)
|
||||
|
||||
@@ -65,8 +65,8 @@
|
||||
appearance_flags = RESET_TRANSFORM | TILE_BOUND
|
||||
invisibility = INVISIBILITY_ABSTRACT
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
|
||||
plane = ATMOS_GROUP_PLANE
|
||||
vis_flags = VIS_INHERIT_PLANE
|
||||
plane = HIGH_GAME_PLANE
|
||||
|
||||
/// Door overlay for animating closets
|
||||
/obj/effect/overlay/closet_door
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
anchored = TRUE
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
layer = ABOVE_ALL_MOB_LAYER
|
||||
vis_flags = VIS_INHERIT_PLANE
|
||||
///typepath of the last location we're in, if it's different when moved then we need to update vis contents
|
||||
var/last_attached_location_type
|
||||
///the main item we're attached to at the moment, particle holders hold particles for something
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
if(SOUTH)
|
||||
target_pixel_y = -16
|
||||
layer = ABOVE_MOB_LAYER
|
||||
plane = GAME_PLANE_UPPER
|
||||
SET_PLANE_IMPLICIT(src, GAME_PLANE_UPPER)
|
||||
if(EAST)
|
||||
target_pixel_x = 16
|
||||
if(WEST)
|
||||
@@ -36,12 +36,12 @@
|
||||
target_pixel_x = 16
|
||||
target_pixel_y = -16
|
||||
layer = ABOVE_MOB_LAYER
|
||||
plane = GAME_PLANE_UPPER
|
||||
SET_PLANE_IMPLICIT(src, GAME_PLANE_UPPER)
|
||||
if(SOUTHWEST)
|
||||
target_pixel_x = -16
|
||||
target_pixel_y = -16
|
||||
layer = ABOVE_MOB_LAYER
|
||||
plane = GAME_PLANE_UPPER
|
||||
SET_PLANE_IMPLICIT(src, GAME_PLANE_UPPER)
|
||||
animate(src, pixel_x = target_pixel_x, pixel_y = target_pixel_y, alpha = 0, time = duration)
|
||||
|
||||
/obj/effect/temp_visual/dir_setting/bloodsplatter/xenosplatter
|
||||
@@ -564,6 +564,7 @@
|
||||
return INITIALIZE_HINT_QDEL
|
||||
modsuit_image = image(icon = icon, loc = looker.loc, icon_state = real_icon_state, layer = ABOVE_ALL_MOB_LAYER, pixel_x = ((creature.x - looker.x) * 32), pixel_y = ((creature.y - looker.y) * 32))
|
||||
modsuit_image.plane = ABOVE_LIGHTING_PLANE
|
||||
SET_PLANE_EXPLICIT(modsuit_image, ABOVE_LIGHTING_PLANE, creature)
|
||||
mod_man = WEAKREF(looker)
|
||||
add_mind(looker)
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
|
||||
/obj/effect/projectile/proc/apply_vars(angle_override, p_x = 0, p_y = 0, color_override, scaling = 1, new_loc, increment = 0)
|
||||
var/mutable_appearance/look = new(src)
|
||||
look.plane = plane
|
||||
SET_PLANE_EXPLICIT(look, plane, new_loc)
|
||||
look.pixel_x = p_x
|
||||
look.pixel_y = p_y
|
||||
if(color_override)
|
||||
|
||||
@@ -1129,18 +1129,22 @@ GLOBAL_DATUM_INIT(welding_sparks, /mutable_appearance, mutable_appearance('icons
|
||||
return 0
|
||||
|
||||
/obj/item/doMove(atom/destination)
|
||||
if (ismob(loc))
|
||||
var/mob/M = loc
|
||||
var/hand_index = M.get_held_index_of_item(src)
|
||||
if(hand_index)
|
||||
M.held_items[hand_index] = null
|
||||
M.update_held_items()
|
||||
if(M.client)
|
||||
M.client.screen -= src
|
||||
layer = initial(layer)
|
||||
plane = initial(plane)
|
||||
appearance_flags &= ~NO_CLIENT_COLOR
|
||||
dropped(M, FALSE)
|
||||
if (!ismob(loc))
|
||||
return ..()
|
||||
|
||||
var/mob/M = loc
|
||||
var/hand_index = M.get_held_index_of_item(src)
|
||||
if(!hand_index)
|
||||
return ..()
|
||||
|
||||
M.held_items[hand_index] = null
|
||||
M.update_held_items()
|
||||
if(M.client)
|
||||
M.client.screen -= src
|
||||
layer = initial(layer)
|
||||
SET_PLANE_IMPLICIT(src, initial(plane))
|
||||
appearance_flags &= ~NO_CLIENT_COLOR
|
||||
dropped(M, FALSE)
|
||||
return ..()
|
||||
|
||||
/obj/item/proc/embedded(atom/embedded_target, obj/item/bodypart/part)
|
||||
@@ -1452,7 +1456,7 @@ GLOBAL_DATUM_INIT(welding_sparks, /mutable_appearance, mutable_appearance('icons
|
||||
if(!istype(loc, /turf))
|
||||
return
|
||||
var/image/pickup_animation = image(icon = src, loc = loc, layer = layer + 0.1)
|
||||
pickup_animation.plane = GAME_PLANE
|
||||
SET_PLANE(pickup_animation, GAME_PLANE, loc)
|
||||
pickup_animation.transform.Scale(0.75)
|
||||
pickup_animation.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA
|
||||
|
||||
|
||||
@@ -148,9 +148,7 @@
|
||||
return html
|
||||
|
||||
/obj/item/camera_bug/proc/get_seens()
|
||||
if(current?.can_use())
|
||||
var/list/seen = current.can_see()
|
||||
return seen
|
||||
return current?.can_see()
|
||||
|
||||
/obj/item/camera_bug/proc/camera_report()
|
||||
// this should only be called if current exists
|
||||
|
||||
@@ -62,10 +62,10 @@
|
||||
return
|
||||
playsound(get_turf(src), 'sound/weapons/flash.ogg', 100, TRUE, -6)
|
||||
to_chat(user, span_notice("Scanned [target]."))
|
||||
var/obj/temp = new/obj()
|
||||
var/obj/temp = new /obj()
|
||||
temp.appearance = target.appearance
|
||||
temp.layer = initial(target.layer) // scanning things in your inventory
|
||||
temp.plane = initial(target.plane)
|
||||
SET_PLANE_EXPLICIT(temp, initial(plane), src)
|
||||
saved_appearance = temp.appearance
|
||||
|
||||
/obj/item/chameleon/proc/check_sprite(atom/target)
|
||||
|
||||
@@ -5,20 +5,23 @@
|
||||
var/obj/item/clothing/accessory/spy_bug/linked_bug
|
||||
|
||||
/obj/item/clothing/glasses/sunglasses/spy/proc/show_to_user(mob/user)//this is the meat of it. most of the map_popup usage is in this.
|
||||
if(!user)
|
||||
return
|
||||
if(!user.client)
|
||||
var/client/cool_guy = user?.client
|
||||
if(!cool_guy)
|
||||
return
|
||||
if(!linked_bug)
|
||||
user.audible_message(span_warning("[src] lets off a shrill beep!"))
|
||||
if(user.client.screen_maps["spypopup_map"]) //alright, the popup this object uses is already IN use, so the window is open. no point in doing any other work here, so we're good.
|
||||
if(cool_guy.screen_maps["spypopup_map"]) //alright, the popup this object uses is already IN use, so the window is open. no point in doing any other work here, so we're good.
|
||||
return
|
||||
user.client.setup_popup("spypopup", 3, 3, 2)
|
||||
user.client.register_map_obj(linked_bug.cam_screen)
|
||||
for(var/plane in linked_bug.cam_plane_masters)
|
||||
user.client.register_map_obj(plane)
|
||||
cool_guy.setup_popup("spypopup", 3, 3, 2, "S.P.Y")
|
||||
linked_bug.cam_screen.display_to(user)
|
||||
RegisterSignal(cool_guy, COMSIG_POPUP_CLEARED, .proc/on_screen_clear)
|
||||
|
||||
linked_bug.update_view()
|
||||
|
||||
/obj/item/clothing/glasses/sunglasses/spy/proc/on_screen_clear(client/source, window)
|
||||
SIGNAL_HANDLER
|
||||
linked_bug.cam_screen.hide_from(source.mob)
|
||||
|
||||
/obj/item/clothing/glasses/sunglasses/spy/equipped(mob/user, slot)
|
||||
. = ..()
|
||||
if(!(slot & ITEM_SLOT_EYES))
|
||||
@@ -51,7 +54,6 @@
|
||||
desc = "An advanced piece of espionage equipment in the shape of a pocket protector. It has a built in 360 degree camera for all your \"admirable\" needs. Microphone not included."
|
||||
var/obj/item/clothing/glasses/sunglasses/spy/linked_glasses
|
||||
var/atom/movable/screen/map_view/cam_screen
|
||||
var/list/cam_plane_masters
|
||||
// Ranges higher than one can be used to see through walls.
|
||||
var/cam_range = 1
|
||||
var/datum/movement_detector/tracker
|
||||
@@ -59,38 +61,19 @@
|
||||
/obj/item/clothing/accessory/spy_bug/Initialize(mapload)
|
||||
. = ..()
|
||||
tracker = new /datum/movement_detector(src, CALLBACK(src, .proc/update_view))
|
||||
|
||||
cam_screen = new
|
||||
cam_screen.name = "screen"
|
||||
cam_screen.assigned_map = "spypopup_map"
|
||||
cam_screen.del_on_map_removal = FALSE
|
||||
cam_screen.set_position(1, 1)
|
||||
|
||||
// We need to add planesmasters to the popup, otherwise
|
||||
// blending fucks up massively. Any planesmaster on the main screen does
|
||||
// NOT apply to map popups. If there's ever a way to make planesmasters
|
||||
// omnipresent, then this wouldn't be needed.
|
||||
cam_plane_masters = list()
|
||||
for(var/plane in subtypesof(/atom/movable/screen/plane_master) - /atom/movable/screen/plane_master/blackness)
|
||||
var/atom/movable/screen/plane_master/instance = new plane()
|
||||
if(instance.blend_mode_override)
|
||||
instance.blend_mode = instance.blend_mode_override
|
||||
instance.assigned_map = "spypopup_map"
|
||||
instance.del_on_map_removal = FALSE
|
||||
instance.screen_loc = "spypopup_map:CENTER"
|
||||
cam_plane_masters += instance
|
||||
cam_screen.generate_view("spypopup_map")
|
||||
|
||||
/obj/item/clothing/accessory/spy_bug/Destroy()
|
||||
if(linked_glasses)
|
||||
linked_glasses.linked_bug = null
|
||||
QDEL_NULL(cam_screen)
|
||||
QDEL_LIST(cam_plane_masters)
|
||||
QDEL_NULL(tracker)
|
||||
. = ..()
|
||||
|
||||
/obj/item/clothing/accessory/spy_bug/proc/update_view()//this doesn't do anything too crazy, just updates the vis_contents of its screen obj
|
||||
cam_screen.vis_contents.Cut()
|
||||
for(var/turf/visible_turf in view(1,get_turf(src)))//fuck you usr
|
||||
for(var/turf/visible_turf in view(cam_range, get_turf(src)))//fuck you usr
|
||||
cam_screen.vis_contents += visible_turf
|
||||
|
||||
//it needs to be linked, hence a kit.
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
name = fried.name //We'll determine the other stuff when it's actually removed
|
||||
appearance = fried.appearance
|
||||
layer = initial(layer)
|
||||
plane = initial(plane)
|
||||
SET_PLANE_IMPLICIT(src, initial(plane))
|
||||
lefthand_file = fried.lefthand_file
|
||||
righthand_file = fried.righthand_file
|
||||
inhand_icon_state = fried.inhand_icon_state
|
||||
|
||||
@@ -205,7 +205,7 @@
|
||||
if(!light_list[i])
|
||||
continue
|
||||
var/mutable_appearance/lit_image = mutable_appearance('icons/obj/puzzle_small.dmi', "light_lit")
|
||||
var/mutable_appearance/emissive_image = emissive_appearance('icons/obj/puzzle_small.dmi', "light_lit")
|
||||
var/mutable_appearance/emissive_image = emissive_appearance('icons/obj/puzzle_small.dmi', "light_lit", src)
|
||||
lit_image.pixel_x = 8 * ((i % 3 || 3 ) - 1)
|
||||
lit_image.pixel_y = -8 * (ROUND_UP(i / 3) - 1)
|
||||
emissive_image.pixel_x = lit_image.pixel_x
|
||||
|
||||
@@ -374,7 +374,7 @@
|
||||
var/mutable_appearance/neon_overlay = mutable_appearance(neon_icon || icon, neon_icon_state || icon_state, alpha = alpha)
|
||||
neon_overlay.color = neon_color
|
||||
. += neon_overlay
|
||||
. += emissive_appearance(neon_icon || icon, neon_icon_state || icon_state, alpha = emissive_alpha)
|
||||
. += emissive_appearance(neon_icon || icon, neon_icon_state || icon_state, src, alpha = emissive_alpha)
|
||||
|
||||
/obj/item/stack/tile/carpet/neon/worn_overlays(mutable_appearance/standing, isinhands, icon_file)
|
||||
. = ..()
|
||||
@@ -384,7 +384,7 @@
|
||||
var/mutable_appearance/neon_overlay = mutable_appearance(icon_file, neon_inhand_icon_state)
|
||||
neon_overlay.color = neon_color
|
||||
. += neon_overlay
|
||||
. += emissive_appearance(icon_file, neon_inhand_icon_state, alpha = emissive_alpha)
|
||||
. += emissive_appearance(icon_file, neon_inhand_icon_state, src, alpha = emissive_alpha)
|
||||
|
||||
/obj/item/stack/tile/carpet/neon/simple
|
||||
name = "simple neon carpet"
|
||||
@@ -1158,11 +1158,11 @@
|
||||
|
||||
/obj/item/stack/tile/emissive_test/update_overlays()
|
||||
. = ..()
|
||||
. += emissive_appearance(icon, icon_state, alpha = alpha)
|
||||
. += emissive_appearance(icon, icon_state, src, alpha = alpha)
|
||||
|
||||
/obj/item/stack/tile/emissive_test/worn_overlays(mutable_appearance/standing, isinhands, icon_file)
|
||||
. = ..()
|
||||
. += emissive_appearance(standing.icon, standing.icon_state, alpha = standing.alpha)
|
||||
. += emissive_appearance(standing.icon, standing.icon_state, src, alpha = standing.alpha)
|
||||
|
||||
/obj/item/stack/tile/emissive_test/sixty
|
||||
amount = 60
|
||||
|
||||
@@ -103,7 +103,7 @@ GLOBAL_LIST_EMPTY(tcgcard_radial_choices)
|
||||
/obj/item/tcgcard/update_desc(updates)
|
||||
. = ..()
|
||||
if(!flipped)
|
||||
var/datum/card/template = SStrading_card_game.cached_cards[series]["ALL"][id]
|
||||
var/datum/card/template = extract_datum()
|
||||
desc = "<i>[template.desc]</i>"
|
||||
else
|
||||
desc = "It's the back of a trading card... no peeking!"
|
||||
@@ -113,7 +113,9 @@ GLOBAL_LIST_EMPTY(tcgcard_radial_choices)
|
||||
icon_state = "cardback"
|
||||
return ..()
|
||||
|
||||
var/datum/card/template = SStrading_card_game.cached_cards[series]["ALL"][id]
|
||||
var/datum/card/template = extract_datum()
|
||||
if(!template)
|
||||
return
|
||||
icon_state = template.icon_state
|
||||
return ..()
|
||||
|
||||
|
||||
@@ -129,9 +129,9 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
|
||||
/obj/item/claymore/highlander/process()
|
||||
if(ishuman(loc))
|
||||
var/mob/living/carbon/human/H = loc
|
||||
loc.plane = GAME_PLANE_UPPER_FOV_HIDDEN //NO HIDING BEHIND PLANTS FOR YOU, DICKWEED (HA GET IT, BECAUSE WEEDS ARE PLANTS)
|
||||
ADD_TRAIT(H, TRAIT_NOBLEED, HIGHLANDER_TRAIT) //AND WE WON'T BLEED OUT LIKE COWARDS
|
||||
var/mob/living/carbon/human/holder = loc
|
||||
SET_PLANE_EXPLICIT(holder, GAME_PLANE_UPPER_FOV_HIDDEN, src) //NO HIDING BEHIND PLANTS FOR YOU, DICKWEED (HA GET IT, BECAUSE WEEDS ARE PLANTS)
|
||||
ADD_TRAIT(holder, TRAIT_NOBLEED, HIGHLANDER_TRAIT) //AND WE WON'T BLEED OUT LIKE COWARDS
|
||||
else
|
||||
if(!(flags_1 & ADMIN_SPAWNED_1))
|
||||
qdel(src)
|
||||
@@ -245,7 +245,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
/obj/item/claymore/highlander/robot/process()
|
||||
loc.plane = GAME_PLANE_UPPER_FOV_HIDDEN
|
||||
SET_PLANE_IMPLICIT(loc, GAME_PLANE_UPPER_FOV_HIDDEN)
|
||||
|
||||
/obj/item/katana
|
||||
name = "katana"
|
||||
|
||||
@@ -30,8 +30,6 @@
|
||||
|
||||
var/drag_slowdown // Amont of multiplicative slowdown applied if pulled. >1 makes you slower, <1 makes you faster.
|
||||
|
||||
vis_flags = VIS_INHERIT_PLANE //when this be added to vis_contents of something it inherit something.plane, important for visualisation of obj in openspace.
|
||||
|
||||
/// Map tag for something. Tired of it being used on snowflake items. Moved here for some semblance of a standard.
|
||||
/// Next pr after the network fix will have me refactor door interactions, so help me god.
|
||||
var/id_tag = null
|
||||
|
||||
@@ -114,10 +114,10 @@
|
||||
/obj/structure/chair/proc/handle_layer()
|
||||
if(has_buckled_mobs() && dir == NORTH)
|
||||
layer = ABOVE_MOB_LAYER
|
||||
plane = GAME_PLANE_UPPER
|
||||
SET_PLANE_IMPLICIT(src, GAME_PLANE_UPPER_FOV_HIDDEN)
|
||||
else
|
||||
layer = OBJ_LAYER
|
||||
plane = GAME_PLANE
|
||||
SET_PLANE_IMPLICIT(src, GAME_PLANE)
|
||||
|
||||
/obj/structure/chair/post_buckle_mob(mob/living/M)
|
||||
. = ..()
|
||||
@@ -175,10 +175,22 @@
|
||||
var/mutable_appearance/armrest
|
||||
|
||||
/obj/structure/chair/comfy/Initialize(mapload)
|
||||
gen_armrest()
|
||||
return ..()
|
||||
|
||||
/obj/structure/chair/comfy/on_changed_z_level(turf/old_turf, turf/new_turf, same_z_layer, notify_contents)
|
||||
if(same_z_layer)
|
||||
return ..()
|
||||
cut_overlay(armrest)
|
||||
QDEL_NULL(armrest)
|
||||
gen_armrest()
|
||||
return ..()
|
||||
|
||||
/obj/structure/chair/comfy/proc/gen_armrest()
|
||||
armrest = GetArmrest()
|
||||
armrest.layer = ABOVE_MOB_LAYER
|
||||
armrest.plane = GAME_PLANE_UPPER
|
||||
return ..()
|
||||
SET_PLANE_EXPLICIT(armrest, GAME_PLANE_UPPER, src)
|
||||
update_armrest()
|
||||
|
||||
/obj/structure/chair/comfy/proc/GetArmrest()
|
||||
return mutable_appearance(icon, "[icon_state]_armrest")
|
||||
|
||||
@@ -19,10 +19,23 @@
|
||||
var/mutable_appearance/leftpewarmrest
|
||||
|
||||
/obj/structure/chair/pew/left/Initialize(mapload)
|
||||
gen_armrest()
|
||||
return ..()
|
||||
|
||||
/obj/structure/chair/pew/left/on_changed_z_level(turf/old_turf, turf/new_turf, same_z_layer, notify_contents)
|
||||
if(same_z_layer)
|
||||
return ..()
|
||||
cut_overlay(leftpewarmrest)
|
||||
QDEL_NULL(leftpewarmrest)
|
||||
gen_armrest()
|
||||
return ..()
|
||||
|
||||
/obj/structure/chair/pew/left/proc/gen_armrest()
|
||||
leftpewarmrest = GetLeftPewArmrest()
|
||||
leftpewarmrest.layer = ABOVE_MOB_LAYER
|
||||
leftpewarmrest.plane = GAME_PLANE_UPPER
|
||||
return ..()
|
||||
SET_PLANE_EXPLICIT(leftpewarmrest, GAME_PLANE_UPPER, src)
|
||||
update_leftpewarmrest()
|
||||
|
||||
|
||||
/obj/structure/chair/pew/left/proc/GetLeftPewArmrest()
|
||||
return mutable_appearance('icons/obj/sofa.dmi', "pewend_left_armrest")
|
||||
@@ -51,10 +64,20 @@
|
||||
var/mutable_appearance/rightpewarmrest
|
||||
|
||||
/obj/structure/chair/pew/right/Initialize(mapload)
|
||||
gen_armrest()
|
||||
return ..()
|
||||
|
||||
/obj/structure/chair/pew/right/on_changed_z_level(turf/old_turf, turf/new_turf, same_z_layer, notify_contents)
|
||||
cut_overlay(rightpewarmrest)
|
||||
QDEL_NULL(rightpewarmrest)
|
||||
gen_armrest()
|
||||
return ..()
|
||||
|
||||
/obj/structure/chair/pew/right/proc/gen_armrest()
|
||||
rightpewarmrest = GetRightPewArmrest()
|
||||
rightpewarmrest.layer = ABOVE_MOB_LAYER
|
||||
rightpewarmrest.plane = GAME_PLANE_UPPER
|
||||
return ..()
|
||||
SET_PLANE_EXPLICIT(rightpewarmrest, GAME_PLANE_UPPER, src)
|
||||
update_rightpewarmrest()
|
||||
|
||||
/obj/structure/chair/pew/right/proc/GetRightPewArmrest()
|
||||
return mutable_appearance('icons/obj/sofa.dmi', "pewend_right_armrest")
|
||||
|
||||
@@ -8,10 +8,22 @@
|
||||
|
||||
/obj/structure/chair/sofa/Initialize(mapload)
|
||||
. = ..()
|
||||
armrest = mutable_appearance(initial(icon), "[icon_state]_armrest", ABOVE_MOB_LAYER)
|
||||
armrest.plane = GAME_PLANE_UPPER
|
||||
gen_armrest()
|
||||
AddElement(/datum/element/soft_landing)
|
||||
|
||||
/obj/structure/chair/sofa/on_changed_z_level(turf/old_turf, turf/new_turf, same_z_layer, notify_contents)
|
||||
if(same_z_layer)
|
||||
return ..()
|
||||
cut_overlay(armrest)
|
||||
QDEL_NULL(armrest)
|
||||
gen_armrest()
|
||||
return ..()
|
||||
|
||||
/obj/structure/chair/sofa/proc/gen_armrest()
|
||||
armrest = mutable_appearance(initial(icon), "[icon_state]_armrest", ABOVE_MOB_LAYER)
|
||||
SET_PLANE_EXPLICIT(armrest, GAME_PLANE_UPPER, src)
|
||||
update_armrest()
|
||||
|
||||
/obj/structure/chair/sofa/electrify_self(obj/item/assembly/shock_kit/input_shock_kit, mob/user, list/overlays_from_child_procs)
|
||||
if(!overlays_from_child_procs)
|
||||
overlays_from_child_procs = list(image('icons/obj/chairs.dmi', loc, "echair_over", pixel_x = -1))
|
||||
|
||||
@@ -45,13 +45,13 @@ LINEN BINS
|
||||
return
|
||||
if(layer == initial(layer))
|
||||
layer = ABOVE_MOB_LAYER
|
||||
plane = GAME_PLANE_UPPER
|
||||
SET_PLANE_IMPLICIT(src, GAME_PLANE_UPPER)
|
||||
to_chat(user, span_notice("You cover yourself with [src]."))
|
||||
pixel_x = 0
|
||||
pixel_y = 0
|
||||
else
|
||||
layer = initial(layer)
|
||||
plane = initial(plane)
|
||||
SET_PLANE_IMPLICIT(src, initial(plane))
|
||||
to_chat(user, span_notice("You smooth [src] out beneath you."))
|
||||
if(user.body_position == LYING_DOWN) //The player isn't laying down currently
|
||||
dir = user.dir
|
||||
|
||||
@@ -120,7 +120,7 @@
|
||||
if(opened && has_opened_overlay)
|
||||
var/mutable_appearance/door_overlay = mutable_appearance(icon, "[icon_state]_open", alpha = src.alpha)
|
||||
. += door_overlay
|
||||
door_overlay.overlays += emissive_blocker(door_overlay.icon, door_overlay.icon_state, alpha = door_overlay.alpha) // If we don't do this the door doesn't block emissives and it looks weird.
|
||||
door_overlay.overlays += emissive_blocker(door_overlay.icon, door_overlay.icon_state, src, alpha = door_overlay.alpha) // If we don't do this the door doesn't block emissives and it looks weird.
|
||||
else if(has_closed_overlay)
|
||||
. += "[icon_door || icon_state]_door"
|
||||
|
||||
@@ -133,7 +133,7 @@
|
||||
if(broken || !secure)
|
||||
return
|
||||
//Overlay is similar enough for both that we can use the same mask for both
|
||||
. += emissive_appearance(icon, "locked", alpha = src.alpha)
|
||||
. += emissive_appearance(icon, "locked", src, alpha = src.alpha)
|
||||
. += locked ? "locked" : "unlocked"
|
||||
|
||||
/obj/structure/closet/vv_edit_var(vname, vval)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user